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