qemu/disas.c
<<
>>
Prefs
   1/* General "disassemble this chunk" code.  Used for debugging. */
   2#include "qemu/osdep.h"
   3#include "qemu-common.h"
   4#include "disas/bfd.h"
   5#include "elf.h"
   6
   7#include "cpu.h"
   8#include "disas/disas.h"
   9#include "disas/capstone.h"
  10
  11typedef struct CPUDebug {
  12    struct disassemble_info info;
  13    CPUState *cpu;
  14} CPUDebug;
  15
  16/* Filled in by elfload.c.  Simplistic, but will do for now. */
  17struct syminfo *syminfos = NULL;
  18
  19/* Get LENGTH bytes from info's buffer, at target address memaddr.
  20   Transfer them to myaddr.  */
  21int
  22buffer_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
  23                   struct disassemble_info *info)
  24{
  25    if (memaddr < info->buffer_vma
  26        || memaddr + length > info->buffer_vma + info->buffer_length)
  27        /* Out of bounds.  Use EIO because GDB uses it.  */
  28        return EIO;
  29    memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
  30    return 0;
  31}
  32
  33/* Get LENGTH bytes from info's buffer, at target address memaddr.
  34   Transfer them to myaddr.  */
  35static int
  36target_read_memory (bfd_vma memaddr,
  37                    bfd_byte *myaddr,
  38                    int length,
  39                    struct disassemble_info *info)
  40{
  41    CPUDebug *s = container_of(info, CPUDebug, info);
  42
  43    cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, 0);
  44    return 0;
  45}
  46
  47/* Print an error message.  We can assume that this is in response to
  48   an error return from buffer_read_memory.  */
  49void
  50perror_memory (int status, bfd_vma memaddr, struct disassemble_info *info)
  51{
  52  if (status != EIO)
  53    /* Can't happen.  */
  54    (*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
  55  else
  56    /* Actually, address between memaddr and memaddr + len was
  57       out of bounds.  */
  58    (*info->fprintf_func) (info->stream,
  59                           "Address 0x%" PRIx64 " is out of bounds.\n", memaddr);
  60}
  61
  62/* This could be in a separate file, to save minuscule amounts of space
  63   in statically linked executables.  */
  64
  65/* Just print the address is hex.  This is included for completeness even
  66   though both GDB and objdump provide their own (to print symbolic
  67   addresses).  */
  68
  69void
  70generic_print_address (bfd_vma addr, struct disassemble_info *info)
  71{
  72    (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr);
  73}
  74
  75/* Print address in hex, truncated to the width of a host virtual address. */
  76static void
  77generic_print_host_address(bfd_vma addr, struct disassemble_info *info)
  78{
  79    uint64_t mask = ~0ULL >> (64 - (sizeof(void *) * 8));
  80    generic_print_address(addr & mask, info);
  81}
  82
  83/* Just return the given address.  */
  84
  85int
  86generic_symbol_at_address (bfd_vma addr, struct disassemble_info *info)
  87{
  88  return 1;
  89}
  90
  91bfd_vma bfd_getl64 (const bfd_byte *addr)
  92{
  93  unsigned long long v;
  94
  95  v = (unsigned long long) addr[0];
  96  v |= (unsigned long long) addr[1] << 8;
  97  v |= (unsigned long long) addr[2] << 16;
  98  v |= (unsigned long long) addr[3] << 24;
  99  v |= (unsigned long long) addr[4] << 32;
 100  v |= (unsigned long long) addr[5] << 40;
 101  v |= (unsigned long long) addr[6] << 48;
 102  v |= (unsigned long long) addr[7] << 56;
 103  return (bfd_vma) v;
 104}
 105
 106bfd_vma bfd_getl32 (const bfd_byte *addr)
 107{
 108  unsigned long v;
 109
 110  v = (unsigned long) addr[0];
 111  v |= (unsigned long) addr[1] << 8;
 112  v |= (unsigned long) addr[2] << 16;
 113  v |= (unsigned long) addr[3] << 24;
 114  return (bfd_vma) v;
 115}
 116
 117bfd_vma bfd_getb32 (const bfd_byte *addr)
 118{
 119  unsigned long v;
 120
 121  v = (unsigned long) addr[0] << 24;
 122  v |= (unsigned long) addr[1] << 16;
 123  v |= (unsigned long) addr[2] << 8;
 124  v |= (unsigned long) addr[3];
 125  return (bfd_vma) v;
 126}
 127
 128bfd_vma bfd_getl16 (const bfd_byte *addr)
 129{
 130  unsigned long v;
 131
 132  v = (unsigned long) addr[0];
 133  v |= (unsigned long) addr[1] << 8;
 134  return (bfd_vma) v;
 135}
 136
 137bfd_vma bfd_getb16 (const bfd_byte *addr)
 138{
 139  unsigned long v;
 140
 141  v = (unsigned long) addr[0] << 24;
 142  v |= (unsigned long) addr[1] << 16;
 143  return (bfd_vma) v;
 144}
 145
 146static int print_insn_objdump(bfd_vma pc, disassemble_info *info,
 147                              const char *prefix)
 148{
 149    int i, n = info->buffer_length;
 150    uint8_t *buf = g_malloc(n);
 151
 152    info->read_memory_func(pc, buf, n, info);
 153
 154    for (i = 0; i < n; ++i) {
 155        if (i % 32 == 0) {
 156            info->fprintf_func(info->stream, "\n%s: ", prefix);
 157        }
 158        info->fprintf_func(info->stream, "%02x", buf[i]);
 159    }
 160
 161    g_free(buf);
 162    return n;
 163}
 164
 165static int print_insn_od_host(bfd_vma pc, disassemble_info *info)
 166{
 167    return print_insn_objdump(pc, info, "OBJD-H");
 168}
 169
 170static int print_insn_od_target(bfd_vma pc, disassemble_info *info)
 171{
 172    return print_insn_objdump(pc, info, "OBJD-T");
 173}
 174
 175#ifdef CONFIG_CAPSTONE
 176/* Temporary storage for the capstone library.  This will be alloced via
 177   malloc with a size private to the library; thus there's no reason not
 178   to share this across calls and across host vs target disassembly.  */
 179static __thread cs_insn *cap_insn;
 180
 181/* Initialize the Capstone library.  */
 182/* ??? It would be nice to cache this.  We would need one handle for the
 183   host and one for the target.  For most targets we can reset specific
 184   parameters via cs_option(CS_OPT_MODE, new_mode), but we cannot change
 185   CS_ARCH_* in this way.  Thus we would need to be able to close and
 186   re-open the target handle with a different arch for the target in order
 187   to handle AArch64 vs AArch32 mode switching.  */
 188static cs_err cap_disas_start(disassemble_info *info, csh *handle)
 189{
 190    cs_mode cap_mode = info->cap_mode;
 191    cs_err err;
 192
 193    cap_mode += (info->endian == BFD_ENDIAN_BIG ? CS_MODE_BIG_ENDIAN
 194                 : CS_MODE_LITTLE_ENDIAN);
 195
 196    err = cs_open(info->cap_arch, cap_mode, handle);
 197    if (err != CS_ERR_OK) {
 198        return err;
 199    }
 200
 201    /* ??? There probably ought to be a better place to put this.  */
 202    if (info->cap_arch == CS_ARCH_X86) {
 203        /* We don't care about errors (if for some reason the library
 204           is compiled without AT&T syntax); the user will just have
 205           to deal with the Intel syntax.  */
 206        cs_option(*handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
 207    }
 208
 209    /* "Disassemble" unknown insns as ".byte W,X,Y,Z".  */
 210    cs_option(*handle, CS_OPT_SKIPDATA, CS_OPT_ON);
 211
 212    /* Allocate temp space for cs_disasm_iter.  */
 213    if (cap_insn == NULL) {
 214        cap_insn = cs_malloc(*handle);
 215        if (cap_insn == NULL) {
 216            cs_close(handle);
 217            return CS_ERR_MEM;
 218        }
 219    }
 220    return CS_ERR_OK;
 221}
 222
 223static void cap_dump_insn_units(disassemble_info *info, cs_insn *insn,
 224                                int i, int n)
 225{
 226    fprintf_function print = info->fprintf_func;
 227    FILE *stream = info->stream;
 228
 229    switch (info->cap_insn_unit) {
 230    case 4:
 231        if (info->endian == BFD_ENDIAN_BIG) {
 232            for (; i < n; i += 4) {
 233                print(stream, " %08x", ldl_be_p(insn->bytes + i));
 234
 235            }
 236        } else {
 237            for (; i < n; i += 4) {
 238                print(stream, " %08x", ldl_le_p(insn->bytes + i));
 239            }
 240        }
 241        break;
 242
 243    case 2:
 244        if (info->endian == BFD_ENDIAN_BIG) {
 245            for (; i < n; i += 2) {
 246                print(stream, " %04x", lduw_be_p(insn->bytes + i));
 247            }
 248        } else {
 249            for (; i < n; i += 2) {
 250                print(stream, " %04x", lduw_le_p(insn->bytes + i));
 251            }
 252        }
 253        break;
 254
 255    default:
 256        for (; i < n; i++) {
 257            print(stream, " %02x", insn->bytes[i]);
 258        }
 259        break;
 260    }
 261}
 262
 263static void cap_dump_insn(disassemble_info *info, cs_insn *insn)
 264{
 265    fprintf_function print = info->fprintf_func;
 266    int i, n, split;
 267
 268    print(info->stream, "0x%08" PRIx64 ": ", insn->address);
 269
 270    n = insn->size;
 271    split = info->cap_insn_split;
 272
 273    /* Dump the first SPLIT bytes of the instruction.  */
 274    cap_dump_insn_units(info, insn, 0, MIN(n, split));
 275
 276    /* Add padding up to SPLIT so that mnemonics line up.  */
 277    if (n < split) {
 278        int width = (split - n) / info->cap_insn_unit;
 279        width *= (2 * info->cap_insn_unit + 1);
 280        print(info->stream, "%*s", width, "");
 281    }
 282
 283    /* Print the actual instruction.  */
 284    print(info->stream, "  %-8s %s\n", insn->mnemonic, insn->op_str);
 285
 286    /* Dump any remaining part of the insn on subsequent lines.  */
 287    for (i = split; i < n; i += split) {
 288        print(info->stream, "0x%08" PRIx64 ": ", insn->address + i);
 289        cap_dump_insn_units(info, insn, i, MIN(n, i + split));
 290        print(info->stream, "\n");
 291    }
 292}
 293
 294/* Disassemble SIZE bytes at PC for the target.  */
 295static bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size)
 296{
 297    uint8_t cap_buf[1024];
 298    csh handle;
 299    cs_insn *insn;
 300    size_t csize = 0;
 301
 302    if (cap_disas_start(info, &handle) != CS_ERR_OK) {
 303        return false;
 304    }
 305    insn = cap_insn;
 306
 307    while (1) {
 308        size_t tsize = MIN(sizeof(cap_buf) - csize, size);
 309        const uint8_t *cbuf = cap_buf;
 310
 311        target_read_memory(pc + csize, cap_buf + csize, tsize, info);
 312        csize += tsize;
 313        size -= tsize;
 314
 315        while (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) {
 316           cap_dump_insn(info, insn);
 317        }
 318
 319        /* If the target memory is not consumed, go back for more... */
 320        if (size != 0) {
 321            /* ... taking care to move any remaining fractional insn
 322               to the beginning of the buffer.  */
 323            if (csize != 0) {
 324                memmove(cap_buf, cbuf, csize);
 325            }
 326            continue;
 327        }
 328
 329        /* Since the target memory is consumed, we should not have
 330           a remaining fractional insn.  */
 331        if (csize != 0) {
 332            (*info->fprintf_func)(info->stream,
 333                "Disassembler disagrees with translator "
 334                "over instruction decoding\n"
 335                "Please report this to qemu-devel@nongnu.org\n");
 336        }
 337        break;
 338    }
 339
 340    cs_close(&handle);
 341    return true;
 342}
 343
 344/* Disassemble SIZE bytes at CODE for the host.  */
 345static bool cap_disas_host(disassemble_info *info, void *code, size_t size)
 346{
 347    csh handle;
 348    const uint8_t *cbuf;
 349    cs_insn *insn;
 350    uint64_t pc;
 351
 352    if (cap_disas_start(info, &handle) != CS_ERR_OK) {
 353        return false;
 354    }
 355    insn = cap_insn;
 356
 357    cbuf = code;
 358    pc = (uintptr_t)code;
 359
 360    while (cs_disasm_iter(handle, &cbuf, &size, &pc, insn)) {
 361       cap_dump_insn(info, insn);
 362    }
 363    if (size != 0) {
 364        (*info->fprintf_func)(info->stream,
 365            "Disassembler disagrees with TCG over instruction encoding\n"
 366            "Please report this to qemu-devel@nongnu.org\n");
 367    }
 368
 369    cs_close(&handle);
 370    return true;
 371}
 372
 373#if !defined(CONFIG_USER_ONLY)
 374/* Disassemble COUNT insns at PC for the target.  */
 375static bool cap_disas_monitor(disassemble_info *info, uint64_t pc, int count)
 376{
 377    uint8_t cap_buf[32];
 378    csh handle;
 379    cs_insn *insn;
 380    size_t csize = 0;
 381
 382    if (cap_disas_start(info, &handle) != CS_ERR_OK) {
 383        return false;
 384    }
 385    insn = cap_insn;
 386
 387    while (1) {
 388        /* We want to read memory for one insn, but generically we do not
 389           know how much memory that is.  We have a small buffer which is
 390           known to be sufficient for all supported targets.  Try to not
 391           read beyond the page, Just In Case.  For even more simplicity,
 392           ignore the actual target page size and use a 1k boundary.  If
 393           that turns out to be insufficient, we'll come back around the
 394           loop and read more.  */
 395        uint64_t epc = QEMU_ALIGN_UP(pc + csize + 1, 1024);
 396        size_t tsize = MIN(sizeof(cap_buf) - csize, epc - pc);
 397        const uint8_t *cbuf = cap_buf;
 398
 399        /* Make certain that we can make progress.  */
 400        assert(tsize != 0);
 401        info->read_memory_func(pc, cap_buf + csize, tsize, info);
 402        csize += tsize;
 403
 404        if (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) {
 405            cap_dump_insn(info, insn);
 406            if (--count <= 0) {
 407                break;
 408            }
 409        }
 410        memmove(cap_buf, cbuf, csize);
 411    }
 412
 413    cs_close(&handle);
 414    return true;
 415}
 416#endif /* !CONFIG_USER_ONLY */
 417#else
 418# define cap_disas_target(i, p, s)  false
 419# define cap_disas_host(i, p, s)  false
 420# define cap_disas_monitor(i, p, c)  false
 421#endif /* CONFIG_CAPSTONE */
 422
 423/* Disassemble this for me please... (debugging).  */
 424void target_disas(FILE *out, CPUState *cpu, target_ulong code,
 425                  target_ulong size)
 426{
 427    CPUClass *cc = CPU_GET_CLASS(cpu);
 428    target_ulong pc;
 429    int count;
 430    CPUDebug s;
 431
 432    INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
 433
 434    s.cpu = cpu;
 435    s.info.read_memory_func = target_read_memory;
 436    s.info.buffer_vma = code;
 437    s.info.buffer_length = size;
 438    s.info.print_address_func = generic_print_address;
 439    s.info.cap_arch = -1;
 440    s.info.cap_mode = 0;
 441    s.info.cap_insn_unit = 4;
 442    s.info.cap_insn_split = 4;
 443
 444#ifdef TARGET_WORDS_BIGENDIAN
 445    s.info.endian = BFD_ENDIAN_BIG;
 446#else
 447    s.info.endian = BFD_ENDIAN_LITTLE;
 448#endif
 449
 450    if (cc->disas_set_info) {
 451        cc->disas_set_info(cpu, &s.info);
 452    }
 453
 454    if (s.info.cap_arch >= 0 && cap_disas_target(&s.info, code, size)) {
 455        return;
 456    }
 457
 458    if (s.info.print_insn == NULL) {
 459        s.info.print_insn = print_insn_od_target;
 460    }
 461
 462    for (pc = code; size > 0; pc += count, size -= count) {
 463        fprintf(out, "0x" TARGET_FMT_lx ":  ", pc);
 464        count = s.info.print_insn(pc, &s.info);
 465        fprintf(out, "\n");
 466        if (count < 0)
 467            break;
 468        if (size < count) {
 469            fprintf(out,
 470                    "Disassembler disagrees with translator over instruction "
 471                    "decoding\n"
 472                    "Please report this to qemu-devel@nongnu.org\n");
 473            break;
 474        }
 475    }
 476}
 477
 478/* Disassemble this for me please... (debugging). */
 479void disas(FILE *out, void *code, unsigned long size)
 480{
 481    uintptr_t pc;
 482    int count;
 483    CPUDebug s;
 484    int (*print_insn)(bfd_vma pc, disassemble_info *info) = NULL;
 485
 486    INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
 487    s.info.print_address_func = generic_print_host_address;
 488
 489    s.info.buffer = code;
 490    s.info.buffer_vma = (uintptr_t)code;
 491    s.info.buffer_length = size;
 492    s.info.cap_arch = -1;
 493    s.info.cap_mode = 0;
 494    s.info.cap_insn_unit = 4;
 495    s.info.cap_insn_split = 4;
 496
 497#ifdef HOST_WORDS_BIGENDIAN
 498    s.info.endian = BFD_ENDIAN_BIG;
 499#else
 500    s.info.endian = BFD_ENDIAN_LITTLE;
 501#endif
 502#if defined(CONFIG_TCG_INTERPRETER)
 503    print_insn = print_insn_tci;
 504#elif defined(__i386__)
 505    s.info.mach = bfd_mach_i386_i386;
 506    print_insn = print_insn_i386;
 507    s.info.cap_arch = CS_ARCH_X86;
 508    s.info.cap_mode = CS_MODE_32;
 509    s.info.cap_insn_unit = 1;
 510    s.info.cap_insn_split = 8;
 511#elif defined(__x86_64__)
 512    s.info.mach = bfd_mach_x86_64;
 513    print_insn = print_insn_i386;
 514    s.info.cap_arch = CS_ARCH_X86;
 515    s.info.cap_mode = CS_MODE_64;
 516    s.info.cap_insn_unit = 1;
 517    s.info.cap_insn_split = 8;
 518#elif defined(_ARCH_PPC)
 519    s.info.disassembler_options = (char *)"any";
 520    print_insn = print_insn_ppc;
 521    s.info.cap_arch = CS_ARCH_PPC;
 522# ifdef _ARCH_PPC64
 523    s.info.cap_mode = CS_MODE_64;
 524# endif
 525#elif defined(__riscv) && defined(CONFIG_RISCV_DIS)
 526#if defined(_ILP32) || (__riscv_xlen == 32)
 527    print_insn = print_insn_riscv32;
 528#elif defined(_LP64)
 529    print_insn = print_insn_riscv64;
 530#else
 531#error unsupported RISC-V ABI
 532#endif
 533#elif defined(__aarch64__) && defined(CONFIG_ARM_A64_DIS)
 534    print_insn = print_insn_arm_a64;
 535    s.info.cap_arch = CS_ARCH_ARM64;
 536#elif defined(__alpha__)
 537    print_insn = print_insn_alpha;
 538#elif defined(__sparc__)
 539    print_insn = print_insn_sparc;
 540    s.info.mach = bfd_mach_sparc_v9b;
 541#elif defined(__arm__)
 542    print_insn = print_insn_arm;
 543    s.info.cap_arch = CS_ARCH_ARM;
 544    /* TCG only generates code for arm mode.  */
 545#elif defined(__MIPSEB__)
 546    print_insn = print_insn_big_mips;
 547#elif defined(__MIPSEL__)
 548    print_insn = print_insn_little_mips;
 549#elif defined(__m68k__)
 550    print_insn = print_insn_m68k;
 551#elif defined(__s390__)
 552    print_insn = print_insn_s390;
 553#elif defined(__hppa__)
 554    print_insn = print_insn_hppa;
 555#endif
 556
 557    if (s.info.cap_arch >= 0 && cap_disas_host(&s.info, code, size)) {
 558        return;
 559    }
 560
 561    if (print_insn == NULL) {
 562        print_insn = print_insn_od_host;
 563    }
 564    for (pc = (uintptr_t)code; size > 0; pc += count, size -= count) {
 565        fprintf(out, "0x%08" PRIxPTR ":  ", pc);
 566        count = print_insn(pc, &s.info);
 567        fprintf(out, "\n");
 568        if (count < 0)
 569            break;
 570    }
 571}
 572
 573/* Look up symbol for debugging purpose.  Returns "" if unknown. */
 574const char *lookup_symbol(target_ulong orig_addr)
 575{
 576    const char *symbol = "";
 577    struct syminfo *s;
 578
 579    for (s = syminfos; s; s = s->next) {
 580        symbol = s->lookup_symbol(s, orig_addr);
 581        if (symbol[0] != '\0') {
 582            break;
 583        }
 584    }
 585
 586    return symbol;
 587}
 588
 589#if !defined(CONFIG_USER_ONLY)
 590
 591#include "monitor/monitor.h"
 592
 593static int
 594physical_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
 595                     struct disassemble_info *info)
 596{
 597    CPUDebug *s = container_of(info, CPUDebug, info);
 598
 599    address_space_read(s->cpu->as, memaddr, MEMTXATTRS_UNSPECIFIED,
 600                       myaddr, length);
 601    return 0;
 602}
 603
 604/* Disassembler for the monitor.  */
 605void monitor_disas(Monitor *mon, CPUState *cpu,
 606                   target_ulong pc, int nb_insn, int is_physical)
 607{
 608    CPUClass *cc = CPU_GET_CLASS(cpu);
 609    int count, i;
 610    CPUDebug s;
 611
 612    INIT_DISASSEMBLE_INFO(s.info, (FILE *)mon, monitor_fprintf);
 613
 614    s.cpu = cpu;
 615    s.info.read_memory_func
 616        = (is_physical ? physical_read_memory : target_read_memory);
 617    s.info.print_address_func = generic_print_address;
 618    s.info.buffer_vma = pc;
 619    s.info.cap_arch = -1;
 620    s.info.cap_mode = 0;
 621    s.info.cap_insn_unit = 4;
 622    s.info.cap_insn_split = 4;
 623
 624#ifdef TARGET_WORDS_BIGENDIAN
 625    s.info.endian = BFD_ENDIAN_BIG;
 626#else
 627    s.info.endian = BFD_ENDIAN_LITTLE;
 628#endif
 629
 630    if (cc->disas_set_info) {
 631        cc->disas_set_info(cpu, &s.info);
 632    }
 633
 634    if (s.info.cap_arch >= 0 && cap_disas_monitor(&s.info, pc, nb_insn)) {
 635        return;
 636    }
 637
 638    if (!s.info.print_insn) {
 639        monitor_printf(mon, "0x" TARGET_FMT_lx
 640                       ": Asm output not supported on this arch\n", pc);
 641        return;
 642    }
 643
 644    for(i = 0; i < nb_insn; i++) {
 645        monitor_printf(mon, "0x" TARGET_FMT_lx ":  ", pc);
 646        count = s.info.print_insn(pc, &s.info);
 647        monitor_printf(mon, "\n");
 648        if (count < 0)
 649            break;
 650        pc += count;
 651    }
 652}
 653#endif
 654