xref: /openbmc/qemu/disas/disas-target.c (revision c0d691ab844db8cdf2be8f6cf43887cfff56e386)
1 /*
2  * Routines for target instruction disassembly.
3  * SPDX-License-Identifier: GPL-2.0-or-later
4  */
5 
6 #include "qemu/osdep.h"
7 #include "disas/disas.h"
8 #include "disas/capstone.h"
9 #include "disas-internal.h"
10 
11 
12 void target_disas(FILE *out, CPUState *cpu, uint64_t code, size_t size)
13 {
14     uint64_t pc;
15     int count;
16     CPUDebug s;
17 
18     disas_initialize_debug_target(&s, cpu);
19     s.info.fprintf_func = fprintf;
20     s.info.stream = out;
21     s.info.buffer_vma = code;
22     s.info.buffer_length = size;
23     s.info.show_opcodes = true;
24 
25     if (s.info.cap_arch >= 0 && cap_disas_target(&s.info, code, size)) {
26         return;
27     }
28 
29     if (s.info.print_insn == NULL) {
30         s.info.print_insn = print_insn_od_target;
31     }
32 
33     for (pc = code; size > 0; pc += count, size -= count) {
34         fprintf(out, "0x%08" PRIx64 ":  ", pc);
35         count = s.info.print_insn(pc, &s.info);
36         fprintf(out, "\n");
37         if (count < 0) {
38             break;
39         }
40         if (size < count) {
41             fprintf(out,
42                     "Disassembler disagrees with translator over instruction "
43                     "decoding\n"
44                     "Please report this to qemu-devel@nongnu.org\n");
45             break;
46         }
47     }
48 }
49 
50 #ifdef CONFIG_PLUGIN
51 static void plugin_print_address(bfd_vma addr, struct disassemble_info *info)
52 {
53     /* does nothing */
54 }
55 
56 /*
57  * We should only be dissembling one instruction at a time here. If
58  * there is left over it usually indicates the front end has read more
59  * bytes than it needed.
60  */
61 char *plugin_disas(CPUState *cpu, uint64_t addr, size_t size)
62 {
63     CPUDebug s;
64     GString *ds = g_string_new(NULL);
65 
66     disas_initialize_debug_target(&s, cpu);
67     s.info.fprintf_func = disas_gstring_printf;
68     s.info.stream = (FILE *)ds;  /* abuse this slot */
69     s.info.buffer_vma = addr;
70     s.info.buffer_length = size;
71     s.info.print_address_func = plugin_print_address;
72 
73     if (s.info.cap_arch >= 0 && cap_disas_plugin(&s.info, addr, size)) {
74         ; /* done */
75     } else if (s.info.print_insn) {
76         s.info.print_insn(addr, &s.info);
77     } else {
78         ; /* cannot disassemble -- return empty string */
79     }
80 
81     /* Return the buffer, freeing the GString container.  */
82     return g_string_free(ds, false);
83 }
84 #endif /* CONFIG_PLUGIN */
85