File:  [Qemu by Fabrice Bellard] / qemu / disas.c
Revision 1.1.1.12 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 18:55:47 2018 UTC (3 years, 1 month ago) by root
Branches: qemu, MAIN
CVS tags: qemu1000, qemu0151, HEAD
qemu 0.15.1

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

unix.superglobalmegacorp.com