📄 bedbug.c.svn-base
字号:
/* $Id$ */#include <common.h>#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)#include <linux/ctype.h>#include <bedbug/bedbug.h>#include <bedbug/ppc.h>#include <bedbug/regs.h>#include <bedbug/tables.h>#define Elf32_Word unsigned long/* USE_SOURCE_CODE enables some symbolic debugging functions of this code. This is only useful if the program will have access to the source code for the binary being examined.*//* #define USE_SOURCE_CODE 1 */#ifdef USE_SOURCE_CODEextern int line_info_from_addr __P ((Elf32_Word, char *, char *, int *));extern struct symreflist *symByAddr;extern char *symbol_name_from_addr __P ((Elf32_Word, int, int *));#endif /* USE_SOURCE_CODE */int print_operands __P ((struct ppc_ctx *));int get_operand_value __P ((struct opcode *, unsigned long, enum OP_FIELD, unsigned long *));struct opcode *find_opcode __P ((unsigned long));struct opcode *find_opcode_by_name __P ((char *));char *spr_name __P ((int));int spr_value __P ((char *));char *tbr_name __P ((int));int tbr_value __P ((char *));int parse_operand __P ((unsigned long, struct opcode *, struct operand *, char *, int *));int get_word __P ((char **, char *));long read_number __P ((char *));int downstring __P ((char *));/*====================================================================== * Entry point for the PPC disassembler. * * Arguments: * memaddr The address to start disassembling from. * * virtual If this value is non-zero, then this will be * used as the base address for the output and * symbol lookups. If this value is zero then * memaddr is used as the absolute address. * * num_instr The number of instructions to disassemble. Since * each instruction is 32 bits long, this can be * computed if you know the total size of the region. * * pfunc The address of a function that is called to print * each line of output. The function should take a * single character pointer as its parameters a la puts. * * flags Sets options for the output. This is a * bitwise-inclusive-OR of the following * values. Note that only one of the radix * options may be set. * * F_RADOCTAL - output radix is unsigned base 8. * F_RADUDECIMAL - output radix is unsigned base 10. * F_RADSDECIMAL - output radix is signed base 10. * F_RADHEX - output radix is unsigned base 16. * F_SIMPLE - use simplified mnemonics. * F_SYMBOL - lookup symbols for addresses. * F_INSTR - output raw instruction. * F_LINENO - show line # info if available. * * Returns TRUE if the area was successfully disassembled or FALSE if * a problem was encountered with accessing the memory. */int disppc (unsigned char *memaddr, unsigned char *virtual, int num_instr, int (*pfunc) (const char *), unsigned long flags){ int i; struct ppc_ctx ctx;#ifdef USE_SOURCE_CODE int line_no = 0; int last_line_no = 0; char funcname[128] = { 0 }; char filename[256] = { 0 }; char last_funcname[128] = { 0 }; int symoffset; char *symname; char *cursym = (char *) 0;#endif /* USE_SOURCE_CODE */ /*------------------------------------------------------------*/ ctx.flags = flags; ctx.virtual = virtual; /* Figure out the output radix before we go any further */ if (ctx.flags & F_RADOCTAL) { /* Unsigned octal output */ strcpy (ctx.radix_fmt, "O%o"); } else if (ctx.flags & F_RADUDECIMAL) { /* Unsigned decimal output */ strcpy (ctx.radix_fmt, "%u"); } else if (ctx.flags & F_RADSDECIMAL) { /* Signed decimal output */ strcpy (ctx.radix_fmt, "%d"); } else { /* Unsigned hex output */ strcpy (ctx.radix_fmt, "0x%x"); } if (ctx.virtual == 0) { ctx.virtual = memaddr; }#ifdef USE_SOURCE_CODE if (ctx.flags & F_SYMBOL) { if (symByAddr == 0) /* no symbols loaded */ ctx.flags &= ~F_SYMBOL; else { cursym = (char *) 0; symoffset = 0; } }#endif /* USE_SOURCE_CODE */ /* format each line as "XXXXXXXX: <symbol> IIIIIIII disassembly" where, XXXXXXXX is the memory address in hex, <symbol> is the symbolic location if F_SYMBOL is set. IIIIIIII is the raw machine code in hex if F_INSTR is set, and disassembly is the disassembled machine code with numbers formatted according to the 'radix' parameter */ for (i = 0; i < num_instr; ++i, memaddr += 4, ctx.virtual += 4) {#ifdef USE_SOURCE_CODE if (ctx.flags & F_LINENO) { if ((line_info_from_addr ((Elf32_Word) ctx.virtual, filename, funcname, &line_no) == TRUE) && ((line_no != last_line_no) || (strcmp (last_funcname, funcname) != 0))) { print_source_line (filename, funcname, line_no, pfunc); } last_line_no = line_no; strcpy (last_funcname, funcname); }#endif /* USE_SOURCE_CODE */ sprintf (ctx.data, "%08lx: ", (unsigned long) ctx.virtual); ctx.datalen = 10;#ifdef USE_SOURCE_CODE if (ctx.flags & F_SYMBOL) { if ((symname = symbol_name_from_addr ((Elf32_Word) ctx.virtual, TRUE, 0)) != 0) { cursym = symname; symoffset = 0; } else { if ((cursym == 0) && ((symname = symbol_name_from_addr ((Elf32_Word) ctx.virtual, FALSE, &symoffset)) != 0)) { cursym = symname; } else { symoffset += 4; } } if (cursym != 0) { sprintf (&ctx.data[ctx.datalen], "<%s+", cursym); ctx.datalen = strlen (ctx.data); sprintf (&ctx.data[ctx.datalen], ctx.radix_fmt, symoffset); strcat (ctx.data, ">"); ctx.datalen = strlen (ctx.data); } }#endif /* USE_SOURCE_CODE */ ctx.instr = INSTRUCTION (memaddr); if (ctx.flags & F_INSTR) { /* Find the opcode structure for this opcode. If one is not found then it must be an illegal instruction */ sprintf (&ctx.data[ctx.datalen], " %02lx %02lx %02lx %02lx ", ((ctx.instr >> 24) & 0xff), ((ctx.instr >> 16) & 0xff), ((ctx.instr >> 8) & 0xff), (ctx.instr & 0xff)); ctx.datalen += 18; } else { strcat (ctx.data, " "); ctx.datalen += 3; } if ((ctx.op = find_opcode (ctx.instr)) == 0) { /* Illegal Opcode */ sprintf (&ctx.data[ctx.datalen], " .long 0x%08lx", ctx.instr); ctx.datalen += 24; (*pfunc) (ctx.data); continue; } if (((ctx.flags & F_SIMPLE) == 0) || (ctx.op->hfunc == 0) || ((*ctx.op->hfunc) (&ctx) == FALSE)) { sprintf (&ctx.data[ctx.datalen], "%-7s ", ctx.op->name); ctx.datalen += 8; print_operands (&ctx); } (*pfunc) (ctx.data); } return TRUE;} /* disppc *//*====================================================================== * Called by the disassembler to print the operands for an instruction. * * Arguments: * ctx A pointer to the disassembler context record. * * always returns 0. */int print_operands (struct ppc_ctx *ctx){ int open_parens = 0; int field; unsigned long operand; struct operand *opr;#ifdef USE_SOURCE_CODE char *symname; int offset;#endif /* USE_SOURCE_CODE */ /*------------------------------------------------------------*/ /* Walk through the operands and list each in order */ for (field = 0; ctx->op->fields[field] != 0; ++field) { if (ctx->op->fields[field] > n_operands) { continue; /* bad operand ?! */ } opr = &operands[ctx->op->fields[field] - 1]; if (opr->hint & OH_SILENT) { continue; } if ((field > 0) && !open_parens) { strcat (ctx->data, ","); ctx->datalen++; } operand = (ctx->instr >> opr->shift) & ((1 << opr->bits) - 1); if (opr->hint & OH_ADDR) { if ((operand & (1 << (opr->bits - 1))) != 0) { operand = operand - (1 << opr->bits); } if (ctx->op->hint & H_RELATIVE) operand = (operand << 2) + (unsigned long) ctx->virtual; else operand = (operand << 2); sprintf (&ctx->data[ctx->datalen], "0x%lx", operand); ctx->datalen = strlen (ctx->data);#ifdef USE_SOURCE_CODE if ((ctx->flags & F_SYMBOL) && ((symname = symbol_name_from_addr (operand, 0, &offset)) != 0)) { sprintf (&ctx->data[ctx->datalen], " <%s", symname); if (offset != 0) { strcat (ctx->data, "+"); ctx->datalen = strlen (ctx->data); sprintf (&ctx->data[ctx->datalen], ctx->radix_fmt, offset); } strcat (ctx->data, ">"); }#endif /* USE_SOURCE_CODE */ } else if (opr->hint & OH_REG) { if ((operand == 0) && (opr->field == O_rA) && (ctx->op->hint & H_RA0_IS_0)) { strcat (ctx->data, "0"); } else { sprintf (&ctx->data[ctx->datalen], "r%d", (short) operand); } if (open_parens) { strcat (ctx->data, ")"); open_parens--; } } else if (opr->hint & OH_SPR) { strcat (ctx->data, spr_name (operand)); } else if (opr->hint & OH_TBR) { strcat (ctx->data, tbr_name (operand)); } else if (opr->hint & OH_LITERAL) { switch (opr->field) { case O_cr2: strcat (ctx->data, "cr2"); ctx->datalen += 3; break; default: break; } } else { sprintf (&ctx->data[ctx->datalen], ctx->radix_fmt, (unsigned short) operand); if (open_parens) { strcat (ctx->data, ")"); open_parens--; } else if (opr->hint & OH_OFFSET) { strcat (ctx->data, "("); open_parens++; } } ctx->datalen = strlen (ctx->data); } return 0;} /* print_operands *//*====================================================================== * Called to get the value of an arbitrary operand with in an instruction. * * Arguments: * op The pointer to the opcode structure to which * the operands belong. * * instr The instruction (32 bits) containing the opcode * and the operands to print. By the time that * this routine is called the operand has already * been added to the output. * * field The field (operand) to get the value of. * * value The address of an unsigned long to be filled in * with the value of the operand if it is found. This * will only be filled in if the function returns * TRUE. This may be passed as 0 if the value is * not required. * * Returns TRUE if the operand was found or FALSE if it was not. */int get_operand_value (struct opcode *op, unsigned long instr, enum OP_FIELD field, unsigned long *value){ int i; struct operand *opr; /*------------------------------------------------------------*/ if (field > n_operands) { return FALSE; /* bad operand ?! */ } /* Walk through the operands and list each in order */ for (i = 0; op->fields[i] != 0; ++i) { if (op->fields[i] != field) { continue; } opr = &operands[op->fields[i] - 1]; if (value) { *value = (instr >> opr->shift) & ((1 << opr->bits) - 1); } return TRUE; } return FALSE;} /* operand_value *//*====================================================================== * Called by the disassembler to match an opcode value to an opcode structure. * * Arguments: * instr The instruction (32 bits) to match. This value * may contain operand values as well as the opcode * since they will be masked out anyway for this * search. * * Returns the address of an opcode struct (from the opcode table) if the * operand successfully matched an entry, or 0 if no match was found. */struct opcode *find_opcode (unsigned long instr){ struct opcode *ptr; int top = 0; int bottom = n_opcodes - 1; int idx; /*------------------------------------------------------------*/ while (top <= bottom) { idx = (top + bottom) >> 1; ptr = &opcodes[idx]; if ((instr & ptr->mask) < ptr->opcode) { bottom = idx - 1; } else if ((instr & ptr->mask) > ptr->opcode) { top = idx + 1; } else { return ptr; } } return (struct opcode *) 0;} /* find_opcode *//*====================================================================== * Called by the assembler to match an opcode name to an opcode structure. * * Arguments: * name The text name of the opcode, e.g. "b", "mtspr", etc. * * The opcodes are sorted numerically by their instruction binary code * so a search for the name cannot use the binary search used by the * other find routine. * * Returns the address of an opcode struct (from the opcode table) if the * name successfully matched an entry, or 0 if no match was found. */struct opcode *find_opcode_by_name (char *name){ int idx; /*------------------------------------------------------------*/ downstring (name); for (idx = 0; idx < n_opcodes; ++idx) { if (!strcmp (name, opcodes[idx].name)) return &opcodes[idx]; } return (struct opcode *) 0;} /* find_opcode_by_name *//*====================================================================== * Convert the 'spr' operand from its numeric value to its symbolic name. * * Arguments: * value The value of the 'spr' operand. This value should * be unmodified from its encoding in the instruction. * the split-field computations will be performed * here before the switch. * * Returns the address of a character array containing the name of the * special purpose register defined by the 'value' parameter, or the * address of a character array containing "???" if no match was found. */char *spr_name (int value){ unsigned short spr; static char other[10]; int i; /*------------------------------------------------------------*/ /* spr is a 10 bit field whose interpretation has the high and low five-bit fields reversed from their encoding in the operand */ spr = ((value >> 5) & 0x1f) | ((value & 0x1f) << 5); for (i = 0; i < n_sprs; ++i) { if (spr == spr_map[i].spr_val) return spr_map[i].spr_name; } sprintf (other, "%d", spr); return other;} /* spr_name *//*====================================================================== * Convert the 'spr' operand from its symbolic name to its numeric value * * Arguments: * name The symbolic name of the 'spr' operand. The * split-field encoding will be done by this routine. * NOTE: name can be a number. * * Returns the numeric value for the spr appropriate for encoding a machine * instruction. Returns 0 if unable to find the SPR. */int spr_value (char *name){ struct spr_info *sprp; int spr; int i; /*------------------------------------------------------------*/ if (!name || !*name) return 0; if (isdigit ((int) name[0])) { i = htonl (read_number (name)); spr = ((i >> 5) & 0x1f) | ((i & 0x1f) << 5); return spr; } downstring (name); for (i = 0; i < n_sprs; ++i) { sprp = &spr_map[i]; if (strcmp (name, sprp->spr_name) == 0) { /* spr is a 10 bit field whose interpretation has the high and low five-bit fields reversed from their encoding in the operand */ i = htonl (sprp->spr_val); spr = ((i >> 5) & 0x1f) | ((i & 0x1f) << 5); return spr; } } return 0;} /* spr_value *//*====================================================================== * Convert the 'tbr' operand from its numeric value to its symbolic name. * * Arguments: * value The value of the 'tbr' operand. This value should * be unmodified from its encoding in the instruction. * the split-field computations will be performed * here before the switch. * * Returns the address of a character array containing the name of the * time base register defined by the 'value' parameter, or the address * of a character array containing "???" if no match was found. */char *tbr_name (int value){ unsigned short tbr; /*------------------------------------------------------------*/ /* tbr is a 10 bit field whose interpretation has the high and low five-bit fields reversed from their encoding in the operand */ tbr = ((value >> 5) & 0x1f) | ((value & 0x1f) << 5); if (tbr == 268) return "TBL"; else if (tbr == 269) return "TBU"; return "???";} /* tbr_name *//*====================================================================== * Convert the 'tbr' operand from its symbolic name to its numeric value. * * Arguments: * name The symbolic name of the 'tbr' operand. The * split-field encoding will be done by this routine. * * Returns the numeric value for the spr appropriate for encoding a machine * instruction. Returns 0 if unable to find the TBR. */int tbr_value (char *name){ int tbr; int val; /*------------------------------------------------------------*/ if (!name || !*name) return 0; downstring (name); if (isdigit ((int) name[0])) { val = read_number (name); if (val != 268 && val != 269) return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -