Home | History | Annotate | Download | only in qemu
      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_getl64 (const bfd_byte *addr)
     77 {
     78   unsigned long long v;
     79 
     80   v = (unsigned long long) addr[0];
     81   v |= (unsigned long long) addr[1] << 8;
     82   v |= (unsigned long long) addr[2] << 16;
     83   v |= (unsigned long long) addr[3] << 24;
     84   v |= (unsigned long long) addr[4] << 32;
     85   v |= (unsigned long long) addr[5] << 40;
     86   v |= (unsigned long long) addr[6] << 48;
     87   v |= (unsigned long long) addr[7] << 56;
     88   return (bfd_vma) v;
     89 }
     90 
     91 bfd_vma bfd_getl32 (const bfd_byte *addr)
     92 {
     93   unsigned long v;
     94 
     95   v = (unsigned long) addr[0];
     96   v |= (unsigned long) addr[1] << 8;
     97   v |= (unsigned long) addr[2] << 16;
     98   v |= (unsigned long) addr[3] << 24;
     99   return (bfd_vma) v;
    100 }
    101 
    102 bfd_vma bfd_getb32 (const bfd_byte *addr)
    103 {
    104   unsigned long v;
    105 
    106   v = (unsigned long) addr[0] << 24;
    107   v |= (unsigned long) addr[1] << 16;
    108   v |= (unsigned long) addr[2] << 8;
    109   v |= (unsigned long) addr[3];
    110   return (bfd_vma) v;
    111 }
    112 
    113 bfd_vma bfd_getl16 (const bfd_byte *addr)
    114 {
    115   unsigned long v;
    116 
    117   v = (unsigned long) addr[0];
    118   v |= (unsigned long) addr[1] << 8;
    119   return (bfd_vma) v;
    120 }
    121 
    122 bfd_vma bfd_getb16 (const bfd_byte *addr)
    123 {
    124   unsigned long v;
    125 
    126   v = (unsigned long) addr[0] << 24;
    127   v |= (unsigned long) addr[1] << 16;
    128   return (bfd_vma) v;
    129 }
    130 
    131 #ifdef TARGET_ARM
    132 static int
    133 print_insn_thumb1(bfd_vma pc, disassemble_info *info)
    134 {
    135   return print_insn_arm(pc | 1, info);
    136 }
    137 #endif
    138 
    139 /* Disassemble this for me please... (debugging). 'flags' has the following
    140    values:
    141     i386 - nonzero means 16 bit code
    142     arm  - nonzero means thumb code
    143     ppc  - nonzero means little endian
    144     other targets - unused
    145  */
    146 void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
    147 {
    148     target_ulong pc;
    149     int count;
    150     struct disassemble_info disasm_info;
    151     int (*print_insn)(bfd_vma pc, disassemble_info *info);
    152 
    153     INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);
    154 
    155     disasm_info.read_memory_func = target_read_memory;
    156     disasm_info.buffer_vma = code;
    157     disasm_info.buffer_length = size;
    158 
    159 #ifdef TARGET_WORDS_BIGENDIAN
    160     disasm_info.endian = BFD_ENDIAN_BIG;
    161 #else
    162     disasm_info.endian = BFD_ENDIAN_LITTLE;
    163 #endif
    164 #if defined(TARGET_I386)
    165     if (flags == 2)
    166         disasm_info.mach = bfd_mach_x86_64;
    167     else if (flags == 1)
    168         disasm_info.mach = bfd_mach_i386_i8086;
    169     else
    170         disasm_info.mach = bfd_mach_i386_i386;
    171     print_insn = print_insn_i386;
    172 #elif defined(TARGET_ARM)
    173     if (flags)
    174 	print_insn = print_insn_thumb1;
    175     else
    176 	print_insn = print_insn_arm;
    177 #elif defined(TARGET_SPARC)
    178     print_insn = print_insn_sparc;
    179 #ifdef TARGET_SPARC64
    180     disasm_info.mach = bfd_mach_sparc_v9b;
    181 #endif
    182 #elif defined(TARGET_PPC)
    183     if (flags >> 16)
    184         disasm_info.endian = BFD_ENDIAN_LITTLE;
    185     if (flags & 0xFFFF) {
    186         /* If we have a precise definitions of the instructions set, use it */
    187         disasm_info.mach = flags & 0xFFFF;
    188     } else {
    189 #ifdef TARGET_PPC64
    190         disasm_info.mach = bfd_mach_ppc64;
    191 #else
    192         disasm_info.mach = bfd_mach_ppc;
    193 #endif
    194     }
    195     print_insn = print_insn_ppc;
    196 #elif defined(TARGET_M68K)
    197     print_insn = print_insn_m68k;
    198 #elif defined(TARGET_MIPS)
    199 #ifdef TARGET_WORDS_BIGENDIAN
    200     print_insn = print_insn_big_mips;
    201 #else
    202     print_insn = print_insn_little_mips;
    203 #endif
    204 #elif defined(TARGET_SH4)
    205     disasm_info.mach = bfd_mach_sh4;
    206     print_insn = print_insn_sh;
    207 #elif defined(TARGET_ALPHA)
    208     disasm_info.mach = bfd_mach_alpha;
    209     print_insn = print_insn_alpha;
    210 #elif defined(TARGET_CRIS)
    211     if (flags != 32) {
    212         disasm_info.mach = bfd_mach_cris_v0_v10;
    213         print_insn = print_insn_crisv10;
    214     } else {
    215     disasm_info.mach = bfd_mach_cris_v32;
    216     print_insn = print_insn_crisv32;
    217     }
    218 #elif defined(TARGET_S390X)
    219     disasm_info.mach = bfd_mach_s390_64;
    220     print_insn = print_insn_s390;
    221 #elif defined(TARGET_MICROBLAZE)
    222     disasm_info.mach = bfd_arch_microblaze;
    223     print_insn = print_insn_microblaze;
    224 #else
    225     fprintf(out, "0x" TARGET_FMT_lx
    226 	    ": Asm output not supported on this arch\n", code);
    227     return;
    228 #endif
    229 
    230     for (pc = code; size > 0; pc += count, size -= count) {
    231 	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;
    248         if (size < count) {
    249             fprintf(out,
    250                     "Disassembler disagrees with translator over instruction "
    251                     "decoding\n"
    252                     "Please report this to qemu-devel (at) nongnu.org\n");
    253             break;
    254         }
    255     }
    256 }
    257 
    258 /* Disassemble this for me please... (debugging). */
    259 void 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 
    272 #ifdef HOST_WORDS_BIGENDIAN
    273     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;
    283 #elif defined(_ARCH_PPC)
    284     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;
    304 #elif defined(__ia64__)
    305     print_insn = print_insn_ia64;
    306 #else
    307     fprintf(out, "0x%lx: Asm output not supported on this arch\n",
    308 	    (long) code);
    309     return;
    310 #endif
    311     for (pc = (unsigned long)code; size > 0; pc += count, size -= count) {
    312 	fprintf(out, "0x%08lx:  ", pc);
    313 	count = print_insn(pc, &disasm_info);
    314 	fprintf(out, "\n");
    315 	if (count < 0)
    316 	    break;
    317     }
    318 }
    319 
    320 /* Look up symbol for debugging purpose.  Returns "" if unknown. */
    321 const char *lookup_symbol(target_ulong orig_addr)
    322 {
    323     const char *symbol = "";
    324     struct syminfo *s;
    325 
    326     for (s = syminfos; s; s = s->next) {
    327         symbol = s->lookup_symbol(s, orig_addr);
    328         if (symbol[0] != '\0') {
    329             break;
    330         }
    331     }
    332 
    333     return symbol;
    334 }
    335 
    336 #if !defined(CONFIG_USER_ONLY)
    337 
    338 #include "monitor.h"
    339 
    340 static int monitor_disas_is_physical;
    341 static CPUState *monitor_disas_env;
    342 
    343 static int
    344 monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length,
    345                      struct disassemble_info *info)
    346 {
    347     if (monitor_disas_is_physical) {
    348         cpu_physical_memory_read(memaddr, myaddr, length);
    349     } else {
    350         cpu_memory_rw_debug(monitor_disas_env, memaddr,myaddr, length, 0);
    351     }
    352     return 0;
    353 }
    354 
    355 static int GCC_FMT_ATTR(2, 3)
    356 monitor_fprintf(FILE *stream, const char *fmt, ...)
    357 {
    358     va_list ap;
    359     va_start(ap, fmt);
    360     monitor_vprintf((Monitor *)stream, fmt, ap);
    361     va_end(ap);
    362     return 0;
    363 }
    364 
    365 void monitor_disas(Monitor *mon, CPUState *env,
    366                    target_ulong pc, int nb_insn, int is_physical, int flags)
    367 {
    368     int count, i;
    369     struct disassemble_info disasm_info;
    370     int (*print_insn)(bfd_vma pc, disassemble_info *info);
    371 
    372     INIT_DISASSEMBLE_INFO(disasm_info, (FILE *)mon, monitor_fprintf);
    373 
    374     monitor_disas_env = env;
    375     monitor_disas_is_physical = is_physical;
    376     disasm_info.read_memory_func = monitor_read_memory;
    377 
    378     disasm_info.buffer_vma = pc;
    379 
    380 #ifdef TARGET_WORDS_BIGENDIAN
    381     disasm_info.endian = BFD_ENDIAN_BIG;
    382 #else
    383     disasm_info.endian = BFD_ENDIAN_LITTLE;
    384 #endif
    385 #if defined(TARGET_I386)
    386     if (flags == 2)
    387         disasm_info.mach = bfd_mach_x86_64;
    388     else if (flags == 1)
    389         disasm_info.mach = bfd_mach_i386_i8086;
    390     else
    391         disasm_info.mach = bfd_mach_i386_i386;
    392     print_insn = print_insn_i386;
    393 #elif defined(TARGET_ARM)
    394     print_insn = print_insn_arm;
    395 #elif defined(TARGET_ALPHA)
    396     print_insn = print_insn_alpha;
    397 #elif defined(TARGET_SPARC)
    398     print_insn = print_insn_sparc;
    399 #ifdef TARGET_SPARC64
    400     disasm_info.mach = bfd_mach_sparc_v9b;
    401 #endif
    402 #elif defined(TARGET_PPC)
    403 #ifdef TARGET_PPC64
    404     disasm_info.mach = bfd_mach_ppc64;
    405 #else
    406     disasm_info.mach = bfd_mach_ppc;
    407 #endif
    408     print_insn = print_insn_ppc;
    409 #elif defined(TARGET_M68K)
    410     print_insn = print_insn_m68k;
    411 #elif defined(TARGET_MIPS)
    412 #ifdef TARGET_WORDS_BIGENDIAN
    413     print_insn = print_insn_big_mips;
    414 #else
    415     print_insn = print_insn_little_mips;
    416 #endif
    417 #elif defined(TARGET_SH4)
    418     disasm_info.mach = bfd_mach_sh4;
    419     print_insn = print_insn_sh;
    420 #elif defined(TARGET_S390X)
    421     disasm_info.mach = bfd_mach_s390_64;
    422     print_insn = print_insn_s390;
    423 #else
    424     monitor_printf(mon, "0x" TARGET_FMT_lx
    425                    ": Asm output not supported on this arch\n", pc);
    426     return;
    427 #endif
    428 
    429     for(i = 0; i < nb_insn; i++) {
    430 	monitor_printf(mon, "0x" TARGET_FMT_lx ":  ", pc);
    431 	count = print_insn(pc, &disasm_info);
    432 	monitor_printf(mon, "\n");
    433 	if (count < 0)
    434 	    break;
    435         pc += count;
    436     }
    437 }
    438 #endif
    439