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 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. */ 42 void 43 perror_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 62 void 63 generic_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 70 int 71 generic_symbol_at_address (bfd_vma addr, struct disassemble_info *info) 72 { 73 return 1; 74 } 75 76 bfd_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 87 bfd_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 98 bfd_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 107 bfd_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 117 static int 118 print_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 */ 131 void 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 (at) nongnu.org\n"); 230 break; 231 } 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 HOST_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. */ 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 #include "monitor.h" 319 320 static int monitor_disas_is_physical; 321 static CPUState *monitor_disas_env; 322 323 static int 324 monitor_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 335 static 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 344 void 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