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

📄 sparc-tcmn.c

📁 早期freebsd实现
💻 C
字号:
/* * Copyright (c) 1992 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Lawrence Berkeley Laboratory, * Berkeley, CA.  The name of the University may not be used to * endorse or promote products derived from this software without * specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */#ifndef lintstatic char rcsid[] =    "@(#) $Header: sparc-tcmn.c,v 1.2 93/02/19 15:25:05 mccanne Exp $ (LBL)";#endif#include <sys/param.h>#include <stdio.h>#include "defs.h"#include "target.h"#include "frame.h"#include "inferior.h"#include "value.h"/* * Sparc instruction format per Fig 4-1 of the Sun SPARC Architecture  * Manual Part No: 800-1399-08 Rev A, Oct 22 1987. */union sparcinsn {	u_long code;	struct {		u_int op:2;		u_int disp30:30;	} f1;	struct insn_f2a {		u_int op:2;		u_int rd:5;		u_int op2:3;		int imm22:22;	} f2a;	struct insn_f2b {		u_int op:2;		u_int a:1;		u_int cond:4;		u_int op2:3;		int disp22:22;	} f2b;	struct insn_f3a {		u_int op:2;		u_int rd:5;		u_int op3:6;		u_int rs1:5;		u_int i:1;		u_int asi:8;		u_int rs2:5;	} f3a;	struct insn_f3b {		u_int op:2;		u_int rd:5;		u_int op3:6;		u_int rs1:5;		u_int i:1;		int simm13:13;	} f3b;};/* * For the instruction INSN at PC, return the address, other than NPC, that * could possibly be executed next.  If the only possibility is npc, return 0. * (There is only one such "other" possible address.) */CORE_ADDRannulled_dest(insn, pc, npc)	union sparcinsn insn;	CORE_ADDR pc, npc;{	register struct insn_f2b i = insn.f2b; 	/*	 * The only time we can branch somewhere other than npc is	 * on a branch intruction with the anull bit set.  In this	 * case, the other possible target is the npc + 4 (because	 * npc was anulled and the branch was not taken) or the	 * branch destination (because npc was anulled and it was	 * a branch always).	 */	if (i.op == 0 && i.a && (i.op2 == 2 || i.op2 == 6 || i.op2 == 7)) {		if (i.cond == 8)			return (pc + 4 * i.disp22);		else			return (npc + 4);	}	return (0);}/* * Non-zero if we just simulated a single-step ptrace call.  This is * needed because we cannot remove the breakpoints in the inferior * process until after the `wait' in `wait_for_inferior'.  * Used for sun4. */int one_stepped;/* * single_step() is called just before we want to resume the inferior, * if we want to single-step it but there is no hardware or kernel single-step * support (as on all SPARCs).  We find all the possible targets of the * coming instruction and breakpoint them. * * single_step is also called just after the inferior stops.  If we had * set up a simulated single-step, we undo our damage. * * Code written by Gary Beihl (beihl@mcc.com); modified by Steven McCanne * (mccanne@ee.lbl.gov). */voidsingle_step(signal)	int signal;{	CORE_ADDR pc;	union sparcinsn insn;	/*	 * Storage for temporary breakpoints.  XXX There should be a uniform	 * interface for breakpoints, so that we could just set one then 	 * clear it.  Note that we need only two outstanding breakpoints,	 * since there can be at most two possiblilities for control flow.	 */	static CORE_ADDR target0;	static CORE_ADDR target1;	static char shadow0[4];	static char shadow1[4];	pc = read_register(PC_REGNUM);	insn.code = read_memory_integer(pc, 4);	if (!one_stepped) {		/*		 * This is a hack to special case call instructions.		 * If we are stepping over subroutines, find each call		 * and trap on return, rather than single step until		 * wait_for_inferior() discovers that we hit a new routine.		 * The reason is that stepping over functions in a remote 		 * kernel can have bad results when the function being 		 * stepped over is used by the kernel in between traps.		 * (i.e., a trap instruction gets poked into the function		 * being stepped over).		 */		if (step_over_calls > 0 &&		    ((insn.code & 0xc0000000) == 0x40000000 || 		     (insn.code & 0xfff80000) == 0x9fc00000)) {			target0 = PC_ADJUST(pc);			target1 = 0;		} else {			target0 = read_register(NPC_REGNUM);			target1 = annulled_dest(insn, pc, target0);			if (target1 == target0)				target1 = 0;		}		target_insert_breakpoint(target0, shadow0);		if (target1)			target_insert_breakpoint(target1, shadow1);		one_stepped = 1;	} else {		/* Remove breakpoints */		if (target1)			target_remove_breakpoint(target1, shadow1);		target_remove_breakpoint(target0, shadow0);		one_stepped = 0;	}}/* XXX this looks polluted */#define	FRAME_SAVED_L0	0		/* Byte offset from SP */#define	FRAME_SAVED_I0	32		/* Byte offset from SP *//* * Find the previous stack frame pointer, given the current frame. * On a sparc, this is just the i6 register that was flushed to * the kernel save area (pointed to by the previous frame's sp, * which is the current frame's fp). */CORE_ADDRsparc_frame_chain(frame)	FRAME frame;{	CORE_ADDR retval;	CORE_ADDR addr;	addr = frame->frame + FRAME_SAVED_I0 +		  REGISTER_RAW_SIZE(FP_REGNUM) * (FP_REGNUM - I0_REGNUM);	if (target_read_memory(addr, (char *)&retval, sizeof(retval)))		return (0);	SWAP_TARGET_AND_HOST(&retval, sizeof(retval));	return (retval);}/* * Read the the first word after the kernel save area of the current * frame.  This is where Sun cc puts a pointer to storage for a structure * return value.  Return 0 on read errors. */CORE_ADDRsparc_extract_struct_value_address(regs)	char *regs;{	CORE_ADDR addr, v;	bcopy(&regs[REGISTER_BYTE(SP_REGNUM)], (char *)&addr, sizeof(addr));	if (target_read_memory(addr, (char *)&v, sizeof(v)))		return (0);	SWAP_TARGET_AND_HOST(&v, sizeof(v));	return (v);}/* * Find the pc saved in frame FRAME.   */CORE_ADDRframe_saved_pc(frame)     FRAME frame;{	return (PC_ADJUST(read_memory_integer(addr_of_pc(frame), 4)));}FRAMEsetup_arbitrary_frame(fp, sp)	FRAME_ADDR fp, sp;{	FRAME f = create_new_frame(fp, 0);	f->bottom = sp;	f->pc = frame_saved_pc(f);	return (f);}static int restore_code[] = {	0x81e80000,		/* restore */	0x91d02001,		/* t 1 */	0x01000000		/* nop */};static voiddo_restore_insn(){	/* From infrun.c */	extern int stop_after_trap;	CORE_ADDR sp = read_register(SP_REGNUM);	CORE_ADDR pc = sp - sizeof(restore_code);		write_memory(pc, (char *)restore_code, sizeof(restore_code));	clear_proceed_status ();	stop_after_trap = 1;	proceed(pc, 0, 0);}/* * True iff sparc insn INSN is a save instruction. */#define SAVE_INSN_P(i) ((insn).f3b.op == 2 && (insn).f3b.op3 == 60)/* * True iff sparc insn INSN is a store instruction of an input register * into the arg overflow area, which starts at [fp + 64] and has a  * length of 24 bytes (enough for i0 through i5). */#define ARGSTORE_INSN_P(insn)\	((insn).f3b.op == 3 && ((insn).f3b.op3 & 0x3c) == 4 && \	 (insn).f3b.rs1 == FP_REGNUM && (insn).f3b.i == 1 && \	 (insn).f3b.simm13 >= 64 && (insn).f3b.simm13 < 64 + 24)CORE_ADDR skip_prologue(addr, frameless_p)	CORE_ADDR addr;	int frameless_p;{	register union sparcinsn insn;	register CORE_ADDR pc = addr;	register int n = 3;	while (--n >= 0) {		insn.code = read_memory_integer(pc, 4);		pc += 4;		if (SAVE_INSN_P(insn)) {			if (frameless_p)				return (pc);			insn.code = read_memory_integer(pc, 4);			while (ARGSTORE_INSN_P(insn)) {				pc += 4;				insn.code = read_memory_integer(pc, 4);			}		}		return (pc);	}	/*	 * Couldn't find a save instruction.	 */	return (addr);}voidsparc_pop_frame(){	register CORE_ADDR pc;	pc = read_register(I7_REGNUM);	do_restore_insn();	/*	 * Return address in %i7 -- 	 * adjust it, then restore PC and NPC from it.	 */	pc = PC_ADJUST(read_memory_integer(pc, 4));	write_register(PC_REGNUM, pc);	write_register(NPC_REGNUM, pc + 4);	flush_cached_frames();	set_current_frame(create_new_frame(read_register(FP_REGNUM), pc));}/* * Sun's cc leaves a hole after a call to function returning a structure * (after the delay slot).  Given a function call at PC, return the * address to which the called function will return. */CORE_ADDRsparc_pc_adjust(pc)	register CORE_ADDR pc;{	u_long op;	if (target_read_memory(pc + 8, (char *)&op, 4) == 0) {		SWAP_TARGET_AND_HOST(&op, 4);		if ((op & ~0x1ff) == 0)			/*			 * The 20 high bits of this opcode are 0, which			 * does not conform to a valid instruction.  			 * It must be the Sun structure length hack.			 */			return (pc + 12);	}	return (pc + 8);}int dummy_code[] = {	0xd003a044,		/* ld	[%sp + 68], %o0 */	0xd203a048,		/* ld	[%sp + 72], %o1 */	0xd403a04c,		/* ld	[%sp + 76], %o2 */	0xd603a050,		/* ld	[%sp + 80], %o3 */	0xd803a054,		/* ld	[%sp + 84], %o4 */#define DUMMY_CALL_INDEX 5	0x40000000,		/* call .		*/	0xda03a058,		/* ld	[%sp + 88], %o5 */#define DUMMY_STRUCTLEN_INDEX 7	0x01000000,		/* nop - extra insn for Sun cc */	0x91d02001,		/* ta	1		*/	0x01000000,		/* nop */};/* * Leave room on the stack for the kernel save area and the pointer * for structure return values. */#define KSA_AND_STRUCT_ADJUST 68/* * Build `dummy' call instructions on inferior's stack to cause * it to call a subroutine. * * N.B. - code in wait_for_inferior requires that sp < pc < fp when * we take the trap 2 above so it will recognize that we stopped * at a `dummy' call.  So, after the call sp is *not* decremented * to clean the arguments, code & other stuff we lay on the stack. * Since the regs are restored to saved values at the breakpoint, * sp will get reset correctly.  Also, this restore means we don't * have to construct frame linkage info to save pc & fp.  The lack * of frame linkage means we can't do a backtrace, etc., if the * called function gets a fault or hits a breakpoint but code in * run_stack_dummy makes this impossible anyway. */CORE_ADDRsetup_dummy(sp, funaddr, nargs, args, struct_return_bytes, gcc_p)	CORE_ADDR sp;	CORE_ADDR funaddr;	int nargs;	value *args;	int struct_return_bytes;	int gcc_p;{	int len, padding, i;	CORE_ADDR top = sp, struct_addr, pc;	pc = sp - sizeof(dummy_code);	len = value_arg_bytes(nargs, args) + KSA_AND_STRUCT_ADJUST + 		sizeof(dummy_code) + struct_return_bytes;	padding = STACK_ALIGN(len) - len;	sp = pc - padding - struct_return_bytes;	struct_addr = sp;	for (i = 0; i < nargs; ++i) {		/* pushfn doesn't actually change SP_REGNUM */		sp = value_arg_push(sp, args[i]);	}	sp -= KSA_AND_STRUCT_ADJUST;	if (struct_return_bytes) {		write_memory(sp + KSA_AND_STRUCT_ADJUST - 4,			     (char *)&struct_addr, 4);		/* Appease Sun's twisted convention for struct returns. */		if (!gcc_p)			dummy_code[DUMMY_STRUCTLEN_INDEX] = 				struct_return_bytes & 0x1fff;	} else		/* nop */		dummy_code[DUMMY_STRUCTLEN_INDEX] = 0x01000000;	write_register(SP_REGNUM, sp);	dummy_code[DUMMY_CALL_INDEX] = 0x40000000 | 		((unsigned)(funaddr - (pc + 4 * DUMMY_CALL_INDEX)) >> 2);	write_memory(pc, (char *)dummy_code, sizeof(dummy_code));	return pc;}/* * Only worry about KSA. */frame_find_saved_regs(fi, srp)	struct frame_info *fi;	struct frame_saved_regs *srp;{	register int i;	FRAME_ADDR frame;	bzero ((char *)srp, sizeof *srp);	frame = fi->bottom;	/* XXX There's no excuse for this. */	if (frame == 0)		abort();	/* ins and locals */	for (i = 16; i < 32; i++)		srp->regs[i] = frame + (i-16) * 4;	if (fi->next != 0) {		frame = fi->next->bottom;		/* outs */		for (i = 8; i < 16; i++)			srp->regs[i] = frame + i * 4;	}	srp->regs[PC_REGNUM] = addr_of_pc(fi);}static voidfix_leaf_frame(arg, from_tty)	char* arg;	int from_tty;{	int arg1 = 0, level;	FRAME fid, nfid;	struct frame_info *fi, *nfi;	if (!target_has_stack)		error ("No inferior or core file.");	if (arg) {		while (*arg && *arg == ' ')			++arg;		if (*arg)			arg1 = parse_and_eval_address(arg);	}	level = arg1;	fid = find_relative_frame(get_current_frame(), &level);	if (level != 0)		error("Can't find frame %d",  arg1);	fi = get_frame_info(fid);	nfid = create_new_frame(fi->frame, fi->pc);	nfi = get_frame_info(nfid);	*nfi = *fi;	nfi->pc = read_register(RP_REGNUM);	nfi->next = fi;	fi->prev = nfi;}void_initialize_sparctcmn(){	add_com("fix-leaf", class_stack, fix_leaf_frame,		"fix up the call stack to account for a leaf routine\n\A new frame is inserted for the routine that called the leaf.");}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -