tests: Factorize out migrate_test_start/end
[qemu/ar7.git] / disas.c
blob92b389d25f85f514fa90077559ae1c5f1184c846
1 /* General "disassemble this chunk" code. Used for debugging. */
2 #include "qemu/osdep.h"
3 #include "qemu-common.h"
4 #include "disas/bfd.h"
5 #include "elf.h"
7 #include "cpu.h"
8 #include "disas/disas.h"
9 #include "disas/capstone.h"
11 typedef struct CPUDebug {
12 struct disassemble_info info;
13 CPUState *cpu;
14 } CPUDebug;
16 /* Filled in by elfload.c. Simplistic, but will do for now. */
17 struct syminfo *syminfos = NULL;
19 /* Get LENGTH bytes from info's buffer, at target address memaddr.
20 Transfer them to myaddr. */
21 int
22 buffer_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
23 struct disassemble_info *info)
25 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;
33 /* Get LENGTH bytes from info's buffer, at target address memaddr.
34 Transfer them to myaddr. */
35 static int
36 target_read_memory (bfd_vma memaddr,
37 bfd_byte *myaddr,
38 int length,
39 struct disassemble_info *info)
41 CPUDebug *s = container_of(info, CPUDebug, info);
43 cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, 0);
44 return 0;
47 /* Print an error message. We can assume that this is in response to
48 an error return from buffer_read_memory. */
49 void
50 perror_memory (int status, bfd_vma memaddr, struct disassemble_info *info)
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,
59 "Address 0x%" PRIx64 " is out of bounds.\n", memaddr);
62 /* This could be in a separate file, to save minuscule amounts of space
63 in statically linked executables. */
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). */
69 void
70 generic_print_address (bfd_vma addr, struct disassemble_info *info)
72 (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr);
75 /* Print address in hex, truncated to the width of a host virtual address. */
76 static void
77 generic_print_host_address(bfd_vma addr, struct disassemble_info *info)
79 uint64_t mask = ~0ULL >> (64 - (sizeof(void *) * 8));
80 generic_print_address(addr & mask, info);
83 /* Just return the given address. */
85 int
86 generic_symbol_at_address (bfd_vma addr, struct disassemble_info *info)
88 return 1;
91 bfd_vma bfd_getl64 (const bfd_byte *addr)
93 unsigned long long v;
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;
106 bfd_vma bfd_getl32 (const bfd_byte *addr)
108 unsigned long v;
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;
117 bfd_vma bfd_getb32 (const bfd_byte *addr)
119 unsigned long v;
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;
128 bfd_vma bfd_getl16 (const bfd_byte *addr)
130 unsigned long v;
132 v = (unsigned long) addr[0];
133 v |= (unsigned long) addr[1] << 8;
134 return (bfd_vma) v;
137 bfd_vma bfd_getb16 (const bfd_byte *addr)
139 unsigned long v;
141 v = (unsigned long) addr[0] << 24;
142 v |= (unsigned long) addr[1] << 16;
143 return (bfd_vma) v;
146 static int print_insn_objdump(bfd_vma pc, disassemble_info *info,
147 const char *prefix)
149 int i, n = info->buffer_length;
150 uint8_t *buf = g_malloc(n);
152 info->read_memory_func(pc, buf, n, info);
154 for (i = 0; i < n; ++i) {
155 if (i % 32 == 0) {
156 info->fprintf_func(info->stream, "\n%s: ", prefix);
158 info->fprintf_func(info->stream, "%02x", buf[i]);
161 g_free(buf);
162 return n;
165 static int print_insn_od_host(bfd_vma pc, disassemble_info *info)
167 return print_insn_objdump(pc, info, "OBJD-H");
170 static int print_insn_od_target(bfd_vma pc, disassemble_info *info)
172 return print_insn_objdump(pc, info, "OBJD-T");
175 #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. */
179 static __thread cs_insn *cap_insn;
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. */
188 static cs_err cap_disas_start(disassemble_info *info, csh *handle)
190 cs_mode cap_mode = info->cap_mode;
191 cs_err err;
193 cap_mode += (info->endian == BFD_ENDIAN_BIG ? CS_MODE_BIG_ENDIAN
194 : CS_MODE_LITTLE_ENDIAN);
196 err = cs_open(info->cap_arch, cap_mode, handle);
197 if (err != CS_ERR_OK) {
198 return err;
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);
209 /* "Disassemble" unknown insns as ".byte W,X,Y,Z". */
210 cs_option(*handle, CS_OPT_SKIPDATA, CS_OPT_ON);
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;
220 return CS_ERR_OK;
223 /* Disassemble SIZE bytes at PC for the target. */
224 static bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size)
226 uint8_t cap_buf[1024];
227 csh handle;
228 cs_insn *insn;
229 size_t csize = 0;
231 if (cap_disas_start(info, &handle) != CS_ERR_OK) {
232 return false;
234 insn = cap_insn;
236 while (1) {
237 size_t tsize = MIN(sizeof(cap_buf) - csize, size);
238 const uint8_t *cbuf = cap_buf;
240 target_read_memory(pc + csize, cap_buf + csize, tsize, info);
241 csize += tsize;
242 size -= tsize;
244 while (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) {
245 (*info->fprintf_func)(info->stream,
246 "0x%08" PRIx64 ": %-12s %s\n",
247 insn->address, insn->mnemonic,
248 insn->op_str);
251 /* If the target memory is not consumed, go back for more... */
252 if (size != 0) {
253 /* ... taking care to move any remaining fractional insn
254 to the beginning of the buffer. */
255 if (csize != 0) {
256 memmove(cap_buf, cbuf, csize);
258 continue;
261 /* Since the target memory is consumed, we should not have
262 a remaining fractional insn. */
263 if (csize != 0) {
264 (*info->fprintf_func)(info->stream,
265 "Disassembler disagrees with translator "
266 "over instruction decoding\n"
267 "Please report this to qemu-devel@nongnu.org\n");
269 break;
272 cs_close(&handle);
273 return true;
276 /* Disassemble SIZE bytes at CODE for the host. */
277 static bool cap_disas_host(disassemble_info *info, void *code, size_t size)
279 csh handle;
280 const uint8_t *cbuf;
281 cs_insn *insn;
282 uint64_t pc;
284 if (cap_disas_start(info, &handle) != CS_ERR_OK) {
285 return false;
287 insn = cap_insn;
289 cbuf = code;
290 pc = (uintptr_t)code;
292 while (cs_disasm_iter(handle, &cbuf, &size, &pc, insn)) {
293 (*info->fprintf_func)(info->stream,
294 "0x%08" PRIx64 ": %-12s %s\n",
295 insn->address, insn->mnemonic,
296 insn->op_str);
298 if (size != 0) {
299 (*info->fprintf_func)(info->stream,
300 "Disassembler disagrees with TCG over instruction encoding\n"
301 "Please report this to qemu-devel@nongnu.org\n");
304 cs_close(&handle);
305 return true;
308 #if !defined(CONFIG_USER_ONLY)
309 /* Disassemble COUNT insns at PC for the target. */
310 static bool cap_disas_monitor(disassemble_info *info, uint64_t pc, int count)
312 uint8_t cap_buf[32];
313 csh handle;
314 cs_insn *insn;
315 size_t csize = 0;
317 if (cap_disas_start(info, &handle) != CS_ERR_OK) {
318 return false;
320 insn = cap_insn;
322 while (1) {
323 /* We want to read memory for one insn, but generically we do not
324 know how much memory that is. We have a small buffer which is
325 known to be sufficient for all supported targets. Try to not
326 read beyond the page, Just In Case. For even more simplicity,
327 ignore the actual target page size and use a 1k boundary. If
328 that turns out to be insufficient, we'll come back around the
329 loop and read more. */
330 uint64_t epc = QEMU_ALIGN_UP(pc + csize + 1, 1024);
331 size_t tsize = MIN(sizeof(cap_buf) - csize, epc - pc);
332 const uint8_t *cbuf = cap_buf;
334 /* Make certain that we can make progress. */
335 assert(tsize != 0);
336 info->read_memory_func(pc, cap_buf + csize, tsize, info);
337 csize += tsize;
339 if (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) {
340 (*info->fprintf_func)(info->stream,
341 "0x%08" PRIx64 ": %-12s %s\n",
342 insn->address, insn->mnemonic,
343 insn->op_str);
344 if (--count <= 0) {
345 break;
348 memmove(cap_buf, cbuf, csize);
351 cs_close(&handle);
352 return true;
354 #endif /* !CONFIG_USER_ONLY */
355 #else
356 # define cap_disas_target(i, p, s) false
357 # define cap_disas_host(i, p, s) false
358 # define cap_disas_monitor(i, p, c) false
359 #endif /* CONFIG_CAPSTONE */
361 /* Disassemble this for me please... (debugging). */
362 void target_disas(FILE *out, CPUState *cpu, target_ulong code,
363 target_ulong size)
365 CPUClass *cc = CPU_GET_CLASS(cpu);
366 target_ulong pc;
367 int count;
368 CPUDebug s;
370 INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
372 s.cpu = cpu;
373 s.info.read_memory_func = target_read_memory;
374 s.info.buffer_vma = code;
375 s.info.buffer_length = size;
376 s.info.print_address_func = generic_print_address;
377 s.info.cap_arch = -1;
378 s.info.cap_mode = 0;
380 #ifdef TARGET_WORDS_BIGENDIAN
381 s.info.endian = BFD_ENDIAN_BIG;
382 #else
383 s.info.endian = BFD_ENDIAN_LITTLE;
384 #endif
386 if (cc->disas_set_info) {
387 cc->disas_set_info(cpu, &s.info);
390 if (s.info.cap_arch >= 0 && cap_disas_target(&s.info, code, size)) {
391 return;
394 if (s.info.print_insn == NULL) {
395 s.info.print_insn = print_insn_od_target;
398 for (pc = code; size > 0; pc += count, size -= count) {
399 fprintf(out, "0x" TARGET_FMT_lx ": ", pc);
400 count = s.info.print_insn(pc, &s.info);
401 fprintf(out, "\n");
402 if (count < 0)
403 break;
404 if (size < count) {
405 fprintf(out,
406 "Disassembler disagrees with translator over instruction "
407 "decoding\n"
408 "Please report this to qemu-devel@nongnu.org\n");
409 break;
414 /* Disassemble this for me please... (debugging). */
415 void disas(FILE *out, void *code, unsigned long size)
417 uintptr_t pc;
418 int count;
419 CPUDebug s;
420 int (*print_insn)(bfd_vma pc, disassemble_info *info) = NULL;
422 INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
423 s.info.print_address_func = generic_print_host_address;
425 s.info.buffer = code;
426 s.info.buffer_vma = (uintptr_t)code;
427 s.info.buffer_length = size;
428 s.info.cap_arch = -1;
429 s.info.cap_mode = 0;
431 #ifdef HOST_WORDS_BIGENDIAN
432 s.info.endian = BFD_ENDIAN_BIG;
433 #else
434 s.info.endian = BFD_ENDIAN_LITTLE;
435 #endif
436 #if defined(CONFIG_TCG_INTERPRETER)
437 print_insn = print_insn_tci;
438 #elif defined(__i386__)
439 s.info.mach = bfd_mach_i386_i386;
440 print_insn = print_insn_i386;
441 s.info.cap_arch = CS_ARCH_X86;
442 s.info.cap_mode = CS_MODE_32;
443 #elif defined(__x86_64__)
444 s.info.mach = bfd_mach_x86_64;
445 print_insn = print_insn_i386;
446 s.info.cap_arch = CS_ARCH_X86;
447 s.info.cap_mode = CS_MODE_64;
448 #elif defined(_ARCH_PPC)
449 s.info.disassembler_options = (char *)"any";
450 print_insn = print_insn_ppc;
451 s.info.cap_arch = CS_ARCH_PPC;
452 # ifdef _ARCH_PPC64
453 s.info.cap_mode = CS_MODE_64;
454 # endif
455 #elif defined(__aarch64__) && defined(CONFIG_ARM_A64_DIS)
456 print_insn = print_insn_arm_a64;
457 s.info.cap_arch = CS_ARCH_ARM64;
458 #elif defined(__alpha__)
459 print_insn = print_insn_alpha;
460 #elif defined(__sparc__)
461 print_insn = print_insn_sparc;
462 s.info.mach = bfd_mach_sparc_v9b;
463 #elif defined(__arm__)
464 print_insn = print_insn_arm;
465 s.info.cap_arch = CS_ARCH_ARM;
466 /* TCG only generates code for arm mode. */
467 #elif defined(__MIPSEB__)
468 print_insn = print_insn_big_mips;
469 #elif defined(__MIPSEL__)
470 print_insn = print_insn_little_mips;
471 #elif defined(__m68k__)
472 print_insn = print_insn_m68k;
473 #elif defined(__s390__)
474 print_insn = print_insn_s390;
475 #elif defined(__hppa__)
476 print_insn = print_insn_hppa;
477 #endif
479 if (s.info.cap_arch >= 0 && cap_disas_host(&s.info, code, size)) {
480 return;
483 if (print_insn == NULL) {
484 print_insn = print_insn_od_host;
486 for (pc = (uintptr_t)code; size > 0; pc += count, size -= count) {
487 fprintf(out, "0x%08" PRIxPTR ": ", pc);
488 count = print_insn(pc, &s.info);
489 fprintf(out, "\n");
490 if (count < 0)
491 break;
495 /* Look up symbol for debugging purpose. Returns "" if unknown. */
496 const char *lookup_symbol(target_ulong orig_addr)
498 const char *symbol = "";
499 struct syminfo *s;
501 for (s = syminfos; s; s = s->next) {
502 symbol = s->lookup_symbol(s, orig_addr);
503 if (symbol[0] != '\0') {
504 break;
508 return symbol;
511 #if !defined(CONFIG_USER_ONLY)
513 #include "monitor/monitor.h"
515 static int
516 physical_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
517 struct disassemble_info *info)
519 cpu_physical_memory_read(memaddr, myaddr, length);
520 return 0;
523 /* Disassembler for the monitor. */
524 void monitor_disas(Monitor *mon, CPUState *cpu,
525 target_ulong pc, int nb_insn, int is_physical)
527 CPUClass *cc = CPU_GET_CLASS(cpu);
528 int count, i;
529 CPUDebug s;
531 INIT_DISASSEMBLE_INFO(s.info, (FILE *)mon, monitor_fprintf);
533 s.cpu = cpu;
534 s.info.read_memory_func
535 = (is_physical ? physical_read_memory : target_read_memory);
536 s.info.print_address_func = generic_print_address;
537 s.info.buffer_vma = pc;
538 s.info.cap_arch = -1;
539 s.info.cap_mode = 0;
541 #ifdef TARGET_WORDS_BIGENDIAN
542 s.info.endian = BFD_ENDIAN_BIG;
543 #else
544 s.info.endian = BFD_ENDIAN_LITTLE;
545 #endif
547 if (cc->disas_set_info) {
548 cc->disas_set_info(cpu, &s.info);
551 if (s.info.cap_arch >= 0 && cap_disas_monitor(&s.info, pc, nb_insn)) {
552 return;
555 if (!s.info.print_insn) {
556 monitor_printf(mon, "0x" TARGET_FMT_lx
557 ": Asm output not supported on this arch\n", pc);
558 return;
561 for(i = 0; i < nb_insn; i++) {
562 monitor_printf(mon, "0x" TARGET_FMT_lx ": ", pc);
563 count = s.info.print_insn(pc, &s.info);
564 monitor_printf(mon, "\n");
565 if (count < 0)
566 break;
567 pc += count;
570 #endif