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
207
    for (pc = code; size > 0; pc += count, size -= 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
279
    for (pc = (unsigned long)code; size > 0; pc += count, size -= count) {
bellard authored
280
	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
#include "monitor.h"
312
313
static int monitor_disas_is_physical;
bellard authored
314
static CPUState *monitor_disas_env;
315
316

static int
317
318
monitor_read_memory (bfd_vma memaddr, bfd_byte *myaddr, int length,
                     struct disassemble_info *info)
319
320
321
322
{
    if (monitor_disas_is_physical) {
        cpu_physical_memory_rw(memaddr, myaddr, length, 0);
    } else {
bellard authored
323
        cpu_memory_rw_debug(monitor_disas_env, memaddr,myaddr, length, 0);
324
325
326
327
    }
    return 0;
}
328
329
330
331
static int monitor_fprintf(FILE *stream, const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
332
    monitor_vprintf((Monitor *)stream, fmt, ap);
333
334
335
336
    va_end(ap);
    return 0;
}
337
void monitor_disas(Monitor *mon, CPUState *env,
bellard authored
338
                   target_ulong pc, int nb_insn, int is_physical, int flags)
339
340
341
342
343
{
    int count, i;
    struct disassemble_info disasm_info;
    int (*print_insn)(bfd_vma pc, disassemble_info *info);
344
    INIT_DISASSEMBLE_INFO(disasm_info, (FILE *)mon, monitor_fprintf);
345
bellard authored
346
    monitor_disas_env = env;
347
348
349
350
351
352
353
354
355
356
357
    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
358
359
    if (flags == 2)
        disasm_info.mach = bfd_mach_x86_64;
360
    else if (flags == 1)
361
        disasm_info.mach = bfd_mach_i386_i8086;
bellard authored
362
363
    else
        disasm_info.mach = bfd_mach_i386_i386;
364
365
366
    print_insn = print_insn_i386;
#elif defined(TARGET_ARM)
    print_insn = print_insn_arm;
ths authored
367
368
#elif defined(TARGET_ALPHA)
    print_insn = print_insn_alpha;
369
370
#elif defined(TARGET_SPARC)
    print_insn = print_insn_sparc;
371
372
373
#ifdef TARGET_SPARC64
    disasm_info.mach = bfd_mach_sparc_v9b;
#endif
374
#elif defined(TARGET_PPC)
bellard authored
375
376
377
378
379
#ifdef TARGET_PPC64
    disasm_info.mach = bfd_mach_ppc64;
#else
    disasm_info.mach = bfd_mach_ppc;
#endif
380
    print_insn = print_insn_ppc;
pbrook authored
381
382
#elif defined(TARGET_M68K)
    print_insn = print_insn_m68k;
bellard authored
383
#elif defined(TARGET_MIPS)
bellard authored
384
#ifdef TARGET_WORDS_BIGENDIAN
bellard authored
385
    print_insn = print_insn_big_mips;
bellard authored
386
387
388
#else
    print_insn = print_insn_little_mips;
#endif
389
#else
390
391
    monitor_printf(mon, "0x" TARGET_FMT_lx
                   ": Asm output not supported on this arch\n", pc);
392
393
394
395
    return;
#endif

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