]> git.proxmox.com Git - mirror_qemu.git/blob - disas.c
disas: Configure capstone for aarch64 host without libvixl
[mirror_qemu.git] / disas.c
1 /* General "disassemble this chunk" code. Used for debugging. */
2 #include "qemu/osdep.h"
3 #include "disas/dis-asm.h"
4 #include "elf.h"
5 #include "qemu/qemu-print.h"
6
7 #include "cpu.h"
8 #include "disas/disas.h"
9 #include "disas/capstone.h"
10
11 typedef struct CPUDebug {
12 struct disassemble_info info;
13 CPUState *cpu;
14 } CPUDebug;
15
16 /* Filled in by elfload.c. Simplistic, but will do for now. */
17 struct syminfo *syminfos = NULL;
18
19 /*
20 * Get LENGTH bytes from info's buffer, at host address memaddr.
21 * Transfer them to myaddr.
22 */
23 static int host_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
24 struct disassemble_info *info)
25 {
26 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 }
31 memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
32 return 0;
33 }
34
35 /*
36 * Get LENGTH bytes from info's buffer, at target address memaddr.
37 * Transfer them to myaddr.
38 */
39 static int target_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
40 struct disassemble_info *info)
41 {
42 CPUDebug *s = container_of(info, CPUDebug, info);
43 int r = cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, 0);
44 return r ? EIO : 0;
45 }
46
47 /*
48 * Print an error message. We can assume that this is in response to
49 * an error return from {host,target}_read_memory.
50 */
51 static void perror_memory(int status, bfd_vma memaddr,
52 struct disassemble_info *info)
53 {
54 if (status != EIO) {
55 /* Can't happen. */
56 info->fprintf_func(info->stream, "Unknown error %d\n", status);
57 } else {
58 /* Address between memaddr and memaddr + len was out of bounds. */
59 info->fprintf_func(info->stream,
60 "Address 0x%" PRIx64 " is out of bounds.\n",
61 memaddr);
62 }
63 }
64
65 /* Print address in hex. */
66 static void print_address(bfd_vma addr, struct disassemble_info *info)
67 {
68 info->fprintf_func(info->stream, "0x%" PRIx64, addr);
69 }
70
71 /* Print address in hex, truncated to the width of a host virtual address. */
72 static void host_print_address(bfd_vma addr, struct disassemble_info *info)
73 {
74 print_address((uintptr_t)addr, info);
75 }
76
77 /* Stub prevents some fruitless earching in optabs disassemblers. */
78 static int symbol_at_address(bfd_vma addr, struct disassemble_info *info)
79 {
80 return 1;
81 }
82
83 static int print_insn_objdump(bfd_vma pc, disassemble_info *info,
84 const char *prefix)
85 {
86 int i, n = info->buffer_length;
87 uint8_t *buf = g_malloc(n);
88
89 info->read_memory_func(pc, buf, n, info);
90
91 for (i = 0; i < n; ++i) {
92 if (i % 32 == 0) {
93 info->fprintf_func(info->stream, "\n%s: ", prefix);
94 }
95 info->fprintf_func(info->stream, "%02x", buf[i]);
96 }
97
98 g_free(buf);
99 return n;
100 }
101
102 static int print_insn_od_host(bfd_vma pc, disassemble_info *info)
103 {
104 return print_insn_objdump(pc, info, "OBJD-H");
105 }
106
107 static int print_insn_od_target(bfd_vma pc, disassemble_info *info)
108 {
109 return print_insn_objdump(pc, info, "OBJD-T");
110 }
111
112 #ifdef CONFIG_CAPSTONE
113 /* Temporary storage for the capstone library. This will be alloced via
114 malloc with a size private to the library; thus there's no reason not
115 to share this across calls and across host vs target disassembly. */
116 static __thread cs_insn *cap_insn;
117
118 /* Initialize the Capstone library. */
119 /* ??? It would be nice to cache this. We would need one handle for the
120 host and one for the target. For most targets we can reset specific
121 parameters via cs_option(CS_OPT_MODE, new_mode), but we cannot change
122 CS_ARCH_* in this way. Thus we would need to be able to close and
123 re-open the target handle with a different arch for the target in order
124 to handle AArch64 vs AArch32 mode switching. */
125 static cs_err cap_disas_start(disassemble_info *info, csh *handle)
126 {
127 cs_mode cap_mode = info->cap_mode;
128 cs_err err;
129
130 cap_mode += (info->endian == BFD_ENDIAN_BIG ? CS_MODE_BIG_ENDIAN
131 : CS_MODE_LITTLE_ENDIAN);
132
133 err = cs_open(info->cap_arch, cap_mode, handle);
134 if (err != CS_ERR_OK) {
135 return err;
136 }
137
138 /* ??? There probably ought to be a better place to put this. */
139 if (info->cap_arch == CS_ARCH_X86) {
140 /* We don't care about errors (if for some reason the library
141 is compiled without AT&T syntax); the user will just have
142 to deal with the Intel syntax. */
143 cs_option(*handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
144 }
145
146 /* "Disassemble" unknown insns as ".byte W,X,Y,Z". */
147 cs_option(*handle, CS_OPT_SKIPDATA, CS_OPT_ON);
148
149 /* Allocate temp space for cs_disasm_iter. */
150 if (cap_insn == NULL) {
151 cap_insn = cs_malloc(*handle);
152 if (cap_insn == NULL) {
153 cs_close(handle);
154 return CS_ERR_MEM;
155 }
156 }
157 return CS_ERR_OK;
158 }
159
160 static void cap_dump_insn_units(disassemble_info *info, cs_insn *insn,
161 int i, int n)
162 {
163 fprintf_function print = info->fprintf_func;
164 FILE *stream = info->stream;
165
166 switch (info->cap_insn_unit) {
167 case 4:
168 if (info->endian == BFD_ENDIAN_BIG) {
169 for (; i < n; i += 4) {
170 print(stream, " %08x", ldl_be_p(insn->bytes + i));
171
172 }
173 } else {
174 for (; i < n; i += 4) {
175 print(stream, " %08x", ldl_le_p(insn->bytes + i));
176 }
177 }
178 break;
179
180 case 2:
181 if (info->endian == BFD_ENDIAN_BIG) {
182 for (; i < n; i += 2) {
183 print(stream, " %04x", lduw_be_p(insn->bytes + i));
184 }
185 } else {
186 for (; i < n; i += 2) {
187 print(stream, " %04x", lduw_le_p(insn->bytes + i));
188 }
189 }
190 break;
191
192 default:
193 for (; i < n; i++) {
194 print(stream, " %02x", insn->bytes[i]);
195 }
196 break;
197 }
198 }
199
200 static void cap_dump_insn(disassemble_info *info, cs_insn *insn)
201 {
202 fprintf_function print = info->fprintf_func;
203 int i, n, split;
204
205 print(info->stream, "0x%08" PRIx64 ": ", insn->address);
206
207 n = insn->size;
208 split = info->cap_insn_split;
209
210 /* Dump the first SPLIT bytes of the instruction. */
211 cap_dump_insn_units(info, insn, 0, MIN(n, split));
212
213 /* Add padding up to SPLIT so that mnemonics line up. */
214 if (n < split) {
215 int width = (split - n) / info->cap_insn_unit;
216 width *= (2 * info->cap_insn_unit + 1);
217 print(info->stream, "%*s", width, "");
218 }
219
220 /* Print the actual instruction. */
221 print(info->stream, " %-8s %s\n", insn->mnemonic, insn->op_str);
222
223 /* Dump any remaining part of the insn on subsequent lines. */
224 for (i = split; i < n; i += split) {
225 print(info->stream, "0x%08" PRIx64 ": ", insn->address + i);
226 cap_dump_insn_units(info, insn, i, MIN(n, i + split));
227 print(info->stream, "\n");
228 }
229 }
230
231 /* Disassemble SIZE bytes at PC for the target. */
232 static bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size)
233 {
234 uint8_t cap_buf[1024];
235 csh handle;
236 cs_insn *insn;
237 size_t csize = 0;
238
239 if (cap_disas_start(info, &handle) != CS_ERR_OK) {
240 return false;
241 }
242 insn = cap_insn;
243
244 while (1) {
245 size_t tsize = MIN(sizeof(cap_buf) - csize, size);
246 const uint8_t *cbuf = cap_buf;
247
248 target_read_memory(pc + csize, cap_buf + csize, tsize, info);
249 csize += tsize;
250 size -= tsize;
251
252 while (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) {
253 cap_dump_insn(info, insn);
254 }
255
256 /* If the target memory is not consumed, go back for more... */
257 if (size != 0) {
258 /* ... taking care to move any remaining fractional insn
259 to the beginning of the buffer. */
260 if (csize != 0) {
261 memmove(cap_buf, cbuf, csize);
262 }
263 continue;
264 }
265
266 /* Since the target memory is consumed, we should not have
267 a remaining fractional insn. */
268 if (csize != 0) {
269 (*info->fprintf_func)(info->stream,
270 "Disassembler disagrees with translator "
271 "over instruction decoding\n"
272 "Please report this to qemu-devel@nongnu.org\n");
273 }
274 break;
275 }
276
277 cs_close(&handle);
278 return true;
279 }
280
281 /* Disassemble SIZE bytes at CODE for the host. */
282 static bool cap_disas_host(disassemble_info *info, void *code, size_t size)
283 {
284 csh handle;
285 const uint8_t *cbuf;
286 cs_insn *insn;
287 uint64_t pc;
288
289 if (cap_disas_start(info, &handle) != CS_ERR_OK) {
290 return false;
291 }
292 insn = cap_insn;
293
294 cbuf = code;
295 pc = (uintptr_t)code;
296
297 while (cs_disasm_iter(handle, &cbuf, &size, &pc, insn)) {
298 cap_dump_insn(info, insn);
299 }
300 if (size != 0) {
301 (*info->fprintf_func)(info->stream,
302 "Disassembler disagrees with TCG over instruction encoding\n"
303 "Please report this to qemu-devel@nongnu.org\n");
304 }
305
306 cs_close(&handle);
307 return true;
308 }
309
310 #if !defined(CONFIG_USER_ONLY)
311 /* Disassemble COUNT insns at PC for the target. */
312 static bool cap_disas_monitor(disassemble_info *info, uint64_t pc, int count)
313 {
314 uint8_t cap_buf[32];
315 csh handle;
316 cs_insn *insn;
317 size_t csize = 0;
318
319 if (cap_disas_start(info, &handle) != CS_ERR_OK) {
320 return false;
321 }
322 insn = cap_insn;
323
324 while (1) {
325 /* We want to read memory for one insn, but generically we do not
326 know how much memory that is. We have a small buffer which is
327 known to be sufficient for all supported targets. Try to not
328 read beyond the page, Just In Case. For even more simplicity,
329 ignore the actual target page size and use a 1k boundary. If
330 that turns out to be insufficient, we'll come back around the
331 loop and read more. */
332 uint64_t epc = QEMU_ALIGN_UP(pc + csize + 1, 1024);
333 size_t tsize = MIN(sizeof(cap_buf) - csize, epc - pc);
334 const uint8_t *cbuf = cap_buf;
335
336 /* Make certain that we can make progress. */
337 assert(tsize != 0);
338 info->read_memory_func(pc, cap_buf + csize, tsize, info);
339 csize += tsize;
340
341 if (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) {
342 cap_dump_insn(info, insn);
343 if (--count <= 0) {
344 break;
345 }
346 }
347 memmove(cap_buf, cbuf, csize);
348 }
349
350 cs_close(&handle);
351 return true;
352 }
353 #endif /* !CONFIG_USER_ONLY */
354 #else
355 # define cap_disas_target(i, p, s) false
356 # define cap_disas_host(i, p, s) false
357 # define cap_disas_monitor(i, p, c) false
358 # define cap_disas_plugin(i, p, c) false
359 #endif /* CONFIG_CAPSTONE */
360
361 static void initialize_debug(CPUDebug *s)
362 {
363 memset(s, 0, sizeof(*s));
364 s->info.arch = bfd_arch_unknown;
365 s->info.cap_arch = -1;
366 s->info.cap_insn_unit = 4;
367 s->info.cap_insn_split = 4;
368 s->info.memory_error_func = perror_memory;
369 s->info.symbol_at_address_func = symbol_at_address;
370 }
371
372 static void initialize_debug_target(CPUDebug *s, CPUState *cpu)
373 {
374 initialize_debug(s);
375
376 s->cpu = cpu;
377 s->info.read_memory_func = target_read_memory;
378 s->info.print_address_func = print_address;
379 #ifdef TARGET_WORDS_BIGENDIAN
380 s->info.endian = BFD_ENDIAN_BIG;
381 #else
382 s->info.endian = BFD_ENDIAN_LITTLE;
383 #endif
384
385 CPUClass *cc = CPU_GET_CLASS(cpu);
386 if (cc->disas_set_info) {
387 cc->disas_set_info(cpu, &s->info);
388 }
389 }
390
391 static void initialize_debug_host(CPUDebug *s)
392 {
393 initialize_debug(s);
394
395 s->info.read_memory_func = host_read_memory;
396 s->info.print_address_func = host_print_address;
397 #ifdef HOST_WORDS_BIGENDIAN
398 s->info.endian = BFD_ENDIAN_BIG;
399 #else
400 s->info.endian = BFD_ENDIAN_LITTLE;
401 #endif
402 #if defined(CONFIG_TCG_INTERPRETER)
403 s->info.print_insn = print_insn_tci;
404 #elif defined(__i386__)
405 s->info.mach = bfd_mach_i386_i386;
406 s->info.print_insn = print_insn_i386;
407 s->info.cap_arch = CS_ARCH_X86;
408 s->info.cap_mode = CS_MODE_32;
409 s->info.cap_insn_unit = 1;
410 s->info.cap_insn_split = 8;
411 #elif defined(__x86_64__)
412 s->info.mach = bfd_mach_x86_64;
413 s->info.print_insn = print_insn_i386;
414 s->info.cap_arch = CS_ARCH_X86;
415 s->info.cap_mode = CS_MODE_64;
416 s->info.cap_insn_unit = 1;
417 s->info.cap_insn_split = 8;
418 #elif defined(_ARCH_PPC)
419 s->info.disassembler_options = (char *)"any";
420 s->info.print_insn = print_insn_ppc;
421 s->info.cap_arch = CS_ARCH_PPC;
422 # ifdef _ARCH_PPC64
423 s->info.cap_mode = CS_MODE_64;
424 # endif
425 #elif defined(__riscv) && defined(CONFIG_RISCV_DIS)
426 #if defined(_ILP32) || (__riscv_xlen == 32)
427 s->info.print_insn = print_insn_riscv32;
428 #elif defined(_LP64)
429 s->info.print_insn = print_insn_riscv64;
430 #else
431 #error unsupported RISC-V ABI
432 #endif
433 #elif defined(__aarch64__)
434 s->info.cap_arch = CS_ARCH_ARM64;
435 # ifdef CONFIG_ARM_A64_DIS
436 s->info.print_insn = print_insn_arm_a64;
437 # endif
438 #elif defined(__alpha__)
439 s->info.print_insn = print_insn_alpha;
440 #elif defined(__sparc__)
441 s->info.print_insn = print_insn_sparc;
442 s->info.mach = bfd_mach_sparc_v9b;
443 #elif defined(__arm__)
444 /* TCG only generates code for arm mode. */
445 s->info.print_insn = print_insn_arm;
446 s->info.cap_arch = CS_ARCH_ARM;
447 #elif defined(__MIPSEB__)
448 s->info.print_insn = print_insn_big_mips;
449 #elif defined(__MIPSEL__)
450 s->info.print_insn = print_insn_little_mips;
451 #elif defined(__m68k__)
452 s->info.print_insn = print_insn_m68k;
453 #elif defined(__s390__)
454 s->info.print_insn = print_insn_s390;
455 #elif defined(__hppa__)
456 s->info.print_insn = print_insn_hppa;
457 #endif
458 }
459
460 /* Disassemble this for me please... (debugging). */
461 void target_disas(FILE *out, CPUState *cpu, target_ulong code,
462 target_ulong size)
463 {
464 target_ulong pc;
465 int count;
466 CPUDebug s;
467
468 initialize_debug_target(&s, cpu);
469 s.info.fprintf_func = fprintf;
470 s.info.stream = out;
471 s.info.buffer_vma = code;
472 s.info.buffer_length = size;
473
474 if (s.info.cap_arch >= 0 && cap_disas_target(&s.info, code, size)) {
475 return;
476 }
477
478 if (s.info.print_insn == NULL) {
479 s.info.print_insn = print_insn_od_target;
480 }
481
482 for (pc = code; size > 0; pc += count, size -= count) {
483 fprintf(out, "0x" TARGET_FMT_lx ": ", pc);
484 count = s.info.print_insn(pc, &s.info);
485 fprintf(out, "\n");
486 if (count < 0)
487 break;
488 if (size < count) {
489 fprintf(out,
490 "Disassembler disagrees with translator over instruction "
491 "decoding\n"
492 "Please report this to qemu-devel@nongnu.org\n");
493 break;
494 }
495 }
496 }
497
498 static int plugin_printf(FILE *stream, const char *fmt, ...)
499 {
500 /* We abuse the FILE parameter to pass a GString. */
501 GString *s = (GString *)stream;
502 int initial_len = s->len;
503 va_list va;
504
505 va_start(va, fmt);
506 g_string_append_vprintf(s, fmt, va);
507 va_end(va);
508
509 return s->len - initial_len;
510 }
511
512 static void plugin_print_address(bfd_vma addr, struct disassemble_info *info)
513 {
514 /* does nothing */
515 }
516
517
518 #ifdef CONFIG_CAPSTONE
519 /* Disassemble a single instruction directly into plugin output */
520 static
521 bool cap_disas_plugin(disassemble_info *info, uint64_t pc, size_t size)
522 {
523 uint8_t cap_buf[64];
524 const uint8_t *cbuf = cap_buf;
525 csh handle;
526
527 if (cap_disas_start(info, &handle) != CS_ERR_OK) {
528 return false;
529 }
530
531 assert(size < sizeof(cap_buf));
532 target_read_memory(pc, cap_buf, size, info);
533
534 if (cs_disasm_iter(handle, &cbuf, &size, &pc, cap_insn)) {
535 GString *s = (GString *)info->stream;
536 g_string_printf(s, "%s %s", cap_insn->mnemonic, cap_insn->op_str);
537 }
538
539 cs_close(&handle);
540 return true;
541 }
542 #endif
543
544 /*
545 * We should only be dissembling one instruction at a time here. If
546 * there is left over it usually indicates the front end has read more
547 * bytes than it needed.
548 */
549 char *plugin_disas(CPUState *cpu, uint64_t addr, size_t size)
550 {
551 CPUDebug s;
552 GString *ds = g_string_new(NULL);
553
554 initialize_debug_target(&s, cpu);
555 s.info.fprintf_func = plugin_printf;
556 s.info.stream = (FILE *)ds; /* abuse this slot */
557 s.info.buffer_vma = addr;
558 s.info.buffer_length = size;
559 s.info.print_address_func = plugin_print_address;
560
561 if (s.info.cap_arch >= 0 && cap_disas_plugin(&s.info, addr, size)) {
562 ; /* done */
563 } else if (s.info.print_insn) {
564 s.info.print_insn(addr, &s.info);
565 } else {
566 ; /* cannot disassemble -- return empty string */
567 }
568
569 /* Return the buffer, freeing the GString container. */
570 return g_string_free(ds, false);
571 }
572
573 /* Disassemble this for me please... (debugging). */
574 void disas(FILE *out, void *code, unsigned long size)
575 {
576 uintptr_t pc;
577 int count;
578 CPUDebug s;
579
580 initialize_debug_host(&s);
581 s.info.fprintf_func = fprintf;
582 s.info.stream = out;
583 s.info.buffer = code;
584 s.info.buffer_vma = (uintptr_t)code;
585 s.info.buffer_length = size;
586
587 if (s.info.cap_arch >= 0 && cap_disas_host(&s.info, code, size)) {
588 return;
589 }
590
591 if (s.info.print_insn == NULL) {
592 s.info.print_insn = print_insn_od_host;
593 }
594 for (pc = (uintptr_t)code; size > 0; pc += count, size -= count) {
595 fprintf(out, "0x%08" PRIxPTR ": ", pc);
596 count = s.info.print_insn(pc, &s.info);
597 fprintf(out, "\n");
598 if (count < 0) {
599 break;
600 }
601 }
602
603 }
604
605 /* Look up symbol for debugging purpose. Returns "" if unknown. */
606 const char *lookup_symbol(target_ulong orig_addr)
607 {
608 const char *symbol = "";
609 struct syminfo *s;
610
611 for (s = syminfos; s; s = s->next) {
612 symbol = s->lookup_symbol(s, orig_addr);
613 if (symbol[0] != '\0') {
614 break;
615 }
616 }
617
618 return symbol;
619 }
620
621 #if !defined(CONFIG_USER_ONLY)
622
623 #include "monitor/monitor.h"
624
625 static int
626 physical_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
627 struct disassemble_info *info)
628 {
629 CPUDebug *s = container_of(info, CPUDebug, info);
630 MemTxResult res;
631
632 res = address_space_read(s->cpu->as, memaddr, MEMTXATTRS_UNSPECIFIED,
633 myaddr, length);
634 return res == MEMTX_OK ? 0 : EIO;
635 }
636
637 /* Disassembler for the monitor. */
638 void monitor_disas(Monitor *mon, CPUState *cpu,
639 target_ulong pc, int nb_insn, int is_physical)
640 {
641 int count, i;
642 CPUDebug s;
643
644 initialize_debug_target(&s, cpu);
645 s.info.fprintf_func = qemu_fprintf;
646 if (is_physical) {
647 s.info.read_memory_func = physical_read_memory;
648 }
649 s.info.buffer_vma = pc;
650
651 if (s.info.cap_arch >= 0 && cap_disas_monitor(&s.info, pc, nb_insn)) {
652 return;
653 }
654
655 if (!s.info.print_insn) {
656 monitor_printf(mon, "0x" TARGET_FMT_lx
657 ": Asm output not supported on this arch\n", pc);
658 return;
659 }
660
661 for(i = 0; i < nb_insn; i++) {
662 monitor_printf(mon, "0x" TARGET_FMT_lx ": ", pc);
663 count = s.info.print_insn(pc, &s.info);
664 monitor_printf(mon, "\n");
665 if (count < 0)
666 break;
667 pc += count;
668 }
669 }
670 #endif