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

📄 fasttrap_isa.c

📁 Sun Solaris 10 中的 DTrace 组件的源代码。请参看: http://www.sun.com/software/solaris/observability.jsp
💻 C
📖 第 1 页 / 共 3 页
字号:
		 * This is an optimization to let us handle function		 * return probes more efficiently. Most non-leaf functions		 * end with the sequence:		 *	ret		 *	restore	<reg>, <reg_or_imm>, %oX		 *		 * We've stashed the instruction:		 *	restore	%g0, %g0, %g0		 *		 * off of %g7 so we just need to place the correct value		 * in the right %i register (since after our fake-o		 * restore, the %i's will become the %o's) and set the %pc		 * to point to our hidden restore. We also set fake_restore to		 * let fasttrap_return_common() know that it will find the		 * return values in the %i's rather than the %o's.		 */		if (I(tp->ftt_instr)) {			int32_t imm;			imm = tp->ftt_instr << 19;			imm >>= 19;			value = fasttrap_getreg(rp, RS1(tp->ftt_instr)) + imm;		} else {			value = fasttrap_getreg(rp, RS1(tp->ftt_instr)) +			    fasttrap_getreg(rp, RS2(tp->ftt_instr));		}		/*		 * Convert %o's to %i's; leave %g's as they are.		 */		rd = RD(tp->ftt_instr);		fasttrap_putreg(rp, ((rd & 0x18) == 0x8) ? rd + 16 : rd, value);		pc = rp->r_g7 + FASTTRAP_OFF_RESTORE;		fake_restore = 1;		break;	}	case FASTTRAP_T_RETURN:	{		uintptr_t target;		/*		 * A return instruction is like a jmpl (without the link		 * part) that executes an implicit restore. We've stashed		 * the instruction:		 *	return %o0		 *		 * off of %g7 so we just need to place the target in %o0		 * and set the %pc to point to the stashed return instruction.		 * We use %o0 since that register disappears after the return		 * executes, erasing any evidence of this tampering.		 */		if (I(tp->ftt_instr)) {			int32_t imm;			imm = tp->ftt_instr << 19;			imm >>= 19;			target = fasttrap_getreg(rp, RS1(tp->ftt_instr)) + imm;		} else {			target = fasttrap_getreg(rp, RS1(tp->ftt_instr)) +			    fasttrap_getreg(rp, RS2(tp->ftt_instr));		}		fasttrap_putreg(rp, R_O0, target);		pc = rp->r_g7 + FASTTRAP_OFF_RETURN;		fake_restore = 1;		break;	}	case FASTTRAP_T_OR:	{		ulong_t value;		if (I(tp->ftt_instr)) {			int32_t imm;			imm = tp->ftt_instr << 19;			imm >>= 19;			value = fasttrap_getreg(rp, RS1(tp->ftt_instr)) | imm;		} else {			value = fasttrap_getreg(rp, RS1(tp->ftt_instr)) |			    fasttrap_getreg(rp, RS2(tp->ftt_instr));		}		fasttrap_putreg(rp, RD(tp->ftt_instr), value);		pc = rp->r_npc;		npc = pc + 4;		break;	}	case FASTTRAP_T_SETHI:		if (RD(tp->ftt_instr) != R_G0) {			uint32_t imm32 = tp->ftt_instr << 10;			fasttrap_putreg(rp, RD(tp->ftt_instr), (ulong_t)imm32);		}		pc = rp->r_npc;		npc = pc + 4;		break;	case FASTTRAP_T_CCR:	{		uint_t c, v, z, n, taken;		uint_t ccr = rp->r_tstate >> TSTATE_CCR_SHIFT;		if (tp->ftt_cc != 0)			ccr >>= 4;		c = (ccr >> 0) & 1;		v = (ccr >> 1) & 1;		z = (ccr >> 2) & 1;		n = (ccr >> 3) & 1;		switch (tp->ftt_code) {		case 0x0:	/* BN */			taken = 0;		break;		case 0x1:	/* BE */			taken = z;		break;		case 0x2:	/* BLE */			taken = z | (n ^ v);	break;		case 0x3:	/* BL */			taken = n ^ v;		break;		case 0x4:	/* BLEU */			taken = c | z;		break;		case 0x5:	/* BCS (BLU) */			taken = c;		break;		case 0x6:	/* BNEG */			taken = n;		break;		case 0x7:	/* BVS */			taken = v;		break;		case 0x8:	/* BA */			/*			 * We handle the BA case differently since the annul			 * bit means something slightly different.			 */			panic("fasttrap: mishandled a branch");			taken = 1;		break;		case 0x9:	/* BNE */			taken = ~z;		break;		case 0xa:	/* BG */			taken = ~(z | (n ^ v));	break;		case 0xb:	/* BGE */			taken = ~(n ^ v);	break;		case 0xc:	/* BGU */			taken = ~(c | z);	break;		case 0xd:	/* BCC (BGEU) */			taken = ~c;		break;		case 0xe:	/* BPOS */			taken = ~n;		break;		case 0xf:	/* BVC */			taken = ~v;		break;		}		if (taken & 1) {			pc = rp->r_npc;			npc = tp->ftt_dest;		} else if (tp->ftt_flags & FASTTRAP_F_ANNUL) {			/*			 * Untaken annulled branches don't execute the			 * instruction in the delay slot.			 */			pc = rp->r_npc + 4;			npc = pc + 4;		} else {			pc = rp->r_npc;			npc = pc + 4;		}		break;	}	case FASTTRAP_T_FCC:	{		uint_t fcc;		uint_t taken;		uint64_t fsr;		dtrace_getfsr(&fsr);		if (tp->ftt_cc == 0) {			fcc = (fsr >> 10) & 0x3;		} else {			uint_t shift;			ASSERT(tp->ftt_cc <= 3);			shift = 30 + tp->ftt_cc * 2;			fcc = (fsr >> shift) & 0x3;		}		switch (tp->ftt_code) {		case 0x0:	/* FBN */			taken = (1 << fcc) & (0|0|0|0);	break;		case 0x1:	/* FBNE */			taken = (1 << fcc) & (8|4|2|0);	break;		case 0x2:	/* FBLG */			taken = (1 << fcc) & (0|4|2|0);	break;		case 0x3:	/* FBUL */			taken = (1 << fcc) & (8|0|2|0);	break;		case 0x4:	/* FBL */			taken = (1 << fcc) & (0|0|2|0);	break;		case 0x5:	/* FBUG */			taken = (1 << fcc) & (8|4|0|0);	break;		case 0x6:	/* FBG */			taken = (1 << fcc) & (0|4|0|0);	break;		case 0x7:	/* FBU */			taken = (1 << fcc) & (8|0|0|0);	break;		case 0x8:	/* FBA */			/*			 * We handle the FBA case differently since the annul			 * bit means something slightly different.			 */			panic("fasttrap: mishandled a branch");			taken = (1 << fcc) & (8|4|2|1);	break;		case 0x9:	/* FBE */			taken = (1 << fcc) & (0|0|0|1);	break;		case 0xa:	/* FBUE */			taken = (1 << fcc) & (8|0|0|1);	break;		case 0xb:	/* FBGE */			taken = (1 << fcc) & (0|4|0|1);	break;		case 0xc:	/* FBUGE */			taken = (1 << fcc) & (8|4|0|1);	break;		case 0xd:	/* FBLE */			taken = (1 << fcc) & (0|0|2|1);	break;		case 0xe:	/* FBULE */			taken = (1 << fcc) & (8|0|2|1);	break;		case 0xf:	/* FBO */			taken = (1 << fcc) & (0|4|2|1);	break;		}		if (taken) {			pc = rp->r_npc;			npc = tp->ftt_dest;		} else if (tp->ftt_flags & FASTTRAP_F_ANNUL) {			/*			 * Untaken annulled branches don't execute the			 * instruction in the delay slot.			 */			pc = rp->r_npc + 4;			npc = pc + 4;		} else {			pc = rp->r_npc;			npc = pc + 4;		}		break;	}	case FASTTRAP_T_REG:	{		uint64_t value;		uint_t taken;		uint_t reg = RS1(tp->ftt_instr);		/*		 * An ILP32 process shouldn't be using a branch predicated on		 * an %i or an %l since it would violate the ABI. It's a		 * violation of the ABI because we can't ensure deterministic		 * behavior. We should have identified this case when we		 * enabled the probe.		 */		ASSERT(p->p_model == DATAMODEL_LP64 || reg < 16);		value = fasttrap_getreg(rp, reg);		switch (tp->ftt_code) {		case 0x1:	/* BRZ */			taken = (value == 0);	break;		case 0x2:	/* BRLEZ */			taken = (value <= 0);	break;		case 0x3:	/* BRLZ */			taken = (value < 0);	break;		case 0x5:	/* BRNZ */			taken = (value != 0);	break;		case 0x6:	/* BRGZ */			taken = (value > 0);	break;		case 0x7:	/* BRGEZ */			taken = (value <= 0);	break;		default:		case 0x0:		case 0x4:			panic("fasttrap: mishandled a branch");		}		if (taken) {			pc = rp->r_npc;			npc = tp->ftt_dest;		} else if (tp->ftt_flags & FASTTRAP_F_ANNUL) {			/*			 * Untaken annulled branches don't execute the			 * instruction in the delay slot.			 */			pc = rp->r_npc + 4;			npc = pc + 4;		} else {			pc = rp->r_npc;			npc = pc + 4;		}		break;	}	case FASTTRAP_T_ALWAYS:		/*		 * BAs, BA,As...		 */		if (tp->ftt_flags & FASTTRAP_F_ANNUL) {			/*			 * Annulled branch always instructions never execute			 * the instruction in the delay slot.			 */			pc = tp->ftt_dest;			npc = tp->ftt_dest + 4;		} else {			pc = rp->r_npc;			npc = tp->ftt_dest;		}		break;	case FASTTRAP_T_RDPC:		fasttrap_putreg(rp, RD(tp->ftt_instr), rp->r_pc);		pc = rp->r_npc;		npc = pc + 4;		break;	case FASTTRAP_T_CALL:		/*		 * It's a call _and_ link remember...		 */		rp->r_o7 = rp->r_pc;		pc = rp->r_npc;		npc = tp->ftt_dest;		break;	case FASTTRAP_T_JMPL:		pc = rp->r_npc;		if (I(tp->ftt_instr)) {			uint_t rs1 = RS1(tp->ftt_instr);			int32_t imm;			imm = tp->ftt_instr << 19;			imm >>= 19;			npc = fasttrap_getreg(rp, rs1) + imm;		} else {			uint_t rs1 = RS1(tp->ftt_instr);			uint_t rs2 = RS2(tp->ftt_instr);			npc = fasttrap_getreg(rp, rs1) +			    fasttrap_getreg(rp, rs2);		}		/*		 * Do the link part of the jump-and-link instruction.		 */		fasttrap_putreg(rp, RD(tp->ftt_instr), rp->r_pc);		break;	case FASTTRAP_T_COMMON:	{		curthread->t_dtrace_scrpc = rp->r_g7;		curthread->t_dtrace_astpc = rp->r_g7 + FASTTRAP_OFF_FTRET;		/*		 * Copy the instruction to a reserved location in the		 * user-land thread structure, then set the PC to that		 * location and leave the NPC alone. We take pains to ensure		 * consistency in the instruction stream (See SPARC		 * Architecture Manual Version 9, sections 8.4.7, A.20, and		 * H.1.6; UltraSPARC I/II User's Manual, sections 3.1.1.1,		 * and 13.6.4) by using the ASI ASI_BLK_COMMIT_S to copy the		 * instruction into the user's address space without		 * bypassing the I$. There's no AS_USER version of this ASI		 * (as exist for other ASIs) so we use the lofault		 * mechanism to catch faults.		 */		if (dtrace_blksuword32(rp->r_g7, &tp->ftt_instr, 1) == -1) {			/*			 * If the copyout fails, then the process's state			 * is not consistent (the effects of the traced			 * instruction will never be seen). This process			 * cannot be allowed to continue execution.			 */			fasttrap_sigtrap(curproc, curthread, pc);			return (0);		}		curthread->t_dtrace_pc = pc;		curthread->t_dtrace_npc = npc;		curthread->t_dtrace_on = 1;		pc = curthread->t_dtrace_scrpc;		if (tp->ftt_retids != NULL) {			curthread->t_dtrace_step = 1;			curthread->t_dtrace_ret = 1;			npc = curthread->t_dtrace_astpc;		}		break;	}	default:		panic("fasttrap: mishandled an instruction");	}	/*	 * This bit me in the ass a couple of times, so lets toss this	 * in as a cursory sanity check.	 */	ASSERT(pc != rp->r_g7 + 4);	ASSERT(pc != rp->r_g7 + 8);	/*	 * If there were no return probes when we first found the tracepoint,	 * we should feel no obligation to honor any return probes that were	 * subsequently enabled -- they'll just have to wait until the next	 * time around.	 */	if (tp->ftt_retids != NULL) {		/*		 * We need to wait until the results of the instruction are		 * apparent before invoking any return probes. If this		 * instruction was emulated we can just call		 * fasttrap_return_common(); if it needs to be executed, we		 * need to wait until we return to the kernel.		 */		if (tp->ftt_type != FASTTRAP_T_COMMON) {			fasttrap_return_common(rp, orig_pc, pid, fake_restore);		} else {			ASSERT(curthread->t_dtrace_ret != 0);			ASSERT(curthread->t_dtrace_pc == orig_pc);			ASSERT(curthread->t_dtrace_scrpc == rp->r_g7);			ASSERT(npc == curthread->t_dtrace_astpc);		}	}	ASSERT(pc != 0);	rp->r_pc = pc;	rp->r_npc = npc;	return (0);}intfasttrap_return_probe(struct regs *rp){	proc_t *p = ttoproc(curthread);	pid_t pid;	uintptr_t pc = curthread->t_dtrace_pc;	uintptr_t npc = curthread->t_dtrace_npc;	curthread->t_dtrace_pc = 0;	curthread->t_dtrace_npc = 0;	curthread->t_dtrace_scrpc = 0;	curthread->t_dtrace_astpc = 0;	/*	 * Treat a child created by a call to vfork(2) as if it were its	 * parent. We know there's only one thread of control in such a	 * process: this one.	 */	while (p->p_flag & SVFORK) {		p = p->p_parent;	}	/*	 * We set the %pc and %npc to their values when the traced	 * instruction was initially executed so that it appears to	 * dtrace_probe() that we're on the original instruction, and so that	 * the user can't easily detect our complex web of lies.	 * dtrace_return_probe() (our caller) will correctly set %pc and %npc	 * after we return.	 */	rp->r_pc = pc;	rp->r_npc = npc;	pid = p->p_pid;	fasttrap_return_common(rp, pc, pid, 0);	return (0);}intfasttrap_tracepoint_install(proc_t *p, fasttrap_tracepoint_t *tp){	fasttrap_instr_t instr = FASTTRAP_INSTR;	if (fasttrap_uwrite(p, &instr, 4, tp->ftt_pc) != 0)		return (-1);	return (0);}intfasttrap_tracepoint_remove(proc_t *p, fasttrap_tracepoint_t *tp){	fasttrap_instr_t instr;	/*	 * Distinguish between read or write failures and a changed	 * instruction.	 */	if (fasttrap_uread(p, &instr, 4, tp->ftt_pc) != 0)

⌨️ 快捷键说明

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