disas.c 11.3 KB
Newer Older
B
bellard 已提交
1
/* General "disassemble this chunk" code.  Used for debugging. */
P
Peter Maydell 已提交
2
#include "qemu/osdep.h"
3
#include "qemu-common.h"
4
#include "disas/bfd.h"
B
bellard 已提交
5 6
#include "elf.h"

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
/* 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 已提交
82 83 84
/* Just return the given address.  */

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

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

145 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
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 已提交
174
/* Disassemble this for me please... (debugging). 'flags' has the following
B
bellard 已提交
175
   values:
F
Frediano Ziglio 已提交
176
    i386 - 1 means 16 bit code, 2 means 64 bit code
T
Tom Musta 已提交
177 178
    ppc  - bits 0:15 specify (optionally) the machine instruction set;
           bit 16 indicates little endian.
B
bellard 已提交
179 180
    other targets - unused
 */
181
void target_disas(FILE *out, CPUState *cpu, target_ulong code,
B
Blue Swirl 已提交
182
                  target_ulong size, int flags)
B
bellard 已提交
183
{
184
    CPUClass *cc = CPU_GET_CLASS(cpu);
B
bellard 已提交
185
    target_ulong pc;
B
bellard 已提交
186
    int count;
B
Blue Swirl 已提交
187
    CPUDebug s;
B
bellard 已提交
188

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

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

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

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

B
bellard 已提交
207
#if defined(TARGET_I386)
B
Blue Swirl 已提交
208 209 210 211 212 213 214
    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;
    }
215
    s.info.print_insn = print_insn_i386;
B
bellard 已提交
216
#elif defined(TARGET_PPC)
T
Tom Musta 已提交
217
    if ((flags >> 16) & 1) {
B
Blue Swirl 已提交
218 219
        s.info.endian = BFD_ENDIAN_LITTLE;
    }
220
    if (flags & 0xFFFF) {
T
Tom Musta 已提交
221
        /* If we have a precise definition of the instruction set, use it. */
B
Blue Swirl 已提交
222
        s.info.mach = flags & 0xFFFF;
223
    } else {
B
bellard 已提交
224
#ifdef TARGET_PPC64
B
Blue Swirl 已提交
225
        s.info.mach = bfd_mach_ppc64;
B
bellard 已提交
226
#else
B
Blue Swirl 已提交
227
        s.info.mach = bfd_mach_ppc;
B
bellard 已提交
228
#endif
229
    }
230
    s.info.disassembler_options = (char *)"any";
231
    s.info.print_insn = print_insn_ppc;
232
#endif
233 234
    if (s.info.print_insn == NULL) {
        s.info.print_insn = print_insn_od_target;
235
    }
236

237
    for (pc = code; size > 0; pc += count, size -= count) {
B
bellard 已提交
238
	fprintf(out, "0x" TARGET_FMT_lx ":  ", pc);
239
	count = s.info.print_insn(pc, &s.info);
B
bellard 已提交
240 241 242 243 244 245
#if 0
        {
            int i;
            uint8_t b;
            fprintf(out, " {");
            for(i = 0; i < count; i++) {
B
Blue Swirl 已提交
246
                target_read_memory(pc + i, &b, 1, &s.info);
B
bellard 已提交
247 248 249 250 251 252 253 254
                fprintf(out, " %02x", b);
            }
            fprintf(out, " }");
        }
#endif
	fprintf(out, "\n");
	if (count < 0)
	    break;
255 256 257 258 259 260 261
        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 已提交
262 263 264 265 266 267
    }
}

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

B
Blue Swirl 已提交
273 274
    INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
    s.info.print_address_func = generic_print_host_address;
B
bellard 已提交
275

B
Blue Swirl 已提交
276 277 278
    s.info.buffer = code;
    s.info.buffer_vma = (uintptr_t)code;
    s.info.buffer_length = size;
B
bellard 已提交
279

280
#ifdef HOST_WORDS_BIGENDIAN
B
Blue Swirl 已提交
281
    s.info.endian = BFD_ENDIAN_BIG;
B
bellard 已提交
282
#else
B
Blue Swirl 已提交
283
    s.info.endian = BFD_ENDIAN_LITTLE;
B
bellard 已提交
284
#endif
S
Stefan Weil 已提交
285 286 287
#if defined(CONFIG_TCG_INTERPRETER)
    print_insn = print_insn_tci;
#elif defined(__i386__)
B
Blue Swirl 已提交
288
    s.info.mach = bfd_mach_i386_i386;
B
bellard 已提交
289
    print_insn = print_insn_i386;
290
#elif defined(__x86_64__)
B
Blue Swirl 已提交
291
    s.info.mach = bfd_mach_x86_64;
B
bellard 已提交
292
    print_insn = print_insn_i386;
M
malc 已提交
293
#elif defined(_ARCH_PPC)
294
    s.info.disassembler_options = (char *)"any";
B
bellard 已提交
295
    print_insn = print_insn_ppc;
296 297
#elif defined(__aarch64__) && defined(CONFIG_ARM_A64_DIS)
    print_insn = print_insn_arm_a64;
B
bellard 已提交
298
#elif defined(__alpha__)
B
bellard 已提交
299
    print_insn = print_insn_alpha;
B
bellard 已提交
300
#elif defined(__sparc__)
B
bellard 已提交
301
    print_insn = print_insn_sparc;
B
Blue Swirl 已提交
302
    s.info.mach = bfd_mach_sparc_v9b;
303
#elif defined(__arm__)
B
bellard 已提交
304
    print_insn = print_insn_arm;
B
bellard 已提交
305 306 307 308
#elif defined(__MIPSEB__)
    print_insn = print_insn_big_mips;
#elif defined(__MIPSEL__)
    print_insn = print_insn_little_mips;
B
bellard 已提交
309 310
#elif defined(__m68k__)
    print_insn = print_insn_m68k;
311 312
#elif defined(__s390__)
    print_insn = print_insn_s390;
313 314
#elif defined(__hppa__)
    print_insn = print_insn_hppa;
B
bellard 已提交
315
#endif
316 317 318
    if (print_insn == NULL) {
        print_insn = print_insn_od_host;
    }
319 320
    for (pc = (uintptr_t)code; size > 0; pc += count, size -= count) {
        fprintf(out, "0x%08" PRIxPTR ":  ", pc);
B
Blue Swirl 已提交
321
        count = print_insn(pc, &s.info);
B
bellard 已提交
322 323 324 325 326 327 328
	fprintf(out, "\n");
	if (count < 0)
	    break;
    }
}

/* Look up symbol for debugging purpose.  Returns "" if unknown. */
B
bellard 已提交
329
const char *lookup_symbol(target_ulong orig_addr)
B
bellard 已提交
330
{
331
    const char *symbol = "";
B
bellard 已提交
332
    struct syminfo *s;
333

B
bellard 已提交
334
    for (s = syminfos; s; s = s->next) {
335 336 337 338
        symbol = s->lookup_symbol(s, orig_addr);
        if (symbol[0] != '\0') {
            break;
        }
B
bellard 已提交
339
    }
340 341

    return symbol;
B
bellard 已提交
342
}
343 344 345

#if !defined(CONFIG_USER_ONLY)

346
#include "monitor/monitor.h"
347

348 349 350
static int monitor_disas_is_physical;

static int
351 352
monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length,
                     struct disassemble_info *info)
353
{
B
Blue Swirl 已提交
354 355
    CPUDebug *s = container_of(info, CPUDebug, info);

356
    if (monitor_disas_is_physical) {
357
        cpu_physical_memory_read(memaddr, myaddr, length);
358
    } else {
359
        cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, 0);
360 361 362 363
    }
    return 0;
}

364 365
/* Disassembler for the monitor.
   See target_disas for a description of flags. */
366
void monitor_disas(Monitor *mon, CPUState *cpu,
B
bellard 已提交
367
                   target_ulong pc, int nb_insn, int is_physical, int flags)
368
{
369
    CPUClass *cc = CPU_GET_CLASS(cpu);
370
    int count, i;
B
Blue Swirl 已提交
371
    CPUDebug s;
372

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

375
    s.cpu = cpu;
376
    monitor_disas_is_physical = is_physical;
B
Blue Swirl 已提交
377
    s.info.read_memory_func = monitor_read_memory;
378
    s.info.print_address_func = generic_print_address;
379

B
Blue Swirl 已提交
380
    s.info.buffer_vma = pc;
381 382

#ifdef TARGET_WORDS_BIGENDIAN
B
Blue Swirl 已提交
383
    s.info.endian = BFD_ENDIAN_BIG;
384
#else
B
Blue Swirl 已提交
385
    s.info.endian = BFD_ENDIAN_LITTLE;
386
#endif
387 388 389 390 391

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

392
#if defined(TARGET_I386)
B
Blue Swirl 已提交
393 394 395 396 397 398 399
    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;
    }
400
    s.info.print_insn = print_insn_i386;
401
#elif defined(TARGET_PPC)
402 403 404 405
    if (flags & 0xFFFF) {
        /* If we have a precise definition of the instruction set, use it. */
        s.info.mach = flags & 0xFFFF;
    } else {
B
bellard 已提交
406
#ifdef TARGET_PPC64
407
        s.info.mach = bfd_mach_ppc64;
B
bellard 已提交
408
#else
409
        s.info.mach = bfd_mach_ppc;
B
bellard 已提交
410
#endif
411 412 413 414
    }
    if ((flags >> 16) & 1) {
        s.info.endian = BFD_ENDIAN_LITTLE;
    }
415
    s.info.print_insn = print_insn_ppc;
416
#endif
417 418 419 420 421
    if (!s.info.print_insn) {
        monitor_printf(mon, "0x" TARGET_FMT_lx
                       ": Asm output not supported on this arch\n", pc);
        return;
    }
422 423

    for(i = 0; i < nb_insn; i++) {
A
aliguori 已提交
424
	monitor_printf(mon, "0x" TARGET_FMT_lx ":  ", pc);
425
        count = s.info.print_insn(pc, &s.info);
A
aliguori 已提交
426
	monitor_printf(mon, "\n");
427 428 429 430 431 432
	if (count < 0)
	    break;
        pc += count;
    }
}
#endif