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

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

B
Blue Swirl 已提交
11 12
typedef struct CPUDebug {
    struct disassemble_info info;
13
    CPUState *cpu;
B
Blue Swirl 已提交
14 15
} CPUDebug;

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

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

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

43
    cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, 0);
44 45 46
    return 0;
}

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

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

75 76 77 78 79 80 81 82
/* 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 已提交
83 84 85
/* Just return the given address.  */

int
P
pbrook 已提交
86
generic_symbol_at_address (bfd_vma addr, struct disassemble_info *info)
B
bellard 已提交
87 88 89 90
{
  return 1;
}

A
Aurelien Jarno 已提交
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
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 已提交
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
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 已提交
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
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;
}

146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
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 已提交
175
/* Disassemble this for me please... (debugging). 'flags' has the following
B
bellard 已提交
176
   values:
F
Frediano Ziglio 已提交
177
    i386 - 1 means 16 bit code, 2 means 64 bit code
T
Tom Musta 已提交
178 179
    ppc  - bits 0:15 specify (optionally) the machine instruction set;
           bit 16 indicates little endian.
B
bellard 已提交
180 181
    other targets - unused
 */
182
void target_disas(FILE *out, CPUState *cpu, target_ulong code,
B
Blue Swirl 已提交
183
                  target_ulong size, int flags)
B
bellard 已提交
184
{
185
    CPUClass *cc = CPU_GET_CLASS(cpu);
B
bellard 已提交
186
    target_ulong pc;
B
bellard 已提交
187
    int count;
B
Blue Swirl 已提交
188
    CPUDebug s;
B
bellard 已提交
189

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

192
    s.cpu = cpu;
B
Blue Swirl 已提交
193 194 195
    s.info.read_memory_func = target_read_memory;
    s.info.buffer_vma = code;
    s.info.buffer_length = size;
196
    s.info.print_address_func = generic_print_address;
B
bellard 已提交
197 198

#ifdef TARGET_WORDS_BIGENDIAN
B
Blue Swirl 已提交
199
    s.info.endian = BFD_ENDIAN_BIG;
B
bellard 已提交
200
#else
B
Blue Swirl 已提交
201
    s.info.endian = BFD_ENDIAN_LITTLE;
B
bellard 已提交
202
#endif
203 204 205 206 207

    if (cc->disas_set_info) {
        cc->disas_set_info(cpu, &s.info);
    }

B
bellard 已提交
208
#if defined(TARGET_I386)
B
Blue Swirl 已提交
209 210 211 212 213 214 215
    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;
    }
216
    s.info.print_insn = print_insn_i386;
B
bellard 已提交
217
#elif defined(TARGET_SPARC)
218
    s.info.print_insn = print_insn_sparc;
B
bellard 已提交
219
#ifdef TARGET_SPARC64
B
Blue Swirl 已提交
220
    s.info.mach = bfd_mach_sparc_v9b;
221
#endif
B
bellard 已提交
222
#elif defined(TARGET_PPC)
T
Tom Musta 已提交
223
    if ((flags >> 16) & 1) {
B
Blue Swirl 已提交
224 225
        s.info.endian = BFD_ENDIAN_LITTLE;
    }
226
    if (flags & 0xFFFF) {
T
Tom Musta 已提交
227
        /* If we have a precise definition of the instruction set, use it. */
B
Blue Swirl 已提交
228
        s.info.mach = flags & 0xFFFF;
229
    } else {
B
bellard 已提交
230
#ifdef TARGET_PPC64
B
Blue Swirl 已提交
231
        s.info.mach = bfd_mach_ppc64;
B
bellard 已提交
232
#else
B
Blue Swirl 已提交
233
        s.info.mach = bfd_mach_ppc;
B
bellard 已提交
234
#endif
235
    }
236
    s.info.disassembler_options = (char *)"any";
237
    s.info.print_insn = print_insn_ppc;
P
pbrook 已提交
238
#elif defined(TARGET_M68K)
239
    s.info.print_insn = print_insn_m68k;
B
bellard 已提交
240
#elif defined(TARGET_MIPS)
B
bellard 已提交
241
#ifdef TARGET_WORDS_BIGENDIAN
242
    s.info.print_insn = print_insn_big_mips;
B
bellard 已提交
243
#else
244
    s.info.print_insn = print_insn_little_mips;
B
bellard 已提交
245
#endif
B
bellard 已提交
246
#elif defined(TARGET_SH4)
B
Blue Swirl 已提交
247
    s.info.mach = bfd_mach_sh4;
248
    s.info.print_insn = print_insn_sh;
J
j_mayer 已提交
249
#elif defined(TARGET_ALPHA)
B
Blue Swirl 已提交
250
    s.info.mach = bfd_mach_alpha_ev6;
251
    s.info.print_insn = print_insn_alpha;
252
#elif defined(TARGET_S390X)
B
Blue Swirl 已提交
253
    s.info.mach = bfd_mach_s390_64;
254
    s.info.print_insn = print_insn_s390;
A
Anthony Green 已提交
255 256
#elif defined(TARGET_MOXIE)
    s.info.mach = bfd_arch_moxie;
257
    s.info.print_insn = print_insn_moxie;
258
#elif defined(TARGET_LM32)
B
Blue Swirl 已提交
259
    s.info.mach = bfd_mach_lm32;
260
    s.info.print_insn = print_insn_lm32;
261
#endif
262 263
    if (s.info.print_insn == NULL) {
        s.info.print_insn = print_insn_od_target;
264
    }
265

266
    for (pc = code; size > 0; pc += count, size -= count) {
B
bellard 已提交
267
	fprintf(out, "0x" TARGET_FMT_lx ":  ", pc);
268
	count = s.info.print_insn(pc, &s.info);
B
bellard 已提交
269 270 271 272 273 274
#if 0
        {
            int i;
            uint8_t b;
            fprintf(out, " {");
            for(i = 0; i < count; i++) {
B
Blue Swirl 已提交
275
                target_read_memory(pc + i, &b, 1, &s.info);
B
bellard 已提交
276 277 278 279 280 281 282 283
                fprintf(out, " %02x", b);
            }
            fprintf(out, " }");
        }
#endif
	fprintf(out, "\n");
	if (count < 0)
	    break;
284 285 286 287 288 289 290
        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 已提交
291 292 293 294 295 296
    }
}

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

B
Blue Swirl 已提交
302 303
    INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
    s.info.print_address_func = generic_print_host_address;
B
bellard 已提交
304

B
Blue Swirl 已提交
305 306 307
    s.info.buffer = code;
    s.info.buffer_vma = (uintptr_t)code;
    s.info.buffer_length = size;
B
bellard 已提交
308

309
#ifdef HOST_WORDS_BIGENDIAN
B
Blue Swirl 已提交
310
    s.info.endian = BFD_ENDIAN_BIG;
B
bellard 已提交
311
#else
B
Blue Swirl 已提交
312
    s.info.endian = BFD_ENDIAN_LITTLE;
B
bellard 已提交
313
#endif
S
Stefan Weil 已提交
314 315 316
#if defined(CONFIG_TCG_INTERPRETER)
    print_insn = print_insn_tci;
#elif defined(__i386__)
B
Blue Swirl 已提交
317
    s.info.mach = bfd_mach_i386_i386;
B
bellard 已提交
318
    print_insn = print_insn_i386;
319
#elif defined(__x86_64__)
B
Blue Swirl 已提交
320
    s.info.mach = bfd_mach_x86_64;
B
bellard 已提交
321
    print_insn = print_insn_i386;
M
malc 已提交
322
#elif defined(_ARCH_PPC)
323
    s.info.disassembler_options = (char *)"any";
B
bellard 已提交
324
    print_insn = print_insn_ppc;
325 326
#elif defined(__aarch64__) && defined(CONFIG_ARM_A64_DIS)
    print_insn = print_insn_arm_a64;
B
bellard 已提交
327
#elif defined(__alpha__)
B
bellard 已提交
328
    print_insn = print_insn_alpha;
B
bellard 已提交
329
#elif defined(__sparc__)
B
bellard 已提交
330
    print_insn = print_insn_sparc;
B
Blue Swirl 已提交
331
    s.info.mach = bfd_mach_sparc_v9b;
332
#elif defined(__arm__)
B
bellard 已提交
333
    print_insn = print_insn_arm;
B
bellard 已提交
334 335 336 337
#elif defined(__MIPSEB__)
    print_insn = print_insn_big_mips;
#elif defined(__MIPSEL__)
    print_insn = print_insn_little_mips;
B
bellard 已提交
338 339
#elif defined(__m68k__)
    print_insn = print_insn_m68k;
340 341
#elif defined(__s390__)
    print_insn = print_insn_s390;
A
aurel32 已提交
342 343
#elif defined(__hppa__)
    print_insn = print_insn_hppa;
A
Aurelien Jarno 已提交
344 345
#elif defined(__ia64__)
    print_insn = print_insn_ia64;
B
bellard 已提交
346
#endif
347 348 349
    if (print_insn == NULL) {
        print_insn = print_insn_od_host;
    }
350 351
    for (pc = (uintptr_t)code; size > 0; pc += count, size -= count) {
        fprintf(out, "0x%08" PRIxPTR ":  ", pc);
B
Blue Swirl 已提交
352
        count = print_insn(pc, &s.info);
B
bellard 已提交
353 354 355 356 357 358 359
	fprintf(out, "\n");
	if (count < 0)
	    break;
    }
}

/* Look up symbol for debugging purpose.  Returns "" if unknown. */
B
bellard 已提交
360
const char *lookup_symbol(target_ulong orig_addr)
B
bellard 已提交
361
{
362
    const char *symbol = "";
B
bellard 已提交
363
    struct syminfo *s;
364

B
bellard 已提交
365
    for (s = syminfos; s; s = s->next) {
366 367 368 369
        symbol = s->lookup_symbol(s, orig_addr);
        if (symbol[0] != '\0') {
            break;
        }
B
bellard 已提交
370
    }
371 372

    return symbol;
B
bellard 已提交
373
}
374 375 376

#if !defined(CONFIG_USER_ONLY)

377
#include "monitor/monitor.h"
378

379 380 381
static int monitor_disas_is_physical;

static int
382 383
monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length,
                     struct disassemble_info *info)
384
{
B
Blue Swirl 已提交
385 386
    CPUDebug *s = container_of(info, CPUDebug, info);

387
    if (monitor_disas_is_physical) {
388
        cpu_physical_memory_read(memaddr, myaddr, length);
389
    } else {
390
        cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, 0);
391 392 393 394
    }
    return 0;
}

S
Stefan Weil 已提交
395 396
static int GCC_FMT_ATTR(2, 3)
monitor_fprintf(FILE *stream, const char *fmt, ...)
397 398 399
{
    va_list ap;
    va_start(ap, fmt);
A
aliguori 已提交
400
    monitor_vprintf((Monitor *)stream, fmt, ap);
401 402 403 404
    va_end(ap);
    return 0;
}

405 406
/* Disassembler for the monitor.
   See target_disas for a description of flags. */
407
void monitor_disas(Monitor *mon, CPUState *cpu,
B
bellard 已提交
408
                   target_ulong pc, int nb_insn, int is_physical, int flags)
409
{
410
    CPUClass *cc = CPU_GET_CLASS(cpu);
411
    int count, i;
B
Blue Swirl 已提交
412
    CPUDebug s;
413

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

416
    s.cpu = cpu;
417
    monitor_disas_is_physical = is_physical;
B
Blue Swirl 已提交
418
    s.info.read_memory_func = monitor_read_memory;
419
    s.info.print_address_func = generic_print_address;
420

B
Blue Swirl 已提交
421
    s.info.buffer_vma = pc;
422 423

#ifdef TARGET_WORDS_BIGENDIAN
B
Blue Swirl 已提交
424
    s.info.endian = BFD_ENDIAN_BIG;
425
#else
B
Blue Swirl 已提交
426
    s.info.endian = BFD_ENDIAN_LITTLE;
427
#endif
428 429 430 431 432

    if (cc->disas_set_info) {
        cc->disas_set_info(cpu, &s.info);
    }

433
#if defined(TARGET_I386)
B
Blue Swirl 已提交
434 435 436 437 438 439 440
    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;
    }
441
    s.info.print_insn = print_insn_i386;
T
ths 已提交
442
#elif defined(TARGET_ALPHA)
443
    s.info.print_insn = print_insn_alpha;
444
#elif defined(TARGET_SPARC)
445
    s.info.print_insn = print_insn_sparc;
446
#ifdef TARGET_SPARC64
B
Blue Swirl 已提交
447
    s.info.mach = bfd_mach_sparc_v9b;
448
#endif
449
#elif defined(TARGET_PPC)
450 451 452 453
    if (flags & 0xFFFF) {
        /* If we have a precise definition of the instruction set, use it. */
        s.info.mach = flags & 0xFFFF;
    } else {
B
bellard 已提交
454
#ifdef TARGET_PPC64
455
        s.info.mach = bfd_mach_ppc64;
B
bellard 已提交
456
#else
457
        s.info.mach = bfd_mach_ppc;
B
bellard 已提交
458
#endif
459 460 461 462
    }
    if ((flags >> 16) & 1) {
        s.info.endian = BFD_ENDIAN_LITTLE;
    }
463
    s.info.print_insn = print_insn_ppc;
P
pbrook 已提交
464
#elif defined(TARGET_M68K)
465
    s.info.print_insn = print_insn_m68k;
B
bellard 已提交
466
#elif defined(TARGET_MIPS)
B
bellard 已提交
467
#ifdef TARGET_WORDS_BIGENDIAN
468
    s.info.print_insn = print_insn_big_mips;
B
bellard 已提交
469
#else
470
    s.info.print_insn = print_insn_little_mips;
B
bellard 已提交
471
#endif
M
Magnus Damm 已提交
472
#elif defined(TARGET_SH4)
B
Blue Swirl 已提交
473
    s.info.mach = bfd_mach_sh4;
474
    s.info.print_insn = print_insn_sh;
475
#elif defined(TARGET_S390X)
B
Blue Swirl 已提交
476
    s.info.mach = bfd_mach_s390_64;
477
    s.info.print_insn = print_insn_s390;
A
Anthony Green 已提交
478 479
#elif defined(TARGET_MOXIE)
    s.info.mach = bfd_arch_moxie;
480
    s.info.print_insn = print_insn_moxie;
481
#elif defined(TARGET_LM32)
B
Blue Swirl 已提交
482
    s.info.mach = bfd_mach_lm32;
483
    s.info.print_insn = print_insn_lm32;
484
#endif
485 486 487 488 489
    if (!s.info.print_insn) {
        monitor_printf(mon, "0x" TARGET_FMT_lx
                       ": Asm output not supported on this arch\n", pc);
        return;
    }
490 491

    for(i = 0; i < nb_insn; i++) {
A
aliguori 已提交
492
	monitor_printf(mon, "0x" TARGET_FMT_lx ":  ", pc);
493
        count = s.info.print_insn(pc, &s.info);
A
aliguori 已提交
494
	monitor_printf(mon, "\n");
495 496 497 498 499 500
	if (count < 0)
	    break;
        pc += count;
    }
}
#endif