disas.c 14.4 KB
Newer Older
bellard's avatar
bellard committed
1
/* General "disassemble this chunk" code.  Used for debugging. */
bellard's avatar
bellard committed
2
#include "config.h"
3
#include "disas/bfd.h"
bellard's avatar
bellard committed
4
#include "elf.h"
5
#include <errno.h>
bellard's avatar
bellard committed
6

7
#include "cpu.h"
8
#include "disas/disas.h"
9

10 11 12 13 14
typedef struct CPUDebug {
    struct disassemble_info info;
    CPUArchState *env;
} CPUDebug;

bellard's avatar
bellard committed
15
/* Filled in by elfload.c.  Simplistic, but will do for now. */
bellard's avatar
bellard committed
16
struct syminfo *syminfos = NULL;
bellard's avatar
bellard committed
17

18 19 20
/* Get LENGTH bytes from info's buffer, at target address memaddr.
   Transfer them to myaddr.  */
int
21 22
buffer_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
                   struct disassemble_info *info)
23
{
24 25 26 27 28 29
    if (memaddr < info->buffer_vma
        || memaddr + length > info->buffer_vma + info->buffer_length)
        /* Out of bounds.  Use EIO because GDB uses it.  */
        return EIO;
    memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
    return 0;
30 31
}

32 33 34
/* Get LENGTH bytes from info's buffer, at target address memaddr.
   Transfer them to myaddr.  */
static int
bellard's avatar
bellard committed
35 36 37 38
target_read_memory (bfd_vma memaddr,
                    bfd_byte *myaddr,
                    int length,
                    struct disassemble_info *info)
39
{
40 41
    CPUDebug *s = container_of(info, CPUDebug, info);

42
    cpu_memory_rw_debug(ENV_GET_CPU(s->env), memaddr, myaddr, length, 0);
43 44 45
    return 0;
}

46 47 48
/* Print an error message.  We can assume that this is in response to
   an error return from buffer_read_memory.  */
void
49
perror_memory (int status, bfd_vma memaddr, struct disassemble_info *info)
50 51 52 53 54 55 56 57
{
  if (status != EIO)
    /* Can't happen.  */
    (*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
  else
    /* Actually, address between memaddr and memaddr + len was
       out of bounds.  */
    (*info->fprintf_func) (info->stream,
bellard's avatar
bellard committed
58
			   "Address 0x%" PRIx64 " is out of bounds.\n", memaddr);
59 60
}

Jim Meyering's avatar
Jim Meyering committed
61
/* This could be in a separate file, to save minuscule amounts of space
62 63 64 65 66 67 68
   in statically linked executables.  */

/* Just print the address is hex.  This is included for completeness even
   though both GDB and objdump provide their own (to print symbolic
   addresses).  */

void
69
generic_print_address (bfd_vma addr, struct disassemble_info *info)
70
{
bellard's avatar
bellard committed
71
    (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr);
72 73
}

74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
/* Print address in hex, truncated to the width of a target virtual address. */
static void
generic_print_target_address(bfd_vma addr, struct disassemble_info *info)
{
    uint64_t mask = ~0ULL >> (64 - TARGET_VIRT_ADDR_SPACE_BITS);
    generic_print_address(addr & mask, info);
}

/* Print address in hex, truncated to the width of a host virtual address. */
static void
generic_print_host_address(bfd_vma addr, struct disassemble_info *info)
{
    uint64_t mask = ~0ULL >> (64 - (sizeof(void *) * 8));
    generic_print_address(addr & mask, info);
}

90 91 92
/* Just return the given address.  */

int
93
generic_symbol_at_address (bfd_vma addr, struct disassemble_info *info)
94 95 96 97
{
  return 1;
}

Aurelien Jarno's avatar
Aurelien Jarno committed
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
bfd_vma bfd_getl64 (const bfd_byte *addr)
{
  unsigned long long v;

  v = (unsigned long long) addr[0];
  v |= (unsigned long long) addr[1] << 8;
  v |= (unsigned long long) addr[2] << 16;
  v |= (unsigned long long) addr[3] << 24;
  v |= (unsigned long long) addr[4] << 32;
  v |= (unsigned long long) addr[5] << 40;
  v |= (unsigned long long) addr[6] << 48;
  v |= (unsigned long long) addr[7] << 56;
  return (bfd_vma) v;
}

113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
bfd_vma bfd_getl32 (const bfd_byte *addr)
{
  unsigned long v;

  v = (unsigned long) addr[0];
  v |= (unsigned long) addr[1] << 8;
  v |= (unsigned long) addr[2] << 16;
  v |= (unsigned long) addr[3] << 24;
  return (bfd_vma) v;
}

bfd_vma bfd_getb32 (const bfd_byte *addr)
{
  unsigned long v;

  v = (unsigned long) addr[0] << 24;
  v |= (unsigned long) addr[1] << 16;
  v |= (unsigned long) addr[2] << 8;
  v |= (unsigned long) addr[3];
  return (bfd_vma) v;
}

bellard's avatar
bellard committed
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
bfd_vma bfd_getl16 (const bfd_byte *addr)
{
  unsigned long v;

  v = (unsigned long) addr[0];
  v |= (unsigned long) addr[1] << 8;
  return (bfd_vma) v;
}

bfd_vma bfd_getb16 (const bfd_byte *addr)
{
  unsigned long v;

  v = (unsigned long) addr[0] << 24;
  v |= (unsigned long) addr[1] << 16;
  return (bfd_vma) v;
}

153 154 155 156 157 158 159 160
#ifdef TARGET_ARM
static int
print_insn_thumb1(bfd_vma pc, disassemble_info *info)
{
  return print_insn_arm(pc | 1, info);
}
#endif

161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
static int print_insn_objdump(bfd_vma pc, disassemble_info *info,
                              const char *prefix)
{
    int i, n = info->buffer_length;
    uint8_t *buf = g_malloc(n);

    info->read_memory_func(pc, buf, n, info);

    for (i = 0; i < n; ++i) {
        if (i % 32 == 0) {
            info->fprintf_func(info->stream, "\n%s: ", prefix);
        }
        info->fprintf_func(info->stream, "%02x", buf[i]);
    }

    g_free(buf);
    return n;
}

static int print_insn_od_host(bfd_vma pc, disassemble_info *info)
{
    return print_insn_objdump(pc, info, "OBJD-H");
}

static int print_insn_od_target(bfd_vma pc, disassemble_info *info)
{
    return print_insn_objdump(pc, info, "OBJD-T");
}

ths's avatar
ths committed
190
/* Disassemble this for me please... (debugging). 'flags' has the following
191
   values:
Frediano Ziglio's avatar
Frediano Ziglio committed
192
    i386 - 1 means 16 bit code, 2 means 64 bit code
193
    arm  - bit 0 = thumb, bit 1 = reverse endian, bit 2 = A64
Tom Musta's avatar
Tom Musta committed
194 195
    ppc  - bits 0:15 specify (optionally) the machine instruction set;
           bit 16 indicates little endian.
196 197
    other targets - unused
 */
198 199
void target_disas(FILE *out, CPUArchState *env, target_ulong code,
                  target_ulong size, int flags)
bellard's avatar
bellard committed
200
{
bellard's avatar
bellard committed
201
    target_ulong pc;
bellard's avatar
bellard committed
202
    int count;
203
    CPUDebug s;
204
    int (*print_insn)(bfd_vma pc, disassemble_info *info) = NULL;
bellard's avatar
bellard committed
205

206
    INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
bellard's avatar
bellard committed
207

208 209 210 211 212
    s.env = env;
    s.info.read_memory_func = target_read_memory;
    s.info.buffer_vma = code;
    s.info.buffer_length = size;
    s.info.print_address_func = generic_print_target_address;
bellard's avatar
bellard committed
213 214

#ifdef TARGET_WORDS_BIGENDIAN
215
    s.info.endian = BFD_ENDIAN_BIG;
bellard's avatar
bellard committed
216
#else
217
    s.info.endian = BFD_ENDIAN_LITTLE;
bellard's avatar
bellard committed
218 219
#endif
#if defined(TARGET_I386)
220 221 222 223 224 225 226
    if (flags == 2) {
        s.info.mach = bfd_mach_x86_64;
    } else if (flags == 1) {
        s.info.mach = bfd_mach_i386_i8086;
    } else {
        s.info.mach = bfd_mach_i386_i386;
    }
bellard's avatar
bellard committed
227 228
    print_insn = print_insn_i386;
#elif defined(TARGET_ARM)
229 230 231 232 233 234 235 236 237
    if (flags & 4) {
        /* We might not be compiled with the A64 disassembler
         * because it needs a C++ compiler; in that case we will
         * fall through to the default print_insn_od case.
         */
#if defined(CONFIG_ARM_A64_DIS)
        print_insn = print_insn_arm_a64;
#endif
    } else if (flags & 1) {
Paul Brook's avatar
Paul Brook committed
238 239 240 241 242 243
        print_insn = print_insn_thumb1;
    } else {
        print_insn = print_insn_arm;
    }
    if (flags & 2) {
#ifdef TARGET_WORDS_BIGENDIAN
244
        s.info.endian = BFD_ENDIAN_LITTLE;
Paul Brook's avatar
Paul Brook committed
245
#else
246
        s.info.endian = BFD_ENDIAN_BIG;
Paul Brook's avatar
Paul Brook committed
247 248
#endif
    }
bellard's avatar
bellard committed
249 250
#elif defined(TARGET_SPARC)
    print_insn = print_insn_sparc;
bellard's avatar
bellard committed
251
#ifdef TARGET_SPARC64
252
    s.info.mach = bfd_mach_sparc_v9b;
253
#endif
bellard's avatar
bellard committed
254
#elif defined(TARGET_PPC)
Tom Musta's avatar
Tom Musta committed
255
    if ((flags >> 16) & 1) {
256 257
        s.info.endian = BFD_ENDIAN_LITTLE;
    }
258
    if (flags & 0xFFFF) {
Tom Musta's avatar
Tom Musta committed
259
        /* If we have a precise definition of the instruction set, use it. */
260
        s.info.mach = flags & 0xFFFF;
261
    } else {
bellard's avatar
bellard committed
262
#ifdef TARGET_PPC64
263
        s.info.mach = bfd_mach_ppc64;
bellard's avatar
bellard committed
264
#else
265
        s.info.mach = bfd_mach_ppc;
bellard's avatar
bellard committed
266
#endif
267
    }
268
    s.info.disassembler_options = (char *)"any";
bellard's avatar
bellard committed
269
    print_insn = print_insn_ppc;
pbrook's avatar
pbrook committed
270 271
#elif defined(TARGET_M68K)
    print_insn = print_insn_m68k;
bellard's avatar
bellard committed
272
#elif defined(TARGET_MIPS)
bellard's avatar
bellard committed
273
#ifdef TARGET_WORDS_BIGENDIAN
bellard's avatar
bellard committed
274
    print_insn = print_insn_big_mips;
bellard's avatar
bellard committed
275 276 277
#else
    print_insn = print_insn_little_mips;
#endif
bellard's avatar
bellard committed
278
#elif defined(TARGET_SH4)
279
    s.info.mach = bfd_mach_sh4;
bellard's avatar
bellard committed
280
    print_insn = print_insn_sh;
281
#elif defined(TARGET_ALPHA)
282
    s.info.mach = bfd_mach_alpha_ev6;
283
    print_insn = print_insn_alpha;
284
#elif defined(TARGET_CRIS)
285
    if (flags != 32) {
286
        s.info.mach = bfd_mach_cris_v0_v10;
287 288
        print_insn = print_insn_crisv10;
    } else {
289
        s.info.mach = bfd_mach_cris_v32;
290 291
        print_insn = print_insn_crisv32;
    }
292
#elif defined(TARGET_S390X)
293
    s.info.mach = bfd_mach_s390_64;
294
    print_insn = print_insn_s390;
295
#elif defined(TARGET_MICROBLAZE)
296
    s.info.mach = bfd_arch_microblaze;
297
    print_insn = print_insn_microblaze;
Anthony Green's avatar
Anthony Green committed
298 299 300
#elif defined(TARGET_MOXIE)
    s.info.mach = bfd_arch_moxie;
    print_insn = print_insn_moxie;
301
#elif defined(TARGET_LM32)
302
    s.info.mach = bfd_mach_lm32;
303
    print_insn = print_insn_lm32;
304
#endif
305 306 307
    if (print_insn == NULL) {
        print_insn = print_insn_od_target;
    }
308

309
    for (pc = code; size > 0; pc += count, size -= count) {
bellard's avatar
bellard committed
310
	fprintf(out, "0x" TARGET_FMT_lx ":  ", pc);
311
	count = print_insn(pc, &s.info);
bellard's avatar
bellard committed
312 313 314 315 316 317
#if 0
        {
            int i;
            uint8_t b;
            fprintf(out, " {");
            for(i = 0; i < count; i++) {
318
                target_read_memory(pc + i, &b, 1, &s.info);
bellard's avatar
bellard committed
319 320 321 322 323 324 325 326
                fprintf(out, " %02x", b);
            }
            fprintf(out, " }");
        }
#endif
	fprintf(out, "\n");
	if (count < 0)
	    break;
327 328 329 330 331 332 333
        if (size < count) {
            fprintf(out,
                    "Disassembler disagrees with translator over instruction "
                    "decoding\n"
                    "Please report this to qemu-devel@nongnu.org\n");
            break;
        }
bellard's avatar
bellard committed
334 335 336 337 338 339
    }
}

/* Disassemble this for me please... (debugging). */
void disas(FILE *out, void *code, unsigned long size)
{
340
    uintptr_t pc;
bellard's avatar
bellard committed
341
    int count;
342
    CPUDebug s;
343
    int (*print_insn)(bfd_vma pc, disassemble_info *info) = NULL;
bellard's avatar
bellard committed
344

345 346
    INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
    s.info.print_address_func = generic_print_host_address;
bellard's avatar
bellard committed
347

348 349 350
    s.info.buffer = code;
    s.info.buffer_vma = (uintptr_t)code;
    s.info.buffer_length = size;
bellard's avatar
bellard committed
351

352
#ifdef HOST_WORDS_BIGENDIAN
353
    s.info.endian = BFD_ENDIAN_BIG;
bellard's avatar
bellard committed
354
#else
355
    s.info.endian = BFD_ENDIAN_LITTLE;
bellard's avatar
bellard committed
356
#endif
Stefan Weil's avatar
Stefan Weil committed
357 358 359
#if defined(CONFIG_TCG_INTERPRETER)
    print_insn = print_insn_tci;
#elif defined(__i386__)
360
    s.info.mach = bfd_mach_i386_i386;
bellard's avatar
bellard committed
361
    print_insn = print_insn_i386;
362
#elif defined(__x86_64__)
363
    s.info.mach = bfd_mach_x86_64;
bellard's avatar
bellard committed
364
    print_insn = print_insn_i386;
malc's avatar
malc committed
365
#elif defined(_ARCH_PPC)
366
    s.info.disassembler_options = (char *)"any";
bellard's avatar
bellard committed
367
    print_insn = print_insn_ppc;
368 369
#elif defined(__aarch64__) && defined(CONFIG_ARM_A64_DIS)
    print_insn = print_insn_arm_a64;
bellard's avatar
bellard committed
370
#elif defined(__alpha__)
bellard's avatar
bellard committed
371
    print_insn = print_insn_alpha;
372
#elif defined(__sparc__)
bellard's avatar
bellard committed
373
    print_insn = print_insn_sparc;
374
    s.info.mach = bfd_mach_sparc_v9b;
375
#elif defined(__arm__)
bellard's avatar
bellard committed
376
    print_insn = print_insn_arm;
bellard's avatar
bellard committed
377 378 379 380
#elif defined(__MIPSEB__)
    print_insn = print_insn_big_mips;
#elif defined(__MIPSEL__)
    print_insn = print_insn_little_mips;
bellard's avatar
bellard committed
381 382
#elif defined(__m68k__)
    print_insn = print_insn_m68k;
383 384
#elif defined(__s390__)
    print_insn = print_insn_s390;
aurel32's avatar
aurel32 committed
385 386
#elif defined(__hppa__)
    print_insn = print_insn_hppa;
Aurelien Jarno's avatar
Aurelien Jarno committed
387 388
#elif defined(__ia64__)
    print_insn = print_insn_ia64;
bellard's avatar
bellard committed
389
#endif
390 391 392
    if (print_insn == NULL) {
        print_insn = print_insn_od_host;
    }
393 394
    for (pc = (uintptr_t)code; size > 0; pc += count, size -= count) {
        fprintf(out, "0x%08" PRIxPTR ":  ", pc);
395
        count = print_insn(pc, &s.info);
bellard's avatar
bellard committed
396 397 398 399 400 401 402
	fprintf(out, "\n");
	if (count < 0)
	    break;
    }
}

/* Look up symbol for debugging purpose.  Returns "" if unknown. */
bellard's avatar
bellard committed
403
const char *lookup_symbol(target_ulong orig_addr)
bellard's avatar
bellard committed
404
{
405
    const char *symbol = "";
bellard's avatar
bellard committed
406
    struct syminfo *s;
407

bellard's avatar
bellard committed
408
    for (s = syminfos; s; s = s->next) {
409 410 411 412
        symbol = s->lookup_symbol(s, orig_addr);
        if (symbol[0] != '\0') {
            break;
        }
bellard's avatar
bellard committed
413
    }
414 415

    return symbol;
bellard's avatar
bellard committed
416
}
417 418 419

#if !defined(CONFIG_USER_ONLY)

420
#include "monitor/monitor.h"
421

422 423 424
static int monitor_disas_is_physical;

static int
425 426
monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length,
                     struct disassemble_info *info)
427
{
428 429
    CPUDebug *s = container_of(info, CPUDebug, info);

430
    if (monitor_disas_is_physical) {
431
        cpu_physical_memory_read(memaddr, myaddr, length);
432
    } else {
433
        cpu_memory_rw_debug(ENV_GET_CPU(s->env), memaddr, myaddr, length, 0);
434 435 436 437
    }
    return 0;
}

438 439
static int GCC_FMT_ATTR(2, 3)
monitor_fprintf(FILE *stream, const char *fmt, ...)
440 441 442
{
    va_list ap;
    va_start(ap, fmt);
443
    monitor_vprintf((Monitor *)stream, fmt, ap);
444 445 446 447
    va_end(ap);
    return 0;
}

448 449
/* Disassembler for the monitor.
   See target_disas for a description of flags. */
450
void monitor_disas(Monitor *mon, CPUArchState *env,
bellard's avatar
bellard committed
451
                   target_ulong pc, int nb_insn, int is_physical, int flags)
452 453
{
    int count, i;
454
    CPUDebug s;
455 456
    int (*print_insn)(bfd_vma pc, disassemble_info *info);

457
    INIT_DISASSEMBLE_INFO(s.info, (FILE *)mon, monitor_fprintf);
458

459
    s.env = env;
460
    monitor_disas_is_physical = is_physical;
461 462
    s.info.read_memory_func = monitor_read_memory;
    s.info.print_address_func = generic_print_target_address;
463

464
    s.info.buffer_vma = pc;
465 466

#ifdef TARGET_WORDS_BIGENDIAN
467
    s.info.endian = BFD_ENDIAN_BIG;
468
#else
469
    s.info.endian = BFD_ENDIAN_LITTLE;
470 471
#endif
#if defined(TARGET_I386)
472 473 474 475 476 477 478
    if (flags == 2) {
        s.info.mach = bfd_mach_x86_64;
    } else if (flags == 1) {
        s.info.mach = bfd_mach_i386_i8086;
    } else {
        s.info.mach = bfd_mach_i386_i386;
    }
479 480 481
    print_insn = print_insn_i386;
#elif defined(TARGET_ARM)
    print_insn = print_insn_arm;
ths's avatar
ths committed
482 483
#elif defined(TARGET_ALPHA)
    print_insn = print_insn_alpha;
484 485
#elif defined(TARGET_SPARC)
    print_insn = print_insn_sparc;
486
#ifdef TARGET_SPARC64
487
    s.info.mach = bfd_mach_sparc_v9b;
488
#endif
489
#elif defined(TARGET_PPC)
490 491 492 493
    if (flags & 0xFFFF) {
        /* If we have a precise definition of the instruction set, use it. */
        s.info.mach = flags & 0xFFFF;
    } else {
bellard's avatar
bellard committed
494
#ifdef TARGET_PPC64
495
        s.info.mach = bfd_mach_ppc64;
bellard's avatar
bellard committed
496
#else
497
        s.info.mach = bfd_mach_ppc;
bellard's avatar
bellard committed
498
#endif
499 500 501 502
    }
    if ((flags >> 16) & 1) {
        s.info.endian = BFD_ENDIAN_LITTLE;
    }
503
    print_insn = print_insn_ppc;
pbrook's avatar
pbrook committed
504 505
#elif defined(TARGET_M68K)
    print_insn = print_insn_m68k;
bellard's avatar
bellard committed
506
#elif defined(TARGET_MIPS)
bellard's avatar
bellard committed
507
#ifdef TARGET_WORDS_BIGENDIAN
bellard's avatar
bellard committed
508
    print_insn = print_insn_big_mips;
bellard's avatar
bellard committed
509 510 511
#else
    print_insn = print_insn_little_mips;
#endif
Magnus Damm's avatar
Magnus Damm committed
512
#elif defined(TARGET_SH4)
513
    s.info.mach = bfd_mach_sh4;
Magnus Damm's avatar
Magnus Damm committed
514
    print_insn = print_insn_sh;
515
#elif defined(TARGET_S390X)
516
    s.info.mach = bfd_mach_s390_64;
517
    print_insn = print_insn_s390;
Anthony Green's avatar
Anthony Green committed
518 519 520
#elif defined(TARGET_MOXIE)
    s.info.mach = bfd_arch_moxie;
    print_insn = print_insn_moxie;
521
#elif defined(TARGET_LM32)
522
    s.info.mach = bfd_mach_lm32;
523
    print_insn = print_insn_lm32;
524
#else
525 526
    monitor_printf(mon, "0x" TARGET_FMT_lx
                   ": Asm output not supported on this arch\n", pc);
527 528 529 530
    return;
#endif

    for(i = 0; i < nb_insn; i++) {
531
	monitor_printf(mon, "0x" TARGET_FMT_lx ":  ", pc);
532
        count = print_insn(pc, &s.info);
533
	monitor_printf(mon, "\n");
534 535 536 537 538 539
	if (count < 0)
	    break;
        pc += count;
    }
}
#endif