1*4882a593Smuzhiyun /* $Id$ */
2*4882a593Smuzhiyun
3*4882a593Smuzhiyun #include <common.h>
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun #include <linux/ctype.h>
6*4882a593Smuzhiyun #include <bedbug/bedbug.h>
7*4882a593Smuzhiyun #include <bedbug/ppc.h>
8*4882a593Smuzhiyun #include <bedbug/regs.h>
9*4882a593Smuzhiyun #include <bedbug/tables.h>
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #define Elf32_Word unsigned long
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun /* USE_SOURCE_CODE enables some symbolic debugging functions of this
14*4882a593Smuzhiyun code. This is only useful if the program will have access to the
15*4882a593Smuzhiyun source code for the binary being examined.
16*4882a593Smuzhiyun */
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun /* #define USE_SOURCE_CODE 1 */
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #ifdef USE_SOURCE_CODE
21*4882a593Smuzhiyun extern int line_info_from_addr __P ((Elf32_Word, char *, char *, int *));
22*4882a593Smuzhiyun extern struct symreflist *symByAddr;
23*4882a593Smuzhiyun extern char *symbol_name_from_addr __P ((Elf32_Word, int, int *));
24*4882a593Smuzhiyun #endif /* USE_SOURCE_CODE */
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun int print_operands __P ((struct ppc_ctx *));
27*4882a593Smuzhiyun int get_operand_value __P ((struct opcode *, unsigned long,
28*4882a593Smuzhiyun enum OP_FIELD, unsigned long *));
29*4882a593Smuzhiyun struct opcode *find_opcode __P ((unsigned long));
30*4882a593Smuzhiyun struct opcode *find_opcode_by_name __P ((char *));
31*4882a593Smuzhiyun char *spr_name __P ((int));
32*4882a593Smuzhiyun int spr_value __P ((char *));
33*4882a593Smuzhiyun char *tbr_name __P ((int));
34*4882a593Smuzhiyun int tbr_value __P ((char *));
35*4882a593Smuzhiyun int parse_operand __P ((unsigned long, struct opcode *,
36*4882a593Smuzhiyun struct operand *, char *, int *));
37*4882a593Smuzhiyun int get_word __P ((char **, char *));
38*4882a593Smuzhiyun long read_number __P ((char *));
39*4882a593Smuzhiyun int downstring __P ((char *));
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun /*======================================================================
43*4882a593Smuzhiyun * Entry point for the PPC disassembler.
44*4882a593Smuzhiyun *
45*4882a593Smuzhiyun * Arguments:
46*4882a593Smuzhiyun * memaddr The address to start disassembling from.
47*4882a593Smuzhiyun *
48*4882a593Smuzhiyun * virtual If this value is non-zero, then this will be
49*4882a593Smuzhiyun * used as the base address for the output and
50*4882a593Smuzhiyun * symbol lookups. If this value is zero then
51*4882a593Smuzhiyun * memaddr is used as the absolute address.
52*4882a593Smuzhiyun *
53*4882a593Smuzhiyun * num_instr The number of instructions to disassemble. Since
54*4882a593Smuzhiyun * each instruction is 32 bits long, this can be
55*4882a593Smuzhiyun * computed if you know the total size of the region.
56*4882a593Smuzhiyun *
57*4882a593Smuzhiyun * pfunc The address of a function that is called to print
58*4882a593Smuzhiyun * each line of output. The function should take a
59*4882a593Smuzhiyun * single character pointer as its parameters a la puts.
60*4882a593Smuzhiyun *
61*4882a593Smuzhiyun * flags Sets options for the output. This is a
62*4882a593Smuzhiyun * bitwise-inclusive-OR of the following
63*4882a593Smuzhiyun * values. Note that only one of the radix
64*4882a593Smuzhiyun * options may be set.
65*4882a593Smuzhiyun *
66*4882a593Smuzhiyun * F_RADOCTAL - output radix is unsigned base 8.
67*4882a593Smuzhiyun * F_RADUDECIMAL - output radix is unsigned base 10.
68*4882a593Smuzhiyun * F_RADSDECIMAL - output radix is signed base 10.
69*4882a593Smuzhiyun * F_RADHEX - output radix is unsigned base 16.
70*4882a593Smuzhiyun * F_SIMPLE - use simplified mnemonics.
71*4882a593Smuzhiyun * F_SYMBOL - lookup symbols for addresses.
72*4882a593Smuzhiyun * F_INSTR - output raw instruction.
73*4882a593Smuzhiyun * F_LINENO - show line # info if available.
74*4882a593Smuzhiyun *
75*4882a593Smuzhiyun * Returns true if the area was successfully disassembled or false if
76*4882a593Smuzhiyun * a problem was encountered with accessing the memory.
77*4882a593Smuzhiyun */
78*4882a593Smuzhiyun
disppc(unsigned char * memaddr,unsigned char * virtual,int num_instr,int (* pfunc)(const char *),unsigned long flags)79*4882a593Smuzhiyun int disppc (unsigned char *memaddr, unsigned char *virtual, int num_instr,
80*4882a593Smuzhiyun int (*pfunc) (const char *), unsigned long flags)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun int i;
83*4882a593Smuzhiyun struct ppc_ctx ctx;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun #ifdef USE_SOURCE_CODE
86*4882a593Smuzhiyun int line_no = 0;
87*4882a593Smuzhiyun int last_line_no = 0;
88*4882a593Smuzhiyun char funcname[128] = { 0 };
89*4882a593Smuzhiyun char filename[256] = { 0 };
90*4882a593Smuzhiyun char last_funcname[128] = { 0 };
91*4882a593Smuzhiyun int symoffset;
92*4882a593Smuzhiyun char *symname;
93*4882a593Smuzhiyun char *cursym = (char *) 0;
94*4882a593Smuzhiyun #endif /* USE_SOURCE_CODE */
95*4882a593Smuzhiyun /*------------------------------------------------------------*/
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun ctx.flags = flags;
98*4882a593Smuzhiyun ctx.virtual = virtual;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun /* Figure out the output radix before we go any further */
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun if (ctx.flags & F_RADOCTAL) {
103*4882a593Smuzhiyun /* Unsigned octal output */
104*4882a593Smuzhiyun strcpy (ctx.radix_fmt, "O%o");
105*4882a593Smuzhiyun } else if (ctx.flags & F_RADUDECIMAL) {
106*4882a593Smuzhiyun /* Unsigned decimal output */
107*4882a593Smuzhiyun strcpy (ctx.radix_fmt, "%u");
108*4882a593Smuzhiyun } else if (ctx.flags & F_RADSDECIMAL) {
109*4882a593Smuzhiyun /* Signed decimal output */
110*4882a593Smuzhiyun strcpy (ctx.radix_fmt, "%d");
111*4882a593Smuzhiyun } else {
112*4882a593Smuzhiyun /* Unsigned hex output */
113*4882a593Smuzhiyun strcpy (ctx.radix_fmt, "0x%x");
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun if (ctx.virtual == 0) {
117*4882a593Smuzhiyun ctx.virtual = memaddr;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun #ifdef USE_SOURCE_CODE
120*4882a593Smuzhiyun if (ctx.flags & F_SYMBOL) {
121*4882a593Smuzhiyun if (symByAddr == 0) /* no symbols loaded */
122*4882a593Smuzhiyun ctx.flags &= ~F_SYMBOL;
123*4882a593Smuzhiyun else {
124*4882a593Smuzhiyun cursym = (char *) 0;
125*4882a593Smuzhiyun symoffset = 0;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun #endif /* USE_SOURCE_CODE */
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun /* format each line as "XXXXXXXX: <symbol> IIIIIIII disassembly" where,
131*4882a593Smuzhiyun XXXXXXXX is the memory address in hex,
132*4882a593Smuzhiyun <symbol> is the symbolic location if F_SYMBOL is set.
133*4882a593Smuzhiyun IIIIIIII is the raw machine code in hex if F_INSTR is set,
134*4882a593Smuzhiyun and disassembly is the disassembled machine code with numbers
135*4882a593Smuzhiyun formatted according to the 'radix' parameter */
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun for (i = 0; i < num_instr; ++i, memaddr += 4, ctx.virtual += 4) {
138*4882a593Smuzhiyun #ifdef USE_SOURCE_CODE
139*4882a593Smuzhiyun if (ctx.flags & F_LINENO) {
140*4882a593Smuzhiyun if ((line_info_from_addr ((Elf32_Word) ctx.virtual,
141*4882a593Smuzhiyun filename, funcname, &line_no) == true) &&
142*4882a593Smuzhiyun ((line_no != last_line_no) ||
143*4882a593Smuzhiyun (strcmp (last_funcname, funcname) != 0))) {
144*4882a593Smuzhiyun print_source_line (filename, funcname, line_no, pfunc);
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun last_line_no = line_no;
147*4882a593Smuzhiyun strcpy (last_funcname, funcname);
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun #endif /* USE_SOURCE_CODE */
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun sprintf (ctx.data, "%08lx: ", (unsigned long) ctx.virtual);
152*4882a593Smuzhiyun ctx.datalen = 10;
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun #ifdef USE_SOURCE_CODE
155*4882a593Smuzhiyun if (ctx.flags & F_SYMBOL) {
156*4882a593Smuzhiyun if ((symname =
157*4882a593Smuzhiyun symbol_name_from_addr((Elf32_Word) ctx.virtual,
158*4882a593Smuzhiyun true, 0)) != 0) {
159*4882a593Smuzhiyun cursym = symname;
160*4882a593Smuzhiyun symoffset = 0;
161*4882a593Smuzhiyun } else {
162*4882a593Smuzhiyun if ((cursym == 0) &&
163*4882a593Smuzhiyun ((symname =
164*4882a593Smuzhiyun symbol_name_from_addr((Elf32_Word) ctx.virtual,
165*4882a593Smuzhiyun false, &symoffset)) != 0)) {
166*4882a593Smuzhiyun cursym = symname;
167*4882a593Smuzhiyun } else {
168*4882a593Smuzhiyun symoffset += 4;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun if (cursym != 0) {
173*4882a593Smuzhiyun sprintf (&ctx.data[ctx.datalen], "<%s+", cursym);
174*4882a593Smuzhiyun ctx.datalen = strlen (ctx.data);
175*4882a593Smuzhiyun sprintf (&ctx.data[ctx.datalen], ctx.radix_fmt, symoffset);
176*4882a593Smuzhiyun strcat (ctx.data, ">");
177*4882a593Smuzhiyun ctx.datalen = strlen (ctx.data);
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun #endif /* USE_SOURCE_CODE */
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun ctx.instr = INSTRUCTION (memaddr);
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun if (ctx.flags & F_INSTR) {
185*4882a593Smuzhiyun /* Find the opcode structure for this opcode. If one is not found
186*4882a593Smuzhiyun then it must be an illegal instruction */
187*4882a593Smuzhiyun sprintf (&ctx.data[ctx.datalen],
188*4882a593Smuzhiyun " %02lx %02lx %02lx %02lx ",
189*4882a593Smuzhiyun ((ctx.instr >> 24) & 0xff),
190*4882a593Smuzhiyun ((ctx.instr >> 16) & 0xff), ((ctx.instr >> 8) & 0xff),
191*4882a593Smuzhiyun (ctx.instr & 0xff));
192*4882a593Smuzhiyun ctx.datalen += 18;
193*4882a593Smuzhiyun } else {
194*4882a593Smuzhiyun strcat (ctx.data, " ");
195*4882a593Smuzhiyun ctx.datalen += 3;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun if ((ctx.op = find_opcode (ctx.instr)) == 0) {
199*4882a593Smuzhiyun /* Illegal Opcode */
200*4882a593Smuzhiyun sprintf (&ctx.data[ctx.datalen], " .long 0x%08lx",
201*4882a593Smuzhiyun ctx.instr);
202*4882a593Smuzhiyun ctx.datalen += 24;
203*4882a593Smuzhiyun (*pfunc) (ctx.data);
204*4882a593Smuzhiyun continue;
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun if (((ctx.flags & F_SIMPLE) == 0) ||
208*4882a593Smuzhiyun (ctx.op->hfunc == 0) ||
209*4882a593Smuzhiyun ((*ctx.op->hfunc) (&ctx) == false)) {
210*4882a593Smuzhiyun sprintf (&ctx.data[ctx.datalen], "%-7s ", ctx.op->name);
211*4882a593Smuzhiyun ctx.datalen += 8;
212*4882a593Smuzhiyun print_operands (&ctx);
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun (*pfunc) (ctx.data);
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun return true;
219*4882a593Smuzhiyun } /* disppc */
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun /*======================================================================
224*4882a593Smuzhiyun * Called by the disassembler to print the operands for an instruction.
225*4882a593Smuzhiyun *
226*4882a593Smuzhiyun * Arguments:
227*4882a593Smuzhiyun * ctx A pointer to the disassembler context record.
228*4882a593Smuzhiyun *
229*4882a593Smuzhiyun * always returns 0.
230*4882a593Smuzhiyun */
231*4882a593Smuzhiyun
print_operands(struct ppc_ctx * ctx)232*4882a593Smuzhiyun int print_operands (struct ppc_ctx *ctx)
233*4882a593Smuzhiyun {
234*4882a593Smuzhiyun int open_parens = 0;
235*4882a593Smuzhiyun int field;
236*4882a593Smuzhiyun unsigned long operand;
237*4882a593Smuzhiyun struct operand *opr;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun #ifdef USE_SOURCE_CODE
240*4882a593Smuzhiyun char *symname;
241*4882a593Smuzhiyun int offset;
242*4882a593Smuzhiyun #endif /* USE_SOURCE_CODE */
243*4882a593Smuzhiyun /*------------------------------------------------------------*/
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun /* Walk through the operands and list each in order */
246*4882a593Smuzhiyun for (field = 0; ctx->op->fields[field] != 0; ++field) {
247*4882a593Smuzhiyun if (ctx->op->fields[field] > n_operands) {
248*4882a593Smuzhiyun continue; /* bad operand ?! */
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun opr = &operands[ctx->op->fields[field] - 1];
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun if (opr->hint & OH_SILENT) {
254*4882a593Smuzhiyun continue;
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun if ((field > 0) && !open_parens) {
258*4882a593Smuzhiyun strcat (ctx->data, ",");
259*4882a593Smuzhiyun ctx->datalen++;
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun operand = (ctx->instr >> opr->shift) & ((1 << opr->bits) - 1);
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun if (opr->hint & OH_ADDR) {
265*4882a593Smuzhiyun if ((operand & (1 << (opr->bits - 1))) != 0) {
266*4882a593Smuzhiyun operand = operand - (1 << opr->bits);
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun if (ctx->op->hint & H_RELATIVE)
270*4882a593Smuzhiyun operand = (operand << 2) + (unsigned long) ctx->virtual;
271*4882a593Smuzhiyun else
272*4882a593Smuzhiyun operand = (operand << 2);
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun sprintf (&ctx->data[ctx->datalen], "0x%lx", operand);
276*4882a593Smuzhiyun ctx->datalen = strlen (ctx->data);
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun #ifdef USE_SOURCE_CODE
279*4882a593Smuzhiyun if ((ctx->flags & F_SYMBOL) &&
280*4882a593Smuzhiyun ((symname =
281*4882a593Smuzhiyun symbol_name_from_addr (operand, 0, &offset)) != 0)) {
282*4882a593Smuzhiyun sprintf (&ctx->data[ctx->datalen], " <%s", symname);
283*4882a593Smuzhiyun if (offset != 0) {
284*4882a593Smuzhiyun strcat (ctx->data, "+");
285*4882a593Smuzhiyun ctx->datalen = strlen (ctx->data);
286*4882a593Smuzhiyun sprintf (&ctx->data[ctx->datalen], ctx->radix_fmt,
287*4882a593Smuzhiyun offset);
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun strcat (ctx->data, ">");
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun #endif /* USE_SOURCE_CODE */
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun else if (opr->hint & OH_REG) {
295*4882a593Smuzhiyun if ((operand == 0) &&
296*4882a593Smuzhiyun (opr->field == O_rA) && (ctx->op->hint & H_RA0_IS_0)) {
297*4882a593Smuzhiyun strcat (ctx->data, "0");
298*4882a593Smuzhiyun } else {
299*4882a593Smuzhiyun sprintf (&ctx->data[ctx->datalen], "r%d", (short) operand);
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun if (open_parens) {
303*4882a593Smuzhiyun strcat (ctx->data, ")");
304*4882a593Smuzhiyun open_parens--;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun else if (opr->hint & OH_SPR) {
309*4882a593Smuzhiyun strcat (ctx->data, spr_name (operand));
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun else if (opr->hint & OH_TBR) {
313*4882a593Smuzhiyun strcat (ctx->data, tbr_name (operand));
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun else if (opr->hint & OH_LITERAL) {
317*4882a593Smuzhiyun switch (opr->field) {
318*4882a593Smuzhiyun case O_cr2:
319*4882a593Smuzhiyun strcat (ctx->data, "cr2");
320*4882a593Smuzhiyun ctx->datalen += 3;
321*4882a593Smuzhiyun break;
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun default:
324*4882a593Smuzhiyun break;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun else {
329*4882a593Smuzhiyun sprintf (&ctx->data[ctx->datalen], ctx->radix_fmt,
330*4882a593Smuzhiyun (unsigned short) operand);
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun if (open_parens) {
333*4882a593Smuzhiyun strcat (ctx->data, ")");
334*4882a593Smuzhiyun open_parens--;
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun else if (opr->hint & OH_OFFSET) {
338*4882a593Smuzhiyun strcat (ctx->data, "(");
339*4882a593Smuzhiyun open_parens++;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun ctx->datalen = strlen (ctx->data);
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun return 0;
347*4882a593Smuzhiyun } /* print_operands */
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun /*======================================================================
352*4882a593Smuzhiyun * Called to get the value of an arbitrary operand with in an instruction.
353*4882a593Smuzhiyun *
354*4882a593Smuzhiyun * Arguments:
355*4882a593Smuzhiyun * op The pointer to the opcode structure to which
356*4882a593Smuzhiyun * the operands belong.
357*4882a593Smuzhiyun *
358*4882a593Smuzhiyun * instr The instruction (32 bits) containing the opcode
359*4882a593Smuzhiyun * and the operands to print. By the time that
360*4882a593Smuzhiyun * this routine is called the operand has already
361*4882a593Smuzhiyun * been added to the output.
362*4882a593Smuzhiyun *
363*4882a593Smuzhiyun * field The field (operand) to get the value of.
364*4882a593Smuzhiyun *
365*4882a593Smuzhiyun * value The address of an unsigned long to be filled in
366*4882a593Smuzhiyun * with the value of the operand if it is found. This
367*4882a593Smuzhiyun * will only be filled in if the function returns
368*4882a593Smuzhiyun * true. This may be passed as 0 if the value is
369*4882a593Smuzhiyun * not required.
370*4882a593Smuzhiyun *
371*4882a593Smuzhiyun * Returns true if the operand was found or false if it was not.
372*4882a593Smuzhiyun */
373*4882a593Smuzhiyun
get_operand_value(struct opcode * op,unsigned long instr,enum OP_FIELD field,unsigned long * value)374*4882a593Smuzhiyun int get_operand_value (struct opcode *op, unsigned long instr,
375*4882a593Smuzhiyun enum OP_FIELD field, unsigned long *value)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun int i;
378*4882a593Smuzhiyun struct operand *opr;
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun /*------------------------------------------------------------*/
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun if (field > n_operands) {
383*4882a593Smuzhiyun return false; /* bad operand ?! */
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun /* Walk through the operands and list each in order */
387*4882a593Smuzhiyun for (i = 0; op->fields[i] != 0; ++i) {
388*4882a593Smuzhiyun if (op->fields[i] != field) {
389*4882a593Smuzhiyun continue;
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun opr = &operands[op->fields[i] - 1];
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun if (value) {
395*4882a593Smuzhiyun *value = (instr >> opr->shift) & ((1 << opr->bits) - 1);
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun return true;
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun return false;
401*4882a593Smuzhiyun } /* operand_value */
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun /*======================================================================
406*4882a593Smuzhiyun * Called by the disassembler to match an opcode value to an opcode structure.
407*4882a593Smuzhiyun *
408*4882a593Smuzhiyun * Arguments:
409*4882a593Smuzhiyun * instr The instruction (32 bits) to match. This value
410*4882a593Smuzhiyun * may contain operand values as well as the opcode
411*4882a593Smuzhiyun * since they will be masked out anyway for this
412*4882a593Smuzhiyun * search.
413*4882a593Smuzhiyun *
414*4882a593Smuzhiyun * Returns the address of an opcode struct (from the opcode table) if the
415*4882a593Smuzhiyun * operand successfully matched an entry, or 0 if no match was found.
416*4882a593Smuzhiyun */
417*4882a593Smuzhiyun
find_opcode(unsigned long instr)418*4882a593Smuzhiyun struct opcode *find_opcode (unsigned long instr)
419*4882a593Smuzhiyun {
420*4882a593Smuzhiyun struct opcode *ptr;
421*4882a593Smuzhiyun int top = 0;
422*4882a593Smuzhiyun int bottom = n_opcodes - 1;
423*4882a593Smuzhiyun int idx;
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun /*------------------------------------------------------------*/
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun while (top <= bottom) {
428*4882a593Smuzhiyun idx = (top + bottom) >> 1;
429*4882a593Smuzhiyun ptr = &opcodes[idx];
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun if ((instr & ptr->mask) < ptr->opcode) {
432*4882a593Smuzhiyun bottom = idx - 1;
433*4882a593Smuzhiyun } else if ((instr & ptr->mask) > ptr->opcode) {
434*4882a593Smuzhiyun top = idx + 1;
435*4882a593Smuzhiyun } else {
436*4882a593Smuzhiyun return ptr;
437*4882a593Smuzhiyun }
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun return (struct opcode *) 0;
441*4882a593Smuzhiyun } /* find_opcode */
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun /*======================================================================
446*4882a593Smuzhiyun * Called by the assembler to match an opcode name to an opcode structure.
447*4882a593Smuzhiyun *
448*4882a593Smuzhiyun * Arguments:
449*4882a593Smuzhiyun * name The text name of the opcode, e.g. "b", "mtspr", etc.
450*4882a593Smuzhiyun *
451*4882a593Smuzhiyun * The opcodes are sorted numerically by their instruction binary code
452*4882a593Smuzhiyun * so a search for the name cannot use the binary search used by the
453*4882a593Smuzhiyun * other find routine.
454*4882a593Smuzhiyun *
455*4882a593Smuzhiyun * Returns the address of an opcode struct (from the opcode table) if the
456*4882a593Smuzhiyun * name successfully matched an entry, or 0 if no match was found.
457*4882a593Smuzhiyun */
458*4882a593Smuzhiyun
find_opcode_by_name(char * name)459*4882a593Smuzhiyun struct opcode *find_opcode_by_name (char *name)
460*4882a593Smuzhiyun {
461*4882a593Smuzhiyun int idx;
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun /*------------------------------------------------------------*/
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun downstring (name);
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun for (idx = 0; idx < n_opcodes; ++idx) {
468*4882a593Smuzhiyun if (!strcmp (name, opcodes[idx].name))
469*4882a593Smuzhiyun return &opcodes[idx];
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun return (struct opcode *) 0;
473*4882a593Smuzhiyun } /* find_opcode_by_name */
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun /*======================================================================
478*4882a593Smuzhiyun * Convert the 'spr' operand from its numeric value to its symbolic name.
479*4882a593Smuzhiyun *
480*4882a593Smuzhiyun * Arguments:
481*4882a593Smuzhiyun * value The value of the 'spr' operand. This value should
482*4882a593Smuzhiyun * be unmodified from its encoding in the instruction.
483*4882a593Smuzhiyun * the split-field computations will be performed
484*4882a593Smuzhiyun * here before the switch.
485*4882a593Smuzhiyun *
486*4882a593Smuzhiyun * Returns the address of a character array containing the name of the
487*4882a593Smuzhiyun * special purpose register defined by the 'value' parameter, or the
488*4882a593Smuzhiyun * address of a character array containing "???" if no match was found.
489*4882a593Smuzhiyun */
490*4882a593Smuzhiyun
spr_name(int value)491*4882a593Smuzhiyun char *spr_name (int value)
492*4882a593Smuzhiyun {
493*4882a593Smuzhiyun unsigned short spr;
494*4882a593Smuzhiyun static char other[10];
495*4882a593Smuzhiyun int i;
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun /*------------------------------------------------------------*/
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun /* spr is a 10 bit field whose interpretation has the high and low
500*4882a593Smuzhiyun five-bit fields reversed from their encoding in the operand */
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun spr = ((value >> 5) & 0x1f) | ((value & 0x1f) << 5);
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun for (i = 0; i < n_sprs; ++i) {
505*4882a593Smuzhiyun if (spr == spr_map[i].spr_val)
506*4882a593Smuzhiyun return spr_map[i].spr_name;
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun sprintf (other, "%d", spr);
510*4882a593Smuzhiyun return other;
511*4882a593Smuzhiyun } /* spr_name */
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun /*======================================================================
516*4882a593Smuzhiyun * Convert the 'spr' operand from its symbolic name to its numeric value
517*4882a593Smuzhiyun *
518*4882a593Smuzhiyun * Arguments:
519*4882a593Smuzhiyun * name The symbolic name of the 'spr' operand. The
520*4882a593Smuzhiyun * split-field encoding will be done by this routine.
521*4882a593Smuzhiyun * NOTE: name can be a number.
522*4882a593Smuzhiyun *
523*4882a593Smuzhiyun * Returns the numeric value for the spr appropriate for encoding a machine
524*4882a593Smuzhiyun * instruction. Returns 0 if unable to find the SPR.
525*4882a593Smuzhiyun */
526*4882a593Smuzhiyun
spr_value(char * name)527*4882a593Smuzhiyun int spr_value (char *name)
528*4882a593Smuzhiyun {
529*4882a593Smuzhiyun struct spr_info *sprp;
530*4882a593Smuzhiyun int spr;
531*4882a593Smuzhiyun int i;
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun /*------------------------------------------------------------*/
534*4882a593Smuzhiyun
535*4882a593Smuzhiyun if (!name || !*name)
536*4882a593Smuzhiyun return 0;
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun if (isdigit ((int) name[0])) {
539*4882a593Smuzhiyun i = htonl (read_number (name));
540*4882a593Smuzhiyun spr = ((i >> 5) & 0x1f) | ((i & 0x1f) << 5);
541*4882a593Smuzhiyun return spr;
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun downstring (name);
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun for (i = 0; i < n_sprs; ++i) {
547*4882a593Smuzhiyun sprp = &spr_map[i];
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun if (strcmp (name, sprp->spr_name) == 0) {
550*4882a593Smuzhiyun /* spr is a 10 bit field whose interpretation has the high and low
551*4882a593Smuzhiyun five-bit fields reversed from their encoding in the operand */
552*4882a593Smuzhiyun i = htonl (sprp->spr_val);
553*4882a593Smuzhiyun spr = ((i >> 5) & 0x1f) | ((i & 0x1f) << 5);
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun return spr;
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun return 0;
560*4882a593Smuzhiyun } /* spr_value */
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun /*======================================================================
565*4882a593Smuzhiyun * Convert the 'tbr' operand from its numeric value to its symbolic name.
566*4882a593Smuzhiyun *
567*4882a593Smuzhiyun * Arguments:
568*4882a593Smuzhiyun * value The value of the 'tbr' operand. This value should
569*4882a593Smuzhiyun * be unmodified from its encoding in the instruction.
570*4882a593Smuzhiyun * the split-field computations will be performed
571*4882a593Smuzhiyun * here before the switch.
572*4882a593Smuzhiyun *
573*4882a593Smuzhiyun * Returns the address of a character array containing the name of the
574*4882a593Smuzhiyun * time base register defined by the 'value' parameter, or the address
575*4882a593Smuzhiyun * of a character array containing "???" if no match was found.
576*4882a593Smuzhiyun */
577*4882a593Smuzhiyun
tbr_name(int value)578*4882a593Smuzhiyun char *tbr_name (int value)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun unsigned short tbr;
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun /*------------------------------------------------------------*/
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun /* tbr is a 10 bit field whose interpretation has the high and low
585*4882a593Smuzhiyun five-bit fields reversed from their encoding in the operand */
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun tbr = ((value >> 5) & 0x1f) | ((value & 0x1f) << 5);
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun if (tbr == 268)
590*4882a593Smuzhiyun return "TBL";
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun else if (tbr == 269)
593*4882a593Smuzhiyun return "TBU";
594*4882a593Smuzhiyun
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun return "???";
597*4882a593Smuzhiyun } /* tbr_name */
598*4882a593Smuzhiyun
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun /*======================================================================
602*4882a593Smuzhiyun * Convert the 'tbr' operand from its symbolic name to its numeric value.
603*4882a593Smuzhiyun *
604*4882a593Smuzhiyun * Arguments:
605*4882a593Smuzhiyun * name The symbolic name of the 'tbr' operand. The
606*4882a593Smuzhiyun * split-field encoding will be done by this routine.
607*4882a593Smuzhiyun *
608*4882a593Smuzhiyun * Returns the numeric value for the spr appropriate for encoding a machine
609*4882a593Smuzhiyun * instruction. Returns 0 if unable to find the TBR.
610*4882a593Smuzhiyun */
611*4882a593Smuzhiyun
tbr_value(char * name)612*4882a593Smuzhiyun int tbr_value (char *name)
613*4882a593Smuzhiyun {
614*4882a593Smuzhiyun int tbr;
615*4882a593Smuzhiyun int val;
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun /*------------------------------------------------------------*/
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun if (!name || !*name)
620*4882a593Smuzhiyun return 0;
621*4882a593Smuzhiyun
622*4882a593Smuzhiyun downstring (name);
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun if (isdigit ((int) name[0])) {
625*4882a593Smuzhiyun val = read_number (name);
626*4882a593Smuzhiyun
627*4882a593Smuzhiyun if (val != 268 && val != 269)
628*4882a593Smuzhiyun return 0;
629*4882a593Smuzhiyun } else if (strcmp (name, "tbl") == 0)
630*4882a593Smuzhiyun val = 268;
631*4882a593Smuzhiyun else if (strcmp (name, "tbu") == 0)
632*4882a593Smuzhiyun val = 269;
633*4882a593Smuzhiyun else
634*4882a593Smuzhiyun return 0;
635*4882a593Smuzhiyun
636*4882a593Smuzhiyun /* tbr is a 10 bit field whose interpretation has the high and low
637*4882a593Smuzhiyun five-bit fields reversed from their encoding in the operand */
638*4882a593Smuzhiyun
639*4882a593Smuzhiyun val = htonl (val);
640*4882a593Smuzhiyun tbr = ((val >> 5) & 0x1f) | ((val & 0x1f) << 5);
641*4882a593Smuzhiyun return tbr;
642*4882a593Smuzhiyun } /* tbr_name */
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun
646*4882a593Smuzhiyun /*======================================================================
647*4882a593Smuzhiyun * The next several functions (handle_xxx) are the routines that handle
648*4882a593Smuzhiyun * disassembling the opcodes with simplified mnemonics.
649*4882a593Smuzhiyun *
650*4882a593Smuzhiyun * Arguments:
651*4882a593Smuzhiyun * ctx A pointer to the disassembler context record.
652*4882a593Smuzhiyun *
653*4882a593Smuzhiyun * Returns true if the simpler form was printed or false if it was not.
654*4882a593Smuzhiyun */
655*4882a593Smuzhiyun
handle_bc(struct ppc_ctx * ctx)656*4882a593Smuzhiyun int handle_bc (struct ppc_ctx *ctx)
657*4882a593Smuzhiyun {
658*4882a593Smuzhiyun unsigned long bo;
659*4882a593Smuzhiyun unsigned long bi;
660*4882a593Smuzhiyun static struct opcode blt = { B_OPCODE (16, 0, 0), B_MASK, {O_BD, 0},
661*4882a593Smuzhiyun 0, "blt", H_RELATIVE
662*4882a593Smuzhiyun };
663*4882a593Smuzhiyun static struct opcode bne =
664*4882a593Smuzhiyun { B_OPCODE (16, 0, 0), B_MASK, {O_cr2, O_BD, 0},
665*4882a593Smuzhiyun 0, "bne", H_RELATIVE
666*4882a593Smuzhiyun };
667*4882a593Smuzhiyun static struct opcode bdnz = { B_OPCODE (16, 0, 0), B_MASK, {O_BD, 0},
668*4882a593Smuzhiyun 0, "bdnz", H_RELATIVE
669*4882a593Smuzhiyun };
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun /*------------------------------------------------------------*/
672*4882a593Smuzhiyun
673*4882a593Smuzhiyun if (get_operand_value(ctx->op, ctx->instr, O_BO, &bo) == false)
674*4882a593Smuzhiyun return false;
675*4882a593Smuzhiyun
676*4882a593Smuzhiyun if (get_operand_value(ctx->op, ctx->instr, O_BI, &bi) == false)
677*4882a593Smuzhiyun return false;
678*4882a593Smuzhiyun
679*4882a593Smuzhiyun if ((bo == 12) && (bi == 0)) {
680*4882a593Smuzhiyun ctx->op = &blt;
681*4882a593Smuzhiyun sprintf (&ctx->data[ctx->datalen], "%-7s ", ctx->op->name);
682*4882a593Smuzhiyun ctx->datalen += 8;
683*4882a593Smuzhiyun print_operands (ctx);
684*4882a593Smuzhiyun return true;
685*4882a593Smuzhiyun } else if ((bo == 4) && (bi == 10)) {
686*4882a593Smuzhiyun ctx->op = =⃥
687*4882a593Smuzhiyun sprintf (&ctx->data[ctx->datalen], "%-7s ", ctx->op->name);
688*4882a593Smuzhiyun ctx->datalen += 8;
689*4882a593Smuzhiyun print_operands (ctx);
690*4882a593Smuzhiyun return true;
691*4882a593Smuzhiyun } else if ((bo == 16) && (bi == 0)) {
692*4882a593Smuzhiyun ctx->op = &bdnz;
693*4882a593Smuzhiyun sprintf (&ctx->data[ctx->datalen], "%-7s ", ctx->op->name);
694*4882a593Smuzhiyun ctx->datalen += 8;
695*4882a593Smuzhiyun print_operands (ctx);
696*4882a593Smuzhiyun return true;
697*4882a593Smuzhiyun }
698*4882a593Smuzhiyun
699*4882a593Smuzhiyun return false;
700*4882a593Smuzhiyun } /* handle_blt */
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun
704*4882a593Smuzhiyun /*======================================================================
705*4882a593Smuzhiyun * Outputs source line information for the disassembler. This should
706*4882a593Smuzhiyun * be modified in the future to lookup the actual line of source code
707*4882a593Smuzhiyun * from the file, but for now this will do.
708*4882a593Smuzhiyun *
709*4882a593Smuzhiyun * Arguments:
710*4882a593Smuzhiyun * filename The address of a character array containing the
711*4882a593Smuzhiyun * absolute path and file name of the source file.
712*4882a593Smuzhiyun *
713*4882a593Smuzhiyun * funcname The address of a character array containing the
714*4882a593Smuzhiyun * name of the function (not C++ demangled (yet))
715*4882a593Smuzhiyun * to which this code belongs.
716*4882a593Smuzhiyun *
717*4882a593Smuzhiyun * line_no An integer specifying the source line number that
718*4882a593Smuzhiyun * generated this code.
719*4882a593Smuzhiyun *
720*4882a593Smuzhiyun * pfunc The address of a function to call to print the output.
721*4882a593Smuzhiyun *
722*4882a593Smuzhiyun *
723*4882a593Smuzhiyun * Returns true if it was able to output the line info, or false if it was
724*4882a593Smuzhiyun * not.
725*4882a593Smuzhiyun */
726*4882a593Smuzhiyun
print_source_line(char * filename,char * funcname,int line_no,int (* pfunc)(const char *))727*4882a593Smuzhiyun int print_source_line (char *filename, char *funcname,
728*4882a593Smuzhiyun int line_no, int (*pfunc) (const char *))
729*4882a593Smuzhiyun {
730*4882a593Smuzhiyun char out_buf[256];
731*4882a593Smuzhiyun
732*4882a593Smuzhiyun /*------------------------------------------------------------*/
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun (*pfunc) (""); /* output a newline */
735*4882a593Smuzhiyun sprintf (out_buf, "%s %s(): line %d", filename, funcname, line_no);
736*4882a593Smuzhiyun (*pfunc) (out_buf);
737*4882a593Smuzhiyun
738*4882a593Smuzhiyun return true;
739*4882a593Smuzhiyun } /* print_source_line */
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun
742*4882a593Smuzhiyun
743*4882a593Smuzhiyun /*======================================================================
744*4882a593Smuzhiyun * Entry point for the PPC assembler.
745*4882a593Smuzhiyun *
746*4882a593Smuzhiyun * Arguments:
747*4882a593Smuzhiyun * asm_buf An array of characters containing the assembly opcode
748*4882a593Smuzhiyun * and operands to convert to a POWERPC machine
749*4882a593Smuzhiyun * instruction.
750*4882a593Smuzhiyun *
751*4882a593Smuzhiyun * Returns the machine instruction or zero.
752*4882a593Smuzhiyun */
753*4882a593Smuzhiyun
asmppc(unsigned long memaddr,char * asm_buf,int * err)754*4882a593Smuzhiyun unsigned long asmppc (unsigned long memaddr, char *asm_buf, int *err)
755*4882a593Smuzhiyun {
756*4882a593Smuzhiyun struct opcode *opc;
757*4882a593Smuzhiyun struct operand *oper[MAX_OPERANDS];
758*4882a593Smuzhiyun unsigned long instr;
759*4882a593Smuzhiyun unsigned long param;
760*4882a593Smuzhiyun char *ptr = asm_buf;
761*4882a593Smuzhiyun char scratch[20];
762*4882a593Smuzhiyun int i;
763*4882a593Smuzhiyun int w_operands = 0; /* wanted # of operands */
764*4882a593Smuzhiyun int n_operands = 0; /* # of operands read */
765*4882a593Smuzhiyun int asm_debug = 0;
766*4882a593Smuzhiyun
767*4882a593Smuzhiyun /*------------------------------------------------------------*/
768*4882a593Smuzhiyun
769*4882a593Smuzhiyun if (err)
770*4882a593Smuzhiyun *err = 0;
771*4882a593Smuzhiyun
772*4882a593Smuzhiyun if (get_word (&ptr, scratch) == 0)
773*4882a593Smuzhiyun return 0;
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun /* Lookup the opcode structure based on the opcode name */
776*4882a593Smuzhiyun if ((opc = find_opcode_by_name (scratch)) == (struct opcode *) 0) {
777*4882a593Smuzhiyun if (err)
778*4882a593Smuzhiyun *err = E_ASM_BAD_OPCODE;
779*4882a593Smuzhiyun return 0;
780*4882a593Smuzhiyun }
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun if (asm_debug) {
783*4882a593Smuzhiyun printf ("asmppc: Opcode = \"%s\"\n", opc->name);
784*4882a593Smuzhiyun }
785*4882a593Smuzhiyun
786*4882a593Smuzhiyun for (i = 0; i < 8; ++i) {
787*4882a593Smuzhiyun if (opc->fields[i] == 0)
788*4882a593Smuzhiyun break;
789*4882a593Smuzhiyun ++w_operands;
790*4882a593Smuzhiyun }
791*4882a593Smuzhiyun
792*4882a593Smuzhiyun if (asm_debug) {
793*4882a593Smuzhiyun printf ("asmppc: Expecting %d operands\n", w_operands);
794*4882a593Smuzhiyun }
795*4882a593Smuzhiyun
796*4882a593Smuzhiyun instr = opc->opcode;
797*4882a593Smuzhiyun
798*4882a593Smuzhiyun /* read each operand */
799*4882a593Smuzhiyun while (n_operands < w_operands) {
800*4882a593Smuzhiyun
801*4882a593Smuzhiyun oper[n_operands] = &operands[opc->fields[n_operands] - 1];
802*4882a593Smuzhiyun
803*4882a593Smuzhiyun if (oper[n_operands]->hint & OH_SILENT) {
804*4882a593Smuzhiyun /* Skip silent operands, they are covered in opc->opcode */
805*4882a593Smuzhiyun
806*4882a593Smuzhiyun if (asm_debug) {
807*4882a593Smuzhiyun printf ("asmppc: Operand %d \"%s\" SILENT\n", n_operands,
808*4882a593Smuzhiyun oper[n_operands]->name);
809*4882a593Smuzhiyun }
810*4882a593Smuzhiyun
811*4882a593Smuzhiyun ++n_operands;
812*4882a593Smuzhiyun continue;
813*4882a593Smuzhiyun }
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun if (get_word (&ptr, scratch) == 0)
816*4882a593Smuzhiyun break;
817*4882a593Smuzhiyun
818*4882a593Smuzhiyun if (asm_debug) {
819*4882a593Smuzhiyun printf ("asmppc: Operand %d \"%s\" : \"%s\"\n", n_operands,
820*4882a593Smuzhiyun oper[n_operands]->name, scratch);
821*4882a593Smuzhiyun }
822*4882a593Smuzhiyun
823*4882a593Smuzhiyun if ((param = parse_operand (memaddr, opc, oper[n_operands],
824*4882a593Smuzhiyun scratch, err)) == -1)
825*4882a593Smuzhiyun return 0;
826*4882a593Smuzhiyun
827*4882a593Smuzhiyun instr |= param;
828*4882a593Smuzhiyun ++n_operands;
829*4882a593Smuzhiyun }
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun if (n_operands < w_operands) {
832*4882a593Smuzhiyun if (err)
833*4882a593Smuzhiyun *err = E_ASM_NUM_OPERANDS;
834*4882a593Smuzhiyun return 0;
835*4882a593Smuzhiyun }
836*4882a593Smuzhiyun
837*4882a593Smuzhiyun if (asm_debug) {
838*4882a593Smuzhiyun printf ("asmppc: Instruction = 0x%08lx\n", instr);
839*4882a593Smuzhiyun }
840*4882a593Smuzhiyun
841*4882a593Smuzhiyun return instr;
842*4882a593Smuzhiyun } /* asmppc */
843*4882a593Smuzhiyun
844*4882a593Smuzhiyun
845*4882a593Smuzhiyun
846*4882a593Smuzhiyun /*======================================================================
847*4882a593Smuzhiyun * Called by the assembler to interpret a single operand
848*4882a593Smuzhiyun *
849*4882a593Smuzhiyun * Arguments:
850*4882a593Smuzhiyun * ctx A pointer to the disassembler context record.
851*4882a593Smuzhiyun *
852*4882a593Smuzhiyun * Returns 0 if the operand is ok, or -1 if it is bad.
853*4882a593Smuzhiyun */
854*4882a593Smuzhiyun
parse_operand(unsigned long memaddr,struct opcode * opc,struct operand * oper,char * txt,int * err)855*4882a593Smuzhiyun int parse_operand (unsigned long memaddr, struct opcode *opc,
856*4882a593Smuzhiyun struct operand *oper, char *txt, int *err)
857*4882a593Smuzhiyun {
858*4882a593Smuzhiyun long data;
859*4882a593Smuzhiyun long mask;
860*4882a593Smuzhiyun int is_neg = 0;
861*4882a593Smuzhiyun
862*4882a593Smuzhiyun /*------------------------------------------------------------*/
863*4882a593Smuzhiyun
864*4882a593Smuzhiyun mask = (1 << oper->bits) - 1;
865*4882a593Smuzhiyun
866*4882a593Smuzhiyun if (oper->hint & OH_ADDR) {
867*4882a593Smuzhiyun data = read_number (txt);
868*4882a593Smuzhiyun
869*4882a593Smuzhiyun if (opc->hint & H_RELATIVE)
870*4882a593Smuzhiyun data = data - memaddr;
871*4882a593Smuzhiyun
872*4882a593Smuzhiyun if (data < 0)
873*4882a593Smuzhiyun is_neg = 1;
874*4882a593Smuzhiyun
875*4882a593Smuzhiyun data >>= 2;
876*4882a593Smuzhiyun data &= (mask >> 1);
877*4882a593Smuzhiyun
878*4882a593Smuzhiyun if (is_neg)
879*4882a593Smuzhiyun data |= 1 << (oper->bits - 1);
880*4882a593Smuzhiyun }
881*4882a593Smuzhiyun
882*4882a593Smuzhiyun else if (oper->hint & OH_REG) {
883*4882a593Smuzhiyun if (txt[0] == 'r' || txt[0] == 'R')
884*4882a593Smuzhiyun txt++;
885*4882a593Smuzhiyun else if (txt[0] == '%' && (txt[1] == 'r' || txt[1] == 'R'))
886*4882a593Smuzhiyun txt += 2;
887*4882a593Smuzhiyun
888*4882a593Smuzhiyun data = read_number (txt);
889*4882a593Smuzhiyun if (data > 31) {
890*4882a593Smuzhiyun if (err)
891*4882a593Smuzhiyun *err = E_ASM_BAD_REGISTER;
892*4882a593Smuzhiyun return -1;
893*4882a593Smuzhiyun }
894*4882a593Smuzhiyun
895*4882a593Smuzhiyun data = htonl (data);
896*4882a593Smuzhiyun }
897*4882a593Smuzhiyun
898*4882a593Smuzhiyun else if (oper->hint & OH_SPR) {
899*4882a593Smuzhiyun if ((data = spr_value (txt)) == 0) {
900*4882a593Smuzhiyun if (err)
901*4882a593Smuzhiyun *err = E_ASM_BAD_SPR;
902*4882a593Smuzhiyun return -1;
903*4882a593Smuzhiyun }
904*4882a593Smuzhiyun }
905*4882a593Smuzhiyun
906*4882a593Smuzhiyun else if (oper->hint & OH_TBR) {
907*4882a593Smuzhiyun if ((data = tbr_value (txt)) == 0) {
908*4882a593Smuzhiyun if (err)
909*4882a593Smuzhiyun *err = E_ASM_BAD_TBR;
910*4882a593Smuzhiyun return -1;
911*4882a593Smuzhiyun }
912*4882a593Smuzhiyun }
913*4882a593Smuzhiyun
914*4882a593Smuzhiyun else {
915*4882a593Smuzhiyun data = htonl (read_number (txt));
916*4882a593Smuzhiyun }
917*4882a593Smuzhiyun
918*4882a593Smuzhiyun return (data & mask) << oper->shift;
919*4882a593Smuzhiyun } /* parse_operand */
920*4882a593Smuzhiyun
921*4882a593Smuzhiyun
asm_error_str(int err)922*4882a593Smuzhiyun char *asm_error_str (int err)
923*4882a593Smuzhiyun {
924*4882a593Smuzhiyun switch (err) {
925*4882a593Smuzhiyun case E_ASM_BAD_OPCODE:
926*4882a593Smuzhiyun return "Bad opcode";
927*4882a593Smuzhiyun case E_ASM_NUM_OPERANDS:
928*4882a593Smuzhiyun return "Bad number of operands";
929*4882a593Smuzhiyun case E_ASM_BAD_REGISTER:
930*4882a593Smuzhiyun return "Bad register number";
931*4882a593Smuzhiyun case E_ASM_BAD_SPR:
932*4882a593Smuzhiyun return "Bad SPR name or number";
933*4882a593Smuzhiyun case E_ASM_BAD_TBR:
934*4882a593Smuzhiyun return "Bad TBR name or number";
935*4882a593Smuzhiyun }
936*4882a593Smuzhiyun
937*4882a593Smuzhiyun return "";
938*4882a593Smuzhiyun } /* asm_error_str */
939*4882a593Smuzhiyun
940*4882a593Smuzhiyun
941*4882a593Smuzhiyun
942*4882a593Smuzhiyun /*======================================================================
943*4882a593Smuzhiyun * Copy a word from one buffer to another, ignores leading white spaces.
944*4882a593Smuzhiyun *
945*4882a593Smuzhiyun * Arguments:
946*4882a593Smuzhiyun * src The address of a character pointer to the
947*4882a593Smuzhiyun * source buffer.
948*4882a593Smuzhiyun * dest A pointer to a character buffer to write the word
949*4882a593Smuzhiyun * into.
950*4882a593Smuzhiyun *
951*4882a593Smuzhiyun * Returns the number of non-white space characters copied, or zero.
952*4882a593Smuzhiyun */
953*4882a593Smuzhiyun
get_word(char ** src,char * dest)954*4882a593Smuzhiyun int get_word (char **src, char *dest)
955*4882a593Smuzhiyun {
956*4882a593Smuzhiyun char *ptr = *src;
957*4882a593Smuzhiyun int nchars = 0;
958*4882a593Smuzhiyun
959*4882a593Smuzhiyun /*------------------------------------------------------------*/
960*4882a593Smuzhiyun
961*4882a593Smuzhiyun /* Eat white spaces */
962*4882a593Smuzhiyun while (*ptr && isblank (*ptr))
963*4882a593Smuzhiyun ptr++;
964*4882a593Smuzhiyun
965*4882a593Smuzhiyun if (*ptr == 0) {
966*4882a593Smuzhiyun *src = ptr;
967*4882a593Smuzhiyun return 0;
968*4882a593Smuzhiyun }
969*4882a593Smuzhiyun
970*4882a593Smuzhiyun /* Find the text of the word */
971*4882a593Smuzhiyun while (*ptr && !isblank (*ptr) && (*ptr != ','))
972*4882a593Smuzhiyun dest[nchars++] = *ptr++;
973*4882a593Smuzhiyun ptr = (*ptr == ',') ? ptr + 1 : ptr;
974*4882a593Smuzhiyun dest[nchars] = 0;
975*4882a593Smuzhiyun
976*4882a593Smuzhiyun *src = ptr;
977*4882a593Smuzhiyun return nchars;
978*4882a593Smuzhiyun } /* get_word */
979*4882a593Smuzhiyun
980*4882a593Smuzhiyun
981*4882a593Smuzhiyun
982*4882a593Smuzhiyun /*======================================================================
983*4882a593Smuzhiyun * Convert a numeric string to a number, be aware of base notations.
984*4882a593Smuzhiyun *
985*4882a593Smuzhiyun * Arguments:
986*4882a593Smuzhiyun * txt The numeric string.
987*4882a593Smuzhiyun *
988*4882a593Smuzhiyun * Returns the converted numeric value.
989*4882a593Smuzhiyun */
990*4882a593Smuzhiyun
read_number(char * txt)991*4882a593Smuzhiyun long read_number (char *txt)
992*4882a593Smuzhiyun {
993*4882a593Smuzhiyun long val;
994*4882a593Smuzhiyun int is_neg = 0;
995*4882a593Smuzhiyun
996*4882a593Smuzhiyun /*------------------------------------------------------------*/
997*4882a593Smuzhiyun
998*4882a593Smuzhiyun if (txt == 0 || *txt == 0)
999*4882a593Smuzhiyun return 0;
1000*4882a593Smuzhiyun
1001*4882a593Smuzhiyun if (*txt == '-') {
1002*4882a593Smuzhiyun is_neg = 1;
1003*4882a593Smuzhiyun ++txt;
1004*4882a593Smuzhiyun }
1005*4882a593Smuzhiyun
1006*4882a593Smuzhiyun if (txt[0] == '0' && (txt[1] == 'x' || txt[1] == 'X')) /* hex */
1007*4882a593Smuzhiyun val = simple_strtoul (&txt[2], NULL, 16);
1008*4882a593Smuzhiyun else /* decimal */
1009*4882a593Smuzhiyun val = simple_strtoul (txt, NULL, 10);
1010*4882a593Smuzhiyun
1011*4882a593Smuzhiyun if (is_neg)
1012*4882a593Smuzhiyun val = -val;
1013*4882a593Smuzhiyun
1014*4882a593Smuzhiyun return val;
1015*4882a593Smuzhiyun } /* read_number */
1016*4882a593Smuzhiyun
1017*4882a593Smuzhiyun
downstring(char * s)1018*4882a593Smuzhiyun int downstring (char *s)
1019*4882a593Smuzhiyun {
1020*4882a593Smuzhiyun if (!s || !*s)
1021*4882a593Smuzhiyun return 0;
1022*4882a593Smuzhiyun
1023*4882a593Smuzhiyun while (*s) {
1024*4882a593Smuzhiyun if (isupper (*s))
1025*4882a593Smuzhiyun *s = tolower (*s);
1026*4882a593Smuzhiyun s++;
1027*4882a593Smuzhiyun }
1028*4882a593Smuzhiyun
1029*4882a593Smuzhiyun return 0;
1030*4882a593Smuzhiyun } /* downstring */
1031*4882a593Smuzhiyun
1032*4882a593Smuzhiyun
1033*4882a593Smuzhiyun
1034*4882a593Smuzhiyun /*======================================================================
1035*4882a593Smuzhiyun * Examines the instruction at the current address and determines the
1036*4882a593Smuzhiyun * next address to be executed. This will take into account branches
1037*4882a593Smuzhiyun * of different types so that a "step" and "next" operations can be
1038*4882a593Smuzhiyun * supported.
1039*4882a593Smuzhiyun *
1040*4882a593Smuzhiyun * Arguments:
1041*4882a593Smuzhiyun * nextaddr The address (to be filled in) of the next
1042*4882a593Smuzhiyun * instruction to execute. This will only be a valid
1043*4882a593Smuzhiyun * address if true is returned.
1044*4882a593Smuzhiyun *
1045*4882a593Smuzhiyun * step_over A flag indicating how to compute addresses for
1046*4882a593Smuzhiyun * branch statements:
1047*4882a593Smuzhiyun * true = Step over the branch (next)
1048*4882a593Smuzhiyun * false = step into the branch (step)
1049*4882a593Smuzhiyun *
1050*4882a593Smuzhiyun * Returns true if it was able to compute the address. Returns false if
1051*4882a593Smuzhiyun * it has a problem reading the current instruction or one of the registers.
1052*4882a593Smuzhiyun */
1053*4882a593Smuzhiyun
find_next_address(unsigned char * nextaddr,int step_over,struct pt_regs * regs)1054*4882a593Smuzhiyun int find_next_address (unsigned char *nextaddr, int step_over,
1055*4882a593Smuzhiyun struct pt_regs *regs)
1056*4882a593Smuzhiyun {
1057*4882a593Smuzhiyun unsigned long pc; /* SRR0 register from PPC */
1058*4882a593Smuzhiyun unsigned long ctr; /* CTR register from PPC */
1059*4882a593Smuzhiyun unsigned long cr; /* CR register from PPC */
1060*4882a593Smuzhiyun unsigned long lr; /* LR register from PPC */
1061*4882a593Smuzhiyun unsigned long instr; /* instruction at SRR0 */
1062*4882a593Smuzhiyun unsigned long next; /* computed instruction for 'next' */
1063*4882a593Smuzhiyun unsigned long step; /* computed instruction for 'step' */
1064*4882a593Smuzhiyun unsigned long addr = 0; /* target address operand */
1065*4882a593Smuzhiyun unsigned long aa = 0; /* AA operand */
1066*4882a593Smuzhiyun unsigned long lk = 0; /* LK operand */
1067*4882a593Smuzhiyun unsigned long bo = 0; /* BO operand */
1068*4882a593Smuzhiyun unsigned long bi = 0; /* BI operand */
1069*4882a593Smuzhiyun struct opcode *op = 0; /* opcode structure for 'instr' */
1070*4882a593Smuzhiyun int ctr_ok = 0;
1071*4882a593Smuzhiyun int cond_ok = 0;
1072*4882a593Smuzhiyun int conditional = 0;
1073*4882a593Smuzhiyun int branch = 0;
1074*4882a593Smuzhiyun
1075*4882a593Smuzhiyun /*------------------------------------------------------------*/
1076*4882a593Smuzhiyun
1077*4882a593Smuzhiyun if (nextaddr == 0 || regs == 0) {
1078*4882a593Smuzhiyun printf ("find_next_address: bad args");
1079*4882a593Smuzhiyun return false;
1080*4882a593Smuzhiyun }
1081*4882a593Smuzhiyun
1082*4882a593Smuzhiyun pc = regs->nip & 0xfffffffc;
1083*4882a593Smuzhiyun instr = INSTRUCTION (pc);
1084*4882a593Smuzhiyun
1085*4882a593Smuzhiyun if ((op = find_opcode (instr)) == (struct opcode *) 0) {
1086*4882a593Smuzhiyun printf ("find_next_address: can't parse opcode 0x%lx", instr);
1087*4882a593Smuzhiyun return false;
1088*4882a593Smuzhiyun }
1089*4882a593Smuzhiyun
1090*4882a593Smuzhiyun ctr = regs->ctr;
1091*4882a593Smuzhiyun cr = regs->ccr;
1092*4882a593Smuzhiyun lr = regs->link;
1093*4882a593Smuzhiyun
1094*4882a593Smuzhiyun switch (op->opcode) {
1095*4882a593Smuzhiyun case B_OPCODE (16, 0, 0): /* bc */
1096*4882a593Smuzhiyun case B_OPCODE (16, 0, 1): /* bcl */
1097*4882a593Smuzhiyun case B_OPCODE (16, 1, 0): /* bca */
1098*4882a593Smuzhiyun case B_OPCODE (16, 1, 1): /* bcla */
1099*4882a593Smuzhiyun if (!get_operand_value (op, instr, O_BD, &addr) ||
1100*4882a593Smuzhiyun !get_operand_value (op, instr, O_BO, &bo) ||
1101*4882a593Smuzhiyun !get_operand_value (op, instr, O_BI, &bi) ||
1102*4882a593Smuzhiyun !get_operand_value (op, instr, O_AA, &aa) ||
1103*4882a593Smuzhiyun !get_operand_value (op, instr, O_LK, &lk))
1104*4882a593Smuzhiyun return false;
1105*4882a593Smuzhiyun
1106*4882a593Smuzhiyun if ((addr & (1 << 13)) != 0)
1107*4882a593Smuzhiyun addr = addr - (1 << 14);
1108*4882a593Smuzhiyun addr <<= 2;
1109*4882a593Smuzhiyun conditional = 1;
1110*4882a593Smuzhiyun branch = 1;
1111*4882a593Smuzhiyun break;
1112*4882a593Smuzhiyun
1113*4882a593Smuzhiyun case I_OPCODE (18, 0, 0): /* b */
1114*4882a593Smuzhiyun case I_OPCODE (18, 0, 1): /* bl */
1115*4882a593Smuzhiyun case I_OPCODE (18, 1, 0): /* ba */
1116*4882a593Smuzhiyun case I_OPCODE (18, 1, 1): /* bla */
1117*4882a593Smuzhiyun if (!get_operand_value (op, instr, O_LI, &addr) ||
1118*4882a593Smuzhiyun !get_operand_value (op, instr, O_AA, &aa) ||
1119*4882a593Smuzhiyun !get_operand_value (op, instr, O_LK, &lk))
1120*4882a593Smuzhiyun return false;
1121*4882a593Smuzhiyun
1122*4882a593Smuzhiyun if ((addr & (1 << 23)) != 0)
1123*4882a593Smuzhiyun addr = addr - (1 << 24);
1124*4882a593Smuzhiyun addr <<= 2;
1125*4882a593Smuzhiyun conditional = 0;
1126*4882a593Smuzhiyun branch = 1;
1127*4882a593Smuzhiyun break;
1128*4882a593Smuzhiyun
1129*4882a593Smuzhiyun case XL_OPCODE (19, 528, 0): /* bcctr */
1130*4882a593Smuzhiyun case XL_OPCODE (19, 528, 1): /* bcctrl */
1131*4882a593Smuzhiyun if (!get_operand_value (op, instr, O_BO, &bo) ||
1132*4882a593Smuzhiyun !get_operand_value (op, instr, O_BI, &bi) ||
1133*4882a593Smuzhiyun !get_operand_value (op, instr, O_LK, &lk))
1134*4882a593Smuzhiyun return false;
1135*4882a593Smuzhiyun
1136*4882a593Smuzhiyun addr = ctr;
1137*4882a593Smuzhiyun aa = 1;
1138*4882a593Smuzhiyun conditional = 1;
1139*4882a593Smuzhiyun branch = 1;
1140*4882a593Smuzhiyun break;
1141*4882a593Smuzhiyun
1142*4882a593Smuzhiyun case XL_OPCODE (19, 16, 0): /* bclr */
1143*4882a593Smuzhiyun case XL_OPCODE (19, 16, 1): /* bclrl */
1144*4882a593Smuzhiyun if (!get_operand_value (op, instr, O_BO, &bo) ||
1145*4882a593Smuzhiyun !get_operand_value (op, instr, O_BI, &bi) ||
1146*4882a593Smuzhiyun !get_operand_value (op, instr, O_LK, &lk))
1147*4882a593Smuzhiyun return false;
1148*4882a593Smuzhiyun
1149*4882a593Smuzhiyun addr = lr;
1150*4882a593Smuzhiyun aa = 1;
1151*4882a593Smuzhiyun conditional = 1;
1152*4882a593Smuzhiyun branch = 1;
1153*4882a593Smuzhiyun break;
1154*4882a593Smuzhiyun
1155*4882a593Smuzhiyun default:
1156*4882a593Smuzhiyun conditional = 0;
1157*4882a593Smuzhiyun branch = 0;
1158*4882a593Smuzhiyun break;
1159*4882a593Smuzhiyun }
1160*4882a593Smuzhiyun
1161*4882a593Smuzhiyun if (conditional) {
1162*4882a593Smuzhiyun switch ((bo & 0x1e) >> 1) {
1163*4882a593Smuzhiyun case 0: /* 0000y */
1164*4882a593Smuzhiyun if (--ctr != 0)
1165*4882a593Smuzhiyun ctr_ok = 1;
1166*4882a593Smuzhiyun
1167*4882a593Smuzhiyun cond_ok = !(cr & (1 << (31 - bi)));
1168*4882a593Smuzhiyun break;
1169*4882a593Smuzhiyun
1170*4882a593Smuzhiyun case 1: /* 0001y */
1171*4882a593Smuzhiyun if (--ctr == 0)
1172*4882a593Smuzhiyun ctr_ok = 1;
1173*4882a593Smuzhiyun
1174*4882a593Smuzhiyun cond_ok = !(cr & (1 << (31 - bi)));
1175*4882a593Smuzhiyun break;
1176*4882a593Smuzhiyun
1177*4882a593Smuzhiyun case 2: /* 001zy */
1178*4882a593Smuzhiyun ctr_ok = 1;
1179*4882a593Smuzhiyun cond_ok = !(cr & (1 << (31 - bi)));
1180*4882a593Smuzhiyun break;
1181*4882a593Smuzhiyun
1182*4882a593Smuzhiyun case 4: /* 0100y */
1183*4882a593Smuzhiyun if (--ctr != 0)
1184*4882a593Smuzhiyun ctr_ok = 1;
1185*4882a593Smuzhiyun
1186*4882a593Smuzhiyun cond_ok = cr & (1 << (31 - bi));
1187*4882a593Smuzhiyun break;
1188*4882a593Smuzhiyun
1189*4882a593Smuzhiyun case 5: /* 0101y */
1190*4882a593Smuzhiyun if (--ctr == 0)
1191*4882a593Smuzhiyun ctr_ok = 1;
1192*4882a593Smuzhiyun
1193*4882a593Smuzhiyun cond_ok = cr & (1 << (31 - bi));
1194*4882a593Smuzhiyun break;
1195*4882a593Smuzhiyun
1196*4882a593Smuzhiyun case 6: /* 011zy */
1197*4882a593Smuzhiyun ctr_ok = 1;
1198*4882a593Smuzhiyun cond_ok = cr & (1 << (31 - bi));
1199*4882a593Smuzhiyun break;
1200*4882a593Smuzhiyun
1201*4882a593Smuzhiyun case 8: /* 1z00y */
1202*4882a593Smuzhiyun if (--ctr != 0)
1203*4882a593Smuzhiyun ctr_ok = cond_ok = 1;
1204*4882a593Smuzhiyun break;
1205*4882a593Smuzhiyun
1206*4882a593Smuzhiyun case 9: /* 1z01y */
1207*4882a593Smuzhiyun if (--ctr == 0)
1208*4882a593Smuzhiyun ctr_ok = cond_ok = 1;
1209*4882a593Smuzhiyun break;
1210*4882a593Smuzhiyun
1211*4882a593Smuzhiyun case 10: /* 1z1zz */
1212*4882a593Smuzhiyun ctr_ok = cond_ok = 1;
1213*4882a593Smuzhiyun break;
1214*4882a593Smuzhiyun }
1215*4882a593Smuzhiyun }
1216*4882a593Smuzhiyun
1217*4882a593Smuzhiyun if (branch && (!conditional || (ctr_ok && cond_ok))) {
1218*4882a593Smuzhiyun if (aa)
1219*4882a593Smuzhiyun step = addr;
1220*4882a593Smuzhiyun else
1221*4882a593Smuzhiyun step = addr + pc;
1222*4882a593Smuzhiyun
1223*4882a593Smuzhiyun if (lk)
1224*4882a593Smuzhiyun next = pc + 4;
1225*4882a593Smuzhiyun else
1226*4882a593Smuzhiyun next = step;
1227*4882a593Smuzhiyun } else {
1228*4882a593Smuzhiyun step = next = pc + 4;
1229*4882a593Smuzhiyun }
1230*4882a593Smuzhiyun
1231*4882a593Smuzhiyun if (step_over == true)
1232*4882a593Smuzhiyun *(unsigned long *) nextaddr = next;
1233*4882a593Smuzhiyun else
1234*4882a593Smuzhiyun *(unsigned long *) nextaddr = step;
1235*4882a593Smuzhiyun
1236*4882a593Smuzhiyun return true;
1237*4882a593Smuzhiyun } /* find_next_address */
1238*4882a593Smuzhiyun
1239*4882a593Smuzhiyun
1240*4882a593Smuzhiyun /*
1241*4882a593Smuzhiyun * Copyright (c) 2000 William L. Pitts and W. Gerald Hicks
1242*4882a593Smuzhiyun * All rights reserved.
1243*4882a593Smuzhiyun *
1244*4882a593Smuzhiyun * Redistribution and use in source and binary forms are freely
1245*4882a593Smuzhiyun * permitted provided that the above copyright notice and this
1246*4882a593Smuzhiyun * paragraph and the following disclaimer are duplicated in all
1247*4882a593Smuzhiyun * such forms.
1248*4882a593Smuzhiyun *
1249*4882a593Smuzhiyun * This software is provided "AS IS" and without any express or
1250*4882a593Smuzhiyun * implied warranties, including, without limitation, the implied
1251*4882a593Smuzhiyun * warranties of merchantability and fitness for a particular
1252*4882a593Smuzhiyun * purpose.
1253*4882a593Smuzhiyun */
1254