1 /* General "disassemble this chunk" code. Used for debugging. */
2 #include "qemu/osdep.h"
3 #include "disas/dis-asm.h"
5 #include "qemu/qemu-print.h"
8 #include "disas/disas.h"
9 #include "disas/capstone.h"
11 typedef struct CPUDebug
{
12 struct disassemble_info info
;
16 /* Filled in by elfload.c. Simplistic, but will do for now. */
17 struct syminfo
*syminfos
= NULL
;
20 * Get LENGTH bytes from info's buffer, at host address memaddr.
21 * Transfer them to myaddr.
23 static int host_read_memory(bfd_vma memaddr
, bfd_byte
*myaddr
, int length
,
24 struct disassemble_info
*info
)
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. */
31 memcpy (myaddr
, info
->buffer
+ (memaddr
- info
->buffer_vma
), length
);
36 * Get LENGTH bytes from info's buffer, at target address memaddr.
37 * Transfer them to myaddr.
39 static int target_read_memory(bfd_vma memaddr
, bfd_byte
*myaddr
, int length
,
40 struct disassemble_info
*info
)
42 CPUDebug
*s
= container_of(info
, CPUDebug
, info
);
43 int r
= cpu_memory_rw_debug(s
->cpu
, memaddr
, myaddr
, length
, 0);
48 * Print an error message. We can assume that this is in response to
49 * an error return from {host,target}_read_memory.
51 static void perror_memory(int status
, bfd_vma memaddr
,
52 struct disassemble_info
*info
)
56 info
->fprintf_func(info
->stream
, "Unknown error %d\n", status
);
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",
65 /* Print address in hex. */
66 static void print_address(bfd_vma addr
, struct disassemble_info
*info
)
68 info
->fprintf_func(info
->stream
, "0x%" PRIx64
, addr
);
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
)
74 print_address((uintptr_t)addr
, info
);
77 /* Stub prevents some fruitless earching in optabs disassemblers. */
78 static int symbol_at_address(bfd_vma addr
, struct disassemble_info
*info
)
83 static int print_insn_objdump(bfd_vma pc
, disassemble_info
*info
,
86 int i
, n
= info
->buffer_length
;
87 uint8_t *buf
= g_malloc(n
);
89 info
->read_memory_func(pc
, buf
, n
, info
);
91 for (i
= 0; i
< n
; ++i
) {
93 info
->fprintf_func(info
->stream
, "\n%s: ", prefix
);
95 info
->fprintf_func(info
->stream
, "%02x", buf
[i
]);
102 static int print_insn_od_host(bfd_vma pc
, disassemble_info
*info
)
104 return print_insn_objdump(pc
, info
, "OBJD-H");
107 static int print_insn_od_target(bfd_vma pc
, disassemble_info
*info
)
109 return print_insn_objdump(pc
, info
, "OBJD-T");
112 static void initialize_debug(CPUDebug
*s
)
114 memset(s
, 0, sizeof(*s
));
115 s
->info
.arch
= bfd_arch_unknown
;
116 s
->info
.cap_arch
= -1;
117 s
->info
.cap_insn_unit
= 4;
118 s
->info
.cap_insn_split
= 4;
119 s
->info
.memory_error_func
= perror_memory
;
120 s
->info
.symbol_at_address_func
= symbol_at_address
;
123 static void initialize_debug_target(CPUDebug
*s
, CPUState
*cpu
)
128 s
->info
.read_memory_func
= target_read_memory
;
129 s
->info
.print_address_func
= print_address
;
130 #ifdef TARGET_WORDS_BIGENDIAN
131 s
->info
.endian
= BFD_ENDIAN_BIG
;
133 s
->info
.endian
= BFD_ENDIAN_LITTLE
;
136 CPUClass
*cc
= CPU_GET_CLASS(cpu
);
137 if (cc
->disas_set_info
) {
138 cc
->disas_set_info(cpu
, &s
->info
);
142 static void initialize_debug_host(CPUDebug
*s
)
146 s
->info
.read_memory_func
= host_read_memory
;
147 s
->info
.print_address_func
= host_print_address
;
148 #ifdef HOST_WORDS_BIGENDIAN
149 s
->info
.endian
= BFD_ENDIAN_BIG
;
151 s
->info
.endian
= BFD_ENDIAN_LITTLE
;
153 #if defined(CONFIG_TCG_INTERPRETER)
154 s
->info
.print_insn
= print_insn_tci
;
155 #elif defined(__i386__)
156 s
->info
.mach
= bfd_mach_i386_i386
;
157 s
->info
.print_insn
= print_insn_i386
;
158 s
->info
.cap_arch
= CS_ARCH_X86
;
159 s
->info
.cap_mode
= CS_MODE_32
;
160 s
->info
.cap_insn_unit
= 1;
161 s
->info
.cap_insn_split
= 8;
162 #elif defined(__x86_64__)
163 s
->info
.mach
= bfd_mach_x86_64
;
164 s
->info
.print_insn
= print_insn_i386
;
165 s
->info
.cap_arch
= CS_ARCH_X86
;
166 s
->info
.cap_mode
= CS_MODE_64
;
167 s
->info
.cap_insn_unit
= 1;
168 s
->info
.cap_insn_split
= 8;
169 #elif defined(_ARCH_PPC)
170 s
->info
.disassembler_options
= (char *)"any";
171 s
->info
.print_insn
= print_insn_ppc
;
172 s
->info
.cap_arch
= CS_ARCH_PPC
;
174 s
->info
.cap_mode
= CS_MODE_64
;
176 #elif defined(__riscv) && defined(CONFIG_RISCV_DIS)
177 #if defined(_ILP32) || (__riscv_xlen == 32)
178 s
->info
.print_insn
= print_insn_riscv32
;
180 s
->info
.print_insn
= print_insn_riscv64
;
182 #error unsupported RISC-V ABI
184 #elif defined(__aarch64__)
185 s
->info
.cap_arch
= CS_ARCH_ARM64
;
186 # ifdef CONFIG_ARM_A64_DIS
187 s
->info
.print_insn
= print_insn_arm_a64
;
189 #elif defined(__alpha__)
190 s
->info
.print_insn
= print_insn_alpha
;
191 #elif defined(__sparc__)
192 s
->info
.print_insn
= print_insn_sparc
;
193 s
->info
.mach
= bfd_mach_sparc_v9b
;
194 #elif defined(__arm__)
195 /* TCG only generates code for arm mode. */
196 s
->info
.print_insn
= print_insn_arm
;
197 s
->info
.cap_arch
= CS_ARCH_ARM
;
198 #elif defined(__MIPSEB__)
199 s
->info
.print_insn
= print_insn_big_mips
;
200 #elif defined(__MIPSEL__)
201 s
->info
.print_insn
= print_insn_little_mips
;
202 #elif defined(__m68k__)
203 s
->info
.print_insn
= print_insn_m68k
;
204 #elif defined(__s390__)
205 s
->info
.print_insn
= print_insn_s390
;
206 s
->info
.cap_arch
= CS_ARCH_SYSZ
;
207 s
->info
.cap_insn_unit
= 2;
208 s
->info
.cap_insn_split
= 6;
209 #elif defined(__hppa__)
210 s
->info
.print_insn
= print_insn_hppa
;
214 /* Disassemble this for me please... (debugging). */
215 void target_disas(FILE *out
, CPUState
*cpu
, target_ulong code
,
222 initialize_debug_target(&s
, cpu
);
223 s
.info
.fprintf_func
= fprintf
;
225 s
.info
.buffer_vma
= code
;
226 s
.info
.buffer_length
= size
;
228 if (s
.info
.cap_arch
>= 0 && cap_disas_target(&s
.info
, code
, size
)) {
232 if (s
.info
.print_insn
== NULL
) {
233 s
.info
.print_insn
= print_insn_od_target
;
236 for (pc
= code
; size
> 0; pc
+= count
, size
-= count
) {
237 fprintf(out
, "0x" TARGET_FMT_lx
": ", pc
);
238 count
= s
.info
.print_insn(pc
, &s
.info
);
244 "Disassembler disagrees with translator over instruction "
246 "Please report this to qemu-devel@nongnu.org\n");
252 static int plugin_printf(FILE *stream
, const char *fmt
, ...)
254 /* We abuse the FILE parameter to pass a GString. */
255 GString
*s
= (GString
*)stream
;
256 int initial_len
= s
->len
;
260 g_string_append_vprintf(s
, fmt
, va
);
263 return s
->len
- initial_len
;
266 static void plugin_print_address(bfd_vma addr
, struct disassemble_info
*info
)
273 * We should only be dissembling one instruction at a time here. If
274 * there is left over it usually indicates the front end has read more
275 * bytes than it needed.
277 char *plugin_disas(CPUState
*cpu
, uint64_t addr
, size_t size
)
280 GString
*ds
= g_string_new(NULL
);
282 initialize_debug_target(&s
, cpu
);
283 s
.info
.fprintf_func
= plugin_printf
;
284 s
.info
.stream
= (FILE *)ds
; /* abuse this slot */
285 s
.info
.buffer_vma
= addr
;
286 s
.info
.buffer_length
= size
;
287 s
.info
.print_address_func
= plugin_print_address
;
289 if (s
.info
.cap_arch
>= 0 && cap_disas_plugin(&s
.info
, addr
, size
)) {
291 } else if (s
.info
.print_insn
) {
292 s
.info
.print_insn(addr
, &s
.info
);
294 ; /* cannot disassemble -- return empty string */
297 /* Return the buffer, freeing the GString container. */
298 return g_string_free(ds
, false);
301 /* Disassemble this for me please... (debugging). */
302 void disas(FILE *out
, const void *code
, unsigned long size
)
308 initialize_debug_host(&s
);
309 s
.info
.fprintf_func
= fprintf
;
311 s
.info
.buffer
= code
;
312 s
.info
.buffer_vma
= (uintptr_t)code
;
313 s
.info
.buffer_length
= size
;
315 if (s
.info
.cap_arch
>= 0 && cap_disas_host(&s
.info
, code
, size
)) {
319 if (s
.info
.print_insn
== NULL
) {
320 s
.info
.print_insn
= print_insn_od_host
;
322 for (pc
= (uintptr_t)code
; size
> 0; pc
+= count
, size
-= count
) {
323 fprintf(out
, "0x%08" PRIxPTR
": ", pc
);
324 count
= s
.info
.print_insn(pc
, &s
.info
);
333 /* Look up symbol for debugging purpose. Returns "" if unknown. */
334 const char *lookup_symbol(target_ulong orig_addr
)
336 const char *symbol
= "";
339 for (s
= syminfos
; s
; s
= s
->next
) {
340 symbol
= s
->lookup_symbol(s
, orig_addr
);
341 if (symbol
[0] != '\0') {
349 #if !defined(CONFIG_USER_ONLY)
351 #include "monitor/monitor.h"
354 physical_read_memory(bfd_vma memaddr
, bfd_byte
*myaddr
, int length
,
355 struct disassemble_info
*info
)
357 CPUDebug
*s
= container_of(info
, CPUDebug
, info
);
360 res
= address_space_read(s
->cpu
->as
, memaddr
, MEMTXATTRS_UNSPECIFIED
,
362 return res
== MEMTX_OK
? 0 : EIO
;
365 /* Disassembler for the monitor. */
366 void monitor_disas(Monitor
*mon
, CPUState
*cpu
,
367 target_ulong pc
, int nb_insn
, int is_physical
)
372 initialize_debug_target(&s
, cpu
);
373 s
.info
.fprintf_func
= qemu_fprintf
;
375 s
.info
.read_memory_func
= physical_read_memory
;
377 s
.info
.buffer_vma
= pc
;
379 if (s
.info
.cap_arch
>= 0 && cap_disas_monitor(&s
.info
, pc
, nb_insn
)) {
383 if (!s
.info
.print_insn
) {
384 monitor_printf(mon
, "0x" TARGET_FMT_lx
385 ": Asm output not supported on this arch\n", pc
);
389 for(i
= 0; i
< nb_insn
; i
++) {
390 monitor_printf(mon
, "0x" TARGET_FMT_lx
": ", pc
);
391 count
= s
.info
.print_insn(pc
, &s
.info
);
392 monitor_printf(mon
, "\n");