xref: /qemu/disas/disas-common.c (revision 5136598e2667f35ef3dc1d757616a266bd5eb3a2)
1 /*
2  * Common routines for 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 "hw/core/cpu.h"
10 #include "disas-internal.h"
11 
12 
13 /* Filled in by elfload.c.  Simplistic, but will do for now. */
14 struct syminfo *syminfos = NULL;
15 
16 /*
17  * Print an error message.  We can assume that this is in response to
18  * an error return from {host,target}_read_memory.
19  */
perror_memory(int status,bfd_vma memaddr,struct disassemble_info * info)20 static void perror_memory(int status, bfd_vma memaddr,
21                           struct disassemble_info *info)
22 {
23     if (status != EIO) {
24         /* Can't happen.  */
25         info->fprintf_func(info->stream, "Unknown error %d\n", status);
26     } else {
27         /* Address between memaddr and memaddr + len was out of bounds.  */
28         info->fprintf_func(info->stream,
29                            "Address 0x%" PRIx64 " is out of bounds.\n",
30                            memaddr);
31     }
32 }
33 
34 /* Print address in hex. */
print_address(bfd_vma addr,struct disassemble_info * info)35 static void print_address(bfd_vma addr, struct disassemble_info *info)
36 {
37     info->fprintf_func(info->stream, "0x%" PRIx64, addr);
38 }
39 
40 /* Stub prevents some fruitless earching in optabs disassemblers. */
symbol_at_address(bfd_vma addr,struct disassemble_info * info)41 static int symbol_at_address(bfd_vma addr, struct disassemble_info *info)
42 {
43     return 1;
44 }
45 
disas_initialize_debug(CPUDebug * s)46 void disas_initialize_debug(CPUDebug *s)
47 {
48     memset(s, 0, sizeof(*s));
49     s->info.arch = bfd_arch_unknown;
50     s->info.cap_arch = -1;
51     s->info.cap_insn_unit = 4;
52     s->info.cap_insn_split = 4;
53     s->info.memory_error_func = perror_memory;
54     s->info.symbol_at_address_func = symbol_at_address;
55 }
56 
disas_initialize_debug_target(CPUDebug * s,CPUState * cpu)57 void disas_initialize_debug_target(CPUDebug *s, CPUState *cpu)
58 {
59     disas_initialize_debug(s);
60 
61     s->cpu = cpu;
62     s->info.print_address_func = print_address;
63     s->info.endian = BFD_ENDIAN_UNKNOWN;
64 
65     if (cpu->cc->disas_set_info) {
66         cpu->cc->disas_set_info(cpu, &s->info);
67         g_assert(s->info.endian != BFD_ENDIAN_UNKNOWN);
68     }
69 }
70 
disas_gstring_printf(FILE * stream,const char * fmt,...)71 int disas_gstring_printf(FILE *stream, const char *fmt, ...)
72 {
73     /* We abuse the FILE parameter to pass a GString. */
74     GString *s = (GString *)stream;
75     int initial_len = s->len;
76     va_list va;
77 
78     va_start(va, fmt);
79     g_string_append_vprintf(s, fmt, va);
80     va_end(va);
81 
82     return s->len - initial_len;
83 }
84 
85 /* Look up symbol for debugging purpose.  Returns "" if unknown. */
lookup_symbol(uint64_t orig_addr)86 const char *lookup_symbol(uint64_t orig_addr)
87 {
88     const char *symbol = "";
89     struct syminfo *s;
90 
91     for (s = syminfos; s; s = s->next) {
92         symbol = s->lookup_symbol(s, orig_addr);
93         if (symbol[0] != '\0') {
94             break;
95         }
96     }
97 
98     return symbol;
99 }
100