xref: /openbmc/qemu/disas/disas-host.c (revision 3dba3c0b)
1 /*
2  * Routines for host 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 /*
13  * Get LENGTH bytes from info's buffer, at host address memaddr.
14  * Transfer them to myaddr.
15  */
16 static int host_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
17                             struct disassemble_info *info)
18 {
19     if (memaddr < info->buffer_vma
20         || memaddr + length > info->buffer_vma + info->buffer_length) {
21         /* Out of bounds.  Use EIO because GDB uses it.  */
22         return EIO;
23     }
24     memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
25     return 0;
26 }
27 
28 /* Print address in hex, truncated to the width of a host virtual address. */
29 static void host_print_address(bfd_vma addr, struct disassemble_info *info)
30 {
31     info->fprintf_func(info->stream, "0x%" PRIxPTR, (uintptr_t)addr);
32 }
33 
34 static void initialize_debug_host(CPUDebug *s)
35 {
36     disas_initialize_debug(s);
37 
38     s->info.read_memory_func = host_read_memory;
39     s->info.print_address_func = host_print_address;
40 #if HOST_BIG_ENDIAN
41     s->info.endian = BFD_ENDIAN_BIG;
42 #else
43     s->info.endian = BFD_ENDIAN_LITTLE;
44 #endif
45 #if defined(CONFIG_TCG_INTERPRETER)
46     s->info.print_insn = print_insn_tci;
47 #elif defined(__i386__)
48     s->info.mach = bfd_mach_i386_i386;
49     s->info.cap_arch = CS_ARCH_X86;
50     s->info.cap_mode = CS_MODE_32;
51     s->info.cap_insn_unit = 1;
52     s->info.cap_insn_split = 8;
53 #elif defined(__x86_64__)
54     s->info.mach = bfd_mach_x86_64;
55     s->info.cap_arch = CS_ARCH_X86;
56     s->info.cap_mode = CS_MODE_64;
57     s->info.cap_insn_unit = 1;
58     s->info.cap_insn_split = 8;
59 #elif defined(_ARCH_PPC)
60     s->info.cap_arch = CS_ARCH_PPC;
61 # ifdef _ARCH_PPC64
62     s->info.cap_mode = CS_MODE_64;
63 # endif
64 #elif defined(__riscv)
65 #if defined(_ILP32) || (__riscv_xlen == 32)
66     s->info.print_insn = print_insn_riscv32;
67 #elif defined(_LP64)
68     s->info.print_insn = print_insn_riscv64;
69 #else
70 #error unsupported RISC-V ABI
71 #endif
72 #elif defined(__aarch64__)
73     s->info.cap_arch = CS_ARCH_ARM64;
74 #elif defined(__alpha__)
75     s->info.print_insn = print_insn_alpha;
76 #elif defined(__sparc__)
77     s->info.print_insn = print_insn_sparc;
78     s->info.mach = bfd_mach_sparc_v9b;
79 #elif defined(__arm__)
80     /* TCG only generates code for arm mode.  */
81     s->info.cap_arch = CS_ARCH_ARM;
82 #elif defined(__MIPSEB__)
83     s->info.print_insn = print_insn_big_mips;
84 #elif defined(__MIPSEL__)
85     s->info.print_insn = print_insn_little_mips;
86 #elif defined(__m68k__)
87     s->info.print_insn = print_insn_m68k;
88 #elif defined(__s390__)
89     s->info.cap_arch = CS_ARCH_SYSZ;
90     s->info.cap_insn_unit = 2;
91     s->info.cap_insn_split = 6;
92 #elif defined(__hppa__)
93     s->info.print_insn = print_insn_hppa;
94 #elif defined(__loongarch__)
95     s->info.print_insn = print_insn_loongarch;
96 #endif
97 }
98 
99 /* Disassemble this for me please... (debugging). */
100 void disas(FILE *out, const void *code, size_t size)
101 {
102     uintptr_t pc;
103     int count;
104     CPUDebug s;
105 
106     initialize_debug_host(&s);
107     s.info.fprintf_func = fprintf;
108     s.info.stream = out;
109     s.info.buffer = code;
110     s.info.buffer_vma = (uintptr_t)code;
111     s.info.buffer_length = size;
112     s.info.show_opcodes = true;
113 
114     if (s.info.cap_arch >= 0 && cap_disas_host(&s.info, code, size)) {
115         return;
116     }
117 
118     if (s.info.print_insn == NULL) {
119         s.info.print_insn = print_insn_od_host;
120     }
121     for (pc = (uintptr_t)code; size > 0; pc += count, size -= count) {
122         fprintf(out, "0x%08" PRIxPTR ":  ", pc);
123         count = s.info.print_insn(pc, &s.info);
124         fprintf(out, "\n");
125         if (count < 0) {
126             break;
127         }
128     }
129 }
130