1
/* General "disassemble this chunk" code. Used for debugging. */
2
# include "config.h"
3
4
# include "dis-asm.h"
# include "elf.h"
5
# include < errno . h >
6
7
8
# include "cpu.h"
# include "exec-all.h"
9
# include "disas.h"
10
11
/* Filled in by elfload.c. Simplistic, but will do for now. */
12
struct syminfo * syminfos = NULL ;
13
14
15
16
17
18
19
20
21
22
/* Get LENGTH bytes from info ' s buffer , at target address memaddr .
Transfer them to myaddr . */
int
buffer_read_memory ( memaddr , myaddr , length , info )
bfd_vma memaddr ;
bfd_byte * myaddr ;
int length ;
struct disassemble_info * info ;
{
23
24
25
26
27
28
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 ;
29
30
}
31
32
33
/* Get LENGTH bytes from info ' s buffer , at target address memaddr .
Transfer them to myaddr . */
static int
34
35
36
37
target_read_memory ( bfd_vma memaddr ,
bfd_byte * myaddr ,
int length ,
struct disassemble_info * info )
38
39
40
{
int i ;
for ( i = 0 ; i < length ; i ++ ) {
41
myaddr [ i ] = ldub_code ( memaddr + i );
42
43
44
45
}
return 0 ;
}
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/* Print an error message . We can assume that this is in response to
an error return from buffer_read_memory . */
void
perror_memory ( status , memaddr , info )
int status ;
bfd_vma memaddr ;
struct disassemble_info * info ;
{
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 ,
61
"Address 0x%" PRIx64 " is out of bounds. \n " , memaddr );
62
63
64
65
66
67
68
69
70
71
72
73
74
75
}
/* 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
generic_print_address ( addr , info )
bfd_vma addr ;
struct disassemble_info * info ;
{
76
( * info -> fprintf_func ) ( info -> stream , "0x%" PRIx64 , addr );
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
}
/* Just return the given address. */
int
generic_symbol_at_address ( addr , info )
bfd_vma addr ;
struct disassemble_info * info ;
{
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 ;
}
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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 ;
}
129
130
131
132
133
134
135
136
# ifdef TARGET_ARM
static int
print_insn_thumb1 ( bfd_vma pc , disassemble_info * info )
{
return print_insn_arm ( pc | 1 , info );
}
# endif
ths
authored
18 years ago
137
/* Disassemble this for me please ... ( debugging ). ' flags ' has the following
138
139
values :
i386 - nonzero means 16 bit code
ths
authored
18 years ago
140
arm - nonzero means thumb code
141
ppc - nonzero means little endian
142
143
other targets - unused
*/
144
void target_disas ( FILE * out , target_ulong code , target_ulong size , int flags )
145
{
146
target_ulong pc ;
147
148
149
150
151
152
int count ;
struct disassemble_info disasm_info ;
int ( * print_insn )( bfd_vma pc , disassemble_info * info );
INIT_DISASSEMBLE_INFO ( disasm_info , out , fprintf );
153
154
155
156
157
158
159
160
161
162
163
164
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 ;
ths
authored
18 years ago
165
else if ( flags == 1 )
166
167
168
169
170
disasm_info . mach = bfd_mach_i386_i8086 ;
else
disasm_info . mach = bfd_mach_i386_i386 ;
print_insn = print_insn_i386 ;
# elif defined ( TARGET_ARM )
171
172
173
174
if ( flags )
print_insn = print_insn_thumb1 ;
else
print_insn = print_insn_arm ;
175
176
# elif defined ( TARGET_SPARC )
print_insn = print_insn_sparc ;
177
178
# ifdef TARGET_SPARC64
disasm_info . mach = bfd_mach_sparc_v9b ;
ths
authored
18 years ago
179
# endif
180
# elif defined ( TARGET_PPC )
181
if ( flags >> 16 )
182
disasm_info . endian = BFD_ENDIAN_LITTLE ;
183
184
185
186
if ( flags & 0xFFFF ) {
/* If we have a precise definitions of the instructions set, use it */
disasm_info . mach = flags & 0xFFFF ;
} else {
187
# ifdef TARGET_PPC64
188
disasm_info . mach = bfd_mach_ppc64 ;
189
# else
190
disasm_info . mach = bfd_mach_ppc ;
191
# endif
192
}
193
print_insn = print_insn_ppc ;
194
195
# elif defined ( TARGET_M68K )
print_insn = print_insn_m68k ;
196
# elif defined ( TARGET_MIPS )
197
# ifdef TARGET_WORDS_BIGENDIAN
198
print_insn = print_insn_big_mips ;
199
200
201
# else
print_insn = print_insn_little_mips ;
# endif
202
203
204
# elif defined ( TARGET_SH4 )
disasm_info . mach = bfd_mach_sh4 ;
print_insn = print_insn_sh ;
205
206
207
# elif defined ( TARGET_ALPHA )
disasm_info . mach = bfd_mach_alpha ;
print_insn = print_insn_alpha ;
ths
authored
17 years ago
208
209
210
# elif defined ( TARGET_CRIS )
disasm_info . mach = bfd_mach_cris_v32 ;
print_insn = print_insn_crisv32 ;
211
# else
212
213
fprintf ( out , "0x" TARGET_FMT_lx
": Asm output not supported on this arch \n " , code );
214
return ;
215
216
# endif
217
for ( pc = code ; pc < code + size ; pc += count ) {
218
fprintf ( out , "0x" TARGET_FMT_lx ": " , pc );
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
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 );
248
249
250
251
252
disasm_info . buffer = code ;
disasm_info . buffer_vma = ( unsigned long ) code ;
disasm_info . buffer_length = size ;
# ifdef WORDS_BIGENDIAN
253
disasm_info . endian = BFD_ENDIAN_BIG ;
254
# else
255
disasm_info . endian = BFD_ENDIAN_LITTLE ;
256
# endif
257
# if defined ( __i386__ )
258
259
disasm_info . mach = bfd_mach_i386_i386 ;
print_insn = print_insn_i386 ;
260
# elif defined ( __x86_64__ )
261
262
disasm_info . mach = bfd_mach_x86_64 ;
print_insn = print_insn_i386 ;
263
# elif defined ( __powerpc__ )
264
print_insn = print_insn_ppc ;
265
# elif defined ( __alpha__ )
266
print_insn = print_insn_alpha ;
267
# elif defined ( __sparc__ )
268
print_insn = print_insn_sparc ;
269
270
271
# if defined ( __sparc_v8plus__ ) || defined ( __sparc_v8plusa__ ) || defined ( __sparc_v9__ )
disasm_info . mach = bfd_mach_sparc_v9b ;
# endif
ths
authored
18 years ago
272
# elif defined ( __arm__ )
273
print_insn = print_insn_arm ;
274
275
276
277
# elif defined ( __MIPSEB__ )
print_insn = print_insn_big_mips ;
# elif defined ( __MIPSEL__ )
print_insn = print_insn_little_mips ;
278
279
# elif defined ( __m68k__ )
print_insn = print_insn_m68k ;
ths
authored
18 years ago
280
281
# elif defined ( __s390__ )
print_insn = print_insn_s390 ;
282
283
# elif defined ( __hppa__ )
print_insn = print_insn_hppa ;
284
# else
285
286
fprintf ( out , "0x%lx: Asm output not supported on this arch \n " ,
( long ) code );
287
return ;
288
# endif
289
290
for ( pc = ( unsigned long ) code ; pc < ( unsigned long ) code + size ; pc += count ) {
fprintf ( out , "0x%08lx: " , pc );
291
# ifdef __arm__
292
/* since data is included in the code , it is better to
293
display code data too */
294
fprintf ( out , "%08x " , ( int ) bfd_getl32 (( const bfd_byte * ) pc ));
295
# endif
296
count = print_insn ( pc , & disasm_info );
297
298
299
300
301
302
303
fprintf ( out , " \n " );
if ( count < 0 )
break ;
}
}
/* Look up symbol for debugging purpose. Returns "" if unknown. */
304
const char * lookup_symbol ( target_ulong orig_addr )
305
306
307
{
unsigned int i ;
/* Hack, because we know this is x86. */
308
309
Elf32_Sym * sym ;
struct syminfo * s ;
310
target_ulong addr ;
ths
authored
18 years ago
311
312
313
314
315
316
317
for ( s = syminfos ; s ; s = s -> next ) {
sym = s -> disas_symtab ;
for ( i = 0 ; i < s -> disas_num_syms ; i ++ ) {
if ( sym [ i ]. st_shndx == SHN_UNDEF
|| sym [ i ]. st_shndx >= SHN_LORESERVE )
continue ;
318
319
320
if ( ELF_ST_TYPE ( sym [ i ]. st_info ) != STT_FUNC )
continue ;
321
322
addr = sym [ i ]. st_value ;
ths
authored
18 years ago
323
324
# if defined ( TARGET_ARM ) || defined ( TARGET_MIPS )
/* The bottom address bit marks a Thumb or MIPS16 symbol. */
325
326
327
328
addr &= ~ ( target_ulong ) 1 ;
# endif
if ( orig_addr >= addr
&& orig_addr < addr + sym [ i ]. st_size )
329
330
return s -> disas_strtab + sym [ i ]. st_name ;
}
331
332
333
}
return "" ;
}
334
335
336
# if ! defined ( CONFIG_USER_ONLY )
337
338
339
void term_vprintf ( const char * fmt , va_list ap );
void term_printf ( const char * fmt , ...);
340
static int monitor_disas_is_physical ;
341
static CPUState * monitor_disas_env ;
342
343
static int
344
345
monitor_read_memory ( bfd_vma memaddr , bfd_byte * myaddr , int length ,
struct disassemble_info * info )
346
347
348
349
{
if ( monitor_disas_is_physical ) {
cpu_physical_memory_rw ( memaddr , myaddr , length , 0 );
} else {
350
cpu_memory_rw_debug ( monitor_disas_env , memaddr , myaddr , length , 0 );
351
352
353
354
}
return 0 ;
}
355
356
357
358
359
360
361
362
363
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 ;
}
364
365
void monitor_disas ( CPUState * env ,
target_ulong pc , int nb_insn , int is_physical , int flags )
366
367
368
369
370
{
int count , i ;
struct disassemble_info disasm_info ;
int ( * print_insn )( bfd_vma pc , disassemble_info * info );
371
INIT_DISASSEMBLE_INFO ( disasm_info , NULL , monitor_fprintf );
372
373
monitor_disas_env = env ;
374
375
376
377
378
379
380
381
382
383
384
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 )
385
386
if ( flags == 2 )
disasm_info . mach = bfd_mach_x86_64 ;
ths
authored
18 years ago
387
else if ( flags == 1 )
388
disasm_info . mach = bfd_mach_i386_i8086 ;
389
390
else
disasm_info . mach = bfd_mach_i386_i386 ;
391
392
393
print_insn = print_insn_i386 ;
# elif defined ( TARGET_ARM )
print_insn = print_insn_arm ;
ths
authored
17 years ago
394
395
# elif defined ( TARGET_ALPHA )
print_insn = print_insn_alpha ;
396
397
# elif defined ( TARGET_SPARC )
print_insn = print_insn_sparc ;
398
399
400
# ifdef TARGET_SPARC64
disasm_info . mach = bfd_mach_sparc_v9b ;
# endif
401
# elif defined ( TARGET_PPC )
402
403
404
405
406
# ifdef TARGET_PPC64
disasm_info . mach = bfd_mach_ppc64 ;
# else
disasm_info . mach = bfd_mach_ppc ;
# endif
407
print_insn = print_insn_ppc ;
408
409
# elif defined ( TARGET_M68K )
print_insn = print_insn_m68k ;
410
# elif defined ( TARGET_MIPS )
411
# ifdef TARGET_WORDS_BIGENDIAN
412
print_insn = print_insn_big_mips ;
413
414
415
# else
print_insn = print_insn_little_mips ;
# endif
416
# else
417
418
term_printf ( "0x" TARGET_FMT_lx
": Asm output not supported on this arch \n " , pc );
419
420
421
422
return ;
# endif
for ( i = 0 ; i < nb_insn ; i ++ ) {
423
term_printf ( "0x" TARGET_FMT_lx ": " , pc );
424
count = print_insn ( pc , & disasm_info );
425
term_printf ( " \n " );
426
427
428
429
430
431
if ( count < 0 )
break ;
pc += count ;
}
}
# endif