⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bedbug.c.svn-base

📁 u-boot loader common files, like cpu, clock, environment...etc...
💻 SVN-BASE
📖 第 1 页 / 共 2 页
字号:
/* $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 + -