Blame view

disas.c 10.5 KB
bellard authored
1
/* General "disassemble this chunk" code.  Used for debugging. */
bellard authored
2
#include "config.h"
bellard authored
3
4
#include "dis-asm.h"
#include "elf.h"
5
#include <errno.h>
bellard authored
6
7
8
#include "cpu.h"
#include "exec-all.h"
9
#include "disas.h"
10
bellard authored
11
/* Filled in by elfload.c.  Simplistic, but will do for now. */
bellard authored
12
struct syminfo *syminfos = NULL;
bellard authored
13
14
15
16
/* Get LENGTH bytes from info's buffer, at target address memaddr.
   Transfer them to myaddr.  */
int
17
18
buffer_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
                   struct disassemble_info *info)
19
{
20
21
22
23
24
25
    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;
26
27
}
28
29
30
/* Get LENGTH bytes from info's buffer, at target address memaddr.
   Transfer them to myaddr.  */
static int
bellard authored
31
32
33
34
target_read_memory (bfd_vma memaddr,
                    bfd_byte *myaddr,
                    int length,
                    struct disassemble_info *info)
35
36
37
{
    int i;
    for(i = 0; i < length; i++) {
bellard authored
38
        myaddr[i] = ldub_code(memaddr + i);
39
40
41
42
    }
    return 0;
}
43
44
45
/* Print an error message.  We can assume that this is in response to
   an error return from buffer_read_memory.  */
void
46
perror_memory (int status, bfd_vma memaddr, struct disassemble_info *info)
47
48
49
50
51
52
53
54
{
  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,
bellard authored
55
			   "Address 0x%" PRIx64 " is out of bounds.\n", memaddr);
56
57
58
59
60
61
62
63
64
65
}

/* This could be in a separate file, to save miniscule amounts of space
   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
66
generic_print_address (bfd_vma addr, struct disassemble_info *info)
67
{
bellard authored
68
    (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr);
69
70
71
72
73
}

/* Just return the given address.  */

int
74
generic_symbol_at_address (bfd_vma addr, struct disassemble_info *info)
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
{
  return 1;
}

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;
}
bellard authored
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
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;
}
119
120
121
122
123
124
125
126
#ifdef TARGET_ARM
static int
print_insn_thumb1(bfd_vma pc, disassemble_info *info)
{
  return print_insn_arm(pc | 1, info);
}
#endif
ths authored
127
/* Disassemble this for me please... (debugging). 'flags' has the following
128
129
   values:
    i386 - nonzero means 16 bit code
130
    arm  - nonzero means thumb code
bellard authored
131
    ppc  - nonzero means little endian
132
133
    other targets - unused
 */
134
void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
bellard authored
135
{
bellard authored
136
    target_ulong pc;
bellard authored
137
138
139
140
141
142
    int count;
    struct disassemble_info disasm_info;
    int (*print_insn)(bfd_vma pc, disassemble_info *info);

    INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);
bellard authored
143
144
145
146
147
148
149
150
151
152
153
154
    disasm_info.read_memory_func = target_read_memory;
    disasm_info.buffer_vma = code;
    disasm_info.buffer_length = size;

#ifdef TARGET_WORDS_BIGENDIAN
    disasm_info.endian = BFD_ENDIAN_BIG;
#else
    disasm_info.endian = BFD_ENDIAN_LITTLE;
#endif
#if defined(TARGET_I386)
    if (flags == 2)
        disasm_info.mach = bfd_mach_x86_64;
155
    else if (flags == 1)
bellard authored
156
157
158
159
160
        disasm_info.mach = bfd_mach_i386_i8086;
    else
        disasm_info.mach = bfd_mach_i386_i386;
    print_insn = print_insn_i386;
#elif defined(TARGET_ARM)
161
162
163
164
    if (flags)
	print_insn = print_insn_thumb1;
    else
	print_insn = print_insn_arm;
bellard authored
165
166
#elif defined(TARGET_SPARC)
    print_insn = print_insn_sparc;
bellard authored
167
168
#ifdef TARGET_SPARC64
    disasm_info.mach = bfd_mach_sparc_v9b;
169
#endif
bellard authored
170
#elif defined(TARGET_PPC)
171
    if (flags >> 16)
172
        disasm_info.endian = BFD_ENDIAN_LITTLE;
173
174
175
176
    if (flags & 0xFFFF) {
        /* If we have a precise definitions of the instructions set, use it */
        disasm_info.mach = flags & 0xFFFF;
    } else {
bellard authored
177
#ifdef TARGET_PPC64
178
        disasm_info.mach = bfd_mach_ppc64;
bellard authored
179
#else
180
        disasm_info.mach = bfd_mach_ppc;
bellard authored
181
#endif
182
    }
bellard authored
183
    print_insn = print_insn_ppc;
pbrook authored
184
185
#elif defined(TARGET_M68K)
    print_insn = print_insn_m68k;
bellard authored
186
#elif defined(TARGET_MIPS)
bellard authored
187
#ifdef TARGET_WORDS_BIGENDIAN
bellard authored
188
    print_insn = print_insn_big_mips;
bellard authored
189
190
191
#else
    print_insn = print_insn_little_mips;
#endif
bellard authored
192
193
194
#elif defined(TARGET_SH4)
    disasm_info.mach = bfd_mach_sh4;
    print_insn = print_insn_sh;
195
196
197
#elif defined(TARGET_ALPHA)
    disasm_info.mach = bfd_mach_alpha;
    print_insn = print_insn_alpha;
198
199
200
#elif defined(TARGET_CRIS)
    disasm_info.mach = bfd_mach_cris_v32;
    print_insn = print_insn_crisv32;
bellard authored
201
#else
202
203
    fprintf(out, "0x" TARGET_FMT_lx
	    ": Asm output not supported on this arch\n", code);
bellard authored
204
    return;
205
206
#endif
bellard authored
207
    for (pc = code; pc < code + size; pc += count) {
bellard authored
208
	fprintf(out, "0x" TARGET_FMT_lx ":  ", pc);
bellard authored
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
	count = print_insn(pc, &disasm_info);
#if 0
        {
            int i;
            uint8_t b;
            fprintf(out, " {");
            for(i = 0; i < count; i++) {
                target_read_memory(pc + i, &b, 1, &disasm_info);
                fprintf(out, " %02x", b);
            }
            fprintf(out, " }");
        }
#endif
	fprintf(out, "\n");
	if (count < 0)
	    break;
    }
}

/* Disassemble this for me please... (debugging). */
void disas(FILE *out, void *code, unsigned long size)
{
    unsigned long pc;
    int count;
    struct disassemble_info disasm_info;
    int (*print_insn)(bfd_vma pc, disassemble_info *info);

    INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);
bellard authored
238
239
240
241
242
    disasm_info.buffer = code;
    disasm_info.buffer_vma = (unsigned long)code;
    disasm_info.buffer_length = size;

#ifdef WORDS_BIGENDIAN
bellard authored
243
    disasm_info.endian = BFD_ENDIAN_BIG;
bellard authored
244
#else
bellard authored
245
    disasm_info.endian = BFD_ENDIAN_LITTLE;
bellard authored
246
#endif
247
#if defined(__i386__)
bellard authored
248
249
    disasm_info.mach = bfd_mach_i386_i386;
    print_insn = print_insn_i386;
250
#elif defined(__x86_64__)
bellard authored
251
252
    disasm_info.mach = bfd_mach_x86_64;
    print_insn = print_insn_i386;
253
#elif defined(_ARCH_PPC)
bellard authored
254
    print_insn = print_insn_ppc;
bellard authored
255
#elif defined(__alpha__)
bellard authored
256
    print_insn = print_insn_alpha;
257
#elif defined(__sparc__)
bellard authored
258
    print_insn = print_insn_sparc;
259
260
261
#if defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__)
    disasm_info.mach = bfd_mach_sparc_v9b;
#endif
262
#elif defined(__arm__)
bellard authored
263
    print_insn = print_insn_arm;
bellard authored
264
265
266
267
#elif defined(__MIPSEB__)
    print_insn = print_insn_big_mips;
#elif defined(__MIPSEL__)
    print_insn = print_insn_little_mips;
268
269
#elif defined(__m68k__)
    print_insn = print_insn_m68k;
270
271
#elif defined(__s390__)
    print_insn = print_insn_s390;
aurel32 authored
272
273
#elif defined(__hppa__)
    print_insn = print_insn_hppa;
bellard authored
274
#else
275
276
    fprintf(out, "0x%lx: Asm output not supported on this arch\n",
	    (long) code);
bellard authored
277
    return;
bellard authored
278
#endif
bellard authored
279
280
    for (pc = (unsigned long)code; pc < (unsigned long)code + size; pc += count) {
	fprintf(out, "0x%08lx:  ", pc);
281
#ifdef __arm__
pbrook authored
282
        /* since data is included in the code, it is better to
283
           display code data too */
pbrook authored
284
        fprintf(out, "%08x  ", (int)bfd_getl32((const bfd_byte *)pc));
285
#endif
bellard authored
286
	count = print_insn(pc, &disasm_info);
bellard authored
287
288
289
290
291
292
293
	fprintf(out, "\n");
	if (count < 0)
	    break;
    }
}

/* Look up symbol for debugging purpose.  Returns "" if unknown. */
bellard authored
294
const char *lookup_symbol(target_ulong orig_addr)
bellard authored
295
{
296
    const char *symbol = "";
bellard authored
297
    struct syminfo *s;
298
bellard authored
299
    for (s = syminfos; s; s = s->next) {
300
301
302
303
        symbol = s->lookup_symbol(s, orig_addr);
        if (symbol[0] != '\0') {
            break;
        }
bellard authored
304
    }
305
306

    return symbol;
bellard authored
307
}
308
309
310

#if !defined(CONFIG_USER_ONLY)
311
312
313
void term_vprintf(const char *fmt, va_list ap);
void term_printf(const char *fmt, ...);
314
static int monitor_disas_is_physical;
bellard authored
315
static CPUState *monitor_disas_env;
316
317

static int
318
319
monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length,
                     struct disassemble_info *info)
320
321
322
323
{
    if (monitor_disas_is_physical) {
        cpu_physical_memory_rw(memaddr, myaddr, length, 0);
    } else {
bellard authored
324
        cpu_memory_rw_debug(monitor_disas_env, memaddr,myaddr, length, 0);
325
326
327
328
    }
    return 0;
}
329
330
331
332
333
334
335
336
337
static int monitor_fprintf(FILE *stream, const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    term_vprintf(fmt, ap);
    va_end(ap);
    return 0;
}
bellard authored
338
339
void monitor_disas(CPUState *env,
                   target_ulong pc, int nb_insn, int is_physical, int flags)
340
341
342
343
344
{
    int count, i;
    struct disassemble_info disasm_info;
    int (*print_insn)(bfd_vma pc, disassemble_info *info);
345
    INIT_DISASSEMBLE_INFO(disasm_info, NULL, monitor_fprintf);
346
bellard authored
347
    monitor_disas_env = env;
348
349
350
351
352
353
354
355
356
357
358
    monitor_disas_is_physical = is_physical;
    disasm_info.read_memory_func = monitor_read_memory;

    disasm_info.buffer_vma = pc;

#ifdef TARGET_WORDS_BIGENDIAN
    disasm_info.endian = BFD_ENDIAN_BIG;
#else
    disasm_info.endian = BFD_ENDIAN_LITTLE;
#endif
#if defined(TARGET_I386)
bellard authored
359
360
    if (flags == 2)
        disasm_info.mach = bfd_mach_x86_64;
361
    else if (flags == 1)
362
        disasm_info.mach = bfd_mach_i386_i8086;
bellard authored
363
364
    else
        disasm_info.mach = bfd_mach_i386_i386;
365
366
367
    print_insn = print_insn_i386;
#elif defined(TARGET_ARM)
    print_insn = print_insn_arm;
ths authored
368
369
#elif defined(TARGET_ALPHA)
    print_insn = print_insn_alpha;
370
371
#elif defined(TARGET_SPARC)
    print_insn = print_insn_sparc;
372
373
374
#ifdef TARGET_SPARC64
    disasm_info.mach = bfd_mach_sparc_v9b;
#endif
375
#elif defined(TARGET_PPC)
bellard authored
376
377
378
379
380
#ifdef TARGET_PPC64
    disasm_info.mach = bfd_mach_ppc64;
#else
    disasm_info.mach = bfd_mach_ppc;
#endif
381
    print_insn = print_insn_ppc;
pbrook authored
382
383
#elif defined(TARGET_M68K)
    print_insn = print_insn_m68k;
bellard authored
384
#elif defined(TARGET_MIPS)
bellard authored
385
#ifdef TARGET_WORDS_BIGENDIAN
bellard authored
386
    print_insn = print_insn_big_mips;
bellard authored
387
388
389
#else
    print_insn = print_insn_little_mips;
#endif
390
#else
391
392
    term_printf("0x" TARGET_FMT_lx
		": Asm output not supported on this arch\n", pc);
393
394
395
396
    return;
#endif

    for(i = 0; i < nb_insn; i++) {
bellard authored
397
	term_printf("0x" TARGET_FMT_lx ":  ", pc);
398
	count = print_insn(pc, &disasm_info);
399
	term_printf("\n");
400
401
402
403
404
405
	if (count < 0)
	    break;
        pc += count;
    }
}
#endif