target/riscv: Enable disassembly via capstone
In capstone v5, riscv support is spare, but v6 is pretty good. Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Richard Henderson committed
Aug 8, 2026 at 11:23 UTC
09d7b5d49ad6dff06c67ae61993fa5657f08dd7c
3 files changed
+133
-1
disas/capstone.c
+19
@@ -49,6 +49,20 @@ static const cs_opt_skipdata cap_skipdata_s390x = {
49
.callback = cap_skipdata_s390x_cb
50
};
51
52
+/* Similarly for RISCV */
53
+static size_t CAPSTONE_API
54
+cap_skipdata_riscv_cb(const uint8_t *code, size_t code_size,
55
+ size_t offset, void *user_data)
56
+{
57
+ /* See insn_len() from target/riscv/internals.h */
58
+ return (code[offset] & 3) == 3 ? 4 : 2;
59
+}
60
+
61
+static const cs_opt_skipdata cap_skipdata_riscv = {
62
+ .mnemonic = ".byte",
63
+ .callback = cap_skipdata_riscv_cb
64
+};
65
+
66
/*
67
* Initialize the Capstone library.
68
*
@@ -76,6 +90,11 @@ static cs_err cap_disas_start(disassemble_info *info, csh *handle)
90
cs_option(*handle, CS_OPT_SKIPDATA, CS_OPT_ON);
91
92
switch (info->cap_arch) {
93
+ case CS_ARCH_RISCV:
94
+ cs_option(*handle, CS_OPT_SKIPDATA_SETUP,
95
+ (uintptr_t)&cap_skipdata_riscv);
96
+ break;
97
+
98
case CS_ARCH_SYSZ:
99
cs_option(*handle, CS_OPT_SKIPDATA_SETUP,
100
(uintptr_t)&cap_skipdata_s390x);
include/disas/capstone.h
+34
@@ -11,6 +11,8 @@
11
12
/* Just enough to allow backends to init without ifdefs. */
13
14
+#define CS_API_MAJOR 0
15
+
16
#define CS_ARCH_ARM -1
17
#define CS_ARCH_ARM64 -1
18
#define CS_ARCH_MIPS -1
@@ -37,4 +39,36 @@
39
#define CS_MODE_MIPS64 0
40
41
#endif /* CONFIG_CAPSTONE */
42
+
43
+#if CS_API_MAJOR < 5
44
+#define CS_ARCH_RISCV -1
45
+#define CS_MODE_RISCV32 0
46
+#define CS_MODE_RISCV64 0
47
+#define CS_MODE_RISCV_C 0
48
+#elif CS_API_MAJOR == 5
49
+/* The C symbol name changed between v5 and v6 */
50
+#define CS_MODE_RISCV_C CS_MODE_RISCVC
51
+#endif
52
+#if CS_API_MAJOR < 6
53
+#define CS_MODE_RISCV_FD 0
54
+#define CS_MODE_RISCV_V 0
55
+#define CS_MODE_RISCV_ZFINX 0
56
+#define CS_MODE_RISCV_ZCMP_ZCMT_ZCE 0
57
+#define CS_MODE_RISCV_ZICFISS 0
58
+#define CS_MODE_RISCV_E 0
59
+#define CS_MODE_RISCV_A 0
60
+#define CS_MODE_RISCV_COREV 0
61
+#define CS_MODE_RISCV_THEAD 0
62
+#define CS_MODE_RISCV_SIFIVE 0
63
+#define CS_MODE_RISCV_BITMANIP 0
64
+#define CS_MODE_RISCV_ZBA 0
65
+#define CS_MODE_RISCV_ZBB 0
66
+#define CS_MODE_RISCV_ZBC 0
67
+#define CS_MODE_RISCV_ZBKB 0
68
+#define CS_MODE_RISCV_ZBKC 0
69
+#define CS_MODE_RISCV_ZBKX 0
70
+#define CS_MODE_RISCV_ZBS 0
71
+#define CS_MODE_RISCV_VENTANA 0
72
+#endif
73
+
74
#endif /* QEMU_CAPSTONE_H */
target/riscv/cpu.c
+80
-1
@@ -39,6 +39,7 @@
39
#include "system/tcg.h"
40
#include "kvm/kvm_riscv.h"
41
#include "tcg/tcg-cpu.h"
42
+#include "disas/capstone.h"
43
#if !defined(CONFIG_USER_ONLY)
44
#include "target/riscv/tcg/debug.h"
45
#endif
@@ -1099,6 +1100,7 @@ static void riscv_cpu_disas_set_info(const CPUState *s, disassemble_info *info)
1100
{
1101
const RISCVCPU *cpu = RISCV_CPU(s);
1102
const CPURISCVState *env = &cpu->env;
1103
+ int cap_mode;
1104
1105
info->target_info = &cpu->cfg;
1106
@@ -1111,16 +1113,93 @@ static void riscv_cpu_disas_set_info(const CPUState *s, disassemble_info *info)
1113
switch (env->xl) {
1114
case MXL_RV32:
1115
info->print_insn = print_insn_riscv32;
1116
+ cap_mode = CS_MODE_RISCV32;
1117
break;
1118
case MXL_RV64:
1119
info->print_insn = print_insn_riscv64;
1120
+ cap_mode = CS_MODE_RISCV64;
1121
break;
1122
case MXL_RV128:
1123
info->print_insn = print_insn_riscv128;
1120
- break;
1124
+ /* capstone v6 doesn't support RV128 */
1125
+ return;
1126
default:
1127
g_assert_not_reached();
1128
}
1129
+
1130
+ info->cap_arch = CS_ARCH_RISCV;
1131
+ info->cap_insn_unit = 4;
1132
+ info->cap_insn_split = 4;
1133
+
1134
+ /*
1135
+ * Capstone compresses some features together. See RISCV_getFeatureBits,
1136
+ * which maps LLVM feature bits to capstone bits.
1137
+ */
1138
+ if (riscv_has_ext(env, RVC) || cpu->cfg.ext_zca) {
1139
+ cap_mode |= CS_MODE_RISCV_C;
1140
+ }
1141
+ if (riscv_has_ext(env, RVF)) {
1142
+ cap_mode |= CS_MODE_RISCV_FD;
1143
+ }
1144
+ if (riscv_has_ext(env, RVV)) {
1145
+ cap_mode |= CS_MODE_RISCV_V;
1146
+ }
1147
+ if (cpu->cfg.ext_zfinx || cpu->cfg.ext_zdinx || cpu->cfg.ext_zhinx) {
1148
+ cap_mode |= CS_MODE_RISCV_ZFINX;
1149
+ }
1150
+ if (cpu->cfg.ext_zcmp || cpu->cfg.ext_zcmt || cpu->cfg.ext_zce) {
1151
+ cap_mode |= CS_MODE_RISCV_ZCMP_ZCMT_ZCE;
1152
+ }
1153
+ if (cpu->cfg.ext_zicfiss) {
1154
+ cap_mode |= CS_MODE_RISCV_ZICFISS;
1155
+ }
1156
+ if (riscv_has_ext(env, RVE)) {
1157
+ cap_mode |= CS_MODE_RISCV_E;
1158
+ }
1159
+ if (riscv_has_ext(env, RVA)) {
1160
+ cap_mode |= CS_MODE_RISCV_A;
1161
+ }
1162
+ if (cpu->cfg.ext_xlrbr) {
1163
+ cap_mode |= CS_MODE_RISCV_BITMANIP;
1164
+ }
1165
+ if (cpu->cfg.ext_zba) {
1166
+ cap_mode |= CS_MODE_RISCV_ZBA;
1167
+ }
1168
+ if (cpu->cfg.ext_zbb) {
1169
+ cap_mode |= CS_MODE_RISCV_ZBB;
1170
+ }
1171
+ if (cpu->cfg.ext_zbc) {
1172
+ cap_mode |= CS_MODE_RISCV_ZBC;
1173
+ }
1174
+ if (cpu->cfg.ext_zbkb) {
1175
+ cap_mode |= CS_MODE_RISCV_ZBKB;
1176
+ }
1177
+ if (cpu->cfg.ext_zbkc) {
1178
+ cap_mode |= CS_MODE_RISCV_ZBKC;
1179
+ }
1180
+ if (cpu->cfg.ext_zbkx) {
1181
+ cap_mode |= CS_MODE_RISCV_ZBKX;
1182
+ }
1183
+ if (cpu->cfg.ext_zbs) {
1184
+ cap_mode |= CS_MODE_RISCV_ZBS;
1185
+ }
1186
+ if (cpu->cfg.ext_xtheadba ||
1187
+ cpu->cfg.ext_xtheadbb ||
1188
+ cpu->cfg.ext_xtheadbs ||
1189
+ cpu->cfg.ext_xtheadcmo ||
1190
+ cpu->cfg.ext_xtheadcondmov ||
1191
+ cpu->cfg.ext_xtheadfmemidx ||
1192
+ cpu->cfg.ext_xtheadfmv ||
1193
+ cpu->cfg.ext_xtheadmac ||
1194
+ cpu->cfg.ext_xtheadmemidx ||
1195
+ cpu->cfg.ext_xtheadmempair ||
1196
+ cpu->cfg.ext_xtheadsync) {
1197
+ cap_mode |= CS_MODE_RISCV_THEAD;
1198
+ }
1199
+ if (cpu->cfg.ext_XVentanaCondOps) {
1200
+ cap_mode |= CS_MODE_RISCV_VENTANA;
1201
+ }
1202
+ info->cap_mode = cap_mode;
1203
}
1204
1205
#ifndef CONFIG_USER_ONLY