Newer
Older
/* $Id$ */
#include <common.h>
#include <linux/ctype.h>
#include <bedbug/bedbug.h>
#include <bedbug/ppc.h>
#include <bedbug/regs.h>
#include <bedbug/tables.h>
#define Elf32_Word unsigned long
/* USE_SOURCE_CODE enables some symbolic debugging functions of this
code. This is only useful if the program will have access to the
source code for the binary being examined.
*/
/* #define USE_SOURCE_CODE 1 */
#ifdef USE_SOURCE_CODE
extern int line_info_from_addr __P ((Elf32_Word, char *, char *, int *));
extern struct symreflist *symByAddr;
extern char *symbol_name_from_addr __P ((Elf32_Word, int, int *));
#endif /* USE_SOURCE_CODE */
int print_operands __P ((struct ppc_ctx *));
int get_operand_value __P ((struct opcode *, unsigned long,
struct opcode *find_opcode __P ((unsigned long));
struct opcode *find_opcode_by_name __P ((char *));
char *spr_name __P ((int));
int spr_value __P ((char *));
char *tbr_name __P ((int));
int tbr_value __P ((char *));
int parse_operand __P ((unsigned long, struct opcode *,
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
int get_word __P ((char **, char *));
long read_number __P ((char *));
int downstring __P ((char *));
/*======================================================================
* Entry point for the PPC disassembler.
*
* Arguments:
* memaddr The address to start disassembling from.
*
* virtual If this value is non-zero, then this will be
* used as the base address for the output and
* symbol lookups. If this value is zero then
* memaddr is used as the absolute address.
*
* num_instr The number of instructions to disassemble. Since
* each instruction is 32 bits long, this can be
* computed if you know the total size of the region.
*
* pfunc The address of a function that is called to print
* each line of output. The function should take a
* single character pointer as its parameters a la puts.
*
* flags Sets options for the output. This is a
* bitwise-inclusive-OR of the following
* values. Note that only one of the radix
* options may be set.
*
* F_RADOCTAL - output radix is unsigned base 8.
* F_RADUDECIMAL - output radix is unsigned base 10.
* F_RADSDECIMAL - output radix is signed base 10.
* F_RADHEX - output radix is unsigned base 16.
* F_SIMPLE - use simplified mnemonics.
* F_SYMBOL - lookup symbols for addresses.
* F_INSTR - output raw instruction.
* F_LINENO - show line # info if available.
*
* Returns true if the area was successfully disassembled or false if
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
* a problem was encountered with accessing the memory.
*/
int disppc (unsigned char *memaddr, unsigned char *virtual, int num_instr,
int (*pfunc) (const char *), unsigned long flags)
{
int i;
struct ppc_ctx ctx;
#ifdef USE_SOURCE_CODE
int line_no = 0;
int last_line_no = 0;
char funcname[128] = { 0 };
char filename[256] = { 0 };
char last_funcname[128] = { 0 };
int symoffset;
char *symname;
char *cursym = (char *) 0;
#endif /* USE_SOURCE_CODE */
/*------------------------------------------------------------*/
ctx.flags = flags;
ctx.virtual = virtual;
/* Figure out the output radix before we go any further */
if (ctx.flags & F_RADOCTAL) {
/* Unsigned octal output */
strcpy (ctx.radix_fmt, "O%o");
} else if (ctx.flags & F_RADUDECIMAL) {
/* Unsigned decimal output */
strcpy (ctx.radix_fmt, "%u");
} else if (ctx.flags & F_RADSDECIMAL) {
/* Signed decimal output */
strcpy (ctx.radix_fmt, "%d");
} else {
/* Unsigned hex output */
strcpy (ctx.radix_fmt, "0x%x");
}
if (ctx.virtual == 0) {
ctx.virtual = memaddr;
}
#ifdef USE_SOURCE_CODE
if (ctx.flags & F_SYMBOL) {
if (symByAddr == 0) /* no symbols loaded */
ctx.flags &= ~F_SYMBOL;
else {
cursym = (char *) 0;
symoffset = 0;
}
}
#endif /* USE_SOURCE_CODE */
/* format each line as "XXXXXXXX: <symbol> IIIIIIII disassembly" where,
XXXXXXXX is the memory address in hex,
<symbol> is the symbolic location if F_SYMBOL is set.
IIIIIIII is the raw machine code in hex if F_INSTR is set,
and disassembly is the disassembled machine code with numbers
formatted according to the 'radix' parameter */
for (i = 0; i < num_instr; ++i, memaddr += 4, ctx.virtual += 4) {
#ifdef USE_SOURCE_CODE
if (ctx.flags & F_LINENO) {
if ((line_info_from_addr ((Elf32_Word) ctx.virtual,
filename, funcname, &line_no) == true) &&
((line_no != last_line_no) ||
(strcmp (last_funcname, funcname) != 0))) {
print_source_line (filename, funcname, line_no, pfunc);
}
last_line_no = line_no;
strcpy (last_funcname, funcname);
}
#endif /* USE_SOURCE_CODE */
sprintf (ctx.data, "%08lx: ", (unsigned long) ctx.virtual);
ctx.datalen = 10;
#ifdef USE_SOURCE_CODE
if (ctx.flags & F_SYMBOL) {
if ((symname =
symbol_name_from_addr((Elf32_Word) ctx.virtual,
true, 0)) != 0) {
cursym = symname;
symoffset = 0;
} else {
if ((cursym == 0) &&
((symname =
symbol_name_from_addr((Elf32_Word) ctx.virtual,
false, &symoffset)) != 0)) {
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
cursym = symname;
} else {
symoffset += 4;
}
}
if (cursym != 0) {
sprintf (&ctx.data[ctx.datalen], "<%s+", cursym);
ctx.datalen = strlen (ctx.data);
sprintf (&ctx.data[ctx.datalen], ctx.radix_fmt, symoffset);
strcat (ctx.data, ">");
ctx.datalen = strlen (ctx.data);
}
}
#endif /* USE_SOURCE_CODE */
ctx.instr = INSTRUCTION (memaddr);
if (ctx.flags & F_INSTR) {
/* Find the opcode structure for this opcode. If one is not found
then it must be an illegal instruction */
sprintf (&ctx.data[ctx.datalen],
" %02lx %02lx %02lx %02lx ",
((ctx.instr >> 24) & 0xff),
((ctx.instr >> 16) & 0xff), ((ctx.instr >> 8) & 0xff),
(ctx.instr & 0xff));
ctx.datalen += 18;
} else {
strcat (ctx.data, " ");
ctx.datalen += 3;
}
if ((ctx.op = find_opcode (ctx.instr)) == 0) {
/* Illegal Opcode */
sprintf (&ctx.data[ctx.datalen], " .long 0x%08lx",
Loading
Loading full blame...