Skip to content
Snippets Groups Projects
bedbug.c 29.9 KiB
Newer Older
Wolfgang Denk's avatar
Wolfgang Denk committed
/* $Id$ */

#include <common.h>

#include <linux/ctype.h>
#include <bedbug/bedbug.h>
#include <bedbug/ppc.h>
#include <bedbug/regs.h>
#include <bedbug/tables.h>

#define Elf32_Word	unsigned long

/* USE_SOURCE_CODE enables some symbolic debugging functions of this
   code.  This is only useful if the program will have access to the
   source code for the binary being examined.
*/

/* #define USE_SOURCE_CODE 1 */

#ifdef USE_SOURCE_CODE
extern int line_info_from_addr __P ((Elf32_Word, char *, char *, int *));
extern struct symreflist *symByAddr;
extern char *symbol_name_from_addr __P ((Elf32_Word, int, int *));
#endif /* USE_SOURCE_CODE */

int print_operands __P ((struct ppc_ctx *));
int get_operand_value __P ((struct opcode *, unsigned long,
Wolfgang Denk's avatar
Wolfgang Denk committed
				enum OP_FIELD, unsigned long *));
Wolfgang Denk's avatar
Wolfgang Denk committed
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 *,
Wolfgang Denk's avatar
Wolfgang Denk committed
			struct operand *, char *, int *));
Wolfgang Denk's avatar
Wolfgang Denk committed
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.
 *
York Sun's avatar
York Sun committed
 * Returns true if the area was successfully disassembled or false if
Wolfgang Denk's avatar
Wolfgang Denk committed
 * 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) {
York Sun's avatar
York Sun committed
			if ((line_info_from_addr ((Elf32_Word) ctx.virtual,
				filename, funcname, &line_no) == true) &&
Wolfgang Denk's avatar
Wolfgang Denk committed
				((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 =
York Sun's avatar
York Sun committed
				 symbol_name_from_addr((Elf32_Word) ctx.virtual,
						true, 0)) != 0) {
Wolfgang Denk's avatar
Wolfgang Denk committed
				cursym = symname;
				symoffset = 0;
			} else {
				if ((cursym == 0) &&
					((symname =
York Sun's avatar
York Sun committed
					  symbol_name_from_addr((Elf32_Word) ctx.virtual,
						false, &symoffset)) != 0)) {
Wolfgang Denk's avatar
Wolfgang Denk committed
					cursym = symname;
				} else {
					symoffset += 4;
				}
			}

			if (cursym != 0) {
				sprintf (&ctx.data[ctx.datalen], "<%s+", cursym);
				ctx.datalen = strlen (ctx.data);
				sprintf (&ctx.data[ctx.datalen], ctx.radix_fmt, symoffset);
				strcat (ctx.data, ">");
				ctx.datalen = strlen (ctx.data);
			}
		}
#endif /* USE_SOURCE_CODE */

		ctx.instr = INSTRUCTION (memaddr);

		if (ctx.flags & F_INSTR) {
			/* Find the opcode structure for this opcode.  If one is not found
			   then it must be an illegal instruction */
			sprintf (&ctx.data[ctx.datalen],
					 "   %02lx %02lx %02lx %02lx    ",
					 ((ctx.instr >> 24) & 0xff),
					 ((ctx.instr >> 16) & 0xff), ((ctx.instr >> 8) & 0xff),
					 (ctx.instr & 0xff));
			ctx.datalen += 18;
		} else {
			strcat (ctx.data, "   ");
			ctx.datalen += 3;
		}

		if ((ctx.op = find_opcode (ctx.instr)) == 0) {
			/* Illegal Opcode */
			sprintf (&ctx.data[ctx.datalen], "        .long 0x%08lx",
Loading
Loading full blame...