Statistics
| Branch: | Revision:

root / disas.c @ feature-archipelago

History | View | Annotate | Download (14 kB)

1
/* General "disassemble this chunk" code.  Used for debugging. */
2
#include "config.h"
3
#include "disas/bfd.h"
4
#include "elf.h"
5
#include <errno.h>
6

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

    
10
typedef struct CPUDebug {
11
    struct disassemble_info info;
12
    CPUArchState *env;
13
} CPUDebug;
14

    
15
/* Filled in by elfload.c.  Simplistic, but will do for now. */
16
struct syminfo *syminfos = NULL;
17

    
18
/* Get LENGTH bytes from info's buffer, at target address memaddr.
19
   Transfer them to myaddr.  */
20
int
21
buffer_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
22
                   struct disassemble_info *info)
23
{
24
    if (memaddr < info->buffer_vma
25
        || memaddr + length > info->buffer_vma + info->buffer_length)
26
        /* Out of bounds.  Use EIO because GDB uses it.  */
27
        return EIO;
28
    memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
29
    return 0;
30
}
31

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

    
42
    cpu_memory_rw_debug(ENV_GET_CPU(s->env), memaddr, myaddr, length, 0);
43
    return 0;
44
}
45

    
46
/* Print an error message.  We can assume that this is in response to
47
   an error return from buffer_read_memory.  */
48
void
49
perror_memory (int status, bfd_vma memaddr, struct disassemble_info *info)
50
{
51
  if (status != EIO)
52
    /* Can't happen.  */
53
    (*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
54
  else
55
    /* Actually, address between memaddr and memaddr + len was
56
       out of bounds.  */
57
    (*info->fprintf_func) (info->stream,
58
                           "Address 0x%" PRIx64 " is out of bounds.\n", memaddr);
59
}
60

    
61
/* This could be in a separate file, to save minuscule amounts of space
62
   in statically linked executables.  */
63

    
64
/* Just print the address is hex.  This is included for completeness even
65
   though both GDB and objdump provide their own (to print symbolic
66
   addresses).  */
67

    
68
void
69
generic_print_address (bfd_vma addr, struct disassemble_info *info)
70
{
71
    (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr);
72
}
73

    
74
/* Print address in hex, truncated to the width of a target virtual address. */
75
static void
76
generic_print_target_address(bfd_vma addr, struct disassemble_info *info)
77
{
78
    uint64_t mask = ~0ULL >> (64 - TARGET_VIRT_ADDR_SPACE_BITS);
79
    generic_print_address(addr & mask, info);
80
}
81

    
82
/* Print address in hex, truncated to the width of a host virtual address. */
83
static void
84
generic_print_host_address(bfd_vma addr, struct disassemble_info *info)
85
{
86
    uint64_t mask = ~0ULL >> (64 - (sizeof(void *) * 8));
87
    generic_print_address(addr & mask, info);
88
}
89

    
90
/* Just return the given address.  */
91

    
92
int
93
generic_symbol_at_address (bfd_vma addr, struct disassemble_info *info)
94
{
95
  return 1;
96
}
97

    
98
bfd_vma bfd_getl64 (const bfd_byte *addr)
99
{
100
  unsigned long long v;
101

    
102
  v = (unsigned long long) addr[0];
103
  v |= (unsigned long long) addr[1] << 8;
104
  v |= (unsigned long long) addr[2] << 16;
105
  v |= (unsigned long long) addr[3] << 24;
106
  v |= (unsigned long long) addr[4] << 32;
107
  v |= (unsigned long long) addr[5] << 40;
108
  v |= (unsigned long long) addr[6] << 48;
109
  v |= (unsigned long long) addr[7] << 56;
110
  return (bfd_vma) v;
111
}
112

    
113
bfd_vma bfd_getl32 (const bfd_byte *addr)
114
{
115
  unsigned long v;
116

    
117
  v = (unsigned long) addr[0];
118
  v |= (unsigned long) addr[1] << 8;
119
  v |= (unsigned long) addr[2] << 16;
120
  v |= (unsigned long) addr[3] << 24;
121
  return (bfd_vma) v;
122
}
123

    
124
bfd_vma bfd_getb32 (const bfd_byte *addr)
125
{
126
  unsigned long v;
127

    
128
  v = (unsigned long) addr[0] << 24;
129
  v |= (unsigned long) addr[1] << 16;
130
  v |= (unsigned long) addr[2] << 8;
131
  v |= (unsigned long) addr[3];
132
  return (bfd_vma) v;
133
}
134

    
135
bfd_vma bfd_getl16 (const bfd_byte *addr)
136
{
137
  unsigned long v;
138

    
139
  v = (unsigned long) addr[0];
140
  v |= (unsigned long) addr[1] << 8;
141
  return (bfd_vma) v;
142
}
143

    
144
bfd_vma bfd_getb16 (const bfd_byte *addr)
145
{
146
  unsigned long v;
147

    
148
  v = (unsigned long) addr[0] << 24;
149
  v |= (unsigned long) addr[1] << 16;
150
  return (bfd_vma) v;
151
}
152

    
153
#ifdef TARGET_ARM
154
static int
155
print_insn_thumb1(bfd_vma pc, disassemble_info *info)
156
{
157
  return print_insn_arm(pc | 1, info);
158
}
159
#endif
160

    
161
static int print_insn_objdump(bfd_vma pc, disassemble_info *info,
162
                              const char *prefix)
163
{
164
    int i, n = info->buffer_length;
165
    uint8_t *buf = g_malloc(n);
166

    
167
    info->read_memory_func(pc, buf, n, info);
168

    
169
    for (i = 0; i < n; ++i) {
170
        if (i % 32 == 0) {
171
            info->fprintf_func(info->stream, "\n%s: ", prefix);
172
        }
173
        info->fprintf_func(info->stream, "%02x", buf[i]);
174
    }
175

    
176
    g_free(buf);
177
    return n;
178
}
179

    
180
static int print_insn_od_host(bfd_vma pc, disassemble_info *info)
181
{
182
    return print_insn_objdump(pc, info, "OBJD-H");
183
}
184

    
185
static int print_insn_od_target(bfd_vma pc, disassemble_info *info)
186
{
187
    return print_insn_objdump(pc, info, "OBJD-T");
188
}
189

    
190
/* Disassemble this for me please... (debugging). 'flags' has the following
191
   values:
192
    i386 - 1 means 16 bit code, 2 means 64 bit code
193
    arm  - bit 0 = thumb, bit 1 = reverse endian, bit 2 = A64
194
    ppc  - nonzero means little endian
195
    other targets - unused
196
 */
197
void target_disas(FILE *out, CPUArchState *env, target_ulong code,
198
                  target_ulong size, int flags)
199
{
200
    target_ulong pc;
201
    int count;
202
    CPUDebug s;
203
    int (*print_insn)(bfd_vma pc, disassemble_info *info) = NULL;
204

    
205
    INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
206

    
207
    s.env = env;
208
    s.info.read_memory_func = target_read_memory;
209
    s.info.buffer_vma = code;
210
    s.info.buffer_length = size;
211
    s.info.print_address_func = generic_print_target_address;
212

    
213
#ifdef TARGET_WORDS_BIGENDIAN
214
    s.info.endian = BFD_ENDIAN_BIG;
215
#else
216
    s.info.endian = BFD_ENDIAN_LITTLE;
217
#endif
218
#if defined(TARGET_I386)
219
    if (flags == 2) {
220
        s.info.mach = bfd_mach_x86_64;
221
    } else if (flags == 1) {
222
        s.info.mach = bfd_mach_i386_i8086;
223
    } else {
224
        s.info.mach = bfd_mach_i386_i386;
225
    }
226
    print_insn = print_insn_i386;
227
#elif defined(TARGET_ARM)
228
    if (flags & 4) {
229
        /* We might not be compiled with the A64 disassembler
230
         * because it needs a C++ compiler; in that case we will
231
         * fall through to the default print_insn_od case.
232
         */
233
#if defined(CONFIG_ARM_A64_DIS)
234
        print_insn = print_insn_arm_a64;
235
#endif
236
    } else if (flags & 1) {
237
        print_insn = print_insn_thumb1;
238
    } else {
239
        print_insn = print_insn_arm;
240
    }
241
    if (flags & 2) {
242
#ifdef TARGET_WORDS_BIGENDIAN
243
        s.info.endian = BFD_ENDIAN_LITTLE;
244
#else
245
        s.info.endian = BFD_ENDIAN_BIG;
246
#endif
247
    }
248
#elif defined(TARGET_SPARC)
249
    print_insn = print_insn_sparc;
250
#ifdef TARGET_SPARC64
251
    s.info.mach = bfd_mach_sparc_v9b;
252
#endif
253
#elif defined(TARGET_PPC)
254
    if (flags >> 16) {
255
        s.info.endian = BFD_ENDIAN_LITTLE;
256
    }
257
    if (flags & 0xFFFF) {
258
        /* If we have a precise definitions of the instructions set, use it */
259
        s.info.mach = flags & 0xFFFF;
260
    } else {
261
#ifdef TARGET_PPC64
262
        s.info.mach = bfd_mach_ppc64;
263
#else
264
        s.info.mach = bfd_mach_ppc;
265
#endif
266
    }
267
    s.info.disassembler_options = (char *)"any";
268
    print_insn = print_insn_ppc;
269
#elif defined(TARGET_M68K)
270
    print_insn = print_insn_m68k;
271
#elif defined(TARGET_MIPS)
272
#ifdef TARGET_WORDS_BIGENDIAN
273
    print_insn = print_insn_big_mips;
274
#else
275
    print_insn = print_insn_little_mips;
276
#endif
277
#elif defined(TARGET_SH4)
278
    s.info.mach = bfd_mach_sh4;
279
    print_insn = print_insn_sh;
280
#elif defined(TARGET_ALPHA)
281
    s.info.mach = bfd_mach_alpha_ev6;
282
    print_insn = print_insn_alpha;
283
#elif defined(TARGET_CRIS)
284
    if (flags != 32) {
285
        s.info.mach = bfd_mach_cris_v0_v10;
286
        print_insn = print_insn_crisv10;
287
    } else {
288
        s.info.mach = bfd_mach_cris_v32;
289
        print_insn = print_insn_crisv32;
290
    }
291
#elif defined(TARGET_S390X)
292
    s.info.mach = bfd_mach_s390_64;
293
    print_insn = print_insn_s390;
294
#elif defined(TARGET_MICROBLAZE)
295
    s.info.mach = bfd_arch_microblaze;
296
    print_insn = print_insn_microblaze;
297
#elif defined(TARGET_MOXIE)
298
    s.info.mach = bfd_arch_moxie;
299
    print_insn = print_insn_moxie;
300
#elif defined(TARGET_LM32)
301
    s.info.mach = bfd_mach_lm32;
302
    print_insn = print_insn_lm32;
303
#endif
304
    if (print_insn == NULL) {
305
        print_insn = print_insn_od_target;
306
    }
307

    
308
    for (pc = code; size > 0; pc += count, size -= count) {
309
        fprintf(out, "0x" TARGET_FMT_lx ":  ", pc);
310
        count = print_insn(pc, &s.info);
311
#if 0
312
        {
313
            int i;
314
            uint8_t b;
315
            fprintf(out, " {");
316
            for(i = 0; i < count; i++) {
317
                target_read_memory(pc + i, &b, 1, &s.info);
318
                fprintf(out, " %02x", b);
319
            }
320
            fprintf(out, " }");
321
        }
322
#endif
323
        fprintf(out, "\n");
324
        if (count < 0)
325
            break;
326
        if (size < count) {
327
            fprintf(out,
328
                    "Disassembler disagrees with translator over instruction "
329
                    "decoding\n"
330
                    "Please report this to qemu-devel@nongnu.org\n");
331
            break;
332
        }
333
    }
334
}
335

    
336
/* Disassemble this for me please... (debugging). */
337
void disas(FILE *out, void *code, unsigned long size)
338
{
339
    uintptr_t pc;
340
    int count;
341
    CPUDebug s;
342
    int (*print_insn)(bfd_vma pc, disassemble_info *info) = NULL;
343

    
344
    INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
345
    s.info.print_address_func = generic_print_host_address;
346

    
347
    s.info.buffer = code;
348
    s.info.buffer_vma = (uintptr_t)code;
349
    s.info.buffer_length = size;
350

    
351
#ifdef HOST_WORDS_BIGENDIAN
352
    s.info.endian = BFD_ENDIAN_BIG;
353
#else
354
    s.info.endian = BFD_ENDIAN_LITTLE;
355
#endif
356
#if defined(CONFIG_TCG_INTERPRETER)
357
    print_insn = print_insn_tci;
358
#elif defined(__i386__)
359
    s.info.mach = bfd_mach_i386_i386;
360
    print_insn = print_insn_i386;
361
#elif defined(__x86_64__)
362
    s.info.mach = bfd_mach_x86_64;
363
    print_insn = print_insn_i386;
364
#elif defined(_ARCH_PPC)
365
    s.info.disassembler_options = (char *)"any";
366
    print_insn = print_insn_ppc;
367
#elif defined(__aarch64__) && defined(CONFIG_ARM_A64_DIS)
368
    print_insn = print_insn_arm_a64;
369
#elif defined(__alpha__)
370
    print_insn = print_insn_alpha;
371
#elif defined(__sparc__)
372
    print_insn = print_insn_sparc;
373
    s.info.mach = bfd_mach_sparc_v9b;
374
#elif defined(__arm__)
375
    print_insn = print_insn_arm;
376
#elif defined(__MIPSEB__)
377
    print_insn = print_insn_big_mips;
378
#elif defined(__MIPSEL__)
379
    print_insn = print_insn_little_mips;
380
#elif defined(__m68k__)
381
    print_insn = print_insn_m68k;
382
#elif defined(__s390__)
383
    print_insn = print_insn_s390;
384
#elif defined(__hppa__)
385
    print_insn = print_insn_hppa;
386
#elif defined(__ia64__)
387
    print_insn = print_insn_ia64;
388
#endif
389
    if (print_insn == NULL) {
390
        print_insn = print_insn_od_host;
391
    }
392
    for (pc = (uintptr_t)code; size > 0; pc += count, size -= count) {
393
        fprintf(out, "0x%08" PRIxPTR ":  ", pc);
394
        count = print_insn(pc, &s.info);
395
        fprintf(out, "\n");
396
        if (count < 0)
397
            break;
398
    }
399
}
400

    
401
/* Look up symbol for debugging purpose.  Returns "" if unknown. */
402
const char *lookup_symbol(target_ulong orig_addr)
403
{
404
    const char *symbol = "";
405
    struct syminfo *s;
406

    
407
    for (s = syminfos; s; s = s->next) {
408
        symbol = s->lookup_symbol(s, orig_addr);
409
        if (symbol[0] != '\0') {
410
            break;
411
        }
412
    }
413

    
414
    return symbol;
415
}
416

    
417
#if !defined(CONFIG_USER_ONLY)
418

    
419
#include "monitor/monitor.h"
420

    
421
static int monitor_disas_is_physical;
422

    
423
static int
424
monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length,
425
                     struct disassemble_info *info)
426
{
427
    CPUDebug *s = container_of(info, CPUDebug, info);
428

    
429
    if (monitor_disas_is_physical) {
430
        cpu_physical_memory_read(memaddr, myaddr, length);
431
    } else {
432
        cpu_memory_rw_debug(ENV_GET_CPU(s->env), memaddr, myaddr, length, 0);
433
    }
434
    return 0;
435
}
436

    
437
static int GCC_FMT_ATTR(2, 3)
438
monitor_fprintf(FILE *stream, const char *fmt, ...)
439
{
440
    va_list ap;
441
    va_start(ap, fmt);
442
    monitor_vprintf((Monitor *)stream, fmt, ap);
443
    va_end(ap);
444
    return 0;
445
}
446

    
447
void monitor_disas(Monitor *mon, CPUArchState *env,
448
                   target_ulong pc, int nb_insn, int is_physical, int flags)
449
{
450
    int count, i;
451
    CPUDebug s;
452
    int (*print_insn)(bfd_vma pc, disassemble_info *info);
453

    
454
    INIT_DISASSEMBLE_INFO(s.info, (FILE *)mon, monitor_fprintf);
455

    
456
    s.env = env;
457
    monitor_disas_is_physical = is_physical;
458
    s.info.read_memory_func = monitor_read_memory;
459
    s.info.print_address_func = generic_print_target_address;
460

    
461
    s.info.buffer_vma = pc;
462

    
463
#ifdef TARGET_WORDS_BIGENDIAN
464
    s.info.endian = BFD_ENDIAN_BIG;
465
#else
466
    s.info.endian = BFD_ENDIAN_LITTLE;
467
#endif
468
#if defined(TARGET_I386)
469
    if (flags == 2) {
470
        s.info.mach = bfd_mach_x86_64;
471
    } else if (flags == 1) {
472
        s.info.mach = bfd_mach_i386_i8086;
473
    } else {
474
        s.info.mach = bfd_mach_i386_i386;
475
    }
476
    print_insn = print_insn_i386;
477
#elif defined(TARGET_ARM)
478
    print_insn = print_insn_arm;
479
#elif defined(TARGET_ALPHA)
480
    print_insn = print_insn_alpha;
481
#elif defined(TARGET_SPARC)
482
    print_insn = print_insn_sparc;
483
#ifdef TARGET_SPARC64
484
    s.info.mach = bfd_mach_sparc_v9b;
485
#endif
486
#elif defined(TARGET_PPC)
487
#ifdef TARGET_PPC64
488
    s.info.mach = bfd_mach_ppc64;
489
#else
490
    s.info.mach = bfd_mach_ppc;
491
#endif
492
    print_insn = print_insn_ppc;
493
#elif defined(TARGET_M68K)
494
    print_insn = print_insn_m68k;
495
#elif defined(TARGET_MIPS)
496
#ifdef TARGET_WORDS_BIGENDIAN
497
    print_insn = print_insn_big_mips;
498
#else
499
    print_insn = print_insn_little_mips;
500
#endif
501
#elif defined(TARGET_SH4)
502
    s.info.mach = bfd_mach_sh4;
503
    print_insn = print_insn_sh;
504
#elif defined(TARGET_S390X)
505
    s.info.mach = bfd_mach_s390_64;
506
    print_insn = print_insn_s390;
507
#elif defined(TARGET_MOXIE)
508
    s.info.mach = bfd_arch_moxie;
509
    print_insn = print_insn_moxie;
510
#elif defined(TARGET_LM32)
511
    s.info.mach = bfd_mach_lm32;
512
    print_insn = print_insn_lm32;
513
#else
514
    monitor_printf(mon, "0x" TARGET_FMT_lx
515
                   ": Asm output not supported on this arch\n", pc);
516
    return;
517
#endif
518

    
519
    for(i = 0; i < nb_insn; i++) {
520
        monitor_printf(mon, "0x" TARGET_FMT_lx ":  ", pc);
521
        count = print_insn(pc, &s.info);
522
        monitor_printf(mon, "\n");
523
        if (count < 0)
524
            break;
525
        pc += count;
526
    }
527
}
528
#endif