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. */ 12struct syminfo *syminfos = NULL; 13 14/* Get LENGTH bytes from info's buffer, at target address memaddr. 15 Transfer them to myaddr. */ 16int 17buffer_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. */ 30static int 31target_read_memory (bfd_vma memaddr, 32 bfd_byte *myaddr, 33 int length, 34 struct disassemble_info *info) 35{ 36 cpu_memory_rw_debug(cpu_single_env, memaddr, myaddr, length, 0); 37 return 0; 38} 39 40/* Print an error message. We can assume that this is in response to 41 an error return from buffer_read_memory. */ 42void 43perror_memory (int status, bfd_vma memaddr, struct disassemble_info *info) 44{ 45 if (status != EIO) 46 /* Can't happen. */ 47 (*info->fprintf_func) (info->stream, "Unknown error %d\n", status); 48 else 49 /* Actually, address between memaddr and memaddr + len was 50 out of bounds. */ 51 (*info->fprintf_func) (info->stream, 52 "Address 0x%" PRIx64 " is out of bounds.\n", memaddr); 53} 54 55/* This could be in a separate file, to save miniscule amounts of space 56 in statically linked executables. */ 57 58/* Just print the address is hex. This is included for completeness even 59 though both GDB and objdump provide their own (to print symbolic 60 addresses). */ 61 62void 63generic_print_address (bfd_vma addr, struct disassemble_info *info) 64{ 65 (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr); 66} 67 68/* Just return the given address. */ 69 70int 71generic_symbol_at_address (bfd_vma addr, struct disassemble_info *info) 72{ 73 return 1; 74} 75 76bfd_vma bfd_getl32 (const bfd_byte *addr) 77{ 78 unsigned long v; 79 80 v = (unsigned long) addr[0]; 81 v |= (unsigned long) addr[1] << 8; 82 v |= (unsigned long) addr[2] << 16; 83 v |= (unsigned long) addr[3] << 24; 84 return (bfd_vma) v; 85} 86 87bfd_vma bfd_getb32 (const bfd_byte *addr) 88{ 89 unsigned long v; 90 91 v = (unsigned long) addr[0] << 24; 92 v |= (unsigned long) addr[1] << 16; 93 v |= (unsigned long) addr[2] << 8; 94 v |= (unsigned long) addr[3]; 95 return (bfd_vma) v; 96} 97 98bfd_vma bfd_getl16 (const bfd_byte *addr) 99{ 100 unsigned long v; 101 102 v = (unsigned long) addr[0]; 103 v |= (unsigned long) addr[1] << 8; 104 return (bfd_vma) v; 105} 106 107bfd_vma bfd_getb16 (const bfd_byte *addr) 108{ 109 unsigned long v; 110 111 v = (unsigned long) addr[0] << 24; 112 v |= (unsigned long) addr[1] << 16; 113 return (bfd_vma) v; 114} 115 116#ifdef TARGET_ARM 117static int 118print_insn_thumb1(bfd_vma pc, disassemble_info *info) 119{ 120 return print_insn_arm(pc | 1, info); 121} 122#endif 123 124/* Disassemble this for me please... (debugging). 'flags' has the following 125 values: 126 i386 - nonzero means 16 bit code 127 arm - nonzero means thumb code 128 ppc - nonzero means little endian 129 other targets - unused 130 */ 131void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) 132{ 133 target_ulong pc; 134 int count; 135 struct disassemble_info disasm_info; 136 int (*print_insn)(bfd_vma pc, disassemble_info *info); 137 138 INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf); 139 140 disasm_info.read_memory_func = target_read_memory; 141 disasm_info.buffer_vma = code; 142 disasm_info.buffer_length = size; 143 144#ifdef TARGET_WORDS_BIGENDIAN 145 disasm_info.endian = BFD_ENDIAN_BIG; 146#else 147 disasm_info.endian = BFD_ENDIAN_LITTLE; 148#endif 149#if defined(TARGET_I386) 150 if (flags == 2) 151 disasm_info.mach = bfd_mach_x86_64; 152 else if (flags == 1) 153 disasm_info.mach = bfd_mach_i386_i8086; 154 else 155 disasm_info.mach = bfd_mach_i386_i386; 156 print_insn = print_insn_i386; 157#elif defined(TARGET_ARM) 158 if (flags) 159 print_insn = print_insn_thumb1; 160 else 161 print_insn = print_insn_arm; 162#elif defined(TARGET_SPARC) 163 print_insn = print_insn_sparc; 164#ifdef TARGET_SPARC64 165 disasm_info.mach = bfd_mach_sparc_v9b; 166#endif 167#elif defined(TARGET_PPC) 168 if (flags >> 16) 169 disasm_info.endian = BFD_ENDIAN_LITTLE; 170 if (flags & 0xFFFF) { 171 /* If we have a precise definitions of the instructions set, use it */ 172 disasm_info.mach = flags & 0xFFFF; 173 } else { 174#ifdef TARGET_PPC64 175 disasm_info.mach = bfd_mach_ppc64; 176#else 177 disasm_info.mach = bfd_mach_ppc; 178#endif 179 } 180 print_insn = print_insn_ppc; 181#elif defined(TARGET_M68K) 182 print_insn = print_insn_m68k; 183#elif defined(TARGET_MIPS) 184#ifdef TARGET_WORDS_BIGENDIAN 185 print_insn = print_insn_big_mips; 186#else 187 print_insn = print_insn_little_mips; 188#endif 189#elif defined(TARGET_SH4) 190 disasm_info.mach = bfd_mach_sh4; 191 print_insn = print_insn_sh; 192#elif defined(TARGET_ALPHA) 193 disasm_info.mach = bfd_mach_alpha; 194 print_insn = print_insn_alpha; 195#elif defined(TARGET_CRIS) 196 disasm_info.mach = bfd_mach_cris_v32; 197 print_insn = print_insn_crisv32; 198#elif defined(TARGET_MICROBLAZE) 199 disasm_info.mach = bfd_arch_microblaze; 200 print_insn = print_insn_microblaze; 201#else 202 fprintf(out, "0x" TARGET_FMT_lx 203 ": Asm output not supported on this arch\n", code); 204 return; 205#endif 206 207 for (pc = code; size > 0; pc += count, size -= count) { 208 fprintf(out, "0x" TARGET_FMT_lx ": ", pc); 209 count = print_insn(pc, &disasm_info); 210#if 0 211 { 212 int i; 213 uint8_t b; 214 fprintf(out, " {"); 215 for(i = 0; i < count; i++) { 216 target_read_memory(pc + i, &b, 1, &disasm_info); 217 fprintf(out, " %02x", b); 218 } 219 fprintf(out, " }"); 220 } 221#endif 222 fprintf(out, "\n"); 223 if (count < 0) 224 break; 225 if (size < count) { 226 fprintf(out, 227 "Disassembler disagrees with translator over instruction " 228 "decoding\n" 229 "Please report this to qemu-devel@nongnu.org\n"); 230 break; 231 } 232 } 233} 234 235/* Disassemble this for me please... (debugging). */ 236void 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(_ARCH_PPC) 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; size > 0; pc += count, size -= 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. */ 301const 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#include "monitor.h" 319 320static int monitor_disas_is_physical; 321static CPUState *monitor_disas_env; 322 323static int 324monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length, 325 struct disassemble_info *info) 326{ 327 if (monitor_disas_is_physical) { 328 cpu_physical_memory_rw(memaddr, myaddr, length, 0); 329 } else { 330 cpu_memory_rw_debug(monitor_disas_env, memaddr,myaddr, length, 0); 331 } 332 return 0; 333} 334 335static int monitor_fprintf(FILE *stream, const char *fmt, ...) 336{ 337 va_list ap; 338 va_start(ap, fmt); 339 monitor_vprintf((Monitor *)stream, fmt, ap); 340 va_end(ap); 341 return 0; 342} 343 344void monitor_disas(Monitor *mon, CPUState *env, 345 target_ulong pc, int nb_insn, int is_physical, int flags) 346{ 347 int count, i; 348 struct disassemble_info disasm_info; 349 int (*print_insn)(bfd_vma pc, disassemble_info *info); 350 351 INIT_DISASSEMBLE_INFO(disasm_info, (FILE *)mon, monitor_fprintf); 352 353 monitor_disas_env = env; 354 monitor_disas_is_physical = is_physical; 355 disasm_info.read_memory_func = monitor_read_memory; 356 357 disasm_info.buffer_vma = pc; 358 359#ifdef TARGET_WORDS_BIGENDIAN 360 disasm_info.endian = BFD_ENDIAN_BIG; 361#else 362 disasm_info.endian = BFD_ENDIAN_LITTLE; 363#endif 364#if defined(TARGET_I386) 365 if (flags == 2) 366 disasm_info.mach = bfd_mach_x86_64; 367 else if (flags == 1) 368 disasm_info.mach = bfd_mach_i386_i8086; 369 else 370 disasm_info.mach = bfd_mach_i386_i386; 371 print_insn = print_insn_i386; 372#elif defined(TARGET_ARM) 373 print_insn = print_insn_arm; 374#elif defined(TARGET_ALPHA) 375 print_insn = print_insn_alpha; 376#elif defined(TARGET_SPARC) 377 print_insn = print_insn_sparc; 378#ifdef TARGET_SPARC64 379 disasm_info.mach = bfd_mach_sparc_v9b; 380#endif 381#elif defined(TARGET_PPC) 382#ifdef TARGET_PPC64 383 disasm_info.mach = bfd_mach_ppc64; 384#else 385 disasm_info.mach = bfd_mach_ppc; 386#endif 387 print_insn = print_insn_ppc; 388#elif defined(TARGET_M68K) 389 print_insn = print_insn_m68k; 390#elif defined(TARGET_MIPS) 391#ifdef TARGET_WORDS_BIGENDIAN 392 print_insn = print_insn_big_mips; 393#else 394 print_insn = print_insn_little_mips; 395#endif 396#else 397 monitor_printf(mon, "0x" TARGET_FMT_lx 398 ": Asm output not supported on this arch\n", pc); 399 return; 400#endif 401 402 for(i = 0; i < nb_insn; i++) { 403 monitor_printf(mon, "0x" TARGET_FMT_lx ": ", pc); 404 count = print_insn(pc, &disasm_info); 405 monitor_printf(mon, "\n"); 406 if (count < 0) 407 break; 408 pc += count; 409 } 410} 411#endif 412