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

📄 fasttrap_isa.c

📁 Sun Solaris 10 中的 DTrace 组件的源代码。请参看: http://www.sun.com/software/solaris/observability.jsp
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright 2005 Sun Microsystems, Inc.  All rights reserved. * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only. * See the file usr/src/LICENSING.NOTICE in this distribution or * http://www.opensolaris.org/license/ for details. */#pragma ident	"@(#)fasttrap_isa.c	1.13	04/11/17 SMI"#include <sys/fasttrap_isa.h>#include <sys/fasttrap_impl.h>#include <sys/dtrace.h>#include <sys/dtrace_impl.h>#include <sys/cmn_err.h>#include <sys/regset.h>#include <sys/privregs.h>#include <sys/segments.h>#include <sys/sysmacros.h>#include <sys/trap.h>/* * Lossless User-Land Tracing on x86 * --------------------------------- * * Most instructions' execution is not dependent on their address; for these * instrutions it is sufficient to copy them into the user process's address * space and execute them. To effectively single-step an instruction in * user-land, we copy out the following sequence of instructions to scratch * space in the user thread's ulwp_t structure. * * We then set the program counter (%eip or %rip) to point to this scratch * space. Once execution resumes, the original instruction is executed and * then control flow is redirected to what was originally the subsequent * instruction. If the kernel attemps to deliver a signal while single- * stepping, the signal is deferred and the program counter is moved into the * second sequence of instructions. The second sequence ends in a trap into * the kernel where the deferred signal is then properly handled and delivered. * * For instructions whose execute is position dependent, we perform simple * emulation. These instructions are limited to control transfer * instructions in 32-bit mode, but in 64-bit mode there's the added wrinkle * of %rip-relative addressing that means that almost any instruction can be * position dependent. For all the details on how we emulate generic * instructions included %rip-relative instructions, see the code in * fasttrap_pid_probe() below where we handle instructions of type * FASTTRAP_T_COMMON (under the header: Generic Instruction Tracing). */#define	FASTTRAP_MODRM_MOD(modrm)	(((modrm) >> 6) & 0x3)#define	FASTTRAP_MODRM_REG(modrm)	(((modrm) >> 3) & 0x7)#define	FASTTRAP_MODRM_RM(modrm)	((modrm) & 0x7)#define	FASTTRAP_MODRM(mod, reg, rm)	(((mod) << 6) | ((reg) << 3) | (rm))#define	FASTTRAP_SIB_SCALE(sib)		(((sib) >> 6) & 0x3)#define	FASTTRAP_SIB_INDEX(sib)		(((sib) >> 3) & 0x7)#define	FASTTRAP_SIB_BASE(sib)		((sib) & 0x7)#define	FASTTRAP_REX_W(rex)		(((rex) >> 3) & 1)#define	FASTTRAP_REX_R(rex)		(((rex) >> 2) & 1)#define	FASTTRAP_REX_X(rex)		(((rex) >> 1) & 1)#define	FASTTRAP_REX_B(rex)		((rex) & 1)#define	FASTTRAP_REX(w, r, x, b)	\	(0x40 | ((w) << 3) | ((r) << 2) | ((x) << 1) | (b))/* * Single-byte op-codes. */#define	FASTTRAP_PUSHL_EBP	0x55#define	FASTTRAP_JO		0x70#define	FASTTRAP_JNO		0x71#define	FASTTRAP_JB		0x72#define	FASTTRAP_JAE		0x73#define	FASTTRAP_JE		0x74#define	FASTTRAP_JNE		0x75#define	FASTTRAP_JBE		0x76#define	FASTTRAP_JA		0x77#define	FASTTRAP_JS		0x78#define	FASTTRAP_JNS		0x79#define	FASTTRAP_JP		0x7a#define	FASTTRAP_JNP		0x7b#define	FASTTRAP_JL		0x7c#define	FASTTRAP_JGE		0x7d#define	FASTTRAP_JLE		0x7e#define	FASTTRAP_JG		0x7f#define	FASTTRAP_MOV_EAX	0xb8#define	FASTTRAP_MOV_ECX	0xb9#define	FASTTRAP_RET16		0xc2#define	FASTTRAP_RET		0xc3#define	FASTTRAP_LOOPNZ		0xe0#define	FASTTRAP_LOOPZ		0xe1#define	FASTTRAP_LOOP		0xe2#define	FASTTRAP_JCXZ		0xe3#define	FASTTRAP_CALL		0xe8#define	FASTTRAP_JMP32		0xe9#define	FASTTRAP_JMP8		0xeb#define	FASTTRAP_INT3		0xcc#define	FASTTRAP_INT		0xcd#define	FASTTRAP_2_BYTE_OP	0x0f#define	FASTTRAP_GROUP5_OP	0xff/* * Two-byte op-codes (second byte only). */#define	FASTTRAP_0F_JO		0x80#define	FASTTRAP_0F_JNO		0x81#define	FASTTRAP_0F_JB		0x82#define	FASTTRAP_0F_JAE		0x83#define	FASTTRAP_0F_JE		0x84#define	FASTTRAP_0F_JNE		0x85#define	FASTTRAP_0F_JBE		0x86#define	FASTTRAP_0F_JA		0x87#define	FASTTRAP_0F_JS		0x88#define	FASTTRAP_0F_JNS		0x89#define	FASTTRAP_0F_JP		0x8a#define	FASTTRAP_0F_JNP		0x8b#define	FASTTRAP_0F_JL		0x8c#define	FASTTRAP_0F_JGE		0x8d#define	FASTTRAP_0F_JLE		0x8e#define	FASTTRAP_0F_JG		0x8f#define	FASTTRAP_EFLAGS_OF	0x800#define	FASTTRAP_EFLAGS_DF	0x400#define	FASTTRAP_EFLAGS_SF	0x080#define	FASTTRAP_EFLAGS_ZF	0x040#define	FASTTRAP_EFLAGS_AF	0x010#define	FASTTRAP_EFLAGS_PF	0x004#define	FASTTRAP_EFLAGS_CF	0x001/* * Instruction prefixes. */#define	FASTTRAP_PREFIX_OPERAND	0x66#define	FASTTRAP_PREFIX_ADDRESS	0x67#define	FASTTRAP_PREFIX_CS	0x2E#define	FASTTRAP_PREFIX_DS	0x3E#define	FASTTRAP_PREFIX_ES	0x26#define	FASTTRAP_PREFIX_FS	0x64#define	FASTTRAP_PREFIX_GS	0x65#define	FASTTRAP_PREFIX_SS	0x36#define	FASTTRAP_PREFIX_LOCK	0xF0#define	FASTTRAP_PREFIX_REP	0xF3#define	FASTTRAP_PREFIX_REPNE	0xF2#define	FASTTRAP_NOREG	0xff/* * Map between instruction register encodings and the kernel constants which * correspond to indicies into struct regs. */#ifdef __amd64static const uint8_t regmap[16] = {	REG_RAX, REG_RCX, REG_RDX, REG_RBX, REG_RSP, REG_RBP, REG_RSI, REG_RDI,	REG_R8, REG_R9, REG_R10, REG_R11, REG_R12, REG_R13, REG_R14, REG_R15,};#elsestatic const uint8_t regmap[8] = {	EAX, ECX, EDX, EBX, UESP, EBP, ESI, EDI};#endifstatic ulong_t fasttrap_getreg(struct regs *, uint_t);static uint64_tfasttrap_anarg(struct regs *rp, int function_entry, int argno){	uint64_t value;	int shift = function_entry ? 1 : 0;#ifdef __amd64	if (curproc->p_model == DATAMODEL_LP64) {		uintptr_t *stack;		/*		 * In 64-bit mode, the first six arguments are stored in		 * registers.		 */		if (argno < 6)			return ((&rp->r_rdi)[argno]);		stack = (uintptr_t *)rp->r_sp;		DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);		value = dtrace_fulword(&stack[argno + shift]);		DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR);	} else {#endif		uint32_t *stack = (uint32_t *)rp->r_sp;		DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);		value = dtrace_fuword32(&stack[argno + shift]);		DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR);#ifdef __amd64	}#endif	return (value);}/*ARGSUSED*/intfasttrap_tracepoint_init(proc_t *p, fasttrap_probe_t *probe,    fasttrap_tracepoint_t *tp, uintptr_t pc){	uint8_t instr[FASTTRAP_MAX_INSTR_SIZE + 10];	size_t len = FASTTRAP_MAX_INSTR_SIZE;	size_t first = MIN(len, PAGESIZE - (pc & PAGEOFFSET));	uint_t start = 0;	int rmindex;	uint8_t rex = 0;	/*	 * Read the instruction at the given address out of the process's	 * address space. We don't have to worry about a debugger	 * changing this instruction before we overwrite it with our trap	 * instruction since P_PR_LOCK is set. Since instructions can span	 * pages, we potentially read the instruction in two parts. If the	 * second part fails, we just zero out that part of the instruction.	 */	if (fasttrap_uread(p, &instr[0], first, pc) != 0)		return (-1);	if (len > first &&	    fasttrap_uread(p, &instr[first], len - first, pc + first) != 0) {		bzero(&instr[first], len - first);		len = first;	}	/*	 * If the disassembly fails, then we have a malformed instruction.	 */	if ((tp->ftt_size = dtrace_instr_size_isa(instr, p->p_model,	    &rmindex)) <= 0)		return (-1);	/*	 * Make sure the disassembler isn't completely broken.	 */	ASSERT(-1 <= rmindex && rmindex < tp->ftt_size);	/*	 * If the computed size is greater than the number of bytes read,	 * then it was a malformed instruction possibly because it fell on a	 * page boundary and the subsequent page was missing or because of	 * some malicious user.	 */	if (tp->ftt_size > len)		return (-1);	/*	 * Find the start of the instruction's opcode by processing any	 * legacy prefixes.	 */	for (;;) {		switch (instr[start]) {		case FASTTRAP_PREFIX_OPERAND:		case FASTTRAP_PREFIX_ADDRESS:		case FASTTRAP_PREFIX_CS:		case FASTTRAP_PREFIX_DS:		case FASTTRAP_PREFIX_ES:		case FASTTRAP_PREFIX_FS:		case FASTTRAP_PREFIX_GS:		case FASTTRAP_PREFIX_SS:		case FASTTRAP_PREFIX_LOCK:		case FASTTRAP_PREFIX_REP:		case FASTTRAP_PREFIX_REPNE:			start++;			continue;		}		break;	}#ifdef __amd64	/*	 * Identify the REX prefix on 64-bit processes.	 */	if (p->p_model == DATAMODEL_LP64 && (instr[start] & 0xf0) == 0x40)		rex = instr[start++];#endif	/*	 * Now that we're pretty sure that the instruction is okay, copy the	 * valid part to the tracepoint.	 */	bcopy(instr, tp->ftt_instr, FASTTRAP_MAX_INSTR_SIZE);	tp->ftt_type = FASTTRAP_T_COMMON;	if (instr[start] == FASTTRAP_2_BYTE_OP) {		switch (instr[start + 1]) {		case FASTTRAP_0F_JO:		case FASTTRAP_0F_JNO:		case FASTTRAP_0F_JB:		case FASTTRAP_0F_JAE:		case FASTTRAP_0F_JE:		case FASTTRAP_0F_JNE:		case FASTTRAP_0F_JBE:		case FASTTRAP_0F_JA:		case FASTTRAP_0F_JS:		case FASTTRAP_0F_JNS:		case FASTTRAP_0F_JP:		case FASTTRAP_0F_JNP:		case FASTTRAP_0F_JL:		case FASTTRAP_0F_JGE:		case FASTTRAP_0F_JLE:		case FASTTRAP_0F_JG:			tp->ftt_type = FASTTRAP_T_JCC;			tp->ftt_code = (instr[start + 1] & 0x0f) | FASTTRAP_JO;			tp->ftt_dest = pc + tp->ftt_size +			    *(int32_t *)&instr[start + 2];			break;		}	} else if (instr[start] == FASTTRAP_GROUP5_OP) {		uint_t mod = FASTTRAP_MODRM_MOD(instr[start + 1]);		uint_t reg = FASTTRAP_MODRM_REG(instr[start + 1]);		uint_t rm = FASTTRAP_MODRM_RM(instr[start + 1]);		if (reg == 2 || reg == 4) {			uint_t i, sz;			if (reg == 2)				tp->ftt_type = FASTTRAP_T_CALL;			else				tp->ftt_type = FASTTRAP_T_JMP;			if (mod == 3)				tp->ftt_code = 2;			else				tp->ftt_code = 1;			ASSERT(p->p_model == DATAMODEL_LP64 || rex == 0);			/*			 * See AMD x86-64 Architecture Programmer's Manual			 * Volume 3, Section 1.2.7, Table 1-12, and			 * Appendix A.3.1, Table A-15.			 */			if (mod != 3 && rm == 4) {				uint8_t sib = instr[start + 2];				uint_t index = FASTTRAP_SIB_INDEX(sib);				uint_t base = FASTTRAP_SIB_BASE(sib);				tp->ftt_scale = FASTTRAP_SIB_SCALE(sib);				tp->ftt_index = (index == 4) ?				    FASTTRAP_NOREG :				    regmap[index | (FASTTRAP_REX_X(rex) << 3)];				tp->ftt_base = (mod == 0 && base == 5) ?				    FASTTRAP_NOREG :				    regmap[base | (FASTTRAP_REX_B(rex) << 3)];				i = 3;				sz = mod == 1 ? 1 : 4;			} else {				/*				 * In 64-bit mode, mod == 0 and r/m == 5				 * denotes %rip-relative addressing; in 32-bit				 * mode, the base register isn't used. In both				 * modes, there is a 32-bit operand.				 */				if (mod == 0 && rm == 5) {#ifdef __amd64					if (p->p_model == DATAMODEL_LP64)						tp->ftt_base = REG_RIP;					else#endif						tp->ftt_base = FASTTRAP_NOREG;					sz = 4;				} else  {					uint8_t base = rm |					    (FASTTRAP_REX_B(rex) << 3);					tp->ftt_base = regmap[base];					sz = mod == 1 ? 1 : mod == 2 ? 4 : 0;				}				tp->ftt_index = FASTTRAP_NOREG;				i = 2;			}			if (sz == 1)				tp->ftt_dest = *(int8_t *)&instr[start + i];			else if (sz == 4)				tp->ftt_dest = *(int32_t *)&instr[start + i];			else				tp->ftt_dest = 0;		}	} else {		switch (instr[start]) {		case FASTTRAP_RET:			tp->ftt_type = FASTTRAP_T_RET;			break;		case FASTTRAP_RET16:			tp->ftt_type = FASTTRAP_T_RET16;			tp->ftt_dest = *(uint16_t *)&instr[start + 1];			break;		case FASTTRAP_JO:		case FASTTRAP_JNO:		case FASTTRAP_JB:		case FASTTRAP_JAE:		case FASTTRAP_JE:		case FASTTRAP_JNE:		case FASTTRAP_JBE:		case FASTTRAP_JA:		case FASTTRAP_JS:		case FASTTRAP_JNS:		case FASTTRAP_JP:		case FASTTRAP_JNP:		case FASTTRAP_JL:		case FASTTRAP_JGE:		case FASTTRAP_JLE:		case FASTTRAP_JG:			tp->ftt_type = FASTTRAP_T_JCC;			tp->ftt_code = instr[start];			tp->ftt_dest = pc + tp->ftt_size +			    (int8_t)instr[start + 1];			break;		case FASTTRAP_LOOPNZ:		case FASTTRAP_LOOPZ:		case FASTTRAP_LOOP:			tp->ftt_type = FASTTRAP_T_LOOP;			tp->ftt_code = instr[start];			tp->ftt_dest = pc + tp->ftt_size +			    (int8_t)instr[start + 1];			break;		case FASTTRAP_JCXZ:			tp->ftt_type = FASTTRAP_T_JCXZ;			tp->ftt_dest = pc + tp->ftt_size +			    (int8_t)instr[start + 1];			break;		case FASTTRAP_CALL:			tp->ftt_type = FASTTRAP_T_CALL;			tp->ftt_dest = pc + tp->ftt_size +			    *(int32_t *)&instr[start + 1];			tp->ftt_code = 0;			break;		case FASTTRAP_JMP32:			tp->ftt_type = FASTTRAP_T_JMP;			tp->ftt_dest = pc + tp->ftt_size +			    *(int32_t *)&instr[start + 1];			break;		case FASTTRAP_JMP8:			tp->ftt_type = FASTTRAP_T_JMP;			tp->ftt_dest = pc + tp->ftt_size +			    (int8_t)instr[start + 1];			break;		case FASTTRAP_PUSHL_EBP:			if (start == 0)				tp->ftt_type = FASTTRAP_T_PUSHL_EBP;			break;		case FASTTRAP_INT3:			/*			 * The pid provider shares the int3 trap with debugger			 * breakpoints so we can't instrument them.			 */			ASSERT(instr[start] == FASTTRAP_INSTR);			return (-1);		}	}#ifdef __amd64	if (p->p_model == DATAMODEL_LP64 && tp->ftt_type == FASTTRAP_T_COMMON) {		/*		 * If the process is 64-bit and the instruction type is still		 * FASTTRAP_T_COMMON -- meaning we're going to copy it out an		 * execute it -- we need to watch for %rip-relative		 * addressing mode. See the portion of fasttrap_pid_probe()		 * below where we handle tracepoints with type		 * FASTTRAP_T_COMMON for how we emulate instructions that		 * employ %rip-relative addressing.		 */		if (rmindex != -1) {			uint_t mod = FASTTRAP_MODRM_MOD(instr[rmindex]);			uint_t reg = FASTTRAP_MODRM_REG(instr[rmindex]);			uint_t rm = FASTTRAP_MODRM_RM(instr[rmindex]);			ASSERT(rmindex > start);			if (mod == 0 && rm == 5) {				/*				 * We need to be sure to avoid other				 * registers used by this instruction. While				 * the reg field may determine the op code				 * rather than denoting a register, assuming				 * that it denotes a register is always safe.				 * We leave the REX field intact and use				 * whatever value's there for simplicity.				 */				if (reg != 0) {					tp->ftt_ripmode = FASTTRAP_RIP_1 |					    (FASTTRAP_RIP_X *

⌨️ 快捷键说明

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