|
1 /* 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 |
|
11 /* Filled in by elfload.c. Simplistic, but will do for now. */ |
|
12 struct syminfo *syminfos = NULL; |
|
13 |
|
14 /* Get LENGTH bytes from info's buffer, at target address memaddr. |
|
15 Transfer them to myaddr. */ |
|
16 int |
|
17 buffer_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length, |
|
18 struct disassemble_info *info) |
|
19 { |
|
20 if (memaddr < info->buffer_vma |
|
21 || memaddr + length > info->buffer_vma + info->buffer_length) |
|
22 /* Out of bounds. Use EIO because GDB uses it. */ |
|
23 return EIO; |
|
24 memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length); |
|
25 return 0; |
|
26 } |
|
27 |
|
28 /* Get LENGTH bytes from info's buffer, at target address memaddr. |
|
29 Transfer them to myaddr. */ |
|
30 static int |
|
31 target_read_memory (bfd_vma memaddr, |
|
32 bfd_byte *myaddr, |
|
33 int length, |
|
34 struct disassemble_info *info) |
|
35 { |
|
36 int i; |
|
37 for(i = 0; i < length; i++) { |
|
38 myaddr[i] = ldub_code(memaddr + i); |
|
39 } |
|
40 return 0; |
|
41 } |
|
42 |
|
43 /* Print an error message. We can assume that this is in response to |
|
44 an error return from buffer_read_memory. */ |
|
45 void |
|
46 perror_memory (int status, bfd_vma memaddr, struct disassemble_info *info) |
|
47 { |
|
48 if (status != EIO) |
|
49 /* Can't happen. */ |
|
50 (*info->fprintf_func) (info->stream, "Unknown error %d\n", status); |
|
51 else |
|
52 /* Actually, address between memaddr and memaddr + len was |
|
53 out of bounds. */ |
|
54 (*info->fprintf_func) (info->stream, |
|
55 "Address 0x%" PRIx64 " is out of bounds.\n", memaddr); |
|
56 } |
|
57 |
|
58 /* This could be in a separate file, to save miniscule amounts of space |
|
59 in statically linked executables. */ |
|
60 |
|
61 /* Just print the address is hex. This is included for completeness even |
|
62 though both GDB and objdump provide their own (to print symbolic |
|
63 addresses). */ |
|
64 |
|
65 void |
|
66 generic_print_address (bfd_vma addr, struct disassemble_info *info) |
|
67 { |
|
68 (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr); |
|
69 } |
|
70 |
|
71 /* Just return the given address. */ |
|
72 |
|
73 int |
|
74 generic_symbol_at_address (bfd_vma addr, struct disassemble_info *info) |
|
75 { |
|
76 return 1; |
|
77 } |
|
78 |
|
79 bfd_vma bfd_getl32 (const bfd_byte *addr) |
|
80 { |
|
81 unsigned long v; |
|
82 |
|
83 v = (unsigned long) addr[0]; |
|
84 v |= (unsigned long) addr[1] << 8; |
|
85 v |= (unsigned long) addr[2] << 16; |
|
86 v |= (unsigned long) addr[3] << 24; |
|
87 return (bfd_vma) v; |
|
88 } |
|
89 |
|
90 bfd_vma bfd_getb32 (const bfd_byte *addr) |
|
91 { |
|
92 unsigned long v; |
|
93 |
|
94 v = (unsigned long) addr[0] << 24; |
|
95 v |= (unsigned long) addr[1] << 16; |
|
96 v |= (unsigned long) addr[2] << 8; |
|
97 v |= (unsigned long) addr[3]; |
|
98 return (bfd_vma) v; |
|
99 } |
|
100 |
|
101 bfd_vma bfd_getl16 (const bfd_byte *addr) |
|
102 { |
|
103 unsigned long v; |
|
104 |
|
105 v = (unsigned long) addr[0]; |
|
106 v |= (unsigned long) addr[1] << 8; |
|
107 return (bfd_vma) v; |
|
108 } |
|
109 |
|
110 bfd_vma bfd_getb16 (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 return (bfd_vma) v; |
|
117 } |
|
118 |
|
119 #ifdef TARGET_ARM |
|
120 static int |
|
121 print_insn_thumb1(bfd_vma pc, disassemble_info *info) |
|
122 { |
|
123 return print_insn_arm(pc | 1, info); |
|
124 } |
|
125 #endif |
|
126 |
|
127 /* Disassemble this for me please... (debugging). 'flags' has the following |
|
128 values: |
|
129 i386 - nonzero means 16 bit code |
|
130 arm - bit 0 = thumb, bit 1 = reverse endian |
|
131 ppc - nonzero means little endian |
|
132 other targets - unused |
|
133 */ |
|
134 void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) |
|
135 { |
|
136 target_ulong pc; |
|
137 int count; |
|
138 struct disassemble_info disasm_info; |
|
139 int (*print_insn)(bfd_vma pc, disassemble_info *info); |
|
140 |
|
141 INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf); |
|
142 |
|
143 disasm_info.read_memory_func = target_read_memory; |
|
144 disasm_info.buffer_vma = code; |
|
145 disasm_info.buffer_length = size; |
|
146 |
|
147 #ifdef TARGET_WORDS_BIGENDIAN |
|
148 disasm_info.endian = BFD_ENDIAN_BIG; |
|
149 #else |
|
150 disasm_info.endian = BFD_ENDIAN_LITTLE; |
|
151 #endif |
|
152 #if defined(TARGET_I386) |
|
153 if (flags == 2) |
|
154 disasm_info.mach = bfd_mach_x86_64; |
|
155 else if (flags == 1) |
|
156 disasm_info.mach = bfd_mach_i386_i8086; |
|
157 else |
|
158 disasm_info.mach = bfd_mach_i386_i386; |
|
159 print_insn = print_insn_i386; |
|
160 #elif defined(TARGET_ARM) |
|
161 if (flags & 1) |
|
162 print_insn = print_insn_thumb1; |
|
163 else |
|
164 print_insn = print_insn_arm; |
|
165 if (flags & 2) { |
|
166 #ifdef TARGET_WORDS_BIGENDIAN |
|
167 disasm_info.endian = BFD_ENDIAN_LITTLE; |
|
168 #else |
|
169 disasm_info.endian = BFD_ENDIAN_BIG; |
|
170 #endif |
|
171 } |
|
172 #elif defined(TARGET_SPARC) |
|
173 print_insn = print_insn_sparc; |
|
174 #ifdef TARGET_SPARC64 |
|
175 disasm_info.mach = bfd_mach_sparc_v9b; |
|
176 #endif |
|
177 #elif defined(TARGET_PPC) |
|
178 if (flags >> 16) |
|
179 disasm_info.endian = BFD_ENDIAN_LITTLE; |
|
180 if (flags & 0xFFFF) { |
|
181 /* If we have a precise definitions of the instructions set, use it */ |
|
182 disasm_info.mach = flags & 0xFFFF; |
|
183 } else { |
|
184 #ifdef TARGET_PPC64 |
|
185 disasm_info.mach = bfd_mach_ppc64; |
|
186 #else |
|
187 disasm_info.mach = bfd_mach_ppc; |
|
188 #endif |
|
189 } |
|
190 print_insn = print_insn_ppc; |
|
191 #elif defined(TARGET_M68K) |
|
192 print_insn = print_insn_m68k; |
|
193 #elif defined(TARGET_MIPS) |
|
194 #ifdef TARGET_WORDS_BIGENDIAN |
|
195 print_insn = print_insn_big_mips; |
|
196 #else |
|
197 print_insn = print_insn_little_mips; |
|
198 #endif |
|
199 #elif defined(TARGET_SH4) |
|
200 disasm_info.mach = bfd_mach_sh4; |
|
201 print_insn = print_insn_sh; |
|
202 #elif defined(TARGET_ALPHA) |
|
203 disasm_info.mach = bfd_mach_alpha; |
|
204 print_insn = print_insn_alpha; |
|
205 #elif defined(TARGET_CRIS) |
|
206 disasm_info.mach = bfd_mach_cris_v32; |
|
207 print_insn = print_insn_crisv32; |
|
208 #else |
|
209 fprintf(out, "0x" TARGET_FMT_lx |
|
210 ": Asm output not supported on this arch\n", code); |
|
211 return; |
|
212 #endif |
|
213 |
|
214 for (pc = code; pc < code + size; pc += count) { |
|
215 fprintf(out, "0x" TARGET_FMT_lx ": ", pc); |
|
216 count = print_insn(pc, &disasm_info); |
|
217 #if 0 |
|
218 { |
|
219 int i; |
|
220 uint8_t b; |
|
221 fprintf(out, " {"); |
|
222 for(i = 0; i < count; i++) { |
|
223 target_read_memory(pc + i, &b, 1, &disasm_info); |
|
224 fprintf(out, " %02x", b); |
|
225 } |
|
226 fprintf(out, " }"); |
|
227 } |
|
228 #endif |
|
229 fprintf(out, "\n"); |
|
230 if (count < 0) |
|
231 break; |
|
232 } |
|
233 } |
|
234 |
|
235 /* Disassemble this for me please... (debugging). */ |
|
236 void disas(FILE *out, void *code, unsigned long size) |
|
237 { |
|
238 unsigned long pc; |
|
239 int count; |
|
240 struct disassemble_info disasm_info; |
|
241 int (*print_insn)(bfd_vma pc, disassemble_info *info); |
|
242 |
|
243 INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf); |
|
244 |
|
245 disasm_info.buffer = code; |
|
246 disasm_info.buffer_vma = (unsigned long)code; |
|
247 disasm_info.buffer_length = size; |
|
248 |
|
249 #ifdef WORDS_BIGENDIAN |
|
250 disasm_info.endian = BFD_ENDIAN_BIG; |
|
251 #else |
|
252 disasm_info.endian = BFD_ENDIAN_LITTLE; |
|
253 #endif |
|
254 #if defined(__i386__) |
|
255 disasm_info.mach = bfd_mach_i386_i386; |
|
256 print_insn = print_insn_i386; |
|
257 #elif defined(__x86_64__) |
|
258 disasm_info.mach = bfd_mach_x86_64; |
|
259 print_insn = print_insn_i386; |
|
260 #elif defined(__powerpc__) |
|
261 print_insn = print_insn_ppc; |
|
262 #elif defined(__alpha__) |
|
263 print_insn = print_insn_alpha; |
|
264 #elif defined(__sparc__) |
|
265 print_insn = print_insn_sparc; |
|
266 #if defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__) |
|
267 disasm_info.mach = bfd_mach_sparc_v9b; |
|
268 #endif |
|
269 #elif defined(__arm__) |
|
270 print_insn = print_insn_arm; |
|
271 #elif defined(__MIPSEB__) |
|
272 print_insn = print_insn_big_mips; |
|
273 #elif defined(__MIPSEL__) |
|
274 print_insn = print_insn_little_mips; |
|
275 #elif defined(__m68k__) |
|
276 print_insn = print_insn_m68k; |
|
277 #elif defined(__s390__) |
|
278 print_insn = print_insn_s390; |
|
279 #elif defined(__hppa__) |
|
280 print_insn = print_insn_hppa; |
|
281 #else |
|
282 fprintf(out, "0x%lx: Asm output not supported on this arch\n", |
|
283 (long) code); |
|
284 return; |
|
285 #endif |
|
286 for (pc = (unsigned long)code; pc < (unsigned long)code + size; pc += count) { |
|
287 fprintf(out, "0x%08lx: ", pc); |
|
288 #ifdef __arm__ |
|
289 /* since data is included in the code, it is better to |
|
290 display code data too */ |
|
291 fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc)); |
|
292 #endif |
|
293 count = print_insn(pc, &disasm_info); |
|
294 fprintf(out, "\n"); |
|
295 if (count < 0) |
|
296 break; |
|
297 } |
|
298 } |
|
299 |
|
300 /* Look up symbol for debugging purpose. Returns "" if unknown. */ |
|
301 const char *lookup_symbol(target_ulong orig_addr) |
|
302 { |
|
303 const char *symbol = ""; |
|
304 struct syminfo *s; |
|
305 |
|
306 for (s = syminfos; s; s = s->next) { |
|
307 symbol = s->lookup_symbol(s, orig_addr); |
|
308 if (symbol[0] != '\0') { |
|
309 break; |
|
310 } |
|
311 } |
|
312 |
|
313 return symbol; |
|
314 } |
|
315 |
|
316 #if !defined(CONFIG_USER_ONLY) |
|
317 |
|
318 void term_vprintf(const char *fmt, va_list ap); |
|
319 void term_printf(const char *fmt, ...); |
|
320 |
|
321 static int monitor_disas_is_physical; |
|
322 static CPUState *monitor_disas_env; |
|
323 |
|
324 static int |
|
325 monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length, |
|
326 struct disassemble_info *info) |
|
327 { |
|
328 if (monitor_disas_is_physical) { |
|
329 cpu_physical_memory_rw(memaddr, myaddr, length, 0); |
|
330 } else { |
|
331 cpu_memory_rw_debug(monitor_disas_env, memaddr,myaddr, length, 0); |
|
332 } |
|
333 return 0; |
|
334 } |
|
335 |
|
336 static int monitor_fprintf(FILE *stream, const char *fmt, ...) |
|
337 { |
|
338 va_list ap; |
|
339 va_start(ap, fmt); |
|
340 term_vprintf(fmt, ap); |
|
341 va_end(ap); |
|
342 return 0; |
|
343 } |
|
344 |
|
345 void monitor_disas(CPUState *env, |
|
346 target_ulong pc, int nb_insn, int is_physical, int flags) |
|
347 { |
|
348 int count, i; |
|
349 struct disassemble_info disasm_info; |
|
350 int (*print_insn)(bfd_vma pc, disassemble_info *info); |
|
351 |
|
352 INIT_DISASSEMBLE_INFO(disasm_info, NULL, monitor_fprintf); |
|
353 |
|
354 monitor_disas_env = env; |
|
355 monitor_disas_is_physical = is_physical; |
|
356 disasm_info.read_memory_func = monitor_read_memory; |
|
357 |
|
358 disasm_info.buffer_vma = pc; |
|
359 |
|
360 #ifdef TARGET_WORDS_BIGENDIAN |
|
361 disasm_info.endian = BFD_ENDIAN_BIG; |
|
362 #else |
|
363 disasm_info.endian = BFD_ENDIAN_LITTLE; |
|
364 #endif |
|
365 #if defined(TARGET_I386) |
|
366 if (flags == 2) |
|
367 disasm_info.mach = bfd_mach_x86_64; |
|
368 else if (flags == 1) |
|
369 disasm_info.mach = bfd_mach_i386_i8086; |
|
370 else |
|
371 disasm_info.mach = bfd_mach_i386_i386; |
|
372 print_insn = print_insn_i386; |
|
373 #elif defined(TARGET_ARM) |
|
374 print_insn = print_insn_arm; |
|
375 #elif defined(TARGET_ALPHA) |
|
376 print_insn = print_insn_alpha; |
|
377 #elif defined(TARGET_SPARC) |
|
378 print_insn = print_insn_sparc; |
|
379 #ifdef TARGET_SPARC64 |
|
380 disasm_info.mach = bfd_mach_sparc_v9b; |
|
381 #endif |
|
382 #elif defined(TARGET_PPC) |
|
383 #ifdef TARGET_PPC64 |
|
384 disasm_info.mach = bfd_mach_ppc64; |
|
385 #else |
|
386 disasm_info.mach = bfd_mach_ppc; |
|
387 #endif |
|
388 print_insn = print_insn_ppc; |
|
389 #elif defined(TARGET_M68K) |
|
390 print_insn = print_insn_m68k; |
|
391 #elif defined(TARGET_MIPS) |
|
392 #ifdef TARGET_WORDS_BIGENDIAN |
|
393 print_insn = print_insn_big_mips; |
|
394 #else |
|
395 print_insn = print_insn_little_mips; |
|
396 #endif |
|
397 #else |
|
398 term_printf("0x" TARGET_FMT_lx |
|
399 ": Asm output not supported on this arch\n", pc); |
|
400 return; |
|
401 #endif |
|
402 |
|
403 for(i = 0; i < nb_insn; i++) { |
|
404 term_printf("0x" TARGET_FMT_lx ": ", pc); |
|
405 count = print_insn(pc, &disasm_info); |
|
406 term_printf("\n"); |
|
407 if (count < 0) |
|
408 break; |
|
409 pc += count; |
|
410 } |
|
411 } |
|
412 #endif |