disas.c 14.0 KB
Newer Older
B
bellard 已提交
1
/* General "disassemble this chunk" code.  Used for debugging. */
B
bellard 已提交
2
#include "config.h"
3
#include "disas/bfd.h"
B
bellard 已提交
4
#include "elf.h"
B
bellard 已提交
5
#include <errno.h>
B
bellard 已提交
6

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

B
Blue Swirl 已提交
10 11 12 13 14
typedef struct CPUDebug {
    struct disassemble_info info;
    CPUArchState *env;
} CPUDebug;

B
bellard 已提交
15
/* Filled in by elfload.c.  Simplistic, but will do for now. */
B
bellard 已提交
16
struct syminfo *syminfos = NULL;
B
bellard 已提交
17

B
bellard 已提交
18 19 20
/* Get LENGTH bytes from info's buffer, at target address memaddr.
   Transfer them to myaddr.  */
int
P
pbrook 已提交
21 22
buffer_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
                   struct disassemble_info *info)
B
bellard 已提交
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;
B
bellard 已提交
30 31
}

32 33 34
/* Get LENGTH bytes from info's buffer, at target address memaddr.
   Transfer them to myaddr.  */
static int
B
bellard 已提交
35 36 37 38
target_read_memory (bfd_vma memaddr,
                    bfd_byte *myaddr,
                    int length,
                    struct disassemble_info *info)
39
{
B
Blue Swirl 已提交
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;
}

B
bellard 已提交
46 47 48
/* Print an error message.  We can assume that this is in response to
   an error return from buffer_read_memory.  */
void
P
pbrook 已提交
49
perror_memory (int status, bfd_vma memaddr, struct disassemble_info *info)
B
bellard 已提交
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,
B
bellard 已提交
58
			   "Address 0x%" PRIx64 " is out of bounds.\n", memaddr);
B
bellard 已提交
59 60
}

J
Jim Meyering 已提交
61
/* This could be in a separate file, to save minuscule amounts of space
B
bellard 已提交
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
P
pbrook 已提交
69
generic_print_address (bfd_vma addr, struct disassemble_info *info)
B
bellard 已提交
70
{
B
bellard 已提交
71
    (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr);
B
bellard 已提交
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);
}

B
bellard 已提交
90 91 92
/* Just return the given address.  */

int
P
pbrook 已提交
93
generic_symbol_at_address (bfd_vma addr, struct disassemble_info *info)
B
bellard 已提交
94 95 96 97
{
  return 1;
}

A
Aurelien Jarno 已提交
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;
}

B
bellard 已提交
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;
}

B
bellard 已提交
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;
}

B
bellard 已提交
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");
}

T
ths 已提交
190
/* Disassemble this for me please... (debugging). 'flags' has the following
B
bellard 已提交
191
   values:
F
Frediano Ziglio 已提交
192
    i386 - 1 means 16 bit code, 2 means 64 bit code
193
    arm  - bit 0 = thumb, bit 1 = reverse endian, bit 2 = A64
B
bellard 已提交
194
    ppc  - nonzero means little endian
B
bellard 已提交
195 196
    other targets - unused
 */
B
Blue Swirl 已提交
197 198
void target_disas(FILE *out, CPUArchState *env, target_ulong code,
                  target_ulong size, int flags)
B
bellard 已提交
199
{
B
bellard 已提交
200
    target_ulong pc;
B
bellard 已提交
201
    int count;
B
Blue Swirl 已提交
202
    CPUDebug s;
203
    int (*print_insn)(bfd_vma pc, disassemble_info *info) = NULL;
B
bellard 已提交
204

B
Blue Swirl 已提交
205
    INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
B
bellard 已提交
206

B
Blue Swirl 已提交
207 208 209 210 211
    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;
B
bellard 已提交
212 213

#ifdef TARGET_WORDS_BIGENDIAN
B
Blue Swirl 已提交
214
    s.info.endian = BFD_ENDIAN_BIG;
B
bellard 已提交
215
#else
B
Blue Swirl 已提交
216
    s.info.endian = BFD_ENDIAN_LITTLE;
B
bellard 已提交
217 218
#endif
#if defined(TARGET_I386)
B
Blue Swirl 已提交
219 220 221 222 223 224 225
    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;
    }
B
bellard 已提交
226 227
    print_insn = print_insn_i386;
#elif defined(TARGET_ARM)
228 229 230 231 232 233 234 235 236
    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) {
P
Paul Brook 已提交
237 238 239 240 241 242
        print_insn = print_insn_thumb1;
    } else {
        print_insn = print_insn_arm;
    }
    if (flags & 2) {
#ifdef TARGET_WORDS_BIGENDIAN
B
Blue Swirl 已提交
243
        s.info.endian = BFD_ENDIAN_LITTLE;
P
Paul Brook 已提交
244
#else
B
Blue Swirl 已提交
245
        s.info.endian = BFD_ENDIAN_BIG;
P
Paul Brook 已提交
246 247
#endif
    }
B
bellard 已提交
248 249
#elif defined(TARGET_SPARC)
    print_insn = print_insn_sparc;
B
bellard 已提交
250
#ifdef TARGET_SPARC64
B
Blue Swirl 已提交
251
    s.info.mach = bfd_mach_sparc_v9b;
252
#endif
B
bellard 已提交
253
#elif defined(TARGET_PPC)
B
Blue Swirl 已提交
254 255 256
    if (flags >> 16) {
        s.info.endian = BFD_ENDIAN_LITTLE;
    }
257 258
    if (flags & 0xFFFF) {
        /* If we have a precise definitions of the instructions set, use it */
B
Blue Swirl 已提交
259
        s.info.mach = flags & 0xFFFF;
260
    } else {
B
bellard 已提交
261
#ifdef TARGET_PPC64
B
Blue Swirl 已提交
262
        s.info.mach = bfd_mach_ppc64;
B
bellard 已提交
263
#else
B
Blue Swirl 已提交
264
        s.info.mach = bfd_mach_ppc;
B
bellard 已提交
265
#endif
266
    }
267
    s.info.disassembler_options = (char *)"any";
B
bellard 已提交
268
    print_insn = print_insn_ppc;
P
pbrook 已提交
269 270
#elif defined(TARGET_M68K)
    print_insn = print_insn_m68k;
B
bellard 已提交
271
#elif defined(TARGET_MIPS)
B
bellard 已提交
272
#ifdef TARGET_WORDS_BIGENDIAN
B
bellard 已提交
273
    print_insn = print_insn_big_mips;
B
bellard 已提交
274 275 276
#else
    print_insn = print_insn_little_mips;
#endif
B
bellard 已提交
277
#elif defined(TARGET_SH4)
B
Blue Swirl 已提交
278
    s.info.mach = bfd_mach_sh4;
B
bellard 已提交
279
    print_insn = print_insn_sh;
J
j_mayer 已提交
280
#elif defined(TARGET_ALPHA)
B
Blue Swirl 已提交
281
    s.info.mach = bfd_mach_alpha_ev6;
J
j_mayer 已提交
282
    print_insn = print_insn_alpha;
283
#elif defined(TARGET_CRIS)
284
    if (flags != 32) {
B
Blue Swirl 已提交
285
        s.info.mach = bfd_mach_cris_v0_v10;
286 287
        print_insn = print_insn_crisv10;
    } else {
B
Blue Swirl 已提交
288
        s.info.mach = bfd_mach_cris_v32;
289 290
        print_insn = print_insn_crisv32;
    }
291
#elif defined(TARGET_S390X)
B
Blue Swirl 已提交
292
    s.info.mach = bfd_mach_s390_64;
293
    print_insn = print_insn_s390;
294
#elif defined(TARGET_MICROBLAZE)
B
Blue Swirl 已提交
295
    s.info.mach = bfd_arch_microblaze;
296
    print_insn = print_insn_microblaze;
A
Anthony Green 已提交
297 298 299
#elif defined(TARGET_MOXIE)
    s.info.mach = bfd_arch_moxie;
    print_insn = print_insn_moxie;
300
#elif defined(TARGET_LM32)
B
Blue Swirl 已提交
301
    s.info.mach = bfd_mach_lm32;
302
    print_insn = print_insn_lm32;
303
#endif
304 305 306
    if (print_insn == NULL) {
        print_insn = print_insn_od_target;
    }
307

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

/* Disassemble this for me please... (debugging). */
void disas(FILE *out, void *code, unsigned long size)
{
339
    uintptr_t pc;
B
bellard 已提交
340
    int count;
B
Blue Swirl 已提交
341
    CPUDebug s;
342
    int (*print_insn)(bfd_vma pc, disassemble_info *info) = NULL;
B
bellard 已提交
343

B
Blue Swirl 已提交
344 345
    INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
    s.info.print_address_func = generic_print_host_address;
B
bellard 已提交
346

B
Blue Swirl 已提交
347 348 349
    s.info.buffer = code;
    s.info.buffer_vma = (uintptr_t)code;
    s.info.buffer_length = size;
B
bellard 已提交
350

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

/* Look up symbol for debugging purpose.  Returns "" if unknown. */
B
bellard 已提交
402
const char *lookup_symbol(target_ulong orig_addr)
B
bellard 已提交
403
{
404
    const char *symbol = "";
B
bellard 已提交
405
    struct syminfo *s;
406

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

    return symbol;
B
bellard 已提交
415
}
416 417 418

#if !defined(CONFIG_USER_ONLY)

419
#include "monitor/monitor.h"
420

421 422 423
static int monitor_disas_is_physical;

static int
424 425
monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length,
                     struct disassemble_info *info)
426
{
B
Blue Swirl 已提交
427 428
    CPUDebug *s = container_of(info, CPUDebug, info);

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

S
Stefan Weil 已提交
437 438
static int GCC_FMT_ATTR(2, 3)
monitor_fprintf(FILE *stream, const char *fmt, ...)
439 440 441
{
    va_list ap;
    va_start(ap, fmt);
A
aliguori 已提交
442
    monitor_vprintf((Monitor *)stream, fmt, ap);
443 444 445 446
    va_end(ap);
    return 0;
}

447
void monitor_disas(Monitor *mon, CPUArchState *env,
B
bellard 已提交
448
                   target_ulong pc, int nb_insn, int is_physical, int flags)
449 450
{
    int count, i;
B
Blue Swirl 已提交
451
    CPUDebug s;
452 453
    int (*print_insn)(bfd_vma pc, disassemble_info *info);

B
Blue Swirl 已提交
454
    INIT_DISASSEMBLE_INFO(s.info, (FILE *)mon, monitor_fprintf);
455

B
Blue Swirl 已提交
456
    s.env = env;
457
    monitor_disas_is_physical = is_physical;
B
Blue Swirl 已提交
458 459
    s.info.read_memory_func = monitor_read_memory;
    s.info.print_address_func = generic_print_target_address;
460

B
Blue Swirl 已提交
461
    s.info.buffer_vma = pc;
462 463

#ifdef TARGET_WORDS_BIGENDIAN
B
Blue Swirl 已提交
464
    s.info.endian = BFD_ENDIAN_BIG;
465
#else
B
Blue Swirl 已提交
466
    s.info.endian = BFD_ENDIAN_LITTLE;
467 468
#endif
#if defined(TARGET_I386)
B
Blue Swirl 已提交
469 470 471 472 473 474 475
    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;
    }
476 477 478
    print_insn = print_insn_i386;
#elif defined(TARGET_ARM)
    print_insn = print_insn_arm;
T
ths 已提交
479 480
#elif defined(TARGET_ALPHA)
    print_insn = print_insn_alpha;
481 482
#elif defined(TARGET_SPARC)
    print_insn = print_insn_sparc;
483
#ifdef TARGET_SPARC64
B
Blue Swirl 已提交
484
    s.info.mach = bfd_mach_sparc_v9b;
485
#endif
486
#elif defined(TARGET_PPC)
B
bellard 已提交
487
#ifdef TARGET_PPC64
B
Blue Swirl 已提交
488
    s.info.mach = bfd_mach_ppc64;
B
bellard 已提交
489
#else
B
Blue Swirl 已提交
490
    s.info.mach = bfd_mach_ppc;
B
bellard 已提交
491
#endif
492
    print_insn = print_insn_ppc;
P
pbrook 已提交
493 494
#elif defined(TARGET_M68K)
    print_insn = print_insn_m68k;
B
bellard 已提交
495
#elif defined(TARGET_MIPS)
B
bellard 已提交
496
#ifdef TARGET_WORDS_BIGENDIAN
B
bellard 已提交
497
    print_insn = print_insn_big_mips;
B
bellard 已提交
498 499 500
#else
    print_insn = print_insn_little_mips;
#endif
M
Magnus Damm 已提交
501
#elif defined(TARGET_SH4)
B
Blue Swirl 已提交
502
    s.info.mach = bfd_mach_sh4;
M
Magnus Damm 已提交
503
    print_insn = print_insn_sh;
504
#elif defined(TARGET_S390X)
B
Blue Swirl 已提交
505
    s.info.mach = bfd_mach_s390_64;
506
    print_insn = print_insn_s390;
A
Anthony Green 已提交
507 508 509
#elif defined(TARGET_MOXIE)
    s.info.mach = bfd_arch_moxie;
    print_insn = print_insn_moxie;
510
#elif defined(TARGET_LM32)
B
Blue Swirl 已提交
511
    s.info.mach = bfd_mach_lm32;
512
    print_insn = print_insn_lm32;
513
#else
A
aliguori 已提交
514 515
    monitor_printf(mon, "0x" TARGET_FMT_lx
                   ": Asm output not supported on this arch\n", pc);
516 517 518 519
    return;
#endif

    for(i = 0; i < nb_insn; i++) {
A
aliguori 已提交
520
	monitor_printf(mon, "0x" TARGET_FMT_lx ":  ", pc);
B
Blue Swirl 已提交
521
        count = print_insn(pc, &s.info);
A
aliguori 已提交
522
	monitor_printf(mon, "\n");
523 524 525 526 527 528
	if (count < 0)
	    break;
        pc += count;
    }
}
#endif