blob: d4ad1089efb3b4ae6639d25e0b177f431bc2b106 [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"
Paolo Bonzini76cad712012-10-24 11:12:21 +02004#include "disas/bfd.h"
bellardb9adb4a2003-04-29 20:41:16 +00005#include "elf.h"
6
bellardc6105c02003-10-27 21:13:58 +00007#include "cpu.h"
Paolo Bonzini76cad712012-10-24 11:12:21 +02008#include "disas/disas.h"
Richard Henderson8ca80762017-09-14 09:41:12 -07009#include "disas/capstone.h"
bellardc6105c02003-10-27 21:13:58 +000010
Blue Swirlf4359b92012-09-08 12:40:00 +000011typedef struct CPUDebug {
12 struct disassemble_info info;
Peter Crosthwaited49190c2015-05-24 14:20:41 -070013 CPUState *cpu;
Blue Swirlf4359b92012-09-08 12:40:00 +000014} CPUDebug;
15
bellardb9adb4a2003-04-29 20:41:16 +000016/* Filled in by elfload.c. Simplistic, but will do for now. */
bellarde80cfcf2004-12-19 23:18:01 +000017struct syminfo *syminfos = NULL;
bellardb9adb4a2003-04-29 20:41:16 +000018
bellardaa0aa4f2003-06-09 15:23:31 +000019/* Get LENGTH bytes from info's buffer, at target address memaddr.
20 Transfer them to myaddr. */
21int
pbrook3a742b72008-10-22 15:55:18 +000022buffer_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
23 struct disassemble_info *info)
bellardaa0aa4f2003-06-09 15:23:31 +000024{
bellardc6105c02003-10-27 21:13:58 +000025 if (memaddr < info->buffer_vma
26 || memaddr + length > info->buffer_vma + info->buffer_length)
27 /* Out of bounds. Use EIO because GDB uses it. */
28 return EIO;
29 memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
30 return 0;
bellardaa0aa4f2003-06-09 15:23:31 +000031}
32
bellardc6105c02003-10-27 21:13:58 +000033/* Get LENGTH bytes from info's buffer, at target address memaddr.
34 Transfer them to myaddr. */
35static int
bellardc27004e2005-01-03 23:35:10 +000036target_read_memory (bfd_vma memaddr,
37 bfd_byte *myaddr,
38 int length,
39 struct disassemble_info *info)
bellardc6105c02003-10-27 21:13:58 +000040{
Blue Swirlf4359b92012-09-08 12:40:00 +000041 CPUDebug *s = container_of(info, CPUDebug, info);
42
Peter Crosthwaited49190c2015-05-24 14:20:41 -070043 cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, 0);
bellardc6105c02003-10-27 21:13:58 +000044 return 0;
45}
bellardc6105c02003-10-27 21:13:58 +000046
bellardaa0aa4f2003-06-09 15:23:31 +000047/* Print an error message. We can assume that this is in response to
48 an error return from buffer_read_memory. */
49void
pbrook3a742b72008-10-22 15:55:18 +000050perror_memory (int status, bfd_vma memaddr, struct disassemble_info *info)
bellardaa0aa4f2003-06-09 15:23:31 +000051{
52 if (status != EIO)
53 /* Can't happen. */
54 (*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
55 else
56 /* Actually, address between memaddr and memaddr + len was
57 out of bounds. */
58 (*info->fprintf_func) (info->stream,
bellard26a76462006-06-25 18:15:32 +000059 "Address 0x%" PRIx64 " is out of bounds.\n", memaddr);
bellardaa0aa4f2003-06-09 15:23:31 +000060}
61
Jim Meyeringa31f0532012-05-09 05:12:04 +000062/* This could be in a separate file, to save minuscule amounts of space
bellardaa0aa4f2003-06-09 15:23:31 +000063 in statically linked executables. */
64
65/* Just print the address is hex. This is included for completeness even
66 though both GDB and objdump provide their own (to print symbolic
67 addresses). */
68
69void
pbrook3a742b72008-10-22 15:55:18 +000070generic_print_address (bfd_vma addr, struct disassemble_info *info)
bellardaa0aa4f2003-06-09 15:23:31 +000071{
bellard26a76462006-06-25 18:15:32 +000072 (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr);
bellardaa0aa4f2003-06-09 15:23:31 +000073}
74
Peter Maydell636bd282012-06-25 04:55:55 +000075/* Print address in hex, truncated to the width of a host virtual address. */
76static void
77generic_print_host_address(bfd_vma addr, struct disassemble_info *info)
78{
79 uint64_t mask = ~0ULL >> (64 - (sizeof(void *) * 8));
80 generic_print_address(addr & mask, info);
81}
82
bellardaa0aa4f2003-06-09 15:23:31 +000083/* Just return the given address. */
84
85int
pbrook3a742b72008-10-22 15:55:18 +000086generic_symbol_at_address (bfd_vma addr, struct disassemble_info *info)
bellardaa0aa4f2003-06-09 15:23:31 +000087{
88 return 1;
89}
90
Aurelien Jarno903ec552010-03-29 02:12:51 +020091bfd_vma bfd_getl64 (const bfd_byte *addr)
92{
93 unsigned long long v;
94
95 v = (unsigned long long) addr[0];
96 v |= (unsigned long long) addr[1] << 8;
97 v |= (unsigned long long) addr[2] << 16;
98 v |= (unsigned long long) addr[3] << 24;
99 v |= (unsigned long long) addr[4] << 32;
100 v |= (unsigned long long) addr[5] << 40;
101 v |= (unsigned long long) addr[6] << 48;
102 v |= (unsigned long long) addr[7] << 56;
103 return (bfd_vma) v;
104}
105
bellardaa0aa4f2003-06-09 15:23:31 +0000106bfd_vma bfd_getl32 (const bfd_byte *addr)
107{
108 unsigned long v;
109
110 v = (unsigned long) addr[0];
111 v |= (unsigned long) addr[1] << 8;
112 v |= (unsigned long) addr[2] << 16;
113 v |= (unsigned long) addr[3] << 24;
114 return (bfd_vma) v;
115}
116
117bfd_vma bfd_getb32 (const bfd_byte *addr)
118{
119 unsigned long v;
120
121 v = (unsigned long) addr[0] << 24;
122 v |= (unsigned long) addr[1] << 16;
123 v |= (unsigned long) addr[2] << 8;
124 v |= (unsigned long) addr[3];
125 return (bfd_vma) v;
126}
127
bellard6af0bf92005-07-02 14:58:51 +0000128bfd_vma bfd_getl16 (const bfd_byte *addr)
129{
130 unsigned long v;
131
132 v = (unsigned long) addr[0];
133 v |= (unsigned long) addr[1] << 8;
134 return (bfd_vma) v;
135}
136
137bfd_vma bfd_getb16 (const bfd_byte *addr)
138{
139 unsigned long v;
140
141 v = (unsigned long) addr[0] << 24;
142 v |= (unsigned long) addr[1] << 16;
143 return (bfd_vma) v;
144}
145
Richard Hendersonc46ffd52013-08-16 23:29:45 -0700146static int print_insn_objdump(bfd_vma pc, disassemble_info *info,
147 const char *prefix)
148{
149 int i, n = info->buffer_length;
150 uint8_t *buf = g_malloc(n);
151
152 info->read_memory_func(pc, buf, n, info);
153
154 for (i = 0; i < n; ++i) {
155 if (i % 32 == 0) {
156 info->fprintf_func(info->stream, "\n%s: ", prefix);
157 }
158 info->fprintf_func(info->stream, "%02x", buf[i]);
159 }
160
161 g_free(buf);
162 return n;
163}
164
165static int print_insn_od_host(bfd_vma pc, disassemble_info *info)
166{
167 return print_insn_objdump(pc, info, "OBJD-H");
168}
169
170static int print_insn_od_target(bfd_vma pc, disassemble_info *info)
171{
172 return print_insn_objdump(pc, info, "OBJD-T");
173}
174
Richard Henderson8ca80762017-09-14 09:41:12 -0700175#ifdef CONFIG_CAPSTONE
176/* Temporary storage for the capstone library. This will be alloced via
177 malloc with a size private to the library; thus there's no reason not
178 to share this across calls and across host vs target disassembly. */
179static __thread cs_insn *cap_insn;
180
181/* Initialize the Capstone library. */
182/* ??? It would be nice to cache this. We would need one handle for the
183 host and one for the target. For most targets we can reset specific
184 parameters via cs_option(CS_OPT_MODE, new_mode), but we cannot change
185 CS_ARCH_* in this way. Thus we would need to be able to close and
186 re-open the target handle with a different arch for the target in order
187 to handle AArch64 vs AArch32 mode switching. */
188static cs_err cap_disas_start(disassemble_info *info, csh *handle)
189{
190 cs_mode cap_mode = info->cap_mode;
191 cs_err err;
192
193 cap_mode += (info->endian == BFD_ENDIAN_BIG ? CS_MODE_BIG_ENDIAN
194 : CS_MODE_LITTLE_ENDIAN);
195
196 err = cs_open(info->cap_arch, cap_mode, handle);
197 if (err != CS_ERR_OK) {
198 return err;
199 }
200
201 /* ??? There probably ought to be a better place to put this. */
202 if (info->cap_arch == CS_ARCH_X86) {
203 /* We don't care about errors (if for some reason the library
204 is compiled without AT&T syntax); the user will just have
205 to deal with the Intel syntax. */
206 cs_option(*handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
207 }
208
209 /* "Disassemble" unknown insns as ".byte W,X,Y,Z". */
210 cs_option(*handle, CS_OPT_SKIPDATA, CS_OPT_ON);
211
212 /* Allocate temp space for cs_disasm_iter. */
213 if (cap_insn == NULL) {
214 cap_insn = cs_malloc(*handle);
215 if (cap_insn == NULL) {
216 cs_close(handle);
217 return CS_ERR_MEM;
218 }
219 }
220 return CS_ERR_OK;
221}
222
Richard Henderson15fa1a02017-11-07 13:19:18 +0100223static void cap_dump_insn_units(disassemble_info *info, cs_insn *insn,
224 int i, int n)
225{
226 fprintf_function print = info->fprintf_func;
227 FILE *stream = info->stream;
228
229 switch (info->cap_insn_unit) {
230 case 4:
231 if (info->endian == BFD_ENDIAN_BIG) {
232 for (; i < n; i += 4) {
233 print(stream, " %08x", ldl_be_p(insn->bytes + i));
234
235 }
236 } else {
237 for (; i < n; i += 4) {
238 print(stream, " %08x", ldl_le_p(insn->bytes + i));
239 }
240 }
241 break;
242
243 case 2:
244 if (info->endian == BFD_ENDIAN_BIG) {
245 for (; i < n; i += 2) {
246 print(stream, " %04x", lduw_be_p(insn->bytes + i));
247 }
248 } else {
249 for (; i < n; i += 2) {
250 print(stream, " %04x", lduw_le_p(insn->bytes + i));
251 }
252 }
253 break;
254
255 default:
256 for (; i < n; i++) {
257 print(stream, " %02x", insn->bytes[i]);
258 }
259 break;
260 }
261}
262
263static void cap_dump_insn(disassemble_info *info, cs_insn *insn)
264{
265 fprintf_function print = info->fprintf_func;
266 int i, n, split;
267
268 print(info->stream, "0x%08" PRIx64 ": ", insn->address);
269
270 n = insn->size;
271 split = info->cap_insn_split;
272
273 /* Dump the first SPLIT bytes of the instruction. */
274 cap_dump_insn_units(info, insn, 0, MIN(n, split));
275
276 /* Add padding up to SPLIT so that mnemonics line up. */
277 if (n < split) {
278 int width = (split - n) / info->cap_insn_unit;
279 width *= (2 * info->cap_insn_unit + 1);
280 print(info->stream, "%*s", width, "");
281 }
282
283 /* Print the actual instruction. */
284 print(info->stream, " %-8s %s\n", insn->mnemonic, insn->op_str);
285
286 /* Dump any remaining part of the insn on subsequent lines. */
287 for (i = split; i < n; i += split) {
288 print(info->stream, "0x%08" PRIx64 ": ", insn->address + i);
289 cap_dump_insn_units(info, insn, i, MIN(n, i + split));
290 print(info->stream, "\n");
291 }
292}
293
Richard Henderson8ca80762017-09-14 09:41:12 -0700294/* Disassemble SIZE bytes at PC for the target. */
295static bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size)
296{
297 uint8_t cap_buf[1024];
298 csh handle;
299 cs_insn *insn;
300 size_t csize = 0;
301
302 if (cap_disas_start(info, &handle) != CS_ERR_OK) {
303 return false;
304 }
305 insn = cap_insn;
306
307 while (1) {
308 size_t tsize = MIN(sizeof(cap_buf) - csize, size);
309 const uint8_t *cbuf = cap_buf;
310
311 target_read_memory(pc + csize, cap_buf + csize, tsize, info);
312 csize += tsize;
313 size -= tsize;
314
315 while (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) {
Richard Henderson15fa1a02017-11-07 13:19:18 +0100316 cap_dump_insn(info, insn);
Richard Henderson8ca80762017-09-14 09:41:12 -0700317 }
318
319 /* If the target memory is not consumed, go back for more... */
320 if (size != 0) {
321 /* ... taking care to move any remaining fractional insn
322 to the beginning of the buffer. */
323 if (csize != 0) {
324 memmove(cap_buf, cbuf, csize);
325 }
326 continue;
327 }
328
329 /* Since the target memory is consumed, we should not have
330 a remaining fractional insn. */
331 if (csize != 0) {
332 (*info->fprintf_func)(info->stream,
333 "Disassembler disagrees with translator "
334 "over instruction decoding\n"
335 "Please report this to qemu-devel@nongnu.org\n");
336 }
337 break;
338 }
339
340 cs_close(&handle);
341 return true;
342}
343
344/* Disassemble SIZE bytes at CODE for the host. */
345static bool cap_disas_host(disassemble_info *info, void *code, size_t size)
346{
347 csh handle;
348 const uint8_t *cbuf;
349 cs_insn *insn;
350 uint64_t pc;
351
352 if (cap_disas_start(info, &handle) != CS_ERR_OK) {
353 return false;
354 }
355 insn = cap_insn;
356
357 cbuf = code;
358 pc = (uintptr_t)code;
359
360 while (cs_disasm_iter(handle, &cbuf, &size, &pc, insn)) {
Richard Henderson15fa1a02017-11-07 13:19:18 +0100361 cap_dump_insn(info, insn);
Richard Henderson8ca80762017-09-14 09:41:12 -0700362 }
363 if (size != 0) {
364 (*info->fprintf_func)(info->stream,
365 "Disassembler disagrees with TCG over instruction encoding\n"
366 "Please report this to qemu-devel@nongnu.org\n");
367 }
368
369 cs_close(&handle);
370 return true;
371}
372
373#if !defined(CONFIG_USER_ONLY)
374/* Disassemble COUNT insns at PC for the target. */
375static bool cap_disas_monitor(disassemble_info *info, uint64_t pc, int count)
376{
377 uint8_t cap_buf[32];
378 csh handle;
379 cs_insn *insn;
380 size_t csize = 0;
381
382 if (cap_disas_start(info, &handle) != CS_ERR_OK) {
383 return false;
384 }
385 insn = cap_insn;
386
387 while (1) {
388 /* We want to read memory for one insn, but generically we do not
389 know how much memory that is. We have a small buffer which is
390 known to be sufficient for all supported targets. Try to not
391 read beyond the page, Just In Case. For even more simplicity,
392 ignore the actual target page size and use a 1k boundary. If
393 that turns out to be insufficient, we'll come back around the
394 loop and read more. */
395 uint64_t epc = QEMU_ALIGN_UP(pc + csize + 1, 1024);
396 size_t tsize = MIN(sizeof(cap_buf) - csize, epc - pc);
397 const uint8_t *cbuf = cap_buf;
398
399 /* Make certain that we can make progress. */
400 assert(tsize != 0);
401 info->read_memory_func(pc, cap_buf + csize, tsize, info);
402 csize += tsize;
403
404 if (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) {
Richard Henderson15fa1a02017-11-07 13:19:18 +0100405 cap_dump_insn(info, insn);
Richard Henderson8ca80762017-09-14 09:41:12 -0700406 if (--count <= 0) {
407 break;
408 }
409 }
410 memmove(cap_buf, cbuf, csize);
411 }
412
413 cs_close(&handle);
414 return true;
415}
416#endif /* !CONFIG_USER_ONLY */
417#else
418# define cap_disas_target(i, p, s) false
419# define cap_disas_host(i, p, s) false
420# define cap_disas_monitor(i, p, c) false
421#endif /* CONFIG_CAPSTONE */
422
Richard Henderson1d484742017-09-14 08:38:35 -0700423/* Disassemble this for me please... (debugging). */
Peter Crosthwaited49190c2015-05-24 14:20:41 -0700424void target_disas(FILE *out, CPUState *cpu, target_ulong code,
Richard Henderson1d484742017-09-14 08:38:35 -0700425 target_ulong size)
bellardb9adb4a2003-04-29 20:41:16 +0000426{
Peter Crosthwaite37b9de42015-06-23 20:57:33 -0700427 CPUClass *cc = CPU_GET_CLASS(cpu);
bellardc27004e2005-01-03 23:35:10 +0000428 target_ulong pc;
bellardb9adb4a2003-04-29 20:41:16 +0000429 int count;
Blue Swirlf4359b92012-09-08 12:40:00 +0000430 CPUDebug s;
bellardb9adb4a2003-04-29 20:41:16 +0000431
Blue Swirlf4359b92012-09-08 12:40:00 +0000432 INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
bellardb9adb4a2003-04-29 20:41:16 +0000433
Peter Crosthwaited49190c2015-05-24 14:20:41 -0700434 s.cpu = cpu;
Blue Swirlf4359b92012-09-08 12:40:00 +0000435 s.info.read_memory_func = target_read_memory;
436 s.info.buffer_vma = code;
437 s.info.buffer_length = size;
Peter Crosthwaite9504c542015-07-05 13:50:32 -0700438 s.info.print_address_func = generic_print_address;
Richard Henderson8ca80762017-09-14 09:41:12 -0700439 s.info.cap_arch = -1;
440 s.info.cap_mode = 0;
Richard Henderson15fa1a02017-11-07 13:19:18 +0100441 s.info.cap_insn_unit = 4;
442 s.info.cap_insn_split = 4;
bellardc27004e2005-01-03 23:35:10 +0000443
444#ifdef TARGET_WORDS_BIGENDIAN
Blue Swirlf4359b92012-09-08 12:40:00 +0000445 s.info.endian = BFD_ENDIAN_BIG;
bellardc27004e2005-01-03 23:35:10 +0000446#else
Blue Swirlf4359b92012-09-08 12:40:00 +0000447 s.info.endian = BFD_ENDIAN_LITTLE;
bellardc6105c02003-10-27 21:13:58 +0000448#endif
Peter Crosthwaite37b9de42015-06-23 20:57:33 -0700449
450 if (cc->disas_set_info) {
451 cc->disas_set_info(cpu, &s.info);
452 }
453
Richard Henderson8ca80762017-09-14 09:41:12 -0700454 if (s.info.cap_arch >= 0 && cap_disas_target(&s.info, code, size)) {
455 return;
456 }
457
Peter Crosthwaite2de295c2015-06-23 20:57:32 -0700458 if (s.info.print_insn == NULL) {
459 s.info.print_insn = print_insn_od_target;
Richard Hendersonc46ffd52013-08-16 23:29:45 -0700460 }
bellardc27004e2005-01-03 23:35:10 +0000461
blueswir17e000c22009-02-13 21:44:41 +0000462 for (pc = code; size > 0; pc += count, size -= count) {
bellardfa15e032005-01-31 23:32:31 +0000463 fprintf(out, "0x" TARGET_FMT_lx ": ", pc);
Peter Crosthwaite2de295c2015-06-23 20:57:32 -0700464 count = s.info.print_insn(pc, &s.info);
bellardc27004e2005-01-03 23:35:10 +0000465 fprintf(out, "\n");
466 if (count < 0)
467 break;
malc754d00a2009-04-21 22:26:22 +0000468 if (size < count) {
469 fprintf(out,
470 "Disassembler disagrees with translator over instruction "
471 "decoding\n"
472 "Please report this to qemu-devel@nongnu.org\n");
473 break;
474 }
bellardc27004e2005-01-03 23:35:10 +0000475 }
476}
477
478/* Disassemble this for me please... (debugging). */
479void disas(FILE *out, void *code, unsigned long size)
480{
Stefan Weilb0b0f1c2012-04-12 15:44:35 +0200481 uintptr_t pc;
bellardc27004e2005-01-03 23:35:10 +0000482 int count;
Blue Swirlf4359b92012-09-08 12:40:00 +0000483 CPUDebug s;
Richard Hendersonc46ffd52013-08-16 23:29:45 -0700484 int (*print_insn)(bfd_vma pc, disassemble_info *info) = NULL;
bellardc27004e2005-01-03 23:35:10 +0000485
Blue Swirlf4359b92012-09-08 12:40:00 +0000486 INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
487 s.info.print_address_func = generic_print_host_address;
bellardc6105c02003-10-27 21:13:58 +0000488
Blue Swirlf4359b92012-09-08 12:40:00 +0000489 s.info.buffer = code;
490 s.info.buffer_vma = (uintptr_t)code;
491 s.info.buffer_length = size;
Richard Henderson8ca80762017-09-14 09:41:12 -0700492 s.info.cap_arch = -1;
493 s.info.cap_mode = 0;
Richard Henderson15fa1a02017-11-07 13:19:18 +0100494 s.info.cap_insn_unit = 4;
495 s.info.cap_insn_split = 4;
bellardb9adb4a2003-04-29 20:41:16 +0000496
Juan Quintelae2542fe2009-07-27 16:13:06 +0200497#ifdef HOST_WORDS_BIGENDIAN
Blue Swirlf4359b92012-09-08 12:40:00 +0000498 s.info.endian = BFD_ENDIAN_BIG;
bellardb9adb4a2003-04-29 20:41:16 +0000499#else
Blue Swirlf4359b92012-09-08 12:40:00 +0000500 s.info.endian = BFD_ENDIAN_LITTLE;
bellardb9adb4a2003-04-29 20:41:16 +0000501#endif
Stefan Weil5826e512011-10-05 20:03:53 +0200502#if defined(CONFIG_TCG_INTERPRETER)
503 print_insn = print_insn_tci;
504#elif defined(__i386__)
Blue Swirlf4359b92012-09-08 12:40:00 +0000505 s.info.mach = bfd_mach_i386_i386;
bellardc27004e2005-01-03 23:35:10 +0000506 print_insn = print_insn_i386;
Richard Hendersonb666d2a2017-09-14 09:50:05 -0700507 s.info.cap_arch = CS_ARCH_X86;
508 s.info.cap_mode = CS_MODE_32;
Richard Henderson15fa1a02017-11-07 13:19:18 +0100509 s.info.cap_insn_unit = 1;
510 s.info.cap_insn_split = 8;
bellardbc51c5c2004-03-17 23:46:04 +0000511#elif defined(__x86_64__)
Blue Swirlf4359b92012-09-08 12:40:00 +0000512 s.info.mach = bfd_mach_x86_64;
bellardc27004e2005-01-03 23:35:10 +0000513 print_insn = print_insn_i386;
Richard Hendersonb666d2a2017-09-14 09:50:05 -0700514 s.info.cap_arch = CS_ARCH_X86;
515 s.info.cap_mode = CS_MODE_64;
Richard Henderson15fa1a02017-11-07 13:19:18 +0100516 s.info.cap_insn_unit = 1;
517 s.info.cap_insn_split = 8;
malce58ffeb2009-01-14 18:39:49 +0000518#elif defined(_ARCH_PPC)
Richard Henderson66d4f6a2013-01-31 11:16:21 -0800519 s.info.disassembler_options = (char *)"any";
bellardc27004e2005-01-03 23:35:10 +0000520 print_insn = print_insn_ppc;
Richard Hendersonac226892017-09-14 10:38:40 -0700521 s.info.cap_arch = CS_ARCH_PPC;
522# ifdef _ARCH_PPC64
523 s.info.cap_mode = CS_MODE_64;
524# endif
Claudio Fontana999b53e2014-02-05 17:27:28 +0000525#elif defined(__aarch64__) && defined(CONFIG_ARM_A64_DIS)
526 print_insn = print_insn_arm_a64;
Richard Henderson110f6c72017-09-14 09:51:06 -0700527 s.info.cap_arch = CS_ARCH_ARM64;
bellarda993ba82003-05-11 12:25:45 +0000528#elif defined(__alpha__)
bellardc27004e2005-01-03 23:35:10 +0000529 print_insn = print_insn_alpha;
bellardaa0aa4f2003-06-09 15:23:31 +0000530#elif defined(__sparc__)
bellardc27004e2005-01-03 23:35:10 +0000531 print_insn = print_insn_sparc;
Blue Swirlf4359b92012-09-08 12:40:00 +0000532 s.info.mach = bfd_mach_sparc_v9b;
ths5fafdf22007-09-16 21:08:06 +0000533#elif defined(__arm__)
bellardc27004e2005-01-03 23:35:10 +0000534 print_insn = print_insn_arm;
Richard Henderson110f6c72017-09-14 09:51:06 -0700535 s.info.cap_arch = CS_ARCH_ARM;
536 /* TCG only generates code for arm mode. */
bellard6af0bf92005-07-02 14:58:51 +0000537#elif defined(__MIPSEB__)
538 print_insn = print_insn_big_mips;
539#elif defined(__MIPSEL__)
540 print_insn = print_insn_little_mips;
bellard48024e42005-11-06 16:52:11 +0000541#elif defined(__m68k__)
542 print_insn = print_insn_m68k;
ths8f860bb2007-07-31 23:44:21 +0000543#elif defined(__s390__)
544 print_insn = print_insn_s390;
Richard Henderson429b31a2016-09-29 10:55:53 -0700545#elif defined(__hppa__)
546 print_insn = print_insn_hppa;
bellardb9adb4a2003-04-29 20:41:16 +0000547#endif
Richard Henderson8ca80762017-09-14 09:41:12 -0700548
549 if (s.info.cap_arch >= 0 && cap_disas_host(&s.info, code, size)) {
550 return;
551 }
552
Richard Hendersonc46ffd52013-08-16 23:29:45 -0700553 if (print_insn == NULL) {
554 print_insn = print_insn_od_host;
555 }
Stefan Weilb0b0f1c2012-04-12 15:44:35 +0200556 for (pc = (uintptr_t)code; size > 0; pc += count, size -= count) {
557 fprintf(out, "0x%08" PRIxPTR ": ", pc);
Blue Swirlf4359b92012-09-08 12:40:00 +0000558 count = print_insn(pc, &s.info);
bellardb9adb4a2003-04-29 20:41:16 +0000559 fprintf(out, "\n");
560 if (count < 0)
561 break;
562 }
563}
564
565/* Look up symbol for debugging purpose. Returns "" if unknown. */
bellardc27004e2005-01-03 23:35:10 +0000566const char *lookup_symbol(target_ulong orig_addr)
bellardb9adb4a2003-04-29 20:41:16 +0000567{
pbrook49918a72008-10-22 15:11:31 +0000568 const char *symbol = "";
bellarde80cfcf2004-12-19 23:18:01 +0000569 struct syminfo *s;
ths3b46e622007-09-17 08:09:54 +0000570
bellarde80cfcf2004-12-19 23:18:01 +0000571 for (s = syminfos; s; s = s->next) {
pbrook49918a72008-10-22 15:11:31 +0000572 symbol = s->lookup_symbol(s, orig_addr);
573 if (symbol[0] != '\0') {
574 break;
575 }
bellardb9adb4a2003-04-29 20:41:16 +0000576 }
pbrook49918a72008-10-22 15:11:31 +0000577
578 return symbol;
bellardb9adb4a2003-04-29 20:41:16 +0000579}
bellard9307c4c2004-04-04 12:57:25 +0000580
581#if !defined(CONFIG_USER_ONLY)
582
Paolo Bonzini83c90892012-12-17 18:19:49 +0100583#include "monitor/monitor.h"
bellard3d2cfdf2004-08-01 21:49:07 +0000584
bellard9307c4c2004-04-04 12:57:25 +0000585static int
Richard Hendersonb8d87202017-09-19 09:40:40 -0500586physical_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
blueswir1a5f1b962008-08-17 20:21:51 +0000587 struct disassemble_info *info)
bellard9307c4c2004-04-04 12:57:25 +0000588{
Richard Hendersonb8d87202017-09-19 09:40:40 -0500589 cpu_physical_memory_read(memaddr, myaddr, length);
bellard9307c4c2004-04-04 12:57:25 +0000590 return 0;
591}
592
Richard Henderson1d484742017-09-14 08:38:35 -0700593/* Disassembler for the monitor. */
Peter Crosthwaited49190c2015-05-24 14:20:41 -0700594void monitor_disas(Monitor *mon, CPUState *cpu,
Richard Henderson1d484742017-09-14 08:38:35 -0700595 target_ulong pc, int nb_insn, int is_physical)
bellard9307c4c2004-04-04 12:57:25 +0000596{
Peter Crosthwaite37b9de42015-06-23 20:57:33 -0700597 CPUClass *cc = CPU_GET_CLASS(cpu);
bellard9307c4c2004-04-04 12:57:25 +0000598 int count, i;
Blue Swirlf4359b92012-09-08 12:40:00 +0000599 CPUDebug s;
bellard9307c4c2004-04-04 12:57:25 +0000600
Blue Swirlf4359b92012-09-08 12:40:00 +0000601 INIT_DISASSEMBLE_INFO(s.info, (FILE *)mon, monitor_fprintf);
bellard9307c4c2004-04-04 12:57:25 +0000602
Peter Crosthwaited49190c2015-05-24 14:20:41 -0700603 s.cpu = cpu;
Richard Hendersonb8d87202017-09-19 09:40:40 -0500604 s.info.read_memory_func
605 = (is_physical ? physical_read_memory : target_read_memory);
Peter Crosthwaite9504c542015-07-05 13:50:32 -0700606 s.info.print_address_func = generic_print_address;
Blue Swirlf4359b92012-09-08 12:40:00 +0000607 s.info.buffer_vma = pc;
Richard Henderson8ca80762017-09-14 09:41:12 -0700608 s.info.cap_arch = -1;
609 s.info.cap_mode = 0;
Richard Henderson15fa1a02017-11-07 13:19:18 +0100610 s.info.cap_insn_unit = 4;
611 s.info.cap_insn_split = 4;
bellard9307c4c2004-04-04 12:57:25 +0000612
613#ifdef TARGET_WORDS_BIGENDIAN
Blue Swirlf4359b92012-09-08 12:40:00 +0000614 s.info.endian = BFD_ENDIAN_BIG;
bellard9307c4c2004-04-04 12:57:25 +0000615#else
Blue Swirlf4359b92012-09-08 12:40:00 +0000616 s.info.endian = BFD_ENDIAN_LITTLE;
bellard9307c4c2004-04-04 12:57:25 +0000617#endif
Peter Crosthwaite37b9de42015-06-23 20:57:33 -0700618
619 if (cc->disas_set_info) {
620 cc->disas_set_info(cpu, &s.info);
621 }
622
Richard Henderson8ca80762017-09-14 09:41:12 -0700623 if (s.info.cap_arch >= 0 && cap_disas_monitor(&s.info, pc, nb_insn)) {
624 return;
625 }
626
Peter Crosthwaite37b9de42015-06-23 20:57:33 -0700627 if (!s.info.print_insn) {
628 monitor_printf(mon, "0x" TARGET_FMT_lx
629 ": Asm output not supported on this arch\n", pc);
630 return;
631 }
bellard9307c4c2004-04-04 12:57:25 +0000632
633 for(i = 0; i < nb_insn; i++) {
aliguori376253e2009-03-05 23:01:23 +0000634 monitor_printf(mon, "0x" TARGET_FMT_lx ": ", pc);
Peter Crosthwaite2de295c2015-06-23 20:57:32 -0700635 count = s.info.print_insn(pc, &s.info);
aliguori376253e2009-03-05 23:01:23 +0000636 monitor_printf(mon, "\n");
bellard9307c4c2004-04-04 12:57:25 +0000637 if (count < 0)
638 break;
639 pc += count;
640 }
641}
642#endif