disas.c 12.5 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;
B
bellard 已提交
238
#elif defined(TARGET_MIPS)
B
bellard 已提交
239
#ifdef TARGET_WORDS_BIGENDIAN
240
    s.info.print_insn = print_insn_big_mips;
B
bellard 已提交
241
#else
242
    s.info.print_insn = print_insn_little_mips;
B
bellard 已提交
243
#endif
B
bellard 已提交
244
#elif defined(TARGET_SH4)
B
Blue Swirl 已提交
245
    s.info.mach = bfd_mach_sh4;
246
    s.info.print_insn = print_insn_sh;
J
j_mayer 已提交
247
#elif defined(TARGET_ALPHA)
B
Blue Swirl 已提交
248
    s.info.mach = bfd_mach_alpha_ev6;
249
    s.info.print_insn = print_insn_alpha;
250
#elif defined(TARGET_LM32)
B
Blue Swirl 已提交
251
    s.info.mach = bfd_mach_lm32;
252
    s.info.print_insn = print_insn_lm32;
253
#endif
254 255
    if (s.info.print_insn == NULL) {
        s.info.print_insn = print_insn_od_target;
256
    }
257

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

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

B
Blue Swirl 已提交
294 295
    INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
    s.info.print_address_func = generic_print_host_address;
B
bellard 已提交
296

B
Blue Swirl 已提交
297 298 299
    s.info.buffer = code;
    s.info.buffer_vma = (uintptr_t)code;
    s.info.buffer_length = size;
B
bellard 已提交
300

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

/* Look up symbol for debugging purpose.  Returns "" if unknown. */
B
bellard 已提交
352
const char *lookup_symbol(target_ulong orig_addr)
B
bellard 已提交
353
{
354
    const char *symbol = "";
B
bellard 已提交
355
    struct syminfo *s;
356

B
bellard 已提交
357
    for (s = syminfos; s; s = s->next) {
358 359 360 361
        symbol = s->lookup_symbol(s, orig_addr);
        if (symbol[0] != '\0') {
            break;
        }
B
bellard 已提交
362
    }
363 364

    return symbol;
B
bellard 已提交
365
}
366 367 368

#if !defined(CONFIG_USER_ONLY)

369
#include "monitor/monitor.h"
370

371 372 373
static int monitor_disas_is_physical;

static int
374 375
monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length,
                     struct disassemble_info *info)
376
{
B
Blue Swirl 已提交
377 378
    CPUDebug *s = container_of(info, CPUDebug, info);

379
    if (monitor_disas_is_physical) {
380
        cpu_physical_memory_read(memaddr, myaddr, length);
381
    } else {
382
        cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, 0);
383 384 385 386
    }
    return 0;
}

387 388
/* Disassembler for the monitor.
   See target_disas for a description of flags. */
389
void monitor_disas(Monitor *mon, CPUState *cpu,
B
bellard 已提交
390
                   target_ulong pc, int nb_insn, int is_physical, int flags)
391
{
392
    CPUClass *cc = CPU_GET_CLASS(cpu);
393
    int count, i;
B
Blue Swirl 已提交
394
    CPUDebug s;
395

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

398
    s.cpu = cpu;
399
    monitor_disas_is_physical = is_physical;
B
Blue Swirl 已提交
400
    s.info.read_memory_func = monitor_read_memory;
401
    s.info.print_address_func = generic_print_address;
402

B
Blue Swirl 已提交
403
    s.info.buffer_vma = pc;
404 405

#ifdef TARGET_WORDS_BIGENDIAN
B
Blue Swirl 已提交
406
    s.info.endian = BFD_ENDIAN_BIG;
407
#else
B
Blue Swirl 已提交
408
    s.info.endian = BFD_ENDIAN_LITTLE;
409
#endif
410 411 412 413 414

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

415
#if defined(TARGET_I386)
B
Blue Swirl 已提交
416 417 418 419 420 421 422
    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;
    }
423
    s.info.print_insn = print_insn_i386;
T
ths 已提交
424
#elif defined(TARGET_ALPHA)
425
    s.info.print_insn = print_insn_alpha;
426
#elif defined(TARGET_SPARC)
427
    s.info.print_insn = print_insn_sparc;
428
#ifdef TARGET_SPARC64
B
Blue Swirl 已提交
429
    s.info.mach = bfd_mach_sparc_v9b;
430
#endif
431
#elif defined(TARGET_PPC)
432 433 434 435
    if (flags & 0xFFFF) {
        /* If we have a precise definition of the instruction set, use it. */
        s.info.mach = flags & 0xFFFF;
    } else {
B
bellard 已提交
436
#ifdef TARGET_PPC64
437
        s.info.mach = bfd_mach_ppc64;
B
bellard 已提交
438
#else
439
        s.info.mach = bfd_mach_ppc;
B
bellard 已提交
440
#endif
441 442 443 444
    }
    if ((flags >> 16) & 1) {
        s.info.endian = BFD_ENDIAN_LITTLE;
    }
445
    s.info.print_insn = print_insn_ppc;
B
bellard 已提交
446
#elif defined(TARGET_MIPS)
B
bellard 已提交
447
#ifdef TARGET_WORDS_BIGENDIAN
448
    s.info.print_insn = print_insn_big_mips;
B
bellard 已提交
449
#else
450
    s.info.print_insn = print_insn_little_mips;
B
bellard 已提交
451
#endif
M
Magnus Damm 已提交
452
#elif defined(TARGET_SH4)
B
Blue Swirl 已提交
453
    s.info.mach = bfd_mach_sh4;
454
    s.info.print_insn = print_insn_sh;
455
#elif defined(TARGET_LM32)
B
Blue Swirl 已提交
456
    s.info.mach = bfd_mach_lm32;
457
    s.info.print_insn = print_insn_lm32;
458
#endif
459 460 461 462 463
    if (!s.info.print_insn) {
        monitor_printf(mon, "0x" TARGET_FMT_lx
                       ": Asm output not supported on this arch\n", pc);
        return;
    }
464 465

    for(i = 0; i < nb_insn; i++) {
A
aliguori 已提交
466
	monitor_printf(mon, "0x" TARGET_FMT_lx ":  ", pc);
467
        count = s.info.print_insn(pc, &s.info);
A
aliguori 已提交
468
	monitor_printf(mon, "\n");
469 470 471 472 473 474
	if (count < 0)
	    break;
        pc += count;
    }
}
#endif