blob: 41ad0102e2b61d5892a3158d2cf0c35d7c8d758d [file] [log] [blame]
bellardb9adb4a2003-04-29 20:41:16 +00001/* General "disassemble this chunk" code. Used for debugging. */
Peter Maydelld38ea872016-01-29 17:50:05 +00002#include "qemu/osdep.h"
Peter Crosthwaite37b9de42015-06-23 20:57:33 -07003#include "qemu-common.h"
Markus Armbruster3979fca2019-04-17 21:18:04 +02004#include "disas/dis-asm.h"
bellardb9adb4a2003-04-29 20:41:16 +00005#include "elf.h"
Markus Armbruster30cc9832019-04-17 21:18:03 +02006#include "qemu/qemu-print.h"
bellardb9adb4a2003-04-29 20:41:16 +00007
bellardc6105c02003-10-27 21:13:58 +00008#include "cpu.h"
Paolo Bonzini76cad712012-10-24 11:12:21 +02009#include "disas/disas.h"
Richard Henderson8ca80762017-09-14 09:41:12 -070010#include "disas/capstone.h"
bellardc6105c02003-10-27 21:13:58 +000011
Blue Swirlf4359b92012-09-08 12:40:00 +000012typedef struct CPUDebug {
13 struct disassemble_info info;
Peter Crosthwaited49190c2015-05-24 14:20:41 -070014 CPUState *cpu;
Blue Swirlf4359b92012-09-08 12:40:00 +000015} CPUDebug;
16
bellardb9adb4a2003-04-29 20:41:16 +000017/* Filled in by elfload.c. Simplistic, but will do for now. */
bellarde80cfcf2004-12-19 23:18:01 +000018struct syminfo *syminfos = NULL;
bellardb9adb4a2003-04-29 20:41:16 +000019
bellardaa0aa4f2003-06-09 15:23:31 +000020/* Get LENGTH bytes from info's buffer, at target address memaddr.
21 Transfer them to myaddr. */
22int
pbrook3a742b72008-10-22 15:55:18 +000023buffer_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
24 struct disassemble_info *info)
bellardaa0aa4f2003-06-09 15:23:31 +000025{
bellardc6105c02003-10-27 21:13:58 +000026 if (memaddr < info->buffer_vma
27 || memaddr + length > info->buffer_vma + info->buffer_length)
28 /* Out of bounds. Use EIO because GDB uses it. */
29 return EIO;
30 memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
31 return 0;
bellardaa0aa4f2003-06-09 15:23:31 +000032}
33
bellardc6105c02003-10-27 21:13:58 +000034/* Get LENGTH bytes from info's buffer, at target address memaddr.
35 Transfer them to myaddr. */
36static int
bellardc27004e2005-01-03 23:35:10 +000037target_read_memory (bfd_vma memaddr,
38 bfd_byte *myaddr,
39 int length,
40 struct disassemble_info *info)
bellardc6105c02003-10-27 21:13:58 +000041{
Blue Swirlf4359b92012-09-08 12:40:00 +000042 CPUDebug *s = container_of(info, CPUDebug, info);
43
Peter Crosthwaited49190c2015-05-24 14:20:41 -070044 cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, 0);
bellardc6105c02003-10-27 21:13:58 +000045 return 0;
46}
bellardc6105c02003-10-27 21:13:58 +000047
bellardaa0aa4f2003-06-09 15:23:31 +000048/* Print an error message. We can assume that this is in response to
49 an error return from buffer_read_memory. */
50void
pbrook3a742b72008-10-22 15:55:18 +000051perror_memory (int status, bfd_vma memaddr, struct disassemble_info *info)
bellardaa0aa4f2003-06-09 15:23:31 +000052{
53 if (status != EIO)
54 /* Can't happen. */
55 (*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
56 else
57 /* Actually, address between memaddr and memaddr + len was
58 out of bounds. */
59 (*info->fprintf_func) (info->stream,
bellard26a76462006-06-25 18:15:32 +000060 "Address 0x%" PRIx64 " is out of bounds.\n", memaddr);
bellardaa0aa4f2003-06-09 15:23:31 +000061}
62
Jim Meyeringa31f0532012-05-09 05:12:04 +000063/* This could be in a separate file, to save minuscule amounts of space
bellardaa0aa4f2003-06-09 15:23:31 +000064 in statically linked executables. */
65
66/* Just print the address is hex. This is included for completeness even
67 though both GDB and objdump provide their own (to print symbolic
68 addresses). */
69
70void
pbrook3a742b72008-10-22 15:55:18 +000071generic_print_address (bfd_vma addr, struct disassemble_info *info)
bellardaa0aa4f2003-06-09 15:23:31 +000072{
bellard26a76462006-06-25 18:15:32 +000073 (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr);
bellardaa0aa4f2003-06-09 15:23:31 +000074}
75
Peter Maydell636bd282012-06-25 04:55:55 +000076/* Print address in hex, truncated to the width of a host virtual address. */
77static void
78generic_print_host_address(bfd_vma addr, struct disassemble_info *info)
79{
80 uint64_t mask = ~0ULL >> (64 - (sizeof(void *) * 8));
81 generic_print_address(addr & mask, info);
82}
83
bellardaa0aa4f2003-06-09 15:23:31 +000084/* Just return the given address. */
85
86int
pbrook3a742b72008-10-22 15:55:18 +000087generic_symbol_at_address (bfd_vma addr, struct disassemble_info *info)
bellardaa0aa4f2003-06-09 15:23:31 +000088{
89 return 1;
90}
91
Aurelien Jarno903ec552010-03-29 02:12:51 +020092bfd_vma bfd_getl64 (const bfd_byte *addr)
93{
94 unsigned long long v;
95
96 v = (unsigned long long) addr[0];
97 v |= (unsigned long long) addr[1] << 8;
98 v |= (unsigned long long) addr[2] << 16;
99 v |= (unsigned long long) addr[3] << 24;
100 v |= (unsigned long long) addr[4] << 32;
101 v |= (unsigned long long) addr[5] << 40;
102 v |= (unsigned long long) addr[6] << 48;
103 v |= (unsigned long long) addr[7] << 56;
104 return (bfd_vma) v;
105}
106
bellardaa0aa4f2003-06-09 15:23:31 +0000107bfd_vma bfd_getl32 (const bfd_byte *addr)
108{
109 unsigned long v;
110
111 v = (unsigned long) addr[0];
112 v |= (unsigned long) addr[1] << 8;
113 v |= (unsigned long) addr[2] << 16;
114 v |= (unsigned long) addr[3] << 24;
115 return (bfd_vma) v;
116}
117
118bfd_vma bfd_getb32 (const bfd_byte *addr)
119{
120 unsigned long v;
121
122 v = (unsigned long) addr[0] << 24;
123 v |= (unsigned long) addr[1] << 16;
124 v |= (unsigned long) addr[2] << 8;
125 v |= (unsigned long) addr[3];
126 return (bfd_vma) v;
127}
128
bellard6af0bf92005-07-02 14:58:51 +0000129bfd_vma bfd_getl16 (const bfd_byte *addr)
130{
131 unsigned long v;
132
133 v = (unsigned long) addr[0];
134 v |= (unsigned long) addr[1] << 8;
135 return (bfd_vma) v;
136}
137
138bfd_vma bfd_getb16 (const bfd_byte *addr)
139{
140 unsigned long v;
141
142 v = (unsigned long) addr[0] << 24;
143 v |= (unsigned long) addr[1] << 16;
144 return (bfd_vma) v;
145}
146
Richard Hendersonc46ffd52013-08-16 23:29:45 -0700147static int print_insn_objdump(bfd_vma pc, disassemble_info *info,
148 const char *prefix)
149{
150 int i, n = info->buffer_length;
151 uint8_t *buf = g_malloc(n);
152
153 info->read_memory_func(pc, buf, n, info);
154
155 for (i = 0; i < n; ++i) {
156 if (i % 32 == 0) {
157 info->fprintf_func(info->stream, "\n%s: ", prefix);
158 }
159 info->fprintf_func(info->stream, "%02x", buf[i]);
160 }
161
162 g_free(buf);
163 return n;
164}
165
166static int print_insn_od_host(bfd_vma pc, disassemble_info *info)
167{
168 return print_insn_objdump(pc, info, "OBJD-H");
169}
170
171static int print_insn_od_target(bfd_vma pc, disassemble_info *info)
172{
173 return print_insn_objdump(pc, info, "OBJD-T");
174}
175
Richard Henderson8ca80762017-09-14 09:41:12 -0700176#ifdef CONFIG_CAPSTONE
177/* Temporary storage for the capstone library. This will be alloced via
178 malloc with a size private to the library; thus there's no reason not
179 to share this across calls and across host vs target disassembly. */
180static __thread cs_insn *cap_insn;
181
182/* Initialize the Capstone library. */
183/* ??? It would be nice to cache this. We would need one handle for the
184 host and one for the target. For most targets we can reset specific
185 parameters via cs_option(CS_OPT_MODE, new_mode), but we cannot change
186 CS_ARCH_* in this way. Thus we would need to be able to close and
187 re-open the target handle with a different arch for the target in order
188 to handle AArch64 vs AArch32 mode switching. */
189static cs_err cap_disas_start(disassemble_info *info, csh *handle)
190{
191 cs_mode cap_mode = info->cap_mode;
192 cs_err err;
193
194 cap_mode += (info->endian == BFD_ENDIAN_BIG ? CS_MODE_BIG_ENDIAN
195 : CS_MODE_LITTLE_ENDIAN);
196
197 err = cs_open(info->cap_arch, cap_mode, handle);
198 if (err != CS_ERR_OK) {
199 return err;
200 }
201
202 /* ??? There probably ought to be a better place to put this. */
203 if (info->cap_arch == CS_ARCH_X86) {
204 /* We don't care about errors (if for some reason the library
205 is compiled without AT&T syntax); the user will just have
206 to deal with the Intel syntax. */
207 cs_option(*handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
208 }
209
210 /* "Disassemble" unknown insns as ".byte W,X,Y,Z". */
211 cs_option(*handle, CS_OPT_SKIPDATA, CS_OPT_ON);
212
213 /* Allocate temp space for cs_disasm_iter. */
214 if (cap_insn == NULL) {
215 cap_insn = cs_malloc(*handle);
216 if (cap_insn == NULL) {
217 cs_close(handle);
218 return CS_ERR_MEM;
219 }
220 }
221 return CS_ERR_OK;
222}
223
Richard Henderson15fa1a02017-11-07 13:19:18 +0100224static void cap_dump_insn_units(disassemble_info *info, cs_insn *insn,
225 int i, int n)
226{
227 fprintf_function print = info->fprintf_func;
228 FILE *stream = info->stream;
229
230 switch (info->cap_insn_unit) {
231 case 4:
232 if (info->endian == BFD_ENDIAN_BIG) {
233 for (; i < n; i += 4) {
234 print(stream, " %08x", ldl_be_p(insn->bytes + i));
235
236 }
237 } else {
238 for (; i < n; i += 4) {
239 print(stream, " %08x", ldl_le_p(insn->bytes + i));
240 }
241 }
242 break;
243
244 case 2:
245 if (info->endian == BFD_ENDIAN_BIG) {
246 for (; i < n; i += 2) {
247 print(stream, " %04x", lduw_be_p(insn->bytes + i));
248 }
249 } else {
250 for (; i < n; i += 2) {
251 print(stream, " %04x", lduw_le_p(insn->bytes + i));
252 }
253 }
254 break;
255
256 default:
257 for (; i < n; i++) {
258 print(stream, " %02x", insn->bytes[i]);
259 }
260 break;
261 }
262}
263
264static void cap_dump_insn(disassemble_info *info, cs_insn *insn)
265{
266 fprintf_function print = info->fprintf_func;
267 int i, n, split;
268
269 print(info->stream, "0x%08" PRIx64 ": ", insn->address);
270
271 n = insn->size;
272 split = info->cap_insn_split;
273
274 /* Dump the first SPLIT bytes of the instruction. */
275 cap_dump_insn_units(info, insn, 0, MIN(n, split));
276
277 /* Add padding up to SPLIT so that mnemonics line up. */
278 if (n < split) {
279 int width = (split - n) / info->cap_insn_unit;
280 width *= (2 * info->cap_insn_unit + 1);
281 print(info->stream, "%*s", width, "");
282 }
283
284 /* Print the actual instruction. */
285 print(info->stream, " %-8s %s\n", insn->mnemonic, insn->op_str);
286
287 /* Dump any remaining part of the insn on subsequent lines. */
288 for (i = split; i < n; i += split) {
289 print(info->stream, "0x%08" PRIx64 ": ", insn->address + i);
290 cap_dump_insn_units(info, insn, i, MIN(n, i + split));
291 print(info->stream, "\n");
292 }
293}
294
Richard Henderson8ca80762017-09-14 09:41:12 -0700295/* Disassemble SIZE bytes at PC for the target. */
296static bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size)
297{
298 uint8_t cap_buf[1024];
299 csh handle;
300 cs_insn *insn;
301 size_t csize = 0;
302
303 if (cap_disas_start(info, &handle) != CS_ERR_OK) {
304 return false;
305 }
306 insn = cap_insn;
307
308 while (1) {
309 size_t tsize = MIN(sizeof(cap_buf) - csize, size);
310 const uint8_t *cbuf = cap_buf;
311
312 target_read_memory(pc + csize, cap_buf + csize, tsize, info);
313 csize += tsize;
314 size -= tsize;
315
316 while (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) {
Richard Henderson15fa1a02017-11-07 13:19:18 +0100317 cap_dump_insn(info, insn);
Richard Henderson8ca80762017-09-14 09:41:12 -0700318 }
319
320 /* If the target memory is not consumed, go back for more... */
321 if (size != 0) {
322 /* ... taking care to move any remaining fractional insn
323 to the beginning of the buffer. */
324 if (csize != 0) {
325 memmove(cap_buf, cbuf, csize);
326 }
327 continue;
328 }
329
330 /* Since the target memory is consumed, we should not have
331 a remaining fractional insn. */
332 if (csize != 0) {
333 (*info->fprintf_func)(info->stream,
334 "Disassembler disagrees with translator "
335 "over instruction decoding\n"
336 "Please report this to qemu-devel@nongnu.org\n");
337 }
338 break;
339 }
340
341 cs_close(&handle);
342 return true;
343}
344
345/* Disassemble SIZE bytes at CODE for the host. */
346static bool cap_disas_host(disassemble_info *info, void *code, size_t size)
347{
348 csh handle;
349 const uint8_t *cbuf;
350 cs_insn *insn;
351 uint64_t pc;
352
353 if (cap_disas_start(info, &handle) != CS_ERR_OK) {
354 return false;
355 }
356 insn = cap_insn;
357
358 cbuf = code;
359 pc = (uintptr_t)code;
360
361 while (cs_disasm_iter(handle, &cbuf, &size, &pc, insn)) {
Richard Henderson15fa1a02017-11-07 13:19:18 +0100362 cap_dump_insn(info, insn);
Richard Henderson8ca80762017-09-14 09:41:12 -0700363 }
364 if (size != 0) {
365 (*info->fprintf_func)(info->stream,
366 "Disassembler disagrees with TCG over instruction encoding\n"
367 "Please report this to qemu-devel@nongnu.org\n");
368 }
369
370 cs_close(&handle);
371 return true;
372}
373
374#if !defined(CONFIG_USER_ONLY)
375/* Disassemble COUNT insns at PC for the target. */
376static bool cap_disas_monitor(disassemble_info *info, uint64_t pc, int count)
377{
378 uint8_t cap_buf[32];
379 csh handle;
380 cs_insn *insn;
381 size_t csize = 0;
382
383 if (cap_disas_start(info, &handle) != CS_ERR_OK) {
384 return false;
385 }
386 insn = cap_insn;
387
388 while (1) {
389 /* We want to read memory for one insn, but generically we do not
390 know how much memory that is. We have a small buffer which is
391 known to be sufficient for all supported targets. Try to not
392 read beyond the page, Just In Case. For even more simplicity,
393 ignore the actual target page size and use a 1k boundary. If
394 that turns out to be insufficient, we'll come back around the
395 loop and read more. */
396 uint64_t epc = QEMU_ALIGN_UP(pc + csize + 1, 1024);
397 size_t tsize = MIN(sizeof(cap_buf) - csize, epc - pc);
398 const uint8_t *cbuf = cap_buf;
399
400 /* Make certain that we can make progress. */
401 assert(tsize != 0);
402 info->read_memory_func(pc, cap_buf + csize, tsize, info);
403 csize += tsize;
404
405 if (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) {
Richard Henderson15fa1a02017-11-07 13:19:18 +0100406 cap_dump_insn(info, insn);
Richard Henderson8ca80762017-09-14 09:41:12 -0700407 if (--count <= 0) {
408 break;
409 }
410 }
411 memmove(cap_buf, cbuf, csize);
412 }
413
414 cs_close(&handle);
415 return true;
416}
417#endif /* !CONFIG_USER_ONLY */
418#else
419# define cap_disas_target(i, p, s) false
420# define cap_disas_host(i, p, s) false
421# define cap_disas_monitor(i, p, c) false
422#endif /* CONFIG_CAPSTONE */
423
Richard Henderson1d484742017-09-14 08:38:35 -0700424/* Disassemble this for me please... (debugging). */
Peter Crosthwaited49190c2015-05-24 14:20:41 -0700425void target_disas(FILE *out, CPUState *cpu, target_ulong code,
Richard Henderson1d484742017-09-14 08:38:35 -0700426 target_ulong size)
bellardb9adb4a2003-04-29 20:41:16 +0000427{
Peter Crosthwaite37b9de42015-06-23 20:57:33 -0700428 CPUClass *cc = CPU_GET_CLASS(cpu);
bellardc27004e2005-01-03 23:35:10 +0000429 target_ulong pc;
bellardb9adb4a2003-04-29 20:41:16 +0000430 int count;
Blue Swirlf4359b92012-09-08 12:40:00 +0000431 CPUDebug s;
bellardb9adb4a2003-04-29 20:41:16 +0000432
Blue Swirlf4359b92012-09-08 12:40:00 +0000433 INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
bellardb9adb4a2003-04-29 20:41:16 +0000434
Peter Crosthwaited49190c2015-05-24 14:20:41 -0700435 s.cpu = cpu;
Blue Swirlf4359b92012-09-08 12:40:00 +0000436 s.info.read_memory_func = target_read_memory;
437 s.info.buffer_vma = code;
438 s.info.buffer_length = size;
Peter Crosthwaite9504c542015-07-05 13:50:32 -0700439 s.info.print_address_func = generic_print_address;
Richard Henderson8ca80762017-09-14 09:41:12 -0700440 s.info.cap_arch = -1;
441 s.info.cap_mode = 0;
Richard Henderson15fa1a02017-11-07 13:19:18 +0100442 s.info.cap_insn_unit = 4;
443 s.info.cap_insn_split = 4;
bellardc27004e2005-01-03 23:35:10 +0000444
445#ifdef TARGET_WORDS_BIGENDIAN
Blue Swirlf4359b92012-09-08 12:40:00 +0000446 s.info.endian = BFD_ENDIAN_BIG;
bellardc27004e2005-01-03 23:35:10 +0000447#else
Blue Swirlf4359b92012-09-08 12:40:00 +0000448 s.info.endian = BFD_ENDIAN_LITTLE;
bellardc6105c02003-10-27 21:13:58 +0000449#endif
Peter Crosthwaite37b9de42015-06-23 20:57:33 -0700450
451 if (cc->disas_set_info) {
452 cc->disas_set_info(cpu, &s.info);
453 }
454
Richard Henderson8ca80762017-09-14 09:41:12 -0700455 if (s.info.cap_arch >= 0 && cap_disas_target(&s.info, code, size)) {
456 return;
457 }
458
Peter Crosthwaite2de295c2015-06-23 20:57:32 -0700459 if (s.info.print_insn == NULL) {
460 s.info.print_insn = print_insn_od_target;
Richard Hendersonc46ffd52013-08-16 23:29:45 -0700461 }
bellardc27004e2005-01-03 23:35:10 +0000462
blueswir17e000c22009-02-13 21:44:41 +0000463 for (pc = code; size > 0; pc += count, size -= count) {
bellardfa15e032005-01-31 23:32:31 +0000464 fprintf(out, "0x" TARGET_FMT_lx ": ", pc);
Peter Crosthwaite2de295c2015-06-23 20:57:32 -0700465 count = s.info.print_insn(pc, &s.info);
bellardc27004e2005-01-03 23:35:10 +0000466 fprintf(out, "\n");
467 if (count < 0)
468 break;
malc754d00a2009-04-21 22:26:22 +0000469 if (size < count) {
470 fprintf(out,
471 "Disassembler disagrees with translator over instruction "
472 "decoding\n"
473 "Please report this to qemu-devel@nongnu.org\n");
474 break;
475 }
bellardc27004e2005-01-03 23:35:10 +0000476 }
477}
478
479/* Disassemble this for me please... (debugging). */
480void disas(FILE *out, void *code, unsigned long size)
481{
Stefan Weilb0b0f1c2012-04-12 15:44:35 +0200482 uintptr_t pc;
bellardc27004e2005-01-03 23:35:10 +0000483 int count;
Blue Swirlf4359b92012-09-08 12:40:00 +0000484 CPUDebug s;
Richard Hendersonc46ffd52013-08-16 23:29:45 -0700485 int (*print_insn)(bfd_vma pc, disassemble_info *info) = NULL;
bellardc27004e2005-01-03 23:35:10 +0000486
Blue Swirlf4359b92012-09-08 12:40:00 +0000487 INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
488 s.info.print_address_func = generic_print_host_address;
bellardc6105c02003-10-27 21:13:58 +0000489
Blue Swirlf4359b92012-09-08 12:40:00 +0000490 s.info.buffer = code;
491 s.info.buffer_vma = (uintptr_t)code;
492 s.info.buffer_length = size;
Richard Henderson8ca80762017-09-14 09:41:12 -0700493 s.info.cap_arch = -1;
494 s.info.cap_mode = 0;
Richard Henderson15fa1a02017-11-07 13:19:18 +0100495 s.info.cap_insn_unit = 4;
496 s.info.cap_insn_split = 4;
bellardb9adb4a2003-04-29 20:41:16 +0000497
Juan Quintelae2542fe2009-07-27 16:13:06 +0200498#ifdef HOST_WORDS_BIGENDIAN
Blue Swirlf4359b92012-09-08 12:40:00 +0000499 s.info.endian = BFD_ENDIAN_BIG;
bellardb9adb4a2003-04-29 20:41:16 +0000500#else
Blue Swirlf4359b92012-09-08 12:40:00 +0000501 s.info.endian = BFD_ENDIAN_LITTLE;
bellardb9adb4a2003-04-29 20:41:16 +0000502#endif
Stefan Weil5826e512011-10-05 20:03:53 +0200503#if defined(CONFIG_TCG_INTERPRETER)
504 print_insn = print_insn_tci;
505#elif defined(__i386__)
Blue Swirlf4359b92012-09-08 12:40:00 +0000506 s.info.mach = bfd_mach_i386_i386;
bellardc27004e2005-01-03 23:35:10 +0000507 print_insn = print_insn_i386;
Richard Hendersonb666d2a2017-09-14 09:50:05 -0700508 s.info.cap_arch = CS_ARCH_X86;
509 s.info.cap_mode = CS_MODE_32;
Richard Henderson15fa1a02017-11-07 13:19:18 +0100510 s.info.cap_insn_unit = 1;
511 s.info.cap_insn_split = 8;
bellardbc51c5c2004-03-17 23:46:04 +0000512#elif defined(__x86_64__)
Blue Swirlf4359b92012-09-08 12:40:00 +0000513 s.info.mach = bfd_mach_x86_64;
bellardc27004e2005-01-03 23:35:10 +0000514 print_insn = print_insn_i386;
Richard Hendersonb666d2a2017-09-14 09:50:05 -0700515 s.info.cap_arch = CS_ARCH_X86;
516 s.info.cap_mode = CS_MODE_64;
Richard Henderson15fa1a02017-11-07 13:19:18 +0100517 s.info.cap_insn_unit = 1;
518 s.info.cap_insn_split = 8;
malce58ffeb2009-01-14 18:39:49 +0000519#elif defined(_ARCH_PPC)
Richard Henderson66d4f6a2013-01-31 11:16:21 -0800520 s.info.disassembler_options = (char *)"any";
bellardc27004e2005-01-03 23:35:10 +0000521 print_insn = print_insn_ppc;
Richard Hendersonac226892017-09-14 10:38:40 -0700522 s.info.cap_arch = CS_ARCH_PPC;
523# ifdef _ARCH_PPC64
524 s.info.cap_mode = CS_MODE_64;
525# endif
Alistair Francis91468b22018-12-19 19:20:09 +0000526#elif defined(__riscv) && defined(CONFIG_RISCV_DIS)
527#if defined(_ILP32) || (__riscv_xlen == 32)
528 print_insn = print_insn_riscv32;
529#elif defined(_LP64)
530 print_insn = print_insn_riscv64;
531#else
532#error unsupported RISC-V ABI
533#endif
Claudio Fontana999b53e2014-02-05 17:27:28 +0000534#elif defined(__aarch64__) && defined(CONFIG_ARM_A64_DIS)
535 print_insn = print_insn_arm_a64;
Richard Henderson110f6c72017-09-14 09:51:06 -0700536 s.info.cap_arch = CS_ARCH_ARM64;
bellarda993ba82003-05-11 12:25:45 +0000537#elif defined(__alpha__)
bellardc27004e2005-01-03 23:35:10 +0000538 print_insn = print_insn_alpha;
bellardaa0aa4f2003-06-09 15:23:31 +0000539#elif defined(__sparc__)
bellardc27004e2005-01-03 23:35:10 +0000540 print_insn = print_insn_sparc;
Blue Swirlf4359b92012-09-08 12:40:00 +0000541 s.info.mach = bfd_mach_sparc_v9b;
ths5fafdf22007-09-16 21:08:06 +0000542#elif defined(__arm__)
bellardc27004e2005-01-03 23:35:10 +0000543 print_insn = print_insn_arm;
Richard Henderson110f6c72017-09-14 09:51:06 -0700544 s.info.cap_arch = CS_ARCH_ARM;
545 /* TCG only generates code for arm mode. */
bellard6af0bf92005-07-02 14:58:51 +0000546#elif defined(__MIPSEB__)
547 print_insn = print_insn_big_mips;
548#elif defined(__MIPSEL__)
549 print_insn = print_insn_little_mips;
bellard48024e42005-11-06 16:52:11 +0000550#elif defined(__m68k__)
551 print_insn = print_insn_m68k;
ths8f860bb2007-07-31 23:44:21 +0000552#elif defined(__s390__)
553 print_insn = print_insn_s390;
Richard Henderson429b31a2016-09-29 10:55:53 -0700554#elif defined(__hppa__)
555 print_insn = print_insn_hppa;
bellardb9adb4a2003-04-29 20:41:16 +0000556#endif
Richard Henderson8ca80762017-09-14 09:41:12 -0700557
558 if (s.info.cap_arch >= 0 && cap_disas_host(&s.info, code, size)) {
559 return;
560 }
561
Richard Hendersonc46ffd52013-08-16 23:29:45 -0700562 if (print_insn == NULL) {
563 print_insn = print_insn_od_host;
564 }
Stefan Weilb0b0f1c2012-04-12 15:44:35 +0200565 for (pc = (uintptr_t)code; size > 0; pc += count, size -= count) {
566 fprintf(out, "0x%08" PRIxPTR ": ", pc);
Blue Swirlf4359b92012-09-08 12:40:00 +0000567 count = print_insn(pc, &s.info);
bellardb9adb4a2003-04-29 20:41:16 +0000568 fprintf(out, "\n");
569 if (count < 0)
570 break;
571 }
572}
573
574/* Look up symbol for debugging purpose. Returns "" if unknown. */
bellardc27004e2005-01-03 23:35:10 +0000575const char *lookup_symbol(target_ulong orig_addr)
bellardb9adb4a2003-04-29 20:41:16 +0000576{
pbrook49918a72008-10-22 15:11:31 +0000577 const char *symbol = "";
bellarde80cfcf2004-12-19 23:18:01 +0000578 struct syminfo *s;
ths3b46e622007-09-17 08:09:54 +0000579
bellarde80cfcf2004-12-19 23:18:01 +0000580 for (s = syminfos; s; s = s->next) {
pbrook49918a72008-10-22 15:11:31 +0000581 symbol = s->lookup_symbol(s, orig_addr);
582 if (symbol[0] != '\0') {
583 break;
584 }
bellardb9adb4a2003-04-29 20:41:16 +0000585 }
pbrook49918a72008-10-22 15:11:31 +0000586
587 return symbol;
bellardb9adb4a2003-04-29 20:41:16 +0000588}
bellard9307c4c2004-04-04 12:57:25 +0000589
590#if !defined(CONFIG_USER_ONLY)
591
Paolo Bonzini83c90892012-12-17 18:19:49 +0100592#include "monitor/monitor.h"
bellard3d2cfdf2004-08-01 21:49:07 +0000593
bellard9307c4c2004-04-04 12:57:25 +0000594static int
Richard Hendersonb8d87202017-09-19 09:40:40 -0500595physical_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
blueswir1a5f1b962008-08-17 20:21:51 +0000596 struct disassemble_info *info)
bellard9307c4c2004-04-04 12:57:25 +0000597{
Peter Maydellf2c6abc2018-12-14 13:30:49 +0000598 CPUDebug *s = container_of(info, CPUDebug, info);
599
600 address_space_read(s->cpu->as, memaddr, MEMTXATTRS_UNSPECIFIED,
601 myaddr, length);
bellard9307c4c2004-04-04 12:57:25 +0000602 return 0;
603}
604
Richard Henderson1d484742017-09-14 08:38:35 -0700605/* Disassembler for the monitor. */
Peter Crosthwaited49190c2015-05-24 14:20:41 -0700606void monitor_disas(Monitor *mon, CPUState *cpu,
Richard Henderson1d484742017-09-14 08:38:35 -0700607 target_ulong pc, int nb_insn, int is_physical)
bellard9307c4c2004-04-04 12:57:25 +0000608{
Peter Crosthwaite37b9de42015-06-23 20:57:33 -0700609 CPUClass *cc = CPU_GET_CLASS(cpu);
bellard9307c4c2004-04-04 12:57:25 +0000610 int count, i;
Blue Swirlf4359b92012-09-08 12:40:00 +0000611 CPUDebug s;
bellard9307c4c2004-04-04 12:57:25 +0000612
Markus Armbruster30cc9832019-04-17 21:18:03 +0200613 INIT_DISASSEMBLE_INFO(s.info, NULL, qemu_fprintf);
bellard9307c4c2004-04-04 12:57:25 +0000614
Peter Crosthwaited49190c2015-05-24 14:20:41 -0700615 s.cpu = cpu;
Richard Hendersonb8d87202017-09-19 09:40:40 -0500616 s.info.read_memory_func
617 = (is_physical ? physical_read_memory : target_read_memory);
Peter Crosthwaite9504c542015-07-05 13:50:32 -0700618 s.info.print_address_func = generic_print_address;
Blue Swirlf4359b92012-09-08 12:40:00 +0000619 s.info.buffer_vma = pc;
Richard Henderson8ca80762017-09-14 09:41:12 -0700620 s.info.cap_arch = -1;
621 s.info.cap_mode = 0;
Richard Henderson15fa1a02017-11-07 13:19:18 +0100622 s.info.cap_insn_unit = 4;
623 s.info.cap_insn_split = 4;
bellard9307c4c2004-04-04 12:57:25 +0000624
625#ifdef TARGET_WORDS_BIGENDIAN
Blue Swirlf4359b92012-09-08 12:40:00 +0000626 s.info.endian = BFD_ENDIAN_BIG;
bellard9307c4c2004-04-04 12:57:25 +0000627#else
Blue Swirlf4359b92012-09-08 12:40:00 +0000628 s.info.endian = BFD_ENDIAN_LITTLE;
bellard9307c4c2004-04-04 12:57:25 +0000629#endif
Peter Crosthwaite37b9de42015-06-23 20:57:33 -0700630
631 if (cc->disas_set_info) {
632 cc->disas_set_info(cpu, &s.info);
633 }
634
Richard Henderson8ca80762017-09-14 09:41:12 -0700635 if (s.info.cap_arch >= 0 && cap_disas_monitor(&s.info, pc, nb_insn)) {
636 return;
637 }
638
Peter Crosthwaite37b9de42015-06-23 20:57:33 -0700639 if (!s.info.print_insn) {
640 monitor_printf(mon, "0x" TARGET_FMT_lx
641 ": Asm output not supported on this arch\n", pc);
642 return;
643 }
bellard9307c4c2004-04-04 12:57:25 +0000644
645 for(i = 0; i < nb_insn; i++) {
aliguori376253e2009-03-05 23:01:23 +0000646 monitor_printf(mon, "0x" TARGET_FMT_lx ": ", pc);
Peter Crosthwaite2de295c2015-06-23 20:57:32 -0700647 count = s.info.print_insn(pc, &s.info);
aliguori376253e2009-03-05 23:01:23 +0000648 monitor_printf(mon, "\n");
bellard9307c4c2004-04-04 12:57:25 +0000649 if (count < 0)
650 break;
651 pc += count;
652 }
653}
654#endif