2 * Interface to the capstone disassembler.
3 * SPDX-License-Identifier: GPL-2.0-or-later
6 #include "qemu/osdep.h"
7 #include "qemu/bswap.h"
8 #include "disas/dis-asm.h"
9 #include "disas/capstone.h"
13 * Temporary storage for the capstone library. This will be alloced via
14 * malloc with a size private to the library; thus there's no reason not
15 * to share this across calls and across host vs target disassembly.
17 static __thread cs_insn
*cap_insn
;
20 * The capstone library always skips 2 bytes for S390X.
21 * This is less than ideal, since we can tell from the first two bits
22 * the size of the insn and thus stay in sync with the insn stream.
24 static size_t CAPSTONE_API
25 cap_skipdata_s390x_cb(const uint8_t *code
, size_t code_size
,
26 size_t offset
, void *user_data
)
30 /* See get_ilen() in target/s390x/internal.h. */
31 switch (code
[offset
] >> 6) {
47 static const cs_opt_skipdata cap_skipdata_s390x
= {
49 .callback
= cap_skipdata_s390x_cb
53 * Initialize the Capstone library.
55 * ??? It would be nice to cache this. We would need one handle for the
56 * host and one for the target. For most targets we can reset specific
57 * parameters via cs_option(CS_OPT_MODE, new_mode), but we cannot change
58 * CS_ARCH_* in this way. Thus we would need to be able to close and
59 * re-open the target handle with a different arch for the target in order
60 * to handle AArch64 vs AArch32 mode switching.
62 static cs_err
cap_disas_start(disassemble_info
*info
, csh
*handle
)
64 cs_mode cap_mode
= info
->cap_mode
;
67 cap_mode
+= (info
->endian
== BFD_ENDIAN_BIG
? CS_MODE_BIG_ENDIAN
68 : CS_MODE_LITTLE_ENDIAN
);
70 err
= cs_open(info
->cap_arch
, cap_mode
, handle
);
71 if (err
!= CS_ERR_OK
) {
75 /* "Disassemble" unknown insns as ".byte W,X,Y,Z". */
76 cs_option(*handle
, CS_OPT_SKIPDATA
, CS_OPT_ON
);
78 switch (info
->cap_arch
) {
80 cs_option(*handle
, CS_OPT_SKIPDATA_SETUP
,
81 (uintptr_t)&cap_skipdata_s390x
);
86 * We don't care about errors (if for some reason the library
87 * is compiled without AT&T syntax); the user will just have
88 * to deal with the Intel syntax.
90 cs_option(*handle
, CS_OPT_SYNTAX
, CS_OPT_SYNTAX_ATT
);
94 /* Allocate temp space for cs_disasm_iter. */
95 if (cap_insn
== NULL
) {
96 cap_insn
= cs_malloc(*handle
);
97 if (cap_insn
== NULL
) {
105 static void cap_dump_insn_units(disassemble_info
*info
, cs_insn
*insn
,
108 fprintf_function print
= info
->fprintf_func
;
109 FILE *stream
= info
->stream
;
111 switch (info
->cap_insn_unit
) {
113 if (info
->endian
== BFD_ENDIAN_BIG
) {
114 for (; i
< n
; i
+= 4) {
115 print(stream
, " %08x", ldl_be_p(insn
->bytes
+ i
));
119 for (; i
< n
; i
+= 4) {
120 print(stream
, " %08x", ldl_le_p(insn
->bytes
+ i
));
126 if (info
->endian
== BFD_ENDIAN_BIG
) {
127 for (; i
< n
; i
+= 2) {
128 print(stream
, " %04x", lduw_be_p(insn
->bytes
+ i
));
131 for (; i
< n
; i
+= 2) {
132 print(stream
, " %04x", lduw_le_p(insn
->bytes
+ i
));
139 print(stream
, " %02x", insn
->bytes
[i
]);
145 static void cap_dump_insn(disassemble_info
*info
, cs_insn
*insn
)
147 fprintf_function print
= info
->fprintf_func
;
148 FILE *stream
= info
->stream
;
151 print(stream
, "0x%08" PRIx64
": ", insn
->address
);
154 split
= info
->cap_insn_split
;
156 /* Dump the first SPLIT bytes of the instruction. */
157 cap_dump_insn_units(info
, insn
, 0, MIN(n
, split
));
159 /* Add padding up to SPLIT so that mnemonics line up. */
161 int width
= (split
- n
) / info
->cap_insn_unit
;
162 width
*= (2 * info
->cap_insn_unit
+ 1);
163 print(stream
, "%*s", width
, "");
166 /* Print the actual instruction. */
167 print(stream
, " %-8s %s\n", insn
->mnemonic
, insn
->op_str
);
169 /* Dump any remaining part of the insn on subsequent lines. */
170 for (i
= split
; i
< n
; i
+= split
) {
171 print(stream
, "0x%08" PRIx64
": ", insn
->address
+ i
);
172 cap_dump_insn_units(info
, insn
, i
, MIN(n
, i
+ split
));
177 /* Disassemble SIZE bytes at PC for the target. */
178 bool cap_disas_target(disassemble_info
*info
, uint64_t pc
, size_t size
)
180 uint8_t cap_buf
[1024];
185 if (cap_disas_start(info
, &handle
) != CS_ERR_OK
) {
191 size_t tsize
= MIN(sizeof(cap_buf
) - csize
, size
);
192 const uint8_t *cbuf
= cap_buf
;
194 info
->read_memory_func(pc
+ csize
, cap_buf
+ csize
, tsize
, info
);
198 while (cs_disasm_iter(handle
, &cbuf
, &csize
, &pc
, insn
)) {
199 cap_dump_insn(info
, insn
);
202 /* If the target memory is not consumed, go back for more... */
205 * ... taking care to move any remaining fractional insn
206 * to the beginning of the buffer.
209 memmove(cap_buf
, cbuf
, csize
);
215 * Since the target memory is consumed, we should not have
216 * a remaining fractional insn.
219 info
->fprintf_func(info
->stream
,
220 "Disassembler disagrees with translator "
221 "over instruction decoding\n"
222 "Please report this to qemu-devel@nongnu.org\n");
231 /* Disassemble SIZE bytes at CODE for the host. */
232 bool cap_disas_host(disassemble_info
*info
, void *code
, size_t size
)
239 if (cap_disas_start(info
, &handle
) != CS_ERR_OK
) {
245 pc
= (uintptr_t)code
;
247 while (cs_disasm_iter(handle
, &cbuf
, &size
, &pc
, insn
)) {
248 cap_dump_insn(info
, insn
);
251 info
->fprintf_func(info
->stream
,
252 "Disassembler disagrees with TCG over instruction encoding\n"
253 "Please report this to qemu-devel@nongnu.org\n");
260 /* Disassemble COUNT insns at PC for the target. */
261 bool cap_disas_monitor(disassemble_info
*info
, uint64_t pc
, int count
)
268 if (cap_disas_start(info
, &handle
) != CS_ERR_OK
) {
275 * We want to read memory for one insn, but generically we do not
276 * know how much memory that is. We have a small buffer which is
277 * known to be sufficient for all supported targets. Try to not
278 * read beyond the page, Just In Case. For even more simplicity,
279 * ignore the actual target page size and use a 1k boundary. If
280 * that turns out to be insufficient, we'll come back around the
281 * loop and read more.
283 uint64_t epc
= QEMU_ALIGN_UP(pc
+ csize
+ 1, 1024);
284 size_t tsize
= MIN(sizeof(cap_buf
) - csize
, epc
- pc
);
285 const uint8_t *cbuf
= cap_buf
;
287 /* Make certain that we can make progress. */
289 info
->read_memory_func(pc
, cap_buf
+ csize
, tsize
, info
);
292 if (cs_disasm_iter(handle
, &cbuf
, &csize
, &pc
, insn
)) {
293 cap_dump_insn(info
, insn
);
298 memmove(cap_buf
, cbuf
, csize
);
305 /* Disassemble a single instruction directly into plugin output */
306 bool cap_disas_plugin(disassemble_info
*info
, uint64_t pc
, size_t size
)
309 const uint8_t *cbuf
= cap_buf
;
312 if (cap_disas_start(info
, &handle
) != CS_ERR_OK
) {
316 assert(size
< sizeof(cap_buf
));
317 info
->read_memory_func(pc
, cap_buf
, size
, info
);
319 if (cs_disasm_iter(handle
, &cbuf
, &size
, &pc
, cap_insn
)) {
320 info
->fprintf_func(info
->stream
, "%s %s",
321 cap_insn
->mnemonic
, cap_insn
->op_str
);