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_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