[PATCH 3/9] target/riscv: Enable disassembly via capstone
Richard Henderson <[email protected]>
| Newsgroups | org.nongnu.qemu-devel,org.nongnu.qemu-riscv |
|---|---|
| Message-ID | <[email protected]> |
In capstone v5, riscv support is spare, but v6 is pretty good. Signed-off-by: Richard Henderson <[email protected]> --- include/disas/capstone.h | 34 +++++++++++++++++ disas/capstone.c | 19 ++++++++++ target/riscv/cpu.c | 81 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 133 insertions(+), 1 deletion(-) diff --git a/include/disas/capstone.h b/include/disas/capstone.h index c43033f7f6..5c78824da2 100644 --- a/include/disas/capstone.h +++ b/include/disas/capstone.h @@ -11,6 +11,8 @@ /* Just enough to allow backends to init without ifdefs. */ +#define CS_API_MAJOR 0 + #define CS_ARCH_ARM -1 #define CS_ARCH_ARM64 -1 #define CS_ARCH_MIPS -1 @@ -37,4 +39,36 @@ #define CS_MODE_MIPS64 0 #endif /* CONFIG_CAPSTONE */ + +#if CS_API_MAJOR < 5 +#define CS_ARCH_RISCV -1 +#define CS_MODE_RISCV32 0 +#define CS_MODE_RISCV64 0 +#define CS_MODE_RISCV_C 0 +#elif CS_API_MAJOR == 5 +/* The C symbol name changed between v5 and v6 */ +#define CS_MODE_RISCV_C CS_MODE_RISCVC +#endif +#if CS_API_MAJOR < 6 +#define CS_MODE_RISCV_FD 0 +#define CS_MODE_RISCV_V 0 +#define CS_MODE_RISCV_ZFINX 0 +#define CS_MODE_RISCV_ZCMP_ZCMT_ZCE 0 +#define CS_MODE_RISCV_ZICFISS 0 +#define CS_MODE_RISCV_E 0 +#define CS_MODE_RISCV_A 0 +#define CS_MODE_RISCV_COREV 0 +#define CS_MODE_RISCV_THEAD 0 +#define CS_MODE_RISCV_SIFIVE 0 +#define CS_MODE_RISCV_BITMANIP 0 +#define CS_MODE_RISCV_ZBA 0 +#define CS_MODE_RISCV_ZBB 0 +#define CS_MODE_RISCV_ZBC 0 +#define CS_MODE_RISCV_ZBKB 0 +#define CS_MODE_RISCV_ZBKC 0 +#define CS_MODE_RISCV_ZBKX 0 +#define CS_MODE_RISCV_ZBS 0 +#define CS_MODE_RISCV_VENTANA 0 +#endif + #endif /* QEMU_CAPSTONE_H */ diff --git a/disas/capstone.c b/disas/capstone.c index 8fb8d0724c..78062339d0 100644 --- a/disas/capstone.c +++ b/disas/capstone.c @@ -49,6 +49,20 @@ static const cs_opt_skipdata cap_skipdata_s390x = { .callback = cap_skipdata_s390x_cb }; +/* Similarly for RISCV */ +static size_t CAPSTONE_API +cap_skipdata_riscv_cb(const uint8_t *code, size_t code_size, + size_t offset, void *user_data) +{ + /* See insn_len() from target/riscv/internals.h */ + return (code[offset] & 3) == 3 ? 4 : 2; +} + +static const cs_opt_skipdata cap_skipdata_riscv = { + .mnemonic = ".byte", + .callback = cap_skipdata_riscv_cb +}; + /* * Initialize the Capstone library. * @@ -76,6 +90,11 @@ static cs_err cap_disas_start(disassemble_info *info, csh *handle) cs_option(*handle, CS_OPT_SKIPDATA, CS_OPT_ON); switch (info->cap_arch) { + case CS_ARCH_RISCV: + cs_option(*handle, CS_OPT_SKIPDATA_SETUP, + (uintptr_t)&cap_skipdata_riscv); + break; + case CS_ARCH_SYSZ: cs_option(*handle, CS_OPT_SKIPDATA_SETUP, (uintptr_t)&cap_skipdata_s390x); diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 5a82e6563b..a1a6c17b98 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -39,6 +39,7 @@ #include "system/tcg.h" #include "kvm/kvm_riscv.h" #include "tcg/tcg-cpu.h" +#include "disas/capstone.h" #if !defined(CONFIG_USER_ONLY) #include "target/riscv/tcg/debug.h" #endif @@ -1099,6 +1100,7 @@ static void riscv_cpu_disas_set_info(const CPUState *s, disassemble_info *info) { const RISCVCPU *cpu = RISCV_CPU(s); const CPURISCVState *env = &cpu->env; + int cap_mode; info->target_info = &cpu->cfg; @@ -1111,16 +1113,93 @@ static void riscv_cpu_disas_set_info(const CPUState *s, disassemble_info *info) switch (env->xl) { case MXL_RV32: info->print_insn = print_insn_riscv32; + cap_mode = CS_MODE_RISCV32; break; case MXL_RV64: info->print_insn = print_insn_riscv64; + cap_mode = CS_MODE_RISCV64; break; case MXL_RV128: info->print_insn = print_insn_riscv128; - break; + /* capstone v6 doesn't support RV128 */ + return; default: g_assert_not_reached(); } + + info->cap_arch = CS_ARCH_RISCV; + info->cap_insn_unit = 4; + info->cap_insn_split = 4; + + /* + * Capstone compresses some features together. See RISCV_getFeatureBits, + * which maps LLVM feature bits to capstone bits. + */ + if (riscv_has_ext(env, RVC) || cpu->cfg.ext_zca) { + cap_mode |= CS_MODE_RISCV_C; + } + if (riscv_has_ext(env, RVF)) { + cap_mode |= CS_MODE_RISCV_FD; + } + if (riscv_has_ext(env, RVV)) { + cap_mode |= CS_MODE_RISCV_V; + } + if (cpu->cfg.ext_zfinx || cpu->cfg.ext_zdinx || cpu->cfg.ext_zhinx) { + cap_mode |= CS_MODE_RISCV_ZFINX; + } + if (cpu->cfg.ext_zcmp || cpu->cfg.ext_zcmt || cpu->cfg.ext_zce) { + cap_mode |= CS_MODE_RISCV_ZCMP_ZCMT_ZCE; + } + if (cpu->cfg.ext_zicfiss) { + cap_mode |= CS_MODE_RISCV_ZICFISS; + } + if (riscv_has_ext(env, RVE)) { + cap_mode |= CS_MODE_RISCV_E; + } + if (riscv_has_ext(env, RVA)) { + cap_mode |= CS_MODE_RISCV_A; + } + if (cpu->cfg.ext_xlrbr) { + cap_mode |= CS_MODE_RISCV_BITMANIP; + } + if (cpu->cfg.ext_zba) { + cap_mode |= CS_MODE_RISCV_ZBA; + } + if (cpu->cfg.ext_zbb) { + cap_mode |= CS_MODE_RISCV_ZBB; + } + if (cpu->cfg.ext_zbc) { + cap_mode |= CS_MODE_RISCV_ZBC; + } + if (cpu->cfg.ext_zbkb) { + cap_mode |= CS_MODE_RISCV_ZBKB; + } + if (cpu->cfg.ext_zbkc) { + cap_mode |= CS_MODE_RISCV_ZBKC; + } + if (cpu->cfg.ext_zbkx) { + cap_mode |= CS_MODE_RISCV_ZBKX; + } + if (cpu->cfg.ext_zbs) { + cap_mode |= CS_MODE_RISCV_ZBS; + } + if (cpu->cfg.ext_xtheadba || + cpu->cfg.ext_xtheadbb || + cpu->cfg.ext_xtheadbs || + cpu->cfg.ext_xtheadcmo || + cpu->cfg.ext_xtheadcondmov || + cpu->cfg.ext_xtheadfmemidx || + cpu->cfg.ext_xtheadfmv || + cpu->cfg.ext_xtheadmac || + cpu->cfg.ext_xtheadmemidx || + cpu->cfg.ext_xtheadmempair || + cpu->cfg.ext_xtheadsync) { + cap_mode |= CS_MODE_RISCV_THEAD; + } + if (cpu->cfg.ext_XVentanaCondOps) { + cap_mode |= CS_MODE_RISCV_VENTANA; + } + info->cap_mode = cap_mode; } #ifndef CONFIG_USER_ONLY -- 2.43.0