disas.c 12.0 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_PPC)
T
Tom Musta 已提交
218
    if ((flags >> 16) & 1) {
B
Blue Swirl 已提交
219 220
        s.info.endian = BFD_ENDIAN_LITTLE;
    }
221
    if (flags & 0xFFFF) {
T
Tom Musta 已提交
222
        /* If we have a precise definition of the instruction set, use it. */
B
Blue Swirl 已提交
223
        s.info.mach = flags & 0xFFFF;
224
    } else {
B
bellard 已提交
225
#ifdef TARGET_PPC64
B
Blue Swirl 已提交
226
        s.info.mach = bfd_mach_ppc64;
B
bellard 已提交
227
#else
B
Blue Swirl 已提交
228
        s.info.mach = bfd_mach_ppc;
B
bellard 已提交
229
#endif
230
    }
231
    s.info.disassembler_options = (char *)"any";
232
    s.info.print_insn = print_insn_ppc;
B
bellard 已提交
233
#elif defined(TARGET_MIPS)
B
bellard 已提交
234
#ifdef TARGET_WORDS_BIGENDIAN
235
    s.info.print_insn = print_insn_big_mips;
B
bellard 已提交
236
#else
237
    s.info.print_insn = print_insn_little_mips;
B
bellard 已提交
238
#endif
B
bellard 已提交
239
#elif defined(TARGET_SH4)
B
Blue Swirl 已提交
240
    s.info.mach = bfd_mach_sh4;
241
    s.info.print_insn = print_insn_sh;
J
j_mayer 已提交
242
#elif defined(TARGET_ALPHA)
B
Blue Swirl 已提交
243
    s.info.mach = bfd_mach_alpha_ev6;
244
    s.info.print_insn = print_insn_alpha;
245
#endif
246 247
    if (s.info.print_insn == NULL) {
        s.info.print_insn = print_insn_od_target;
248
    }
249

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

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

B
Blue Swirl 已提交
286 287
    INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
    s.info.print_address_func = generic_print_host_address;
B
bellard 已提交
288

B
Blue Swirl 已提交
289 290 291
    s.info.buffer = code;
    s.info.buffer_vma = (uintptr_t)code;
    s.info.buffer_length = size;
B
bellard 已提交
292

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

/* Look up symbol for debugging purpose.  Returns "" if unknown. */
B
bellard 已提交
344
const char *lookup_symbol(target_ulong orig_addr)
B
bellard 已提交
345
{
346
    const char *symbol = "";
B
bellard 已提交
347
    struct syminfo *s;
348

B
bellard 已提交
349
    for (s = syminfos; s; s = s->next) {
350 351 352 353
        symbol = s->lookup_symbol(s, orig_addr);
        if (symbol[0] != '\0') {
            break;
        }
B
bellard 已提交
354
    }
355 356

    return symbol;
B
bellard 已提交
357
}
358 359 360

#if !defined(CONFIG_USER_ONLY)

361
#include "monitor/monitor.h"
362

363 364 365
static int monitor_disas_is_physical;

static int
366 367
monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length,
                     struct disassemble_info *info)
368
{
B
Blue Swirl 已提交
369 370
    CPUDebug *s = container_of(info, CPUDebug, info);

371
    if (monitor_disas_is_physical) {
372
        cpu_physical_memory_read(memaddr, myaddr, length);
373
    } else {
374
        cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, 0);
375 376 377 378
    }
    return 0;
}

379 380
/* Disassembler for the monitor.
   See target_disas for a description of flags. */
381
void monitor_disas(Monitor *mon, CPUState *cpu,
B
bellard 已提交
382
                   target_ulong pc, int nb_insn, int is_physical, int flags)
383
{
384
    CPUClass *cc = CPU_GET_CLASS(cpu);
385
    int count, i;
B
Blue Swirl 已提交
386
    CPUDebug s;
387

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

390
    s.cpu = cpu;
391
    monitor_disas_is_physical = is_physical;
B
Blue Swirl 已提交
392
    s.info.read_memory_func = monitor_read_memory;
393
    s.info.print_address_func = generic_print_address;
394

B
Blue Swirl 已提交
395
    s.info.buffer_vma = pc;
396 397

#ifdef TARGET_WORDS_BIGENDIAN
B
Blue Swirl 已提交
398
    s.info.endian = BFD_ENDIAN_BIG;
399
#else
B
Blue Swirl 已提交
400
    s.info.endian = BFD_ENDIAN_LITTLE;
401
#endif
402 403 404 405 406

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

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

    for(i = 0; i < nb_insn; i++) {
A
aliguori 已提交
450
	monitor_printf(mon, "0x" TARGET_FMT_lx ":  ", pc);
451
        count = s.info.print_insn(pc, &s.info);
A
aliguori 已提交
452
	monitor_printf(mon, "\n");
453 454 455 456 457 458
	if (count < 0)
	    break;
        pc += count;
    }
}
#endif