disas.c 14.5 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
typedef struct CPUDebug {
    struct disassemble_info info;
12
    CPUState *cpu;
B
Blue Swirl 已提交
13 14
} 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(s->cpu, 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
 */
198
void target_disas(FILE *out, CPUState *cpu, target_ulong code,
B
Blue Swirl 已提交
199
                  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;
B
bellard 已提交
204

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

207
    s.cpu = cpu;
B
Blue Swirl 已提交
208 209 210 211
    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;
    }
226
    s.info.print_insn = print_insn_i386;
B
bellard 已提交
227
#elif defined(TARGET_ARM)
228 229 230 231 232 233
    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)
234
        s.info.print_insn = print_insn_arm_a64;
235 236
#endif
    } else if (flags & 1) {
237
        s.info.print_insn = print_insn_thumb1;
P
Paul Brook 已提交
238
    } else {
239
        s.info.print_insn = print_insn_arm;
P
Paul Brook 已提交
240 241 242
    }
    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
#elif defined(TARGET_SPARC)
249
    s.info.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)
T
Tom Musta 已提交
254
    if ((flags >> 16) & 1) {
B
Blue Swirl 已提交
255 256
        s.info.endian = BFD_ENDIAN_LITTLE;
    }
257
    if (flags & 0xFFFF) {
T
Tom Musta 已提交
258
        /* If we have a precise definition of the instruction 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";
268
    s.info.print_insn = print_insn_ppc;
P
pbrook 已提交
269
#elif defined(TARGET_M68K)
270
    s.info.print_insn = print_insn_m68k;
B
bellard 已提交
271
#elif defined(TARGET_MIPS)
B
bellard 已提交
272
#ifdef TARGET_WORDS_BIGENDIAN
273
    s.info.print_insn = print_insn_big_mips;
B
bellard 已提交
274
#else
275
    s.info.print_insn = print_insn_little_mips;
B
bellard 已提交
276
#endif
B
bellard 已提交
277
#elif defined(TARGET_SH4)
B
Blue Swirl 已提交
278
    s.info.mach = bfd_mach_sh4;
279
    s.info.print_insn = print_insn_sh;
J
j_mayer 已提交
280
#elif defined(TARGET_ALPHA)
B
Blue Swirl 已提交
281
    s.info.mach = bfd_mach_alpha_ev6;
282
    s.info.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
        s.info.print_insn = print_insn_crisv10;
287
    } else {
B
Blue Swirl 已提交
288
        s.info.mach = bfd_mach_cris_v32;
289
        s.info.print_insn = print_insn_crisv32;
290
    }
291
#elif defined(TARGET_S390X)
B
Blue Swirl 已提交
292
    s.info.mach = bfd_mach_s390_64;
293
    s.info.print_insn = print_insn_s390;
294
#elif defined(TARGET_MICROBLAZE)
B
Blue Swirl 已提交
295
    s.info.mach = bfd_arch_microblaze;
296
    s.info.print_insn = print_insn_microblaze;
A
Anthony Green 已提交
297 298
#elif defined(TARGET_MOXIE)
    s.info.mach = bfd_arch_moxie;
299
    s.info.print_insn = print_insn_moxie;
300
#elif defined(TARGET_LM32)
B
Blue Swirl 已提交
301
    s.info.mach = bfd_mach_lm32;
302
    s.info.print_insn = print_insn_lm32;
303
#endif
304 305
    if (s.info.print_insn == NULL) {
        s.info.print_insn = print_insn_od_target;
306
    }
307

308
    for (pc = code; size > 0; pc += count, size -= count) {
B
bellard 已提交
309
	fprintf(out, "0x" TARGET_FMT_lx ":  ", pc);
310
	count = s.info.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(s->cpu, 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 448
/* Disassembler for the monitor.
   See target_disas for a description of flags. */
449
void monitor_disas(Monitor *mon, CPUState *cpu,
B
bellard 已提交
450
                   target_ulong pc, int nb_insn, int is_physical, int flags)
451 452
{
    int count, i;
B
Blue Swirl 已提交
453
    CPUDebug s;
454

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

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

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

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

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