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