blob: 475aa86c89856c5f43b77bcc10c0c33fe50a3126 [file] [log] [blame]
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001/* General "disassemble this chunk" code. Used for debugging. */
2#include "config.h"
3#include "dis-asm.h"
4#include "elf.h"
5#include <errno.h>
6
7#include "cpu.h"
8#include "exec-all.h"
9#include "disas.h"
10
Jun Nakajima1321c762011-03-04 17:17:45 -080011#ifdef TARGET_I386
12#include "kvm.h"
13#endif
14
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080015/* Filled in by elfload.c. Simplistic, but will do for now. */
16struct syminfo *syminfos = NULL;
17
18/* Get LENGTH bytes from info's buffer, at target address memaddr.
19 Transfer them to myaddr. */
20int
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070021buffer_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
22 struct disassemble_info *info)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080023{
24 if (memaddr < info->buffer_vma
25 || memaddr + length > info->buffer_vma + info->buffer_length)
26 /* Out of bounds. Use EIO because GDB uses it. */
27 return EIO;
28 memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
29 return 0;
30}
31
32/* Get LENGTH bytes from info's buffer, at target address memaddr.
33 Transfer them to myaddr. */
34static int
35target_read_memory (bfd_vma memaddr,
36 bfd_byte *myaddr,
37 int length,
38 struct disassemble_info *info)
39{
Jun Nakajima1321c762011-03-04 17:17:45 -080040#ifdef TARGET_I386
41 if (kvm_enabled())
42 cpu_synchronize_state(cpu_single_env, 0);
43#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070044 cpu_memory_rw_debug(cpu_single_env, memaddr, myaddr, length, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080045 return 0;
46}
47
48/* Print an error message. We can assume that this is in response to
49 an error return from buffer_read_memory. */
50void
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070051perror_memory (int status, bfd_vma memaddr, struct disassemble_info *info)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080052{
53 if (status != EIO)
54 /* Can't happen. */
55 (*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
56 else
57 /* Actually, address between memaddr and memaddr + len was
58 out of bounds. */
59 (*info->fprintf_func) (info->stream,
60 "Address 0x%" PRIx64 " is out of bounds.\n", memaddr);
61}
62
63/* This could be in a separate file, to save miniscule amounts of space
64 in statically linked executables. */
65
66/* Just print the address is hex. This is included for completeness even
67 though both GDB and objdump provide their own (to print symbolic
68 addresses). */
69
70void
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070071generic_print_address (bfd_vma addr, struct disassemble_info *info)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080072{
73 (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr);
74}
75
76/* Just return the given address. */
77
78int
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070079generic_symbol_at_address (bfd_vma addr, struct disassemble_info *info)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080080{
81 return 1;
82}
83
David Turner75fb4a02010-09-09 22:56:10 +020084bfd_vma bfd_getl64 (const bfd_byte *addr)
85{
86 unsigned long long v;
87
88 v = (unsigned long long) addr[0];
89 v |= (unsigned long long) addr[1] << 8;
90 v |= (unsigned long long) addr[2] << 16;
91 v |= (unsigned long long) addr[3] << 24;
92 v |= (unsigned long long) addr[4] << 32;
93 v |= (unsigned long long) addr[5] << 40;
94 v |= (unsigned long long) addr[6] << 48;
95 v |= (unsigned long long) addr[7] << 56;
96 return (bfd_vma) v;
97}
98
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080099bfd_vma bfd_getl32 (const bfd_byte *addr)
100{
101 unsigned long v;
102
103 v = (unsigned long) addr[0];
104 v |= (unsigned long) addr[1] << 8;
105 v |= (unsigned long) addr[2] << 16;
106 v |= (unsigned long) addr[3] << 24;
107 return (bfd_vma) v;
108}
109
110bfd_vma bfd_getb32 (const bfd_byte *addr)
111{
112 unsigned long v;
113
114 v = (unsigned long) addr[0] << 24;
115 v |= (unsigned long) addr[1] << 16;
116 v |= (unsigned long) addr[2] << 8;
117 v |= (unsigned long) addr[3];
118 return (bfd_vma) v;
119}
120
121bfd_vma bfd_getl16 (const bfd_byte *addr)
122{
123 unsigned long v;
124
125 v = (unsigned long) addr[0];
126 v |= (unsigned long) addr[1] << 8;
127 return (bfd_vma) v;
128}
129
130bfd_vma bfd_getb16 (const bfd_byte *addr)
131{
132 unsigned long v;
133
134 v = (unsigned long) addr[0] << 24;
135 v |= (unsigned long) addr[1] << 16;
136 return (bfd_vma) v;
137}
138
139#ifdef TARGET_ARM
140static int
141print_insn_thumb1(bfd_vma pc, disassemble_info *info)
142{
143 return print_insn_arm(pc | 1, info);
144}
145#endif
146
147/* Disassemble this for me please... (debugging). 'flags' has the following
148 values:
149 i386 - nonzero means 16 bit code
150 arm - nonzero means thumb code
151 ppc - nonzero means little endian
152 other targets - unused
153 */
154void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
155{
156 target_ulong pc;
157 int count;
158 struct disassemble_info disasm_info;
159 int (*print_insn)(bfd_vma pc, disassemble_info *info);
160
161 INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);
162
163 disasm_info.read_memory_func = target_read_memory;
164 disasm_info.buffer_vma = code;
165 disasm_info.buffer_length = size;
166
167#ifdef TARGET_WORDS_BIGENDIAN
168 disasm_info.endian = BFD_ENDIAN_BIG;
169#else
170 disasm_info.endian = BFD_ENDIAN_LITTLE;
171#endif
172#if defined(TARGET_I386)
173 if (flags == 2)
174 disasm_info.mach = bfd_mach_x86_64;
175 else if (flags == 1)
176 disasm_info.mach = bfd_mach_i386_i8086;
177 else
178 disasm_info.mach = bfd_mach_i386_i386;
179 print_insn = print_insn_i386;
180#elif defined(TARGET_ARM)
181 if (flags)
182 print_insn = print_insn_thumb1;
183 else
184 print_insn = print_insn_arm;
185#elif defined(TARGET_SPARC)
186 print_insn = print_insn_sparc;
187#ifdef TARGET_SPARC64
188 disasm_info.mach = bfd_mach_sparc_v9b;
189#endif
190#elif defined(TARGET_PPC)
191 if (flags >> 16)
192 disasm_info.endian = BFD_ENDIAN_LITTLE;
193 if (flags & 0xFFFF) {
194 /* If we have a precise definitions of the instructions set, use it */
195 disasm_info.mach = flags & 0xFFFF;
196 } else {
197#ifdef TARGET_PPC64
198 disasm_info.mach = bfd_mach_ppc64;
199#else
200 disasm_info.mach = bfd_mach_ppc;
201#endif
202 }
203 print_insn = print_insn_ppc;
204#elif defined(TARGET_M68K)
205 print_insn = print_insn_m68k;
206#elif defined(TARGET_MIPS)
207#ifdef TARGET_WORDS_BIGENDIAN
208 print_insn = print_insn_big_mips;
209#else
210 print_insn = print_insn_little_mips;
211#endif
212#elif defined(TARGET_SH4)
213 disasm_info.mach = bfd_mach_sh4;
214 print_insn = print_insn_sh;
215#elif defined(TARGET_ALPHA)
216 disasm_info.mach = bfd_mach_alpha;
217 print_insn = print_insn_alpha;
218#elif defined(TARGET_CRIS)
219 disasm_info.mach = bfd_mach_cris_v32;
220 print_insn = print_insn_crisv32;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700221#elif defined(TARGET_MICROBLAZE)
222 disasm_info.mach = bfd_arch_microblaze;
223 print_insn = print_insn_microblaze;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800224#else
225 fprintf(out, "0x" TARGET_FMT_lx
226 ": Asm output not supported on this arch\n", code);
227 return;
228#endif
229
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700230 for (pc = code; size > 0; pc += count, size -= count) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800231 fprintf(out, "0x" TARGET_FMT_lx ": ", pc);
232 count = print_insn(pc, &disasm_info);
233#if 0
234 {
235 int i;
236 uint8_t b;
237 fprintf(out, " {");
238 for(i = 0; i < count; i++) {
239 target_read_memory(pc + i, &b, 1, &disasm_info);
240 fprintf(out, " %02x", b);
241 }
242 fprintf(out, " }");
243 }
244#endif
245 fprintf(out, "\n");
246 if (count < 0)
247 break;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700248 if (size < count) {
249 fprintf(out,
250 "Disassembler disagrees with translator over instruction "
251 "decoding\n"
252 "Please report this to qemu-devel@nongnu.org\n");
253 break;
254 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800255 }
256}
257
258/* Disassemble this for me please... (debugging). */
259void disas(FILE *out, void *code, unsigned long size)
260{
261 unsigned long pc;
262 int count;
263 struct disassemble_info disasm_info;
264 int (*print_insn)(bfd_vma pc, disassemble_info *info);
265
266 INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);
267
268 disasm_info.buffer = code;
269 disasm_info.buffer_vma = (unsigned long)code;
270 disasm_info.buffer_length = size;
271
David 'Digit' Turner20894ae2010-05-10 17:07:36 -0700272#ifdef HOST_WORDS_BIGENDIAN
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800273 disasm_info.endian = BFD_ENDIAN_BIG;
274#else
275 disasm_info.endian = BFD_ENDIAN_LITTLE;
276#endif
277#if defined(__i386__)
278 disasm_info.mach = bfd_mach_i386_i386;
279 print_insn = print_insn_i386;
280#elif defined(__x86_64__)
281 disasm_info.mach = bfd_mach_x86_64;
282 print_insn = print_insn_i386;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700283#elif defined(_ARCH_PPC)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800284 print_insn = print_insn_ppc;
285#elif defined(__alpha__)
286 print_insn = print_insn_alpha;
287#elif defined(__sparc__)
288 print_insn = print_insn_sparc;
289#if defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__)
290 disasm_info.mach = bfd_mach_sparc_v9b;
291#endif
292#elif defined(__arm__)
293 print_insn = print_insn_arm;
294#elif defined(__MIPSEB__)
295 print_insn = print_insn_big_mips;
296#elif defined(__MIPSEL__)
297 print_insn = print_insn_little_mips;
298#elif defined(__m68k__)
299 print_insn = print_insn_m68k;
300#elif defined(__s390__)
301 print_insn = print_insn_s390;
302#elif defined(__hppa__)
303 print_insn = print_insn_hppa;
David Turner75fb4a02010-09-09 22:56:10 +0200304#elif defined(__ia64__)
305 print_insn = print_insn_ia64;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800306#else
307 fprintf(out, "0x%lx: Asm output not supported on this arch\n",
308 (long) code);
309 return;
310#endif
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700311 for (pc = (unsigned long)code; size > 0; pc += count, size -= count) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800312 fprintf(out, "0x%08lx: ", pc);
313#ifdef __arm__
314 /* since data is included in the code, it is better to
315 display code data too */
316 fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc));
317#endif
318 count = print_insn(pc, &disasm_info);
319 fprintf(out, "\n");
320 if (count < 0)
321 break;
322 }
323}
324
325/* Look up symbol for debugging purpose. Returns "" if unknown. */
326const char *lookup_symbol(target_ulong orig_addr)
327{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700328 const char *symbol = "";
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800329 struct syminfo *s;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800330
331 for (s = syminfos; s; s = s->next) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700332 symbol = s->lookup_symbol(s, orig_addr);
333 if (symbol[0] != '\0') {
334 break;
335 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800336 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700337
338 return symbol;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800339}
340
341#if !defined(CONFIG_USER_ONLY)
342
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700343#include "monitor.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800344
345static int monitor_disas_is_physical;
346static CPUState *monitor_disas_env;
347
348static int
349monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length,
350 struct disassemble_info *info)
351{
352 if (monitor_disas_is_physical) {
353 cpu_physical_memory_rw(memaddr, myaddr, length, 0);
354 } else {
355 cpu_memory_rw_debug(monitor_disas_env, memaddr,myaddr, length, 0);
356 }
357 return 0;
358}
359
360static int monitor_fprintf(FILE *stream, const char *fmt, ...)
361{
362 va_list ap;
363 va_start(ap, fmt);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700364 monitor_vprintf((Monitor *)stream, fmt, ap);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800365 va_end(ap);
366 return 0;
367}
368
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700369void monitor_disas(Monitor *mon, CPUState *env,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800370 target_ulong pc, int nb_insn, int is_physical, int flags)
371{
372 int count, i;
373 struct disassemble_info disasm_info;
374 int (*print_insn)(bfd_vma pc, disassemble_info *info);
375
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700376 INIT_DISASSEMBLE_INFO(disasm_info, (FILE *)mon, monitor_fprintf);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800377
378 monitor_disas_env = env;
379 monitor_disas_is_physical = is_physical;
380 disasm_info.read_memory_func = monitor_read_memory;
381
382 disasm_info.buffer_vma = pc;
383
384#ifdef TARGET_WORDS_BIGENDIAN
385 disasm_info.endian = BFD_ENDIAN_BIG;
386#else
387 disasm_info.endian = BFD_ENDIAN_LITTLE;
388#endif
389#if defined(TARGET_I386)
390 if (flags == 2)
391 disasm_info.mach = bfd_mach_x86_64;
392 else if (flags == 1)
393 disasm_info.mach = bfd_mach_i386_i8086;
394 else
395 disasm_info.mach = bfd_mach_i386_i386;
396 print_insn = print_insn_i386;
397#elif defined(TARGET_ARM)
398 print_insn = print_insn_arm;
399#elif defined(TARGET_ALPHA)
400 print_insn = print_insn_alpha;
401#elif defined(TARGET_SPARC)
402 print_insn = print_insn_sparc;
403#ifdef TARGET_SPARC64
404 disasm_info.mach = bfd_mach_sparc_v9b;
405#endif
406#elif defined(TARGET_PPC)
407#ifdef TARGET_PPC64
408 disasm_info.mach = bfd_mach_ppc64;
409#else
410 disasm_info.mach = bfd_mach_ppc;
411#endif
412 print_insn = print_insn_ppc;
413#elif defined(TARGET_M68K)
414 print_insn = print_insn_m68k;
415#elif defined(TARGET_MIPS)
416#ifdef TARGET_WORDS_BIGENDIAN
417 print_insn = print_insn_big_mips;
418#else
419 print_insn = print_insn_little_mips;
420#endif
David Turner75fb4a02010-09-09 22:56:10 +0200421#elif defined(TARGET_SH4)
422 disasm_info.mach = bfd_mach_sh4;
423 print_insn = print_insn_sh;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800424#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700425 monitor_printf(mon, "0x" TARGET_FMT_lx
426 ": Asm output not supported on this arch\n", pc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800427 return;
428#endif
429
430 for(i = 0; i < nb_insn; i++) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700431 monitor_printf(mon, "0x" TARGET_FMT_lx ": ", pc);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800432 count = print_insn(pc, &disasm_info);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700433 monitor_printf(mon, "\n");
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800434 if (count < 0)
435 break;
436 pc += count;
437 }
438}
439#endif