disas.c 14.4 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
T
Tom Musta 已提交
194 195
    ppc  - bits 0:15 specify (optionally) the machine instruction set;
           bit 16 indicates little endian.
B
bellard 已提交
196 197
    other targets - unused
 */
B
Blue Swirl 已提交
198 199
void target_disas(FILE *out, CPUArchState *env, target_ulong code,
                  target_ulong size, int flags)
B
bellard 已提交
200
{
B
bellard 已提交
201
    target_ulong pc;
B
bellard 已提交
202
    int count;
B
Blue Swirl 已提交
203
    CPUDebug s;
204
    int (*print_insn)(bfd_vma pc, disassemble_info *info) = NULL;
B
bellard 已提交
205

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

B
Blue Swirl 已提交
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;
B
bellard 已提交
213 214

#ifdef TARGET_WORDS_BIGENDIAN
B
Blue Swirl 已提交
215
    s.info.endian = BFD_ENDIAN_BIG;
B
bellard 已提交
216
#else
B
Blue Swirl 已提交
217
    s.info.endian = BFD_ENDIAN_LITTLE;
B
bellard 已提交
218 219
#endif
#if defined(TARGET_I386)
B
Blue Swirl 已提交
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;
    }
B
bellard 已提交
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) {
P
Paul Brook 已提交
238 239 240 241 242 243
        print_insn = print_insn_thumb1;
    } else {
        print_insn = print_insn_arm;
    }
    if (flags & 2) {
#ifdef TARGET_WORDS_BIGENDIAN
B
Blue Swirl 已提交
244
        s.info.endian = BFD_ENDIAN_LITTLE;
P
Paul Brook 已提交
245
#else
B
Blue Swirl 已提交
246
        s.info.endian = BFD_ENDIAN_BIG;
P
Paul Brook 已提交
247 248
#endif
    }
B
bellard 已提交
249 250
#elif defined(TARGET_SPARC)
    print_insn = print_insn_sparc;
B
bellard 已提交
251
#ifdef TARGET_SPARC64
B
Blue Swirl 已提交
252
    s.info.mach = bfd_mach_sparc_v9b;
253
#endif
B
bellard 已提交
254
#elif defined(TARGET_PPC)
T
Tom Musta 已提交
255
    if ((flags >> 16) & 1) {
B
Blue Swirl 已提交
256 257
        s.info.endian = BFD_ENDIAN_LITTLE;
    }
258
    if (flags & 0xFFFF) {
T
Tom Musta 已提交
259
        /* If we have a precise definition of the instruction set, use it. */
B
Blue Swirl 已提交
260
        s.info.mach = flags & 0xFFFF;
261
    } else {
B
bellard 已提交
262
#ifdef TARGET_PPC64
B
Blue Swirl 已提交
263
        s.info.mach = bfd_mach_ppc64;
B
bellard 已提交
264
#else
B
Blue Swirl 已提交
265
        s.info.mach = bfd_mach_ppc;
B
bellard 已提交
266
#endif
267
    }
268
    s.info.disassembler_options = (char *)"any";
B
bellard 已提交
269
    print_insn = print_insn_ppc;
P
pbrook 已提交
270 271
#elif defined(TARGET_M68K)
    print_insn = print_insn_m68k;
B
bellard 已提交
272
#elif defined(TARGET_MIPS)
B
bellard 已提交
273
#ifdef TARGET_WORDS_BIGENDIAN
B
bellard 已提交
274
    print_insn = print_insn_big_mips;
B
bellard 已提交
275 276 277
#else
    print_insn = print_insn_little_mips;
#endif
B
bellard 已提交
278
#elif defined(TARGET_SH4)
B
Blue Swirl 已提交
279
    s.info.mach = bfd_mach_sh4;
B
bellard 已提交
280
    print_insn = print_insn_sh;
J
j_mayer 已提交
281
#elif defined(TARGET_ALPHA)
B
Blue Swirl 已提交
282
    s.info.mach = bfd_mach_alpha_ev6;
J
j_mayer 已提交
283
    print_insn = print_insn_alpha;
284
#elif defined(TARGET_CRIS)
285
    if (flags != 32) {
B
Blue Swirl 已提交
286
        s.info.mach = bfd_mach_cris_v0_v10;
287 288
        print_insn = print_insn_crisv10;
    } else {
B
Blue Swirl 已提交
289
        s.info.mach = bfd_mach_cris_v32;
290 291
        print_insn = print_insn_crisv32;
    }
292
#elif defined(TARGET_S390X)
B
Blue Swirl 已提交
293
    s.info.mach = bfd_mach_s390_64;
294
    print_insn = print_insn_s390;
295
#elif defined(TARGET_MICROBLAZE)
B
Blue Swirl 已提交
296
    s.info.mach = bfd_arch_microblaze;
297
    print_insn = print_insn_microblaze;
A
Anthony Green 已提交
298 299 300
#elif defined(TARGET_MOXIE)
    s.info.mach = bfd_arch_moxie;
    print_insn = print_insn_moxie;
301
#elif defined(TARGET_LM32)
B
Blue Swirl 已提交
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) {
B
bellard 已提交
310
	fprintf(out, "0x" TARGET_FMT_lx ":  ", pc);
B
Blue Swirl 已提交
311
	count = print_insn(pc, &s.info);
B
bellard 已提交
312 313 314 315 316 317
#if 0
        {
            int i;
            uint8_t b;
            fprintf(out, " {");
            for(i = 0; i < count; i++) {
B
Blue Swirl 已提交
318
                target_read_memory(pc + i, &b, 1, &s.info);
B
bellard 已提交
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;
        }
B
bellard 已提交
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;
B
bellard 已提交
341
    int count;
B
Blue Swirl 已提交
342
    CPUDebug s;
343
    int (*print_insn)(bfd_vma pc, disassemble_info *info) = NULL;
B
bellard 已提交
344

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

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

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

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

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

    return symbol;
B
bellard 已提交
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
{
B
Blue Swirl 已提交
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;
}

S
Stefan Weil 已提交
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);
A
aliguori 已提交
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,
B
bellard 已提交
451
                   target_ulong pc, int nb_insn, int is_physical, int flags)
452 453
{
    int count, i;
B
Blue Swirl 已提交
454
    CPUDebug s;
455 456
    int (*print_insn)(bfd_vma pc, disassemble_info *info);

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

B
Blue Swirl 已提交
459
    s.env = env;
460
    monitor_disas_is_physical = is_physical;
B
Blue Swirl 已提交
461 462
    s.info.read_memory_func = monitor_read_memory;
    s.info.print_address_func = generic_print_target_address;
463

B
Blue Swirl 已提交
464
    s.info.buffer_vma = pc;
465 466

#ifdef TARGET_WORDS_BIGENDIAN
B
Blue Swirl 已提交
467
    s.info.endian = BFD_ENDIAN_BIG;
468
#else
B
Blue Swirl 已提交
469
    s.info.endian = BFD_ENDIAN_LITTLE;
470 471
#endif
#if defined(TARGET_I386)
B
Blue Swirl 已提交
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;
T
ths 已提交
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
B
Blue Swirl 已提交
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 {
B
bellard 已提交
494
#ifdef TARGET_PPC64
495
        s.info.mach = bfd_mach_ppc64;
B
bellard 已提交
496
#else
497
        s.info.mach = bfd_mach_ppc;
B
bellard 已提交
498
#endif
499 500 501 502
    }
    if ((flags >> 16) & 1) {
        s.info.endian = BFD_ENDIAN_LITTLE;
    }
503
    print_insn = print_insn_ppc;
P
pbrook 已提交
504 505
#elif defined(TARGET_M68K)
    print_insn = print_insn_m68k;
B
bellard 已提交
506
#elif defined(TARGET_MIPS)
B
bellard 已提交
507
#ifdef TARGET_WORDS_BIGENDIAN
B
bellard 已提交
508
    print_insn = print_insn_big_mips;
B
bellard 已提交
509 510 511
#else
    print_insn = print_insn_little_mips;
#endif
M
Magnus Damm 已提交
512
#elif defined(TARGET_SH4)
B
Blue Swirl 已提交
513
    s.info.mach = bfd_mach_sh4;
M
Magnus Damm 已提交
514
    print_insn = print_insn_sh;
515
#elif defined(TARGET_S390X)
B
Blue Swirl 已提交
516
    s.info.mach = bfd_mach_s390_64;
517
    print_insn = print_insn_s390;
A
Anthony Green 已提交
518 519 520
#elif defined(TARGET_MOXIE)
    s.info.mach = bfd_arch_moxie;
    print_insn = print_insn_moxie;
521
#elif defined(TARGET_LM32)
B
Blue Swirl 已提交
522
    s.info.mach = bfd_mach_lm32;
523
    print_insn = print_insn_lm32;
524
#else
A
aliguori 已提交
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++) {
A
aliguori 已提交
531
	monitor_printf(mon, "0x" TARGET_FMT_lx ":  ", pc);
B
Blue Swirl 已提交
532
        count = print_insn(pc, &s.info);
A
aliguori 已提交
533
	monitor_printf(mon, "\n");
534 535 536 537 538 539
	if (count < 0)
	    break;
        pc += count;
    }
}
#endif