xref: /freebsd-src/sys/cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c (revision 8370e9dfa188da4716c209a475e360d2b1a842f7)
16e19f4deSRui Paulo /*
26e19f4deSRui Paulo  * CDDL HEADER START
36e19f4deSRui Paulo  *
46e19f4deSRui Paulo  * The contents of this file are subject to the terms of the
56e19f4deSRui Paulo  * Common Development and Distribution License (the "License").
66e19f4deSRui Paulo  * You may not use this file except in compliance with the License.
76e19f4deSRui Paulo  *
86e19f4deSRui Paulo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96e19f4deSRui Paulo  * or http://www.opensolaris.org/os/licensing.
106e19f4deSRui Paulo  * See the License for the specific language governing permissions
116e19f4deSRui Paulo  * and limitations under the License.
126e19f4deSRui Paulo  *
136e19f4deSRui Paulo  * When distributing Covered Code, include this CDDL HEADER in each
146e19f4deSRui Paulo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156e19f4deSRui Paulo  * If applicable, add the following below this CDDL HEADER, with the
166e19f4deSRui Paulo  * fields enclosed by brackets "[]" replaced with your own identifying
176e19f4deSRui Paulo  * information: Portions Copyright [yyyy] [name of copyright owner]
186e19f4deSRui Paulo  *
196e19f4deSRui Paulo  * CDDL HEADER END
20625564deSRui Paulo  *
21625564deSRui Paulo  * Portions Copyright 2010 The FreeBSD Foundation
226e19f4deSRui Paulo  */
236e19f4deSRui Paulo 
246e19f4deSRui Paulo /*
256e19f4deSRui Paulo  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
266e19f4deSRui Paulo  * Use is subject to license terms.
276e19f4deSRui Paulo  */
286e19f4deSRui Paulo 
296e19f4deSRui Paulo #include <sys/fasttrap_isa.h>
306e19f4deSRui Paulo #include <sys/fasttrap_impl.h>
316e19f4deSRui Paulo #include <sys/dtrace.h>
326e19f4deSRui Paulo #include <sys/dtrace_impl.h>
336e19f4deSRui Paulo #include <sys/cmn_err.h>
34625564deSRui Paulo #include <sys/types.h>
356d1ffb50SMark Johnston #include <sys/dtrace_bsd.h>
36625564deSRui Paulo #include <sys/proc.h>
37b7924341SAndrew Turner #include <sys/reg.h>
38380344a7SMark Johnston #include <sys/rmlock.h>
396d1ffb50SMark Johnston #include <cddl/dev/dtrace/dtrace_cddl.h>
400339a1c2SMark Johnston #include <cddl/dev/dtrace/x86/regset.h>
41625564deSRui Paulo #include <machine/segments.h>
42625564deSRui Paulo #include <machine/pcb.h>
43d41e41f9SJohn Baldwin #include <machine/trap.h>
446e19f4deSRui Paulo #include <sys/sysmacros.h>
45625564deSRui Paulo #include <sys/ptrace.h>
469e579a58SMark Johnston 
47625564deSRui Paulo #ifdef __i386__
48625564deSRui Paulo #define	r_rax	r_eax
49625564deSRui Paulo #define	r_rbx	r_ebx
50625564deSRui Paulo #define	r_rip	r_eip
51625564deSRui Paulo #define	r_rflags r_eflags
52625564deSRui Paulo #define	r_rsp	r_esp
53165de3f3SMark Johnston #define	r_rbp	r_ebp
54625564deSRui Paulo #endif
556e19f4deSRui Paulo 
566e19f4deSRui Paulo /*
576e19f4deSRui Paulo  * Lossless User-Land Tracing on x86
586e19f4deSRui Paulo  * ---------------------------------
596e19f4deSRui Paulo  *
606e19f4deSRui Paulo  * The execution of most instructions is not dependent on the address; for
616e19f4deSRui Paulo  * these instructions it is sufficient to copy them into the user process's
626e19f4deSRui Paulo  * address space and execute them. To effectively single-step an instruction
636e19f4deSRui Paulo  * in user-land, we copy out the following sequence of instructions to scratch
646e19f4deSRui Paulo  * space in the user thread's ulwp_t structure.
656e19f4deSRui Paulo  *
666e19f4deSRui Paulo  * We then set the program counter (%eip or %rip) to point to this scratch
676e19f4deSRui Paulo  * space. Once execution resumes, the original instruction is executed and
686e19f4deSRui Paulo  * then control flow is redirected to what was originally the subsequent
696e19f4deSRui Paulo  * instruction. If the kernel attemps to deliver a signal while single-
706e19f4deSRui Paulo  * stepping, the signal is deferred and the program counter is moved into the
716e19f4deSRui Paulo  * second sequence of instructions. The second sequence ends in a trap into
726e19f4deSRui Paulo  * the kernel where the deferred signal is then properly handled and delivered.
736e19f4deSRui Paulo  *
746e19f4deSRui Paulo  * For instructions whose execute is position dependent, we perform simple
756e19f4deSRui Paulo  * emulation. These instructions are limited to control transfer
766e19f4deSRui Paulo  * instructions in 32-bit mode, but in 64-bit mode there's the added wrinkle
776e19f4deSRui Paulo  * of %rip-relative addressing that means that almost any instruction can be
786e19f4deSRui Paulo  * position dependent. For all the details on how we emulate generic
796e19f4deSRui Paulo  * instructions included %rip-relative instructions, see the code in
806e19f4deSRui Paulo  * fasttrap_pid_probe() below where we handle instructions of type
816e19f4deSRui Paulo  * FASTTRAP_T_COMMON (under the header: Generic Instruction Tracing).
826e19f4deSRui Paulo  */
836e19f4deSRui Paulo 
846e19f4deSRui Paulo #define	FASTTRAP_MODRM_MOD(modrm)	(((modrm) >> 6) & 0x3)
856e19f4deSRui Paulo #define	FASTTRAP_MODRM_REG(modrm)	(((modrm) >> 3) & 0x7)
866e19f4deSRui Paulo #define	FASTTRAP_MODRM_RM(modrm)	((modrm) & 0x7)
876e19f4deSRui Paulo #define	FASTTRAP_MODRM(mod, reg, rm)	(((mod) << 6) | ((reg) << 3) | (rm))
886e19f4deSRui Paulo 
896e19f4deSRui Paulo #define	FASTTRAP_SIB_SCALE(sib)		(((sib) >> 6) & 0x3)
906e19f4deSRui Paulo #define	FASTTRAP_SIB_INDEX(sib)		(((sib) >> 3) & 0x7)
916e19f4deSRui Paulo #define	FASTTRAP_SIB_BASE(sib)		((sib) & 0x7)
926e19f4deSRui Paulo 
936e19f4deSRui Paulo #define	FASTTRAP_REX_W(rex)		(((rex) >> 3) & 1)
946e19f4deSRui Paulo #define	FASTTRAP_REX_R(rex)		(((rex) >> 2) & 1)
956e19f4deSRui Paulo #define	FASTTRAP_REX_X(rex)		(((rex) >> 1) & 1)
966e19f4deSRui Paulo #define	FASTTRAP_REX_B(rex)		((rex) & 1)
976e19f4deSRui Paulo #define	FASTTRAP_REX(w, r, x, b)	\
986e19f4deSRui Paulo 	(0x40 | ((w) << 3) | ((r) << 2) | ((x) << 1) | (b))
996e19f4deSRui Paulo 
1006e19f4deSRui Paulo /*
1016e19f4deSRui Paulo  * Single-byte op-codes.
1026e19f4deSRui Paulo  */
1036e19f4deSRui Paulo #define	FASTTRAP_PUSHL_EBP	0x55
1046e19f4deSRui Paulo 
1056e19f4deSRui Paulo #define	FASTTRAP_JO		0x70
1066e19f4deSRui Paulo #define	FASTTRAP_JNO		0x71
1076e19f4deSRui Paulo #define	FASTTRAP_JB		0x72
1086e19f4deSRui Paulo #define	FASTTRAP_JAE		0x73
1096e19f4deSRui Paulo #define	FASTTRAP_JE		0x74
1106e19f4deSRui Paulo #define	FASTTRAP_JNE		0x75
1116e19f4deSRui Paulo #define	FASTTRAP_JBE		0x76
1126e19f4deSRui Paulo #define	FASTTRAP_JA		0x77
1136e19f4deSRui Paulo #define	FASTTRAP_JS		0x78
1146e19f4deSRui Paulo #define	FASTTRAP_JNS		0x79
1156e19f4deSRui Paulo #define	FASTTRAP_JP		0x7a
1166e19f4deSRui Paulo #define	FASTTRAP_JNP		0x7b
1176e19f4deSRui Paulo #define	FASTTRAP_JL		0x7c
1186e19f4deSRui Paulo #define	FASTTRAP_JGE		0x7d
1196e19f4deSRui Paulo #define	FASTTRAP_JLE		0x7e
1206e19f4deSRui Paulo #define	FASTTRAP_JG		0x7f
1216e19f4deSRui Paulo 
1226e19f4deSRui Paulo #define	FASTTRAP_NOP		0x90
1236e19f4deSRui Paulo 
1246e19f4deSRui Paulo #define	FASTTRAP_MOV_EAX	0xb8
1256e19f4deSRui Paulo #define	FASTTRAP_MOV_ECX	0xb9
1266e19f4deSRui Paulo 
1276e19f4deSRui Paulo #define	FASTTRAP_RET16		0xc2
1286e19f4deSRui Paulo #define	FASTTRAP_RET		0xc3
1296e19f4deSRui Paulo 
1306e19f4deSRui Paulo #define	FASTTRAP_LOOPNZ		0xe0
1316e19f4deSRui Paulo #define	FASTTRAP_LOOPZ		0xe1
1326e19f4deSRui Paulo #define	FASTTRAP_LOOP		0xe2
1336e19f4deSRui Paulo #define	FASTTRAP_JCXZ		0xe3
1346e19f4deSRui Paulo 
1356e19f4deSRui Paulo #define	FASTTRAP_CALL		0xe8
1366e19f4deSRui Paulo #define	FASTTRAP_JMP32		0xe9
1376e19f4deSRui Paulo #define	FASTTRAP_JMP8		0xeb
1386e19f4deSRui Paulo 
1396e19f4deSRui Paulo #define	FASTTRAP_INT3		0xcc
1406e19f4deSRui Paulo #define	FASTTRAP_INT		0xcd
1416e19f4deSRui Paulo 
1426e19f4deSRui Paulo #define	FASTTRAP_2_BYTE_OP	0x0f
1436e19f4deSRui Paulo #define	FASTTRAP_GROUP5_OP	0xff
1446e19f4deSRui Paulo 
1456e19f4deSRui Paulo /*
1466e19f4deSRui Paulo  * Two-byte op-codes (second byte only).
1476e19f4deSRui Paulo  */
1486e19f4deSRui Paulo #define	FASTTRAP_0F_JO		0x80
1496e19f4deSRui Paulo #define	FASTTRAP_0F_JNO		0x81
1506e19f4deSRui Paulo #define	FASTTRAP_0F_JB		0x82
1516e19f4deSRui Paulo #define	FASTTRAP_0F_JAE		0x83
1526e19f4deSRui Paulo #define	FASTTRAP_0F_JE		0x84
1536e19f4deSRui Paulo #define	FASTTRAP_0F_JNE		0x85
1546e19f4deSRui Paulo #define	FASTTRAP_0F_JBE		0x86
1556e19f4deSRui Paulo #define	FASTTRAP_0F_JA		0x87
1566e19f4deSRui Paulo #define	FASTTRAP_0F_JS		0x88
1576e19f4deSRui Paulo #define	FASTTRAP_0F_JNS		0x89
1586e19f4deSRui Paulo #define	FASTTRAP_0F_JP		0x8a
1596e19f4deSRui Paulo #define	FASTTRAP_0F_JNP		0x8b
1606e19f4deSRui Paulo #define	FASTTRAP_0F_JL		0x8c
1616e19f4deSRui Paulo #define	FASTTRAP_0F_JGE		0x8d
1626e19f4deSRui Paulo #define	FASTTRAP_0F_JLE		0x8e
1636e19f4deSRui Paulo #define	FASTTRAP_0F_JG		0x8f
1646e19f4deSRui Paulo 
1656e19f4deSRui Paulo #define	FASTTRAP_EFLAGS_OF	0x800
1666e19f4deSRui Paulo #define	FASTTRAP_EFLAGS_DF	0x400
1676e19f4deSRui Paulo #define	FASTTRAP_EFLAGS_SF	0x080
1686e19f4deSRui Paulo #define	FASTTRAP_EFLAGS_ZF	0x040
1696e19f4deSRui Paulo #define	FASTTRAP_EFLAGS_AF	0x010
1706e19f4deSRui Paulo #define	FASTTRAP_EFLAGS_PF	0x004
1716e19f4deSRui Paulo #define	FASTTRAP_EFLAGS_CF	0x001
1726e19f4deSRui Paulo 
1736e19f4deSRui Paulo /*
1746e19f4deSRui Paulo  * Instruction prefixes.
1756e19f4deSRui Paulo  */
1766e19f4deSRui Paulo #define	FASTTRAP_PREFIX_OPERAND	0x66
1776e19f4deSRui Paulo #define	FASTTRAP_PREFIX_ADDRESS	0x67
1786e19f4deSRui Paulo #define	FASTTRAP_PREFIX_CS	0x2E
1796e19f4deSRui Paulo #define	FASTTRAP_PREFIX_DS	0x3E
1806e19f4deSRui Paulo #define	FASTTRAP_PREFIX_ES	0x26
1816e19f4deSRui Paulo #define	FASTTRAP_PREFIX_FS	0x64
1826e19f4deSRui Paulo #define	FASTTRAP_PREFIX_GS	0x65
1836e19f4deSRui Paulo #define	FASTTRAP_PREFIX_SS	0x36
1846e19f4deSRui Paulo #define	FASTTRAP_PREFIX_LOCK	0xF0
1856e19f4deSRui Paulo #define	FASTTRAP_PREFIX_REP	0xF3
1866e19f4deSRui Paulo #define	FASTTRAP_PREFIX_REPNE	0xF2
1876e19f4deSRui Paulo 
1886e19f4deSRui Paulo #define	FASTTRAP_NOREG	0xff
1896e19f4deSRui Paulo 
1906e19f4deSRui Paulo /*
1916e19f4deSRui Paulo  * Map between instruction register encodings and the kernel constants which
1926e19f4deSRui Paulo  * correspond to indicies into struct regs.
1936e19f4deSRui Paulo  */
1946e19f4deSRui Paulo #ifdef __amd64
1956e19f4deSRui Paulo static const uint8_t regmap[16] = {
1966e19f4deSRui Paulo 	REG_RAX, REG_RCX, REG_RDX, REG_RBX, REG_RSP, REG_RBP, REG_RSI, REG_RDI,
1976e19f4deSRui Paulo 	REG_R8, REG_R9, REG_R10, REG_R11, REG_R12, REG_R13, REG_R14, REG_R15,
1986e19f4deSRui Paulo };
1996e19f4deSRui Paulo #else
2006e19f4deSRui Paulo static const uint8_t regmap[8] = {
2016e19f4deSRui Paulo 	EAX, ECX, EDX, EBX, UESP, EBP, ESI, EDI
2026e19f4deSRui Paulo };
2036e19f4deSRui Paulo #endif
2046e19f4deSRui Paulo 
205625564deSRui Paulo static ulong_t fasttrap_getreg(struct reg *, uint_t);
2066e19f4deSRui Paulo 
2076e19f4deSRui Paulo static uint64_t
208625564deSRui Paulo fasttrap_anarg(struct reg *rp, int function_entry, int argno)
2096e19f4deSRui Paulo {
210625564deSRui Paulo 	uint64_t value = 0;
2116e19f4deSRui Paulo 	int shift = function_entry ? 1 : 0;
2126e19f4deSRui Paulo 
2136e19f4deSRui Paulo #ifdef __amd64
2146e19f4deSRui Paulo 	if (curproc->p_model == DATAMODEL_LP64) {
2156e19f4deSRui Paulo 		uintptr_t *stack;
2166e19f4deSRui Paulo 
2176e19f4deSRui Paulo 		/*
2186e19f4deSRui Paulo 		 * In 64-bit mode, the first six arguments are stored in
2196e19f4deSRui Paulo 		 * registers.
2206e19f4deSRui Paulo 		 */
2216e19f4deSRui Paulo 		if (argno < 6)
2227e75d586SMark Johnston 			switch (argno) {
2237e75d586SMark Johnston 			case 0:
2247e75d586SMark Johnston 				return (rp->r_rdi);
2257e75d586SMark Johnston 			case 1:
2267e75d586SMark Johnston 				return (rp->r_rsi);
2277e75d586SMark Johnston 			case 2:
2287e75d586SMark Johnston 				return (rp->r_rdx);
2297e75d586SMark Johnston 			case 3:
2307e75d586SMark Johnston 				return (rp->r_rcx);
2317e75d586SMark Johnston 			case 4:
2327e75d586SMark Johnston 				return (rp->r_r8);
2337e75d586SMark Johnston 			case 5:
2347e75d586SMark Johnston 				return (rp->r_r9);
2357e75d586SMark Johnston 			}
2366e19f4deSRui Paulo 
237625564deSRui Paulo 		stack = (uintptr_t *)rp->r_rsp;
2386e19f4deSRui Paulo 		DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
2396e19f4deSRui Paulo 		value = dtrace_fulword(&stack[argno - 6 + shift]);
2406e19f4deSRui Paulo 		DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR);
2416e19f4deSRui Paulo 	} else {
2426e19f4deSRui Paulo #endif
2436d1ffb50SMark Johnston 		uint32_t *stack = (uint32_t *)rp->r_rsp;
2446e19f4deSRui Paulo 		DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
2456e19f4deSRui Paulo 		value = dtrace_fuword32(&stack[argno + shift]);
2466e19f4deSRui Paulo 		DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR);
2476e19f4deSRui Paulo #ifdef __amd64
2486e19f4deSRui Paulo 	}
2496e19f4deSRui Paulo #endif
2506e19f4deSRui Paulo 
2516e19f4deSRui Paulo 	return (value);
2526e19f4deSRui Paulo }
2536e19f4deSRui Paulo 
2546e19f4deSRui Paulo /*ARGSUSED*/
2556e19f4deSRui Paulo int
2566e19f4deSRui Paulo fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, uintptr_t pc,
2576e19f4deSRui Paulo     fasttrap_probe_type_t type)
2586e19f4deSRui Paulo {
2596e19f4deSRui Paulo 	uint8_t instr[FASTTRAP_MAX_INSTR_SIZE + 10];
2606e19f4deSRui Paulo 	size_t len = FASTTRAP_MAX_INSTR_SIZE;
2616e19f4deSRui Paulo 	size_t first = MIN(len, PAGESIZE - (pc & PAGEOFFSET));
2626e19f4deSRui Paulo 	uint_t start = 0;
2636e19f4deSRui Paulo 	int rmindex, size;
2646e19f4deSRui Paulo 	uint8_t seg, rex = 0;
2656e19f4deSRui Paulo 
2666e19f4deSRui Paulo 	/*
2676e19f4deSRui Paulo 	 * Read the instruction at the given address out of the process's
2686e19f4deSRui Paulo 	 * address space. We don't have to worry about a debugger
2696e19f4deSRui Paulo 	 * changing this instruction before we overwrite it with our trap
2706e19f4deSRui Paulo 	 * instruction since P_PR_LOCK is set. Since instructions can span
2716e19f4deSRui Paulo 	 * pages, we potentially read the instruction in two parts. If the
2726e19f4deSRui Paulo 	 * second part fails, we just zero out that part of the instruction.
2736e19f4deSRui Paulo 	 */
2746e19f4deSRui Paulo 	if (uread(p, &instr[0], first, pc) != 0)
2756e19f4deSRui Paulo 		return (-1);
2766e19f4deSRui Paulo 	if (len > first &&
2776e19f4deSRui Paulo 	    uread(p, &instr[first], len - first, pc + first) != 0) {
2786e19f4deSRui Paulo 		bzero(&instr[first], len - first);
2796e19f4deSRui Paulo 		len = first;
2806e19f4deSRui Paulo 	}
2816e19f4deSRui Paulo 
2826e19f4deSRui Paulo 	/*
2836e19f4deSRui Paulo 	 * If the disassembly fails, then we have a malformed instruction.
2846e19f4deSRui Paulo 	 */
2856e19f4deSRui Paulo 	if ((size = dtrace_instr_size_isa(instr, p->p_model, &rmindex)) <= 0)
2866e19f4deSRui Paulo 		return (-1);
2876e19f4deSRui Paulo 
2886e19f4deSRui Paulo 	/*
2896e19f4deSRui Paulo 	 * Make sure the disassembler isn't completely broken.
2906e19f4deSRui Paulo 	 */
2916e19f4deSRui Paulo 	ASSERT(-1 <= rmindex && rmindex < size);
2926e19f4deSRui Paulo 
2936e19f4deSRui Paulo 	/*
2946e19f4deSRui Paulo 	 * If the computed size is greater than the number of bytes read,
2956e19f4deSRui Paulo 	 * then it was a malformed instruction possibly because it fell on a
2966e19f4deSRui Paulo 	 * page boundary and the subsequent page was missing or because of
2976e19f4deSRui Paulo 	 * some malicious user.
2986e19f4deSRui Paulo 	 */
2996e19f4deSRui Paulo 	if (size > len)
3006e19f4deSRui Paulo 		return (-1);
3016e19f4deSRui Paulo 
3026e19f4deSRui Paulo 	tp->ftt_size = (uint8_t)size;
3036e19f4deSRui Paulo 	tp->ftt_segment = FASTTRAP_SEG_NONE;
3046e19f4deSRui Paulo 
3056e19f4deSRui Paulo 	/*
3066e19f4deSRui Paulo 	 * Find the start of the instruction's opcode by processing any
3076e19f4deSRui Paulo 	 * legacy prefixes.
3086e19f4deSRui Paulo 	 */
3096e19f4deSRui Paulo 	for (;;) {
3106e19f4deSRui Paulo 		seg = 0;
3116e19f4deSRui Paulo 		switch (instr[start]) {
3126e19f4deSRui Paulo 		case FASTTRAP_PREFIX_SS:
3136e19f4deSRui Paulo 			seg++;
3146e19f4deSRui Paulo 			/*FALLTHRU*/
3156e19f4deSRui Paulo 		case FASTTRAP_PREFIX_GS:
3166e19f4deSRui Paulo 			seg++;
3176e19f4deSRui Paulo 			/*FALLTHRU*/
3186e19f4deSRui Paulo 		case FASTTRAP_PREFIX_FS:
3196e19f4deSRui Paulo 			seg++;
3206e19f4deSRui Paulo 			/*FALLTHRU*/
3216e19f4deSRui Paulo 		case FASTTRAP_PREFIX_ES:
3226e19f4deSRui Paulo 			seg++;
3236e19f4deSRui Paulo 			/*FALLTHRU*/
3246e19f4deSRui Paulo 		case FASTTRAP_PREFIX_DS:
3256e19f4deSRui Paulo 			seg++;
3266e19f4deSRui Paulo 			/*FALLTHRU*/
3276e19f4deSRui Paulo 		case FASTTRAP_PREFIX_CS:
3286e19f4deSRui Paulo 			seg++;
3296e19f4deSRui Paulo 			/*FALLTHRU*/
3306e19f4deSRui Paulo 		case FASTTRAP_PREFIX_OPERAND:
3316e19f4deSRui Paulo 		case FASTTRAP_PREFIX_ADDRESS:
3326e19f4deSRui Paulo 		case FASTTRAP_PREFIX_LOCK:
3336e19f4deSRui Paulo 		case FASTTRAP_PREFIX_REP:
3346e19f4deSRui Paulo 		case FASTTRAP_PREFIX_REPNE:
3356e19f4deSRui Paulo 			if (seg != 0) {
3366e19f4deSRui Paulo 				/*
3376e19f4deSRui Paulo 				 * It's illegal for an instruction to specify
3386e19f4deSRui Paulo 				 * two segment prefixes -- give up on this
3396e19f4deSRui Paulo 				 * illegal instruction.
3406e19f4deSRui Paulo 				 */
3416e19f4deSRui Paulo 				if (tp->ftt_segment != FASTTRAP_SEG_NONE)
3426e19f4deSRui Paulo 					return (-1);
3436e19f4deSRui Paulo 
3446e19f4deSRui Paulo 				tp->ftt_segment = seg;
3456e19f4deSRui Paulo 			}
3466e19f4deSRui Paulo 			start++;
3476e19f4deSRui Paulo 			continue;
3486e19f4deSRui Paulo 		}
3496e19f4deSRui Paulo 		break;
3506e19f4deSRui Paulo 	}
3516e19f4deSRui Paulo 
3526e19f4deSRui Paulo #ifdef __amd64
3536e19f4deSRui Paulo 	/*
3546e19f4deSRui Paulo 	 * Identify the REX prefix on 64-bit processes.
3556e19f4deSRui Paulo 	 */
3566e19f4deSRui Paulo 	if (p->p_model == DATAMODEL_LP64 && (instr[start] & 0xf0) == 0x40)
3576e19f4deSRui Paulo 		rex = instr[start++];
3586e19f4deSRui Paulo #endif
3596e19f4deSRui Paulo 
3606e19f4deSRui Paulo 	/*
3616e19f4deSRui Paulo 	 * Now that we're pretty sure that the instruction is okay, copy the
3626e19f4deSRui Paulo 	 * valid part to the tracepoint.
3636e19f4deSRui Paulo 	 */
3646e19f4deSRui Paulo 	bcopy(instr, tp->ftt_instr, FASTTRAP_MAX_INSTR_SIZE);
3656e19f4deSRui Paulo 
3666e19f4deSRui Paulo 	tp->ftt_type = FASTTRAP_T_COMMON;
3676e19f4deSRui Paulo 	if (instr[start] == FASTTRAP_2_BYTE_OP) {
3686e19f4deSRui Paulo 		switch (instr[start + 1]) {
3696e19f4deSRui Paulo 		case FASTTRAP_0F_JO:
3706e19f4deSRui Paulo 		case FASTTRAP_0F_JNO:
3716e19f4deSRui Paulo 		case FASTTRAP_0F_JB:
3726e19f4deSRui Paulo 		case FASTTRAP_0F_JAE:
3736e19f4deSRui Paulo 		case FASTTRAP_0F_JE:
3746e19f4deSRui Paulo 		case FASTTRAP_0F_JNE:
3756e19f4deSRui Paulo 		case FASTTRAP_0F_JBE:
3766e19f4deSRui Paulo 		case FASTTRAP_0F_JA:
3776e19f4deSRui Paulo 		case FASTTRAP_0F_JS:
3786e19f4deSRui Paulo 		case FASTTRAP_0F_JNS:
3796e19f4deSRui Paulo 		case FASTTRAP_0F_JP:
3806e19f4deSRui Paulo 		case FASTTRAP_0F_JNP:
3816e19f4deSRui Paulo 		case FASTTRAP_0F_JL:
3826e19f4deSRui Paulo 		case FASTTRAP_0F_JGE:
3836e19f4deSRui Paulo 		case FASTTRAP_0F_JLE:
3846e19f4deSRui Paulo 		case FASTTRAP_0F_JG:
3856e19f4deSRui Paulo 			tp->ftt_type = FASTTRAP_T_JCC;
3866e19f4deSRui Paulo 			tp->ftt_code = (instr[start + 1] & 0x0f) | FASTTRAP_JO;
3876e19f4deSRui Paulo 			tp->ftt_dest = pc + tp->ftt_size +
3886e19f4deSRui Paulo 			    /* LINTED - alignment */
3896e19f4deSRui Paulo 			    *(int32_t *)&instr[start + 2];
3906e19f4deSRui Paulo 			break;
3916e19f4deSRui Paulo 		}
3926e19f4deSRui Paulo 	} else if (instr[start] == FASTTRAP_GROUP5_OP) {
3936e19f4deSRui Paulo 		uint_t mod = FASTTRAP_MODRM_MOD(instr[start + 1]);
3946e19f4deSRui Paulo 		uint_t reg = FASTTRAP_MODRM_REG(instr[start + 1]);
3956e19f4deSRui Paulo 		uint_t rm = FASTTRAP_MODRM_RM(instr[start + 1]);
3966e19f4deSRui Paulo 
3976e19f4deSRui Paulo 		if (reg == 2 || reg == 4) {
3986e19f4deSRui Paulo 			uint_t i, sz;
3996e19f4deSRui Paulo 
4006e19f4deSRui Paulo 			if (reg == 2)
4016e19f4deSRui Paulo 				tp->ftt_type = FASTTRAP_T_CALL;
4026e19f4deSRui Paulo 			else
4036e19f4deSRui Paulo 				tp->ftt_type = FASTTRAP_T_JMP;
4046e19f4deSRui Paulo 
4056e19f4deSRui Paulo 			if (mod == 3)
4066e19f4deSRui Paulo 				tp->ftt_code = 2;
4076e19f4deSRui Paulo 			else
4086e19f4deSRui Paulo 				tp->ftt_code = 1;
4096e19f4deSRui Paulo 
4106e19f4deSRui Paulo 			ASSERT(p->p_model == DATAMODEL_LP64 || rex == 0);
4116e19f4deSRui Paulo 
4126e19f4deSRui Paulo 			/*
4136e19f4deSRui Paulo 			 * See AMD x86-64 Architecture Programmer's Manual
4146e19f4deSRui Paulo 			 * Volume 3, Section 1.2.7, Table 1-12, and
4156e19f4deSRui Paulo 			 * Appendix A.3.1, Table A-15.
4166e19f4deSRui Paulo 			 */
4176e19f4deSRui Paulo 			if (mod != 3 && rm == 4) {
4186e19f4deSRui Paulo 				uint8_t sib = instr[start + 2];
4196e19f4deSRui Paulo 				uint_t index = FASTTRAP_SIB_INDEX(sib);
4206e19f4deSRui Paulo 				uint_t base = FASTTRAP_SIB_BASE(sib);
4216e19f4deSRui Paulo 
4226e19f4deSRui Paulo 				tp->ftt_scale = FASTTRAP_SIB_SCALE(sib);
4236e19f4deSRui Paulo 
4246e19f4deSRui Paulo 				tp->ftt_index = (index == 4) ?
4256e19f4deSRui Paulo 				    FASTTRAP_NOREG :
4266e19f4deSRui Paulo 				    regmap[index | (FASTTRAP_REX_X(rex) << 3)];
4276e19f4deSRui Paulo 				tp->ftt_base = (mod == 0 && base == 5) ?
4286e19f4deSRui Paulo 				    FASTTRAP_NOREG :
4296e19f4deSRui Paulo 				    regmap[base | (FASTTRAP_REX_B(rex) << 3)];
4306e19f4deSRui Paulo 
4316e19f4deSRui Paulo 				i = 3;
4326e19f4deSRui Paulo 				sz = mod == 1 ? 1 : 4;
4336e19f4deSRui Paulo 			} else {
4346e19f4deSRui Paulo 				/*
4356e19f4deSRui Paulo 				 * In 64-bit mode, mod == 0 and r/m == 5
4366e19f4deSRui Paulo 				 * denotes %rip-relative addressing; in 32-bit
4376e19f4deSRui Paulo 				 * mode, the base register isn't used. In both
4386e19f4deSRui Paulo 				 * modes, there is a 32-bit operand.
4396e19f4deSRui Paulo 				 */
4406e19f4deSRui Paulo 				if (mod == 0 && rm == 5) {
4416e19f4deSRui Paulo #ifdef __amd64
4426e19f4deSRui Paulo 					if (p->p_model == DATAMODEL_LP64)
4436e19f4deSRui Paulo 						tp->ftt_base = REG_RIP;
4446e19f4deSRui Paulo 					else
4456e19f4deSRui Paulo #endif
4466e19f4deSRui Paulo 						tp->ftt_base = FASTTRAP_NOREG;
4476e19f4deSRui Paulo 					sz = 4;
4486e19f4deSRui Paulo 				} else  {
4496e19f4deSRui Paulo 					uint8_t base = rm |
4506e19f4deSRui Paulo 					    (FASTTRAP_REX_B(rex) << 3);
4516e19f4deSRui Paulo 
4526e19f4deSRui Paulo 					tp->ftt_base = regmap[base];
4536e19f4deSRui Paulo 					sz = mod == 1 ? 1 : mod == 2 ? 4 : 0;
4546e19f4deSRui Paulo 				}
4556e19f4deSRui Paulo 				tp->ftt_index = FASTTRAP_NOREG;
4566e19f4deSRui Paulo 				i = 2;
4576e19f4deSRui Paulo 			}
4586e19f4deSRui Paulo 
4596e19f4deSRui Paulo 			if (sz == 1) {
4606e19f4deSRui Paulo 				tp->ftt_dest = *(int8_t *)&instr[start + i];
4616e19f4deSRui Paulo 			} else if (sz == 4) {
4626e19f4deSRui Paulo 				/* LINTED - alignment */
4636e19f4deSRui Paulo 				tp->ftt_dest = *(int32_t *)&instr[start + i];
4646e19f4deSRui Paulo 			} else {
4656e19f4deSRui Paulo 				tp->ftt_dest = 0;
4666e19f4deSRui Paulo 			}
4676e19f4deSRui Paulo 		}
4686e19f4deSRui Paulo 	} else {
4696e19f4deSRui Paulo 		switch (instr[start]) {
4706e19f4deSRui Paulo 		case FASTTRAP_RET:
4716e19f4deSRui Paulo 			tp->ftt_type = FASTTRAP_T_RET;
4726e19f4deSRui Paulo 			break;
4736e19f4deSRui Paulo 
4746e19f4deSRui Paulo 		case FASTTRAP_RET16:
4756e19f4deSRui Paulo 			tp->ftt_type = FASTTRAP_T_RET16;
4766e19f4deSRui Paulo 			/* LINTED - alignment */
4776e19f4deSRui Paulo 			tp->ftt_dest = *(uint16_t *)&instr[start + 1];
4786e19f4deSRui Paulo 			break;
4796e19f4deSRui Paulo 
4806e19f4deSRui Paulo 		case FASTTRAP_JO:
4816e19f4deSRui Paulo 		case FASTTRAP_JNO:
4826e19f4deSRui Paulo 		case FASTTRAP_JB:
4836e19f4deSRui Paulo 		case FASTTRAP_JAE:
4846e19f4deSRui Paulo 		case FASTTRAP_JE:
4856e19f4deSRui Paulo 		case FASTTRAP_JNE:
4866e19f4deSRui Paulo 		case FASTTRAP_JBE:
4876e19f4deSRui Paulo 		case FASTTRAP_JA:
4886e19f4deSRui Paulo 		case FASTTRAP_JS:
4896e19f4deSRui Paulo 		case FASTTRAP_JNS:
4906e19f4deSRui Paulo 		case FASTTRAP_JP:
4916e19f4deSRui Paulo 		case FASTTRAP_JNP:
4926e19f4deSRui Paulo 		case FASTTRAP_JL:
4936e19f4deSRui Paulo 		case FASTTRAP_JGE:
4946e19f4deSRui Paulo 		case FASTTRAP_JLE:
4956e19f4deSRui Paulo 		case FASTTRAP_JG:
4966e19f4deSRui Paulo 			tp->ftt_type = FASTTRAP_T_JCC;
4976e19f4deSRui Paulo 			tp->ftt_code = instr[start];
4986e19f4deSRui Paulo 			tp->ftt_dest = pc + tp->ftt_size +
4996e19f4deSRui Paulo 			    (int8_t)instr[start + 1];
5006e19f4deSRui Paulo 			break;
5016e19f4deSRui Paulo 
5026e19f4deSRui Paulo 		case FASTTRAP_LOOPNZ:
5036e19f4deSRui Paulo 		case FASTTRAP_LOOPZ:
5046e19f4deSRui Paulo 		case FASTTRAP_LOOP:
5056e19f4deSRui Paulo 			tp->ftt_type = FASTTRAP_T_LOOP;
5066e19f4deSRui Paulo 			tp->ftt_code = instr[start];
5076e19f4deSRui Paulo 			tp->ftt_dest = pc + tp->ftt_size +
5086e19f4deSRui Paulo 			    (int8_t)instr[start + 1];
5096e19f4deSRui Paulo 			break;
5106e19f4deSRui Paulo 
5116e19f4deSRui Paulo 		case FASTTRAP_JCXZ:
5126e19f4deSRui Paulo 			tp->ftt_type = FASTTRAP_T_JCXZ;
5136e19f4deSRui Paulo 			tp->ftt_dest = pc + tp->ftt_size +
5146e19f4deSRui Paulo 			    (int8_t)instr[start + 1];
5156e19f4deSRui Paulo 			break;
5166e19f4deSRui Paulo 
5176e19f4deSRui Paulo 		case FASTTRAP_CALL:
5186e19f4deSRui Paulo 			tp->ftt_type = FASTTRAP_T_CALL;
5196e19f4deSRui Paulo 			tp->ftt_dest = pc + tp->ftt_size +
5206e19f4deSRui Paulo 			    /* LINTED - alignment */
5216e19f4deSRui Paulo 			    *(int32_t *)&instr[start + 1];
5226e19f4deSRui Paulo 			tp->ftt_code = 0;
5236e19f4deSRui Paulo 			break;
5246e19f4deSRui Paulo 
5256e19f4deSRui Paulo 		case FASTTRAP_JMP32:
5266e19f4deSRui Paulo 			tp->ftt_type = FASTTRAP_T_JMP;
5276e19f4deSRui Paulo 			tp->ftt_dest = pc + tp->ftt_size +
5286e19f4deSRui Paulo 			    /* LINTED - alignment */
5296e19f4deSRui Paulo 			    *(int32_t *)&instr[start + 1];
5306e19f4deSRui Paulo 			break;
5316e19f4deSRui Paulo 		case FASTTRAP_JMP8:
5326e19f4deSRui Paulo 			tp->ftt_type = FASTTRAP_T_JMP;
5336e19f4deSRui Paulo 			tp->ftt_dest = pc + tp->ftt_size +
5346e19f4deSRui Paulo 			    (int8_t)instr[start + 1];
5356e19f4deSRui Paulo 			break;
5366e19f4deSRui Paulo 
5376e19f4deSRui Paulo 		case FASTTRAP_PUSHL_EBP:
5386e19f4deSRui Paulo 			if (start == 0)
5396e19f4deSRui Paulo 				tp->ftt_type = FASTTRAP_T_PUSHL_EBP;
5406e19f4deSRui Paulo 			break;
5416e19f4deSRui Paulo 
5426e19f4deSRui Paulo 		case FASTTRAP_NOP:
5436e19f4deSRui Paulo #ifdef __amd64
5446e19f4deSRui Paulo 			ASSERT(p->p_model == DATAMODEL_LP64 || rex == 0);
5456e19f4deSRui Paulo 
5466e19f4deSRui Paulo 			/*
5476e19f4deSRui Paulo 			 * On amd64 we have to be careful not to confuse a nop
5486e19f4deSRui Paulo 			 * (actually xchgl %eax, %eax) with an instruction using
5496e19f4deSRui Paulo 			 * the same opcode, but that does something different
5506e19f4deSRui Paulo 			 * (e.g. xchgl %r8d, %eax or xcghq %r8, %rax).
5516e19f4deSRui Paulo 			 */
5526e19f4deSRui Paulo 			if (FASTTRAP_REX_B(rex) == 0)
5536e19f4deSRui Paulo #endif
5546e19f4deSRui Paulo 				tp->ftt_type = FASTTRAP_T_NOP;
5556e19f4deSRui Paulo 			break;
5566e19f4deSRui Paulo 
5576e19f4deSRui Paulo 		case FASTTRAP_INT3:
5586e19f4deSRui Paulo 			/*
5596e19f4deSRui Paulo 			 * The pid provider shares the int3 trap with debugger
5606e19f4deSRui Paulo 			 * breakpoints so we can't instrument them.
5616e19f4deSRui Paulo 			 */
5626e19f4deSRui Paulo 			ASSERT(instr[start] == FASTTRAP_INSTR);
5636e19f4deSRui Paulo 			return (-1);
5646e19f4deSRui Paulo 
5656e19f4deSRui Paulo 		case FASTTRAP_INT:
5666e19f4deSRui Paulo 			/*
5676e19f4deSRui Paulo 			 * Interrupts seem like they could be traced with
5686e19f4deSRui Paulo 			 * no negative implications, but it's possible that
5696e19f4deSRui Paulo 			 * a thread could be redirected by the trap handling
5706e19f4deSRui Paulo 			 * code which would eventually return to the
5716e19f4deSRui Paulo 			 * instruction after the interrupt. If the interrupt
5726e19f4deSRui Paulo 			 * were in our scratch space, the subsequent
5736e19f4deSRui Paulo 			 * instruction might be overwritten before we return.
5746e19f4deSRui Paulo 			 * Accordingly we refuse to instrument any interrupt.
5756e19f4deSRui Paulo 			 */
5766e19f4deSRui Paulo 			return (-1);
5776e19f4deSRui Paulo 		}
5786e19f4deSRui Paulo 	}
5796e19f4deSRui Paulo 
5806e19f4deSRui Paulo #ifdef __amd64
5816e19f4deSRui Paulo 	if (p->p_model == DATAMODEL_LP64 && tp->ftt_type == FASTTRAP_T_COMMON) {
5826e19f4deSRui Paulo 		/*
5836e19f4deSRui Paulo 		 * If the process is 64-bit and the instruction type is still
5846e19f4deSRui Paulo 		 * FASTTRAP_T_COMMON -- meaning we're going to copy it out an
5856e19f4deSRui Paulo 		 * execute it -- we need to watch for %rip-relative
5866e19f4deSRui Paulo 		 * addressing mode. See the portion of fasttrap_pid_probe()
5876e19f4deSRui Paulo 		 * below where we handle tracepoints with type
5886e19f4deSRui Paulo 		 * FASTTRAP_T_COMMON for how we emulate instructions that
5896e19f4deSRui Paulo 		 * employ %rip-relative addressing.
5906e19f4deSRui Paulo 		 */
5916e19f4deSRui Paulo 		if (rmindex != -1) {
5926e19f4deSRui Paulo 			uint_t mod = FASTTRAP_MODRM_MOD(instr[rmindex]);
5936e19f4deSRui Paulo 			uint_t reg = FASTTRAP_MODRM_REG(instr[rmindex]);
5946e19f4deSRui Paulo 			uint_t rm = FASTTRAP_MODRM_RM(instr[rmindex]);
5956e19f4deSRui Paulo 
5966e19f4deSRui Paulo 			ASSERT(rmindex > start);
5976e19f4deSRui Paulo 
5986e19f4deSRui Paulo 			if (mod == 0 && rm == 5) {
5996e19f4deSRui Paulo 				/*
6006e19f4deSRui Paulo 				 * We need to be sure to avoid other
6016e19f4deSRui Paulo 				 * registers used by this instruction. While
6026e19f4deSRui Paulo 				 * the reg field may determine the op code
6036e19f4deSRui Paulo 				 * rather than denoting a register, assuming
6046e19f4deSRui Paulo 				 * that it denotes a register is always safe.
6056e19f4deSRui Paulo 				 * We leave the REX field intact and use
6066e19f4deSRui Paulo 				 * whatever value's there for simplicity.
6076e19f4deSRui Paulo 				 */
6086e19f4deSRui Paulo 				if (reg != 0) {
6096e19f4deSRui Paulo 					tp->ftt_ripmode = FASTTRAP_RIP_1 |
6106e19f4deSRui Paulo 					    (FASTTRAP_RIP_X *
6116e19f4deSRui Paulo 					    FASTTRAP_REX_B(rex));
6126e19f4deSRui Paulo 					rm = 0;
6136e19f4deSRui Paulo 				} else {
6146e19f4deSRui Paulo 					tp->ftt_ripmode = FASTTRAP_RIP_2 |
6156e19f4deSRui Paulo 					    (FASTTRAP_RIP_X *
6166e19f4deSRui Paulo 					    FASTTRAP_REX_B(rex));
6176e19f4deSRui Paulo 					rm = 1;
6186e19f4deSRui Paulo 				}
6196e19f4deSRui Paulo 
6206e19f4deSRui Paulo 				tp->ftt_modrm = tp->ftt_instr[rmindex];
6216e19f4deSRui Paulo 				tp->ftt_instr[rmindex] =
6226e19f4deSRui Paulo 				    FASTTRAP_MODRM(2, reg, rm);
6236e19f4deSRui Paulo 			}
6246e19f4deSRui Paulo 		}
6256e19f4deSRui Paulo 	}
6266e19f4deSRui Paulo #endif
6276e19f4deSRui Paulo 
6286e19f4deSRui Paulo 	return (0);
6296e19f4deSRui Paulo }
6306e19f4deSRui Paulo 
6316e19f4deSRui Paulo int
6326e19f4deSRui Paulo fasttrap_tracepoint_install(proc_t *p, fasttrap_tracepoint_t *tp)
6336e19f4deSRui Paulo {
6346e19f4deSRui Paulo 	fasttrap_instr_t instr = FASTTRAP_INSTR;
6356e19f4deSRui Paulo 
6366e19f4deSRui Paulo 	if (uwrite(p, &instr, 1, tp->ftt_pc) != 0)
6376e19f4deSRui Paulo 		return (-1);
6386e19f4deSRui Paulo 
6396e19f4deSRui Paulo 	return (0);
6406e19f4deSRui Paulo }
6416e19f4deSRui Paulo 
6426e19f4deSRui Paulo int
6436e19f4deSRui Paulo fasttrap_tracepoint_remove(proc_t *p, fasttrap_tracepoint_t *tp)
6446e19f4deSRui Paulo {
6456e19f4deSRui Paulo 	uint8_t instr;
6466e19f4deSRui Paulo 
6476e19f4deSRui Paulo 	/*
6486e19f4deSRui Paulo 	 * Distinguish between read or write failures and a changed
6496e19f4deSRui Paulo 	 * instruction.
6506e19f4deSRui Paulo 	 */
6516e19f4deSRui Paulo 	if (uread(p, &instr, 1, tp->ftt_pc) != 0)
6526e19f4deSRui Paulo 		return (0);
6536e19f4deSRui Paulo 	if (instr != FASTTRAP_INSTR)
6546e19f4deSRui Paulo 		return (0);
6556e19f4deSRui Paulo 	if (uwrite(p, &tp->ftt_instr[0], 1, tp->ftt_pc) != 0)
6566e19f4deSRui Paulo 		return (-1);
6576e19f4deSRui Paulo 
6586e19f4deSRui Paulo 	return (0);
6596e19f4deSRui Paulo }
6606e19f4deSRui Paulo 
6616e19f4deSRui Paulo #ifdef __amd64
6626e19f4deSRui Paulo static uintptr_t
6636e19f4deSRui Paulo fasttrap_fulword_noerr(const void *uaddr)
6646e19f4deSRui Paulo {
6656e19f4deSRui Paulo 	uintptr_t ret;
6666e19f4deSRui Paulo 
667625564deSRui Paulo 	if ((ret = fasttrap_fulword(uaddr)) != -1)
6686e19f4deSRui Paulo 		return (ret);
6696e19f4deSRui Paulo 
6706e19f4deSRui Paulo 	return (0);
6716e19f4deSRui Paulo }
6726e19f4deSRui Paulo #endif
6736e19f4deSRui Paulo 
6746e19f4deSRui Paulo static uint32_t
6756e19f4deSRui Paulo fasttrap_fuword32_noerr(const void *uaddr)
6766e19f4deSRui Paulo {
6776e19f4deSRui Paulo 	uint32_t ret;
6786e19f4deSRui Paulo 
679625564deSRui Paulo 	if ((ret = fasttrap_fuword32(uaddr)) != -1)
6806e19f4deSRui Paulo 		return (ret);
6816e19f4deSRui Paulo 
6826e19f4deSRui Paulo 	return (0);
6836e19f4deSRui Paulo }
6846e19f4deSRui Paulo 
6856e19f4deSRui Paulo static void
686625564deSRui Paulo fasttrap_return_common(struct reg *rp, uintptr_t pc, pid_t pid,
6876e19f4deSRui Paulo     uintptr_t new_pc)
6886e19f4deSRui Paulo {
6896e19f4deSRui Paulo 	fasttrap_tracepoint_t *tp;
6906e19f4deSRui Paulo 	fasttrap_bucket_t *bucket;
6916e19f4deSRui Paulo 	fasttrap_id_t *id;
692380344a7SMark Johnston 	struct rm_priotracker tracker;
693380344a7SMark Johnston 
694380344a7SMark Johnston 	rm_rlock(&fasttrap_tp_lock, &tracker);
6956e19f4deSRui Paulo 	bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)];
6966e19f4deSRui Paulo 
6976e19f4deSRui Paulo 	for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
6986e19f4deSRui Paulo 		if (pid == tp->ftt_pid && pc == tp->ftt_pc &&
6996e19f4deSRui Paulo 		    tp->ftt_proc->ftpc_acount != 0)
7006e19f4deSRui Paulo 			break;
7016e19f4deSRui Paulo 	}
7026e19f4deSRui Paulo 
7036e19f4deSRui Paulo 	/*
7046e19f4deSRui Paulo 	 * Don't sweat it if we can't find the tracepoint again; unlike
7056e19f4deSRui Paulo 	 * when we're in fasttrap_pid_probe(), finding the tracepoint here
7066e19f4deSRui Paulo 	 * is not essential to the correct execution of the process.
7076e19f4deSRui Paulo 	 */
7086e19f4deSRui Paulo 	if (tp == NULL) {
709380344a7SMark Johnston 		rm_runlock(&fasttrap_tp_lock, &tracker);
7106e19f4deSRui Paulo 		return;
7116e19f4deSRui Paulo 	}
7126e19f4deSRui Paulo 
7136e19f4deSRui Paulo 	for (id = tp->ftt_retids; id != NULL; id = id->fti_next) {
7146e19f4deSRui Paulo 		/*
7156e19f4deSRui Paulo 		 * If there's a branch that could act as a return site, we
7166e19f4deSRui Paulo 		 * need to trace it, and check here if the program counter is
7176e19f4deSRui Paulo 		 * external to the function.
7186e19f4deSRui Paulo 		 */
7196e19f4deSRui Paulo 		if (tp->ftt_type != FASTTRAP_T_RET &&
7206e19f4deSRui Paulo 		    tp->ftt_type != FASTTRAP_T_RET16 &&
7216e19f4deSRui Paulo 		    new_pc - id->fti_probe->ftp_faddr <
7226e19f4deSRui Paulo 		    id->fti_probe->ftp_fsize)
7236e19f4deSRui Paulo 			continue;
7246e19f4deSRui Paulo 
7256e19f4deSRui Paulo 		dtrace_probe(id->fti_probe->ftp_id,
7266e19f4deSRui Paulo 		    pc - id->fti_probe->ftp_faddr,
727625564deSRui Paulo 		    rp->r_rax, rp->r_rbx, 0, 0);
7286e19f4deSRui Paulo 	}
7296e19f4deSRui Paulo 
730380344a7SMark Johnston 	rm_runlock(&fasttrap_tp_lock, &tracker);
7316e19f4deSRui Paulo }
7326e19f4deSRui Paulo 
7336e19f4deSRui Paulo static void
7346e19f4deSRui Paulo fasttrap_sigsegv(proc_t *p, kthread_t *t, uintptr_t addr)
7356e19f4deSRui Paulo {
7368e7127fdSMark Johnston 	ksiginfo_t ksi;
737625564deSRui Paulo 
7388e7127fdSMark Johnston 	ksiginfo_init(&ksi);
7398e7127fdSMark Johnston 	ksi.ksi_signo = SIGSEGV;
7408e7127fdSMark Johnston 	ksi.ksi_code = SEGV_MAPERR;
7418e7127fdSMark Johnston 	ksi.ksi_addr = (caddr_t)addr;
7428e7127fdSMark Johnston 	PROC_LOCK(p);
7438e7127fdSMark Johnston 	(void)tdksignal(t, SIGSEGV, &ksi);
7448e7127fdSMark Johnston 	PROC_UNLOCK(p);
7456e19f4deSRui Paulo }
7466e19f4deSRui Paulo 
7476e19f4deSRui Paulo #ifdef __amd64
7486e19f4deSRui Paulo static void
749625564deSRui Paulo fasttrap_usdt_args64(fasttrap_probe_t *probe, struct reg *rp, int argc,
7506e19f4deSRui Paulo     uintptr_t *argv)
7516e19f4deSRui Paulo {
7526e19f4deSRui Paulo 	int i, x, cap = MIN(argc, probe->ftp_nargs);
753625564deSRui Paulo 	uintptr_t *stack = (uintptr_t *)rp->r_rsp;
7546e19f4deSRui Paulo 
7556e19f4deSRui Paulo 	for (i = 0; i < cap; i++) {
7566e19f4deSRui Paulo 		x = probe->ftp_argmap[i];
7576e19f4deSRui Paulo 
7586e19f4deSRui Paulo 		if (x < 6)
7596e19f4deSRui Paulo 			argv[i] = (&rp->r_rdi)[x];
7606e19f4deSRui Paulo 		else
7616e19f4deSRui Paulo 			argv[i] = fasttrap_fulword_noerr(&stack[x]);
7626e19f4deSRui Paulo 	}
7636e19f4deSRui Paulo 
7646e19f4deSRui Paulo 	for (; i < argc; i++) {
7656e19f4deSRui Paulo 		argv[i] = 0;
7666e19f4deSRui Paulo 	}
7676e19f4deSRui Paulo }
7686e19f4deSRui Paulo #endif
7696e19f4deSRui Paulo 
7706e19f4deSRui Paulo static void
771625564deSRui Paulo fasttrap_usdt_args32(fasttrap_probe_t *probe, struct reg *rp, int argc,
7726e19f4deSRui Paulo     uint32_t *argv)
7736e19f4deSRui Paulo {
7746e19f4deSRui Paulo 	int i, x, cap = MIN(argc, probe->ftp_nargs);
775625564deSRui Paulo 	uint32_t *stack = (uint32_t *)rp->r_rsp;
7766e19f4deSRui Paulo 
7776e19f4deSRui Paulo 	for (i = 0; i < cap; i++) {
7786e19f4deSRui Paulo 		x = probe->ftp_argmap[i];
7796e19f4deSRui Paulo 
7806e19f4deSRui Paulo 		argv[i] = fasttrap_fuword32_noerr(&stack[x]);
7816e19f4deSRui Paulo 	}
7826e19f4deSRui Paulo 
7836e19f4deSRui Paulo 	for (; i < argc; i++) {
7846e19f4deSRui Paulo 		argv[i] = 0;
7856e19f4deSRui Paulo 	}
7866e19f4deSRui Paulo }
7876e19f4deSRui Paulo 
7886e19f4deSRui Paulo static int
789625564deSRui Paulo fasttrap_do_seg(fasttrap_tracepoint_t *tp, struct reg *rp, uintptr_t *addr)
7906e19f4deSRui Paulo {
7916e19f4deSRui Paulo 	proc_t *p = curproc;
792625564deSRui Paulo #ifdef __i386__
793625564deSRui Paulo 	struct segment_descriptor *desc;
794625564deSRui Paulo #else
795625564deSRui Paulo 	struct user_segment_descriptor *desc;
796625564deSRui Paulo #endif
797625564deSRui Paulo 	uint16_t sel = 0, ndx, type;
7986e19f4deSRui Paulo 	uintptr_t limit;
7996e19f4deSRui Paulo 
8006e19f4deSRui Paulo 	switch (tp->ftt_segment) {
8016e19f4deSRui Paulo 	case FASTTRAP_SEG_CS:
8026e19f4deSRui Paulo 		sel = rp->r_cs;
8036e19f4deSRui Paulo 		break;
8046e19f4deSRui Paulo 	case FASTTRAP_SEG_DS:
8056e19f4deSRui Paulo 		sel = rp->r_ds;
8066e19f4deSRui Paulo 		break;
8076e19f4deSRui Paulo 	case FASTTRAP_SEG_ES:
8086e19f4deSRui Paulo 		sel = rp->r_es;
8096e19f4deSRui Paulo 		break;
8106e19f4deSRui Paulo 	case FASTTRAP_SEG_FS:
8116e19f4deSRui Paulo 		sel = rp->r_fs;
8126e19f4deSRui Paulo 		break;
8136e19f4deSRui Paulo 	case FASTTRAP_SEG_GS:
8146e19f4deSRui Paulo 		sel = rp->r_gs;
8156e19f4deSRui Paulo 		break;
8166e19f4deSRui Paulo 	case FASTTRAP_SEG_SS:
8176e19f4deSRui Paulo 		sel = rp->r_ss;
8186e19f4deSRui Paulo 		break;
8196e19f4deSRui Paulo 	}
8206e19f4deSRui Paulo 
8216e19f4deSRui Paulo 	/*
8226e19f4deSRui Paulo 	 * Make sure the given segment register specifies a user priority
8236e19f4deSRui Paulo 	 * selector rather than a kernel selector.
8246e19f4deSRui Paulo 	 */
825625564deSRui Paulo 	if (ISPL(sel) != SEL_UPL)
8266e19f4deSRui Paulo 		return (-1);
8276e19f4deSRui Paulo 
828625564deSRui Paulo 	ndx = IDXSEL(sel);
8296e19f4deSRui Paulo 
8306e19f4deSRui Paulo 	/*
8316e19f4deSRui Paulo 	 * Check the bounds and grab the descriptor out of the specified
8326e19f4deSRui Paulo 	 * descriptor table.
8336e19f4deSRui Paulo 	 */
834625564deSRui Paulo 	if (ISLDT(sel)) {
835625564deSRui Paulo #ifdef __i386__
836625564deSRui Paulo 		if (ndx > p->p_md.md_ldt->ldt_len)
8376e19f4deSRui Paulo 			return (-1);
8386e19f4deSRui Paulo 
839625564deSRui Paulo 		desc = (struct segment_descriptor *)
840625564deSRui Paulo 		    p->p_md.md_ldt[ndx].ldt_base;
841625564deSRui Paulo #else
842625564deSRui Paulo 		if (ndx > max_ldt_segment)
843625564deSRui Paulo 			return (-1);
844625564deSRui Paulo 
845625564deSRui Paulo 		desc = (struct user_segment_descriptor *)
846625564deSRui Paulo 		    p->p_md.md_ldt[ndx].ldt_base;
847625564deSRui Paulo #endif
8486e19f4deSRui Paulo 
8496e19f4deSRui Paulo 	} else {
8506e19f4deSRui Paulo 		if (ndx >= NGDT)
8516e19f4deSRui Paulo 			return (-1);
8526e19f4deSRui Paulo 
853625564deSRui Paulo #ifdef __i386__
854625564deSRui Paulo 		desc = &gdt[ndx].sd;
855625564deSRui Paulo #else
856a7af4a3eSKonstantin Belousov 		desc = PCPU_PTR(gdt)[ndx];
857625564deSRui Paulo #endif
8586e19f4deSRui Paulo 	}
8596e19f4deSRui Paulo 
8606e19f4deSRui Paulo 	/*
8616e19f4deSRui Paulo 	 * The descriptor must have user privilege level and it must be
8626e19f4deSRui Paulo 	 * present in memory.
8636e19f4deSRui Paulo 	 */
864625564deSRui Paulo 	if (desc->sd_dpl != SEL_UPL || desc->sd_p != 1)
8656e19f4deSRui Paulo 		return (-1);
8666e19f4deSRui Paulo 
867625564deSRui Paulo 	type = desc->sd_type;
8686e19f4deSRui Paulo 
8696e19f4deSRui Paulo 	/*
8706e19f4deSRui Paulo 	 * If the S bit in the type field is not set, this descriptor can
8716e19f4deSRui Paulo 	 * only be used in system context.
8726e19f4deSRui Paulo 	 */
8736e19f4deSRui Paulo 	if ((type & 0x10) != 0x10)
8746e19f4deSRui Paulo 		return (-1);
8756e19f4deSRui Paulo 
876625564deSRui Paulo 	limit = USD_GETLIMIT(desc) * (desc->sd_gran ? PAGESIZE : 1);
8776e19f4deSRui Paulo 
8786e19f4deSRui Paulo 	if (tp->ftt_segment == FASTTRAP_SEG_CS) {
8796e19f4deSRui Paulo 		/*
8806e19f4deSRui Paulo 		 * The code/data bit and readable bit must both be set.
8816e19f4deSRui Paulo 		 */
8826e19f4deSRui Paulo 		if ((type & 0xa) != 0xa)
8836e19f4deSRui Paulo 			return (-1);
8846e19f4deSRui Paulo 
8856e19f4deSRui Paulo 		if (*addr > limit)
8866e19f4deSRui Paulo 			return (-1);
8876e19f4deSRui Paulo 	} else {
8886e19f4deSRui Paulo 		/*
8896e19f4deSRui Paulo 		 * The code/data bit must be clear.
8906e19f4deSRui Paulo 		 */
8916e19f4deSRui Paulo 		if ((type & 0x8) != 0)
8926e19f4deSRui Paulo 			return (-1);
8936e19f4deSRui Paulo 
8946e19f4deSRui Paulo 		/*
8956e19f4deSRui Paulo 		 * If the expand-down bit is clear, we just check the limit as
8966e19f4deSRui Paulo 		 * it would naturally be applied. Otherwise, we need to check
8976e19f4deSRui Paulo 		 * that the address is the range [limit + 1 .. 0xffff] or
8986e19f4deSRui Paulo 		 * [limit + 1 ... 0xffffffff] depending on if the default
8996e19f4deSRui Paulo 		 * operand size bit is set.
9006e19f4deSRui Paulo 		 */
9016e19f4deSRui Paulo 		if ((type & 0x4) == 0) {
9026e19f4deSRui Paulo 			if (*addr > limit)
9036e19f4deSRui Paulo 				return (-1);
904625564deSRui Paulo 		} else if (desc->sd_def32) {
9056e19f4deSRui Paulo 			if (*addr < limit + 1 || 0xffff < *addr)
9066e19f4deSRui Paulo 				return (-1);
9076e19f4deSRui Paulo 		} else {
9086e19f4deSRui Paulo 			if (*addr < limit + 1 || 0xffffffff < *addr)
9096e19f4deSRui Paulo 				return (-1);
9106e19f4deSRui Paulo 		}
9116e19f4deSRui Paulo 	}
9126e19f4deSRui Paulo 
913625564deSRui Paulo 	*addr += USD_GETBASE(desc);
9146e19f4deSRui Paulo 
9156e19f4deSRui Paulo 	return (0);
9166e19f4deSRui Paulo }
9176e19f4deSRui Paulo 
9186e19f4deSRui Paulo int
9195bab6234SMark Johnston fasttrap_pid_probe(struct trapframe *tf)
9206e19f4deSRui Paulo {
9215bab6234SMark Johnston 	struct reg reg, *rp;
9225bab6234SMark Johnston 	proc_t *p = curproc, *pp;
923380344a7SMark Johnston 	struct rm_priotracker tracker;
9244f1b715cSMark Johnston 	uint64_t gen;
9255bab6234SMark Johnston 	uintptr_t pc;
926625564deSRui Paulo 	uintptr_t new_pc = 0;
9276e19f4deSRui Paulo 	fasttrap_bucket_t *bucket;
9286e19f4deSRui Paulo 	fasttrap_tracepoint_t *tp, tp_local;
9296e19f4deSRui Paulo 	pid_t pid;
9306e19f4deSRui Paulo 	dtrace_icookie_t cookie;
9316e19f4deSRui Paulo 	uint_t is_enabled = 0;
9326e19f4deSRui Paulo 
9335bab6234SMark Johnston 	fill_frame_regs(tf, &reg);
9345bab6234SMark Johnston 	rp = &reg;
9355bab6234SMark Johnston 
9365bab6234SMark Johnston 	pc = rp->r_rip - 1;
9375bab6234SMark Johnston 
9386e19f4deSRui Paulo 	/*
9396e19f4deSRui Paulo 	 * It's possible that a user (in a veritable orgy of bad planning)
9406e19f4deSRui Paulo 	 * could redirect this thread's flow of control before it reached the
9416e19f4deSRui Paulo 	 * return probe fasttrap. In this case we need to kill the process
9426e19f4deSRui Paulo 	 * since it's in a unrecoverable state.
9436e19f4deSRui Paulo 	 */
9446e19f4deSRui Paulo 	if (curthread->t_dtrace_step) {
9456e19f4deSRui Paulo 		ASSERT(curthread->t_dtrace_on);
9466e19f4deSRui Paulo 		fasttrap_sigtrap(p, curthread, pc);
9476e19f4deSRui Paulo 		return (0);
9486e19f4deSRui Paulo 	}
9496e19f4deSRui Paulo 
9506e19f4deSRui Paulo 	/*
9516e19f4deSRui Paulo 	 * Clear all user tracing flags.
9526e19f4deSRui Paulo 	 */
9536e19f4deSRui Paulo 	curthread->t_dtrace_ft = 0;
9546e19f4deSRui Paulo 	curthread->t_dtrace_pc = 0;
9556e19f4deSRui Paulo 	curthread->t_dtrace_npc = 0;
9566e19f4deSRui Paulo 	curthread->t_dtrace_scrpc = 0;
9576e19f4deSRui Paulo 	curthread->t_dtrace_astpc = 0;
9586e19f4deSRui Paulo #ifdef __amd64
9596e19f4deSRui Paulo 	curthread->t_dtrace_regv = 0;
9606e19f4deSRui Paulo #endif
9616e19f4deSRui Paulo 
9626e19f4deSRui Paulo 	/*
9636e19f4deSRui Paulo 	 * Treat a child created by a call to vfork(2) as if it were its
9646e19f4deSRui Paulo 	 * parent. We know that there's only one thread of control in such a
9656e19f4deSRui Paulo 	 * process: this one.
9666e19f4deSRui Paulo 	 */
9677159310fSMark Johnston 	pp = p;
9687159310fSMark Johnston 	sx_slock(&proctree_lock);
9697159310fSMark Johnston 	while (pp->p_vmspace == pp->p_pptr->p_vmspace)
9707159310fSMark Johnston 		pp = pp->p_pptr;
9717159310fSMark Johnston 	pid = pp->p_pid;
9724f1b715cSMark Johnston 	if (pp != p) {
9734f1b715cSMark Johnston 		PROC_LOCK(pp);
9744f1b715cSMark Johnston 		if ((pp->p_flag & P_WEXIT) != 0) {
9754f1b715cSMark Johnston 			/*
9764f1b715cSMark Johnston 			 * This can happen if the child was created with
9774f1b715cSMark Johnston 			 * rfork(2).  Userspace tracing cannot work reliably in
9784f1b715cSMark Johnston 			 * such a scenario, but we can at least try.
9794f1b715cSMark Johnston 			 */
9804f1b715cSMark Johnston 			PROC_UNLOCK(pp);
9817159310fSMark Johnston 			sx_sunlock(&proctree_lock);
9824f1b715cSMark Johnston 			return (-1);
9834f1b715cSMark Johnston 		}
984*8370e9dfSMark Johnston 		_PHOLD(pp);
9854f1b715cSMark Johnston 		PROC_UNLOCK(pp);
9864f1b715cSMark Johnston 	}
9874f1b715cSMark Johnston 	sx_sunlock(&proctree_lock);
9886e19f4deSRui Paulo 
989380344a7SMark Johnston 	rm_rlock(&fasttrap_tp_lock, &tracker);
9907159310fSMark Johnston 
9916e19f4deSRui Paulo 	bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)];
9926e19f4deSRui Paulo 
9936e19f4deSRui Paulo 	/*
9946e19f4deSRui Paulo 	 * Lookup the tracepoint that the process just hit.
9956e19f4deSRui Paulo 	 */
9966e19f4deSRui Paulo 	for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
9976e19f4deSRui Paulo 		if (pid == tp->ftt_pid && pc == tp->ftt_pc &&
9986e19f4deSRui Paulo 		    tp->ftt_proc->ftpc_acount != 0)
9996e19f4deSRui Paulo 			break;
10006e19f4deSRui Paulo 	}
10016e19f4deSRui Paulo 
10026e19f4deSRui Paulo 	/*
10036e19f4deSRui Paulo 	 * If we couldn't find a matching tracepoint, either a tracepoint has
10046e19f4deSRui Paulo 	 * been inserted without using the pid<pid> ioctl interface (see
10056e19f4deSRui Paulo 	 * fasttrap_ioctl), or somehow we have mislaid this tracepoint.
10066e19f4deSRui Paulo 	 */
10076e19f4deSRui Paulo 	if (tp == NULL) {
1008380344a7SMark Johnston 		rm_runlock(&fasttrap_tp_lock, &tracker);
10094f1b715cSMark Johnston 		gen = atomic_load_acq_64(&pp->p_fasttrap_tp_gen);
10104f1b715cSMark Johnston 		if (pp != p)
10114f1b715cSMark Johnston 			PRELE(pp);
10124f1b715cSMark Johnston 		if (curthread->t_fasttrap_tp_gen != gen) {
10134f1b715cSMark Johnston 			/*
10144f1b715cSMark Johnston 			 * At least one tracepoint associated with this PID has
10154f1b715cSMark Johnston 			 * been removed from the table since #BP was raised.
10164f1b715cSMark Johnston 			 * Speculate that we hit a tracepoint that has since
10174f1b715cSMark Johnston 			 * been removed, and retry the instruction.
10184f1b715cSMark Johnston 			 */
10194f1b715cSMark Johnston 			curthread->t_fasttrap_tp_gen = gen;
1020f23e684bSMark Johnston #ifdef __amd64
10214f1b715cSMark Johnston 			tf->tf_rip = pc;
1022f23e684bSMark Johnston #else
1023f23e684bSMark Johnston 			tf->tf_eip = pc;
1024f23e684bSMark Johnston #endif
10254f1b715cSMark Johnston 			return (0);
10266e19f4deSRui Paulo 		}
10274f1b715cSMark Johnston 		return (-1);
10284f1b715cSMark Johnston 	}
10294f1b715cSMark Johnston 	if (pp != p)
10304f1b715cSMark Johnston 		PRELE(pp);
10316e19f4deSRui Paulo 
10326e19f4deSRui Paulo 	/*
10336e19f4deSRui Paulo 	 * Set the program counter to the address of the traced instruction
10346e19f4deSRui Paulo 	 * so that it looks right in ustack() output.
10356e19f4deSRui Paulo 	 */
1036625564deSRui Paulo 	rp->r_rip = pc;
10376e19f4deSRui Paulo 
10386e19f4deSRui Paulo 	if (tp->ftt_ids != NULL) {
10396e19f4deSRui Paulo 		fasttrap_id_t *id;
10406e19f4deSRui Paulo 
104157185c52SMark Johnston #ifdef __amd64
10426e19f4deSRui Paulo 		if (p->p_model == DATAMODEL_LP64) {
10436e19f4deSRui Paulo 			for (id = tp->ftt_ids; id != NULL; id = id->fti_next) {
10446e19f4deSRui Paulo 				fasttrap_probe_t *probe = id->fti_probe;
10456e19f4deSRui Paulo 
10466e19f4deSRui Paulo 				if (id->fti_ptype == DTFTP_ENTRY) {
10476e19f4deSRui Paulo 					/*
10486e19f4deSRui Paulo 					 * We note that this was an entry
10496e19f4deSRui Paulo 					 * probe to help ustack() find the
10506e19f4deSRui Paulo 					 * first caller.
10516e19f4deSRui Paulo 					 */
10526e19f4deSRui Paulo 					cookie = dtrace_interrupt_disable();
10536e19f4deSRui Paulo 					DTRACE_CPUFLAG_SET(CPU_DTRACE_ENTRY);
10546e19f4deSRui Paulo 					dtrace_probe(probe->ftp_id, rp->r_rdi,
10556e19f4deSRui Paulo 					    rp->r_rsi, rp->r_rdx, rp->r_rcx,
10566e19f4deSRui Paulo 					    rp->r_r8);
10576e19f4deSRui Paulo 					DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_ENTRY);
10586e19f4deSRui Paulo 					dtrace_interrupt_enable(cookie);
10596e19f4deSRui Paulo 				} else if (id->fti_ptype == DTFTP_IS_ENABLED) {
10606e19f4deSRui Paulo 					/*
10616e19f4deSRui Paulo 					 * Note that in this case, we don't
10626e19f4deSRui Paulo 					 * call dtrace_probe() since it's only
10636e19f4deSRui Paulo 					 * an artificial probe meant to change
10646e19f4deSRui Paulo 					 * the flow of control so that it
10656e19f4deSRui Paulo 					 * encounters the true probe.
10666e19f4deSRui Paulo 					 */
10676e19f4deSRui Paulo 					is_enabled = 1;
10686e19f4deSRui Paulo 				} else if (probe->ftp_argmap == NULL) {
10696e19f4deSRui Paulo 					dtrace_probe(probe->ftp_id, rp->r_rdi,
10706e19f4deSRui Paulo 					    rp->r_rsi, rp->r_rdx, rp->r_rcx,
10716e19f4deSRui Paulo 					    rp->r_r8);
10726e19f4deSRui Paulo 				} else {
10736e19f4deSRui Paulo 					uintptr_t t[5];
10746e19f4deSRui Paulo 
10756e19f4deSRui Paulo 					fasttrap_usdt_args64(probe, rp,
10766e19f4deSRui Paulo 					    sizeof (t) / sizeof (t[0]), t);
10776e19f4deSRui Paulo 
10786e19f4deSRui Paulo 					dtrace_probe(probe->ftp_id, t[0], t[1],
10796e19f4deSRui Paulo 					    t[2], t[3], t[4]);
10806e19f4deSRui Paulo 				}
10816e19f4deSRui Paulo 			}
10826e19f4deSRui Paulo 		} else {
108357185c52SMark Johnston #endif
10846e19f4deSRui Paulo 			uintptr_t s0, s1, s2, s3, s4, s5;
10856d1ffb50SMark Johnston 			uint32_t *stack = (uint32_t *)rp->r_rsp;
10866e19f4deSRui Paulo 
10876e19f4deSRui Paulo 			/*
10886e19f4deSRui Paulo 			 * In 32-bit mode, all arguments are passed on the
10896e19f4deSRui Paulo 			 * stack. If this is a function entry probe, we need
10906e19f4deSRui Paulo 			 * to skip the first entry on the stack as it
10916e19f4deSRui Paulo 			 * represents the return address rather than a
10926e19f4deSRui Paulo 			 * parameter to the function.
10936e19f4deSRui Paulo 			 */
10946e19f4deSRui Paulo 			s0 = fasttrap_fuword32_noerr(&stack[0]);
10956e19f4deSRui Paulo 			s1 = fasttrap_fuword32_noerr(&stack[1]);
10966e19f4deSRui Paulo 			s2 = fasttrap_fuword32_noerr(&stack[2]);
10976e19f4deSRui Paulo 			s3 = fasttrap_fuword32_noerr(&stack[3]);
10986e19f4deSRui Paulo 			s4 = fasttrap_fuword32_noerr(&stack[4]);
10996e19f4deSRui Paulo 			s5 = fasttrap_fuword32_noerr(&stack[5]);
11006e19f4deSRui Paulo 
11016e19f4deSRui Paulo 			for (id = tp->ftt_ids; id != NULL; id = id->fti_next) {
11026e19f4deSRui Paulo 				fasttrap_probe_t *probe = id->fti_probe;
11036e19f4deSRui Paulo 
11046e19f4deSRui Paulo 				if (id->fti_ptype == DTFTP_ENTRY) {
11056e19f4deSRui Paulo 					/*
11066e19f4deSRui Paulo 					 * We note that this was an entry
11076e19f4deSRui Paulo 					 * probe to help ustack() find the
11086e19f4deSRui Paulo 					 * first caller.
11096e19f4deSRui Paulo 					 */
11106e19f4deSRui Paulo 					cookie = dtrace_interrupt_disable();
11116e19f4deSRui Paulo 					DTRACE_CPUFLAG_SET(CPU_DTRACE_ENTRY);
11126e19f4deSRui Paulo 					dtrace_probe(probe->ftp_id, s1, s2,
11136e19f4deSRui Paulo 					    s3, s4, s5);
11146e19f4deSRui Paulo 					DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_ENTRY);
11156e19f4deSRui Paulo 					dtrace_interrupt_enable(cookie);
11166e19f4deSRui Paulo 				} else if (id->fti_ptype == DTFTP_IS_ENABLED) {
11176e19f4deSRui Paulo 					/*
11186e19f4deSRui Paulo 					 * Note that in this case, we don't
11196e19f4deSRui Paulo 					 * call dtrace_probe() since it's only
11206e19f4deSRui Paulo 					 * an artificial probe meant to change
11216e19f4deSRui Paulo 					 * the flow of control so that it
11226e19f4deSRui Paulo 					 * encounters the true probe.
11236e19f4deSRui Paulo 					 */
11246e19f4deSRui Paulo 					is_enabled = 1;
11256e19f4deSRui Paulo 				} else if (probe->ftp_argmap == NULL) {
11266e19f4deSRui Paulo 					dtrace_probe(probe->ftp_id, s0, s1,
11276e19f4deSRui Paulo 					    s2, s3, s4);
11286e19f4deSRui Paulo 				} else {
11296e19f4deSRui Paulo 					uint32_t t[5];
11306e19f4deSRui Paulo 
11316e19f4deSRui Paulo 					fasttrap_usdt_args32(probe, rp,
11326e19f4deSRui Paulo 					    sizeof (t) / sizeof (t[0]), t);
11336e19f4deSRui Paulo 
11346e19f4deSRui Paulo 					dtrace_probe(probe->ftp_id, t[0], t[1],
11356e19f4deSRui Paulo 					    t[2], t[3], t[4]);
11366e19f4deSRui Paulo 				}
11376e19f4deSRui Paulo 			}
113857185c52SMark Johnston #ifdef __amd64
11396e19f4deSRui Paulo 		}
114057185c52SMark Johnston #endif
11416e19f4deSRui Paulo 	}
11426e19f4deSRui Paulo 
11436e19f4deSRui Paulo 	/*
11446e19f4deSRui Paulo 	 * We're about to do a bunch of work so we cache a local copy of
11456e19f4deSRui Paulo 	 * the tracepoint to emulate the instruction, and then find the
11466e19f4deSRui Paulo 	 * tracepoint again later if we need to light up any return probes.
11476e19f4deSRui Paulo 	 */
11486e19f4deSRui Paulo 	tp_local = *tp;
1149380344a7SMark Johnston 	rm_runlock(&fasttrap_tp_lock, &tracker);
11506e19f4deSRui Paulo 	tp = &tp_local;
11516e19f4deSRui Paulo 
11526e19f4deSRui Paulo 	/*
11536e19f4deSRui Paulo 	 * Set the program counter to appear as though the traced instruction
11546e19f4deSRui Paulo 	 * had completely executed. This ensures that fasttrap_getreg() will
11556e19f4deSRui Paulo 	 * report the expected value for REG_RIP.
11566e19f4deSRui Paulo 	 */
1157625564deSRui Paulo 	rp->r_rip = pc + tp->ftt_size;
11586e19f4deSRui Paulo 
11596e19f4deSRui Paulo 	/*
11606e19f4deSRui Paulo 	 * If there's an is-enabled probe connected to this tracepoint it
11616e19f4deSRui Paulo 	 * means that there was a 'xorl %eax, %eax' or 'xorq %rax, %rax'
11626e19f4deSRui Paulo 	 * instruction that was placed there by DTrace when the binary was
11636e19f4deSRui Paulo 	 * linked. As this probe is, in fact, enabled, we need to stuff 1
11646e19f4deSRui Paulo 	 * into %eax or %rax. Accordingly, we can bypass all the instruction
11656e19f4deSRui Paulo 	 * emulation logic since we know the inevitable result. It's possible
11666e19f4deSRui Paulo 	 * that a user could construct a scenario where the 'is-enabled'
11676e19f4deSRui Paulo 	 * probe was on some other instruction, but that would be a rather
11686e19f4deSRui Paulo 	 * exotic way to shoot oneself in the foot.
11696e19f4deSRui Paulo 	 */
11706e19f4deSRui Paulo 	if (is_enabled) {
1171625564deSRui Paulo 		rp->r_rax = 1;
1172625564deSRui Paulo 		new_pc = rp->r_rip;
11736e19f4deSRui Paulo 		goto done;
11746e19f4deSRui Paulo 	}
11756e19f4deSRui Paulo 
11766e19f4deSRui Paulo 	/*
11776e19f4deSRui Paulo 	 * We emulate certain types of instructions to ensure correctness
11786e19f4deSRui Paulo 	 * (in the case of position dependent instructions) or optimize
11796e19f4deSRui Paulo 	 * common cases. The rest we have the thread execute back in user-
11806e19f4deSRui Paulo 	 * land.
11816e19f4deSRui Paulo 	 */
11826e19f4deSRui Paulo 	switch (tp->ftt_type) {
11836e19f4deSRui Paulo 	case FASTTRAP_T_RET:
11846e19f4deSRui Paulo 	case FASTTRAP_T_RET16:
11856e19f4deSRui Paulo 	{
1186625564deSRui Paulo 		uintptr_t dst = 0;
1187625564deSRui Paulo 		uintptr_t addr = 0;
1188625564deSRui Paulo 		int ret = 0;
11896e19f4deSRui Paulo 
11906e19f4deSRui Paulo 		/*
11916e19f4deSRui Paulo 		 * We have to emulate _every_ facet of the behavior of a ret
11926e19f4deSRui Paulo 		 * instruction including what happens if the load from %esp
11936e19f4deSRui Paulo 		 * fails; in that case, we send a SIGSEGV.
11946e19f4deSRui Paulo 		 */
11956e19f4deSRui Paulo #ifdef __amd64
11966e19f4deSRui Paulo 		if (p->p_model == DATAMODEL_NATIVE) {
1197625564deSRui Paulo 			ret = dst = fasttrap_fulword((void *)rp->r_rsp);
1198625564deSRui Paulo 			addr = rp->r_rsp + sizeof (uintptr_t);
11996e19f4deSRui Paulo 		} else {
1200625564deSRui Paulo #endif
12016e19f4deSRui Paulo 			uint32_t dst32;
12026d1ffb50SMark Johnston 			ret = dst32 = fasttrap_fuword32((void *)rp->r_rsp);
12036e19f4deSRui Paulo 			dst = dst32;
12046d1ffb50SMark Johnston 			addr = rp->r_rsp + sizeof (uint32_t);
1205625564deSRui Paulo #ifdef __amd64
12066e19f4deSRui Paulo 		}
12076e19f4deSRui Paulo #endif
12086e19f4deSRui Paulo 
12096e19f4deSRui Paulo 		if (ret == -1) {
1210625564deSRui Paulo 			fasttrap_sigsegv(p, curthread, rp->r_rsp);
12116e19f4deSRui Paulo 			new_pc = pc;
12126e19f4deSRui Paulo 			break;
12136e19f4deSRui Paulo 		}
12146e19f4deSRui Paulo 
12156e19f4deSRui Paulo 		if (tp->ftt_type == FASTTRAP_T_RET16)
12166e19f4deSRui Paulo 			addr += tp->ftt_dest;
12176e19f4deSRui Paulo 
1218625564deSRui Paulo 		rp->r_rsp = addr;
12196e19f4deSRui Paulo 		new_pc = dst;
12206e19f4deSRui Paulo 		break;
12216e19f4deSRui Paulo 	}
12226e19f4deSRui Paulo 
12236e19f4deSRui Paulo 	case FASTTRAP_T_JCC:
12246e19f4deSRui Paulo 	{
1225625564deSRui Paulo 		uint_t taken = 0;
12266e19f4deSRui Paulo 
12276e19f4deSRui Paulo 		switch (tp->ftt_code) {
12286e19f4deSRui Paulo 		case FASTTRAP_JO:
1229625564deSRui Paulo 			taken = (rp->r_rflags & FASTTRAP_EFLAGS_OF) != 0;
12306e19f4deSRui Paulo 			break;
12316e19f4deSRui Paulo 		case FASTTRAP_JNO:
1232625564deSRui Paulo 			taken = (rp->r_rflags & FASTTRAP_EFLAGS_OF) == 0;
12336e19f4deSRui Paulo 			break;
12346e19f4deSRui Paulo 		case FASTTRAP_JB:
1235625564deSRui Paulo 			taken = (rp->r_rflags & FASTTRAP_EFLAGS_CF) != 0;
12366e19f4deSRui Paulo 			break;
12376e19f4deSRui Paulo 		case FASTTRAP_JAE:
1238625564deSRui Paulo 			taken = (rp->r_rflags & FASTTRAP_EFLAGS_CF) == 0;
12396e19f4deSRui Paulo 			break;
12406e19f4deSRui Paulo 		case FASTTRAP_JE:
1241625564deSRui Paulo 			taken = (rp->r_rflags & FASTTRAP_EFLAGS_ZF) != 0;
12426e19f4deSRui Paulo 			break;
12436e19f4deSRui Paulo 		case FASTTRAP_JNE:
1244625564deSRui Paulo 			taken = (rp->r_rflags & FASTTRAP_EFLAGS_ZF) == 0;
12456e19f4deSRui Paulo 			break;
12466e19f4deSRui Paulo 		case FASTTRAP_JBE:
1247625564deSRui Paulo 			taken = (rp->r_rflags & FASTTRAP_EFLAGS_CF) != 0 ||
1248625564deSRui Paulo 			    (rp->r_rflags & FASTTRAP_EFLAGS_ZF) != 0;
12496e19f4deSRui Paulo 			break;
12506e19f4deSRui Paulo 		case FASTTRAP_JA:
1251625564deSRui Paulo 			taken = (rp->r_rflags & FASTTRAP_EFLAGS_CF) == 0 &&
1252625564deSRui Paulo 			    (rp->r_rflags & FASTTRAP_EFLAGS_ZF) == 0;
12536e19f4deSRui Paulo 			break;
12546e19f4deSRui Paulo 		case FASTTRAP_JS:
1255625564deSRui Paulo 			taken = (rp->r_rflags & FASTTRAP_EFLAGS_SF) != 0;
12566e19f4deSRui Paulo 			break;
12576e19f4deSRui Paulo 		case FASTTRAP_JNS:
1258625564deSRui Paulo 			taken = (rp->r_rflags & FASTTRAP_EFLAGS_SF) == 0;
12596e19f4deSRui Paulo 			break;
12606e19f4deSRui Paulo 		case FASTTRAP_JP:
1261625564deSRui Paulo 			taken = (rp->r_rflags & FASTTRAP_EFLAGS_PF) != 0;
12626e19f4deSRui Paulo 			break;
12636e19f4deSRui Paulo 		case FASTTRAP_JNP:
1264625564deSRui Paulo 			taken = (rp->r_rflags & FASTTRAP_EFLAGS_PF) == 0;
12656e19f4deSRui Paulo 			break;
12666e19f4deSRui Paulo 		case FASTTRAP_JL:
1267625564deSRui Paulo 			taken = ((rp->r_rflags & FASTTRAP_EFLAGS_SF) == 0) !=
1268625564deSRui Paulo 			    ((rp->r_rflags & FASTTRAP_EFLAGS_OF) == 0);
12696e19f4deSRui Paulo 			break;
12706e19f4deSRui Paulo 		case FASTTRAP_JGE:
1271625564deSRui Paulo 			taken = ((rp->r_rflags & FASTTRAP_EFLAGS_SF) == 0) ==
1272625564deSRui Paulo 			    ((rp->r_rflags & FASTTRAP_EFLAGS_OF) == 0);
12736e19f4deSRui Paulo 			break;
12746e19f4deSRui Paulo 		case FASTTRAP_JLE:
1275625564deSRui Paulo 			taken = (rp->r_rflags & FASTTRAP_EFLAGS_ZF) != 0 ||
1276625564deSRui Paulo 			    ((rp->r_rflags & FASTTRAP_EFLAGS_SF) == 0) !=
1277625564deSRui Paulo 			    ((rp->r_rflags & FASTTRAP_EFLAGS_OF) == 0);
12786e19f4deSRui Paulo 			break;
12796e19f4deSRui Paulo 		case FASTTRAP_JG:
1280625564deSRui Paulo 			taken = (rp->r_rflags & FASTTRAP_EFLAGS_ZF) == 0 &&
1281625564deSRui Paulo 			    ((rp->r_rflags & FASTTRAP_EFLAGS_SF) == 0) ==
1282625564deSRui Paulo 			    ((rp->r_rflags & FASTTRAP_EFLAGS_OF) == 0);
12836e19f4deSRui Paulo 			break;
12846e19f4deSRui Paulo 
12856e19f4deSRui Paulo 		}
12866e19f4deSRui Paulo 
12876e19f4deSRui Paulo 		if (taken)
12886e19f4deSRui Paulo 			new_pc = tp->ftt_dest;
12896e19f4deSRui Paulo 		else
12906e19f4deSRui Paulo 			new_pc = pc + tp->ftt_size;
12916e19f4deSRui Paulo 		break;
12926e19f4deSRui Paulo 	}
12936e19f4deSRui Paulo 
12946e19f4deSRui Paulo 	case FASTTRAP_T_LOOP:
12956e19f4deSRui Paulo 	{
1296625564deSRui Paulo 		uint_t taken = 0;
12976e19f4deSRui Paulo #ifdef __amd64
12986e19f4deSRui Paulo 		greg_t cx = rp->r_rcx--;
12996e19f4deSRui Paulo #else
13006e19f4deSRui Paulo 		greg_t cx = rp->r_ecx--;
13016e19f4deSRui Paulo #endif
13026e19f4deSRui Paulo 
13036e19f4deSRui Paulo 		switch (tp->ftt_code) {
13046e19f4deSRui Paulo 		case FASTTRAP_LOOPNZ:
1305625564deSRui Paulo 			taken = (rp->r_rflags & FASTTRAP_EFLAGS_ZF) == 0 &&
13066e19f4deSRui Paulo 			    cx != 0;
13076e19f4deSRui Paulo 			break;
13086e19f4deSRui Paulo 		case FASTTRAP_LOOPZ:
1309625564deSRui Paulo 			taken = (rp->r_rflags & FASTTRAP_EFLAGS_ZF) != 0 &&
13106e19f4deSRui Paulo 			    cx != 0;
13116e19f4deSRui Paulo 			break;
13126e19f4deSRui Paulo 		case FASTTRAP_LOOP:
13136e19f4deSRui Paulo 			taken = (cx != 0);
13146e19f4deSRui Paulo 			break;
13156e19f4deSRui Paulo 		}
13166e19f4deSRui Paulo 
13176e19f4deSRui Paulo 		if (taken)
13186e19f4deSRui Paulo 			new_pc = tp->ftt_dest;
13196e19f4deSRui Paulo 		else
13206e19f4deSRui Paulo 			new_pc = pc + tp->ftt_size;
13216e19f4deSRui Paulo 		break;
13226e19f4deSRui Paulo 	}
13236e19f4deSRui Paulo 
13246e19f4deSRui Paulo 	case FASTTRAP_T_JCXZ:
13256e19f4deSRui Paulo 	{
13266e19f4deSRui Paulo #ifdef __amd64
13276e19f4deSRui Paulo 		greg_t cx = rp->r_rcx;
13286e19f4deSRui Paulo #else
13296e19f4deSRui Paulo 		greg_t cx = rp->r_ecx;
13306e19f4deSRui Paulo #endif
13316e19f4deSRui Paulo 
13326e19f4deSRui Paulo 		if (cx == 0)
13336e19f4deSRui Paulo 			new_pc = tp->ftt_dest;
13346e19f4deSRui Paulo 		else
13356e19f4deSRui Paulo 			new_pc = pc + tp->ftt_size;
13366e19f4deSRui Paulo 		break;
13376e19f4deSRui Paulo 	}
13386e19f4deSRui Paulo 
13396e19f4deSRui Paulo 	case FASTTRAP_T_PUSHL_EBP:
13406e19f4deSRui Paulo 	{
1341625564deSRui Paulo 		int ret = 0;
1342add89852SRyan Stone 
13436e19f4deSRui Paulo #ifdef __amd64
13446e19f4deSRui Paulo 		if (p->p_model == DATAMODEL_NATIVE) {
1345165de3f3SMark Johnston 			rp->r_rsp -= sizeof (uintptr_t);
1346a4cbcb12SMark Johnston 			ret = fasttrap_sulword((void *)rp->r_rsp, rp->r_rbp);
13476e19f4deSRui Paulo 		} else {
1348625564deSRui Paulo #endif
1349165de3f3SMark Johnston 			rp->r_rsp -= sizeof (uint32_t);
1350a4cbcb12SMark Johnston 			ret = fasttrap_suword32((void *)rp->r_rsp, rp->r_rbp);
1351625564deSRui Paulo #ifdef __amd64
13526e19f4deSRui Paulo 		}
13536e19f4deSRui Paulo #endif
13546e19f4deSRui Paulo 
13556e19f4deSRui Paulo 		if (ret == -1) {
1356165de3f3SMark Johnston 			fasttrap_sigsegv(p, curthread, rp->r_rsp);
13576e19f4deSRui Paulo 			new_pc = pc;
13586e19f4deSRui Paulo 			break;
13596e19f4deSRui Paulo 		}
13606e19f4deSRui Paulo 
13616e19f4deSRui Paulo 		new_pc = pc + tp->ftt_size;
13626e19f4deSRui Paulo 		break;
13636e19f4deSRui Paulo 	}
13646e19f4deSRui Paulo 
13656e19f4deSRui Paulo 	case FASTTRAP_T_NOP:
13666e19f4deSRui Paulo 		new_pc = pc + tp->ftt_size;
13676e19f4deSRui Paulo 		break;
13686e19f4deSRui Paulo 
13696e19f4deSRui Paulo 	case FASTTRAP_T_JMP:
13706e19f4deSRui Paulo 	case FASTTRAP_T_CALL:
13716e19f4deSRui Paulo 		if (tp->ftt_code == 0) {
13726e19f4deSRui Paulo 			new_pc = tp->ftt_dest;
13736e19f4deSRui Paulo 		} else {
1374ae520d3dSMark Johnston 			uintptr_t value, addr = tp->ftt_dest;
13756e19f4deSRui Paulo 
13766e19f4deSRui Paulo 			if (tp->ftt_base != FASTTRAP_NOREG)
13776e19f4deSRui Paulo 				addr += fasttrap_getreg(rp, tp->ftt_base);
13786e19f4deSRui Paulo 			if (tp->ftt_index != FASTTRAP_NOREG)
13796e19f4deSRui Paulo 				addr += fasttrap_getreg(rp, tp->ftt_index) <<
13806e19f4deSRui Paulo 				    tp->ftt_scale;
13816e19f4deSRui Paulo 
13826e19f4deSRui Paulo 			if (tp->ftt_code == 1) {
13836e19f4deSRui Paulo 				/*
13846e19f4deSRui Paulo 				 * If there's a segment prefix for this
13856e19f4deSRui Paulo 				 * instruction, we'll need to check permissions
13866e19f4deSRui Paulo 				 * and bounds on the given selector, and adjust
13876e19f4deSRui Paulo 				 * the address accordingly.
13886e19f4deSRui Paulo 				 */
13896e19f4deSRui Paulo 				if (tp->ftt_segment != FASTTRAP_SEG_NONE &&
13906e19f4deSRui Paulo 				    fasttrap_do_seg(tp, rp, &addr) != 0) {
13916e19f4deSRui Paulo 					fasttrap_sigsegv(p, curthread, addr);
13926e19f4deSRui Paulo 					new_pc = pc;
13936e19f4deSRui Paulo 					break;
13946e19f4deSRui Paulo 				}
13956e19f4deSRui Paulo 
13966e19f4deSRui Paulo #ifdef __amd64
13976e19f4deSRui Paulo 				if (p->p_model == DATAMODEL_NATIVE) {
1398ae520d3dSMark Johnston #endif
1399625564deSRui Paulo 					if ((value = fasttrap_fulword((void *)addr))
1400625564deSRui Paulo 					     == -1) {
14016e19f4deSRui Paulo 						fasttrap_sigsegv(p, curthread,
14026e19f4deSRui Paulo 						    addr);
14036e19f4deSRui Paulo 						new_pc = pc;
14046e19f4deSRui Paulo 						break;
14056e19f4deSRui Paulo 					}
14066e19f4deSRui Paulo 					new_pc = value;
1407ae520d3dSMark Johnston #ifdef __amd64
14086e19f4deSRui Paulo 				} else {
14096e19f4deSRui Paulo 					uint32_t value32;
14106e19f4deSRui Paulo 					addr = (uintptr_t)(uint32_t)addr;
1411625564deSRui Paulo 					if ((value32 = fasttrap_fuword32((void *)addr))
1412625564deSRui Paulo 					    == -1) {
14136e19f4deSRui Paulo 						fasttrap_sigsegv(p, curthread,
14146e19f4deSRui Paulo 						    addr);
14156e19f4deSRui Paulo 						new_pc = pc;
14166e19f4deSRui Paulo 						break;
14176e19f4deSRui Paulo 					}
14186e19f4deSRui Paulo 					new_pc = value32;
1419625564deSRui Paulo 				}
1420ae520d3dSMark Johnston #endif
14216e19f4deSRui Paulo 			} else {
14226e19f4deSRui Paulo 				new_pc = addr;
14236e19f4deSRui Paulo 			}
14246e19f4deSRui Paulo 		}
14256e19f4deSRui Paulo 
14266e19f4deSRui Paulo 		/*
14276e19f4deSRui Paulo 		 * If this is a call instruction, we need to push the return
14286e19f4deSRui Paulo 		 * address onto the stack. If this fails, we send the process
14296e19f4deSRui Paulo 		 * a SIGSEGV and reset the pc to emulate what would happen if
14306e19f4deSRui Paulo 		 * this instruction weren't traced.
14316e19f4deSRui Paulo 		 */
14326e19f4deSRui Paulo 		if (tp->ftt_type == FASTTRAP_T_CALL) {
1433625564deSRui Paulo 			int ret = 0;
1434625564deSRui Paulo 			uintptr_t addr = 0, pcps;
14356e19f4deSRui Paulo #ifdef __amd64
14366e19f4deSRui Paulo 			if (p->p_model == DATAMODEL_NATIVE) {
1437625564deSRui Paulo 				addr = rp->r_rsp - sizeof (uintptr_t);
1438625564deSRui Paulo 				pcps = pc + tp->ftt_size;
1439a4cbcb12SMark Johnston 				ret = fasttrap_sulword((void *)addr, pcps);
14406e19f4deSRui Paulo 			} else {
14416e19f4deSRui Paulo #endif
1442625564deSRui Paulo 				addr = rp->r_rsp - sizeof (uint32_t);
1443625564deSRui Paulo 				pcps = (uint32_t)(pc + tp->ftt_size);
1444a4cbcb12SMark Johnston 				ret = fasttrap_suword32((void *)addr, pcps);
14456e19f4deSRui Paulo #ifdef __amd64
14466e19f4deSRui Paulo 			}
14476e19f4deSRui Paulo #endif
14486e19f4deSRui Paulo 
14496e19f4deSRui Paulo 			if (ret == -1) {
14506e19f4deSRui Paulo 				fasttrap_sigsegv(p, curthread, addr);
14516e19f4deSRui Paulo 				new_pc = pc;
14526e19f4deSRui Paulo 				break;
14536e19f4deSRui Paulo 			}
14546e19f4deSRui Paulo 
1455625564deSRui Paulo 			rp->r_rsp = addr;
14566e19f4deSRui Paulo 		}
14576e19f4deSRui Paulo 
14586e19f4deSRui Paulo 		break;
14596e19f4deSRui Paulo 
14606e19f4deSRui Paulo 	case FASTTRAP_T_COMMON:
14616e19f4deSRui Paulo 	{
14626e19f4deSRui Paulo 		uintptr_t addr;
14636e19f4deSRui Paulo #if defined(__amd64)
14646e19f4deSRui Paulo 		uint8_t scratch[2 * FASTTRAP_MAX_INSTR_SIZE + 22];
14656e19f4deSRui Paulo #else
14666e19f4deSRui Paulo 		uint8_t scratch[2 * FASTTRAP_MAX_INSTR_SIZE + 7];
14676e19f4deSRui Paulo #endif
14686e19f4deSRui Paulo 		uint_t i = 0;
14690626f3e4SMark Johnston 		fasttrap_scrspace_t *scrspace;
14700626f3e4SMark Johnston 		scrspace = fasttrap_scraddr(curthread, tp->ftt_proc);
14710626f3e4SMark Johnston 		if (scrspace == NULL) {
14720626f3e4SMark Johnston 			/*
14730626f3e4SMark Johnston 			 * We failed to allocate scratch space for this thread.
14740626f3e4SMark Johnston 			 * Try to write the original instruction back out and
14750626f3e4SMark Johnston 			 * reset the pc.
14760626f3e4SMark Johnston 			 */
14770626f3e4SMark Johnston 			if (fasttrap_copyout(tp->ftt_instr, (void *)pc,
14780626f3e4SMark Johnston 			    tp->ftt_size))
14790626f3e4SMark Johnston 				fasttrap_sigtrap(p, curthread, pc);
14800626f3e4SMark Johnston 			new_pc = pc;
14810626f3e4SMark Johnston 			break;
14820626f3e4SMark Johnston 		}
14830626f3e4SMark Johnston 		addr = scrspace->ftss_addr;
14846e19f4deSRui Paulo 
14856e19f4deSRui Paulo 		/*
14866e19f4deSRui Paulo 		 * Generic Instruction Tracing
14876e19f4deSRui Paulo 		 * ---------------------------
14886e19f4deSRui Paulo 		 *
14896e19f4deSRui Paulo 		 * This is the layout of the scratch space in the user-land
14906e19f4deSRui Paulo 		 * thread structure for our generated instructions.
14916e19f4deSRui Paulo 		 *
14926e19f4deSRui Paulo 		 *	32-bit mode			bytes
14936e19f4deSRui Paulo 		 *	------------------------	-----
14946e19f4deSRui Paulo 		 * a:	<original instruction>		<= 15
14956e19f4deSRui Paulo 		 *	jmp	<pc + tp->ftt_size>	    5
1496add89852SRyan Stone 		 * b:	<original instruction>		<= 15
14976e19f4deSRui Paulo 		 *	int	T_DTRACE_RET		    2
14986e19f4deSRui Paulo 		 *					-----
14996e19f4deSRui Paulo 		 *					<= 37
15006e19f4deSRui Paulo 		 *
15016e19f4deSRui Paulo 		 *	64-bit mode			bytes
15026e19f4deSRui Paulo 		 *	------------------------	-----
15036e19f4deSRui Paulo 		 * a:	<original instruction>		<= 15
15046e19f4deSRui Paulo 		 *	jmp	0(%rip)			    6
15056e19f4deSRui Paulo 		 *	<pc + tp->ftt_size>		    8
15066e19f4deSRui Paulo 		 * b:	<original instruction>		<= 15
15076e19f4deSRui Paulo 		 * 	int	T_DTRACE_RET		    2
15086e19f4deSRui Paulo 		 * 					-----
15096e19f4deSRui Paulo 		 * 					<= 46
15106e19f4deSRui Paulo 		 *
15116e19f4deSRui Paulo 		 * The %pc is set to a, and curthread->t_dtrace_astpc is set
15126e19f4deSRui Paulo 		 * to b. If we encounter a signal on the way out of the
15136e19f4deSRui Paulo 		 * kernel, trap() will set %pc to curthread->t_dtrace_astpc
15146e19f4deSRui Paulo 		 * so that we execute the original instruction and re-enter
15156e19f4deSRui Paulo 		 * the kernel rather than redirecting to the next instruction.
15166e19f4deSRui Paulo 		 *
15176e19f4deSRui Paulo 		 * If there are return probes (so we know that we're going to
15186e19f4deSRui Paulo 		 * need to reenter the kernel after executing the original
15196e19f4deSRui Paulo 		 * instruction), the scratch space will just contain the
15206e19f4deSRui Paulo 		 * original instruction followed by an interrupt -- the same
15216e19f4deSRui Paulo 		 * data as at b.
15226e19f4deSRui Paulo 		 *
15236e19f4deSRui Paulo 		 * %rip-relative Addressing
15246e19f4deSRui Paulo 		 * ------------------------
15256e19f4deSRui Paulo 		 *
15266e19f4deSRui Paulo 		 * There's a further complication in 64-bit mode due to %rip-
15276e19f4deSRui Paulo 		 * relative addressing. While this is clearly a beneficial
15286e19f4deSRui Paulo 		 * architectural decision for position independent code, it's
15296e19f4deSRui Paulo 		 * hard not to see it as a personal attack against the pid
15306e19f4deSRui Paulo 		 * provider since before there was a relatively small set of
15316e19f4deSRui Paulo 		 * instructions to emulate; with %rip-relative addressing,
15326e19f4deSRui Paulo 		 * almost every instruction can potentially depend on the
15336e19f4deSRui Paulo 		 * address at which it's executed. Rather than emulating
15346e19f4deSRui Paulo 		 * the broad spectrum of instructions that can now be
15356e19f4deSRui Paulo 		 * position dependent, we emulate jumps and others as in
15366e19f4deSRui Paulo 		 * 32-bit mode, and take a different tack for instructions
15376e19f4deSRui Paulo 		 * using %rip-relative addressing.
15386e19f4deSRui Paulo 		 *
15396e19f4deSRui Paulo 		 * For every instruction that uses the ModRM byte, the
15406e19f4deSRui Paulo 		 * in-kernel disassembler reports its location. We use the
15416e19f4deSRui Paulo 		 * ModRM byte to identify that an instruction uses
15426e19f4deSRui Paulo 		 * %rip-relative addressing and to see what other registers
15436e19f4deSRui Paulo 		 * the instruction uses. To emulate those instructions,
15446e19f4deSRui Paulo 		 * we modify the instruction to be %rax-relative rather than
15456e19f4deSRui Paulo 		 * %rip-relative (or %rcx-relative if the instruction uses
15466e19f4deSRui Paulo 		 * %rax; or %r8- or %r9-relative if the REX.B is present so
15476e19f4deSRui Paulo 		 * we don't have to rewrite the REX prefix). We then load
15486e19f4deSRui Paulo 		 * the value that %rip would have been into the scratch
15496e19f4deSRui Paulo 		 * register and generate an instruction to reset the scratch
15506e19f4deSRui Paulo 		 * register back to its original value. The instruction
15516e19f4deSRui Paulo 		 * sequence looks like this:
15526e19f4deSRui Paulo 		 *
15536e19f4deSRui Paulo 		 *	64-mode %rip-relative		bytes
15546e19f4deSRui Paulo 		 *	------------------------	-----
15556e19f4deSRui Paulo 		 * a:	<modified instruction>		<= 15
15566e19f4deSRui Paulo 		 *	movq	$<value>, %<scratch>	    6
15576e19f4deSRui Paulo 		 *	jmp	0(%rip)			    6
15586e19f4deSRui Paulo 		 *	<pc + tp->ftt_size>		    8
15596e19f4deSRui Paulo 		 * b:	<modified instruction>  	<= 15
15606e19f4deSRui Paulo 		 * 	int	T_DTRACE_RET		    2
15616e19f4deSRui Paulo 		 * 					-----
15626e19f4deSRui Paulo 		 *					   52
15636e19f4deSRui Paulo 		 *
15646e19f4deSRui Paulo 		 * We set curthread->t_dtrace_regv so that upon receiving
15656e19f4deSRui Paulo 		 * a signal we can reset the value of the scratch register.
15666e19f4deSRui Paulo 		 */
15676e19f4deSRui Paulo 
1568da5320b9SMark Johnston 		ASSERT(tp->ftt_size <= FASTTRAP_MAX_INSTR_SIZE);
15696e19f4deSRui Paulo 
15706e19f4deSRui Paulo 		curthread->t_dtrace_scrpc = addr;
15716e19f4deSRui Paulo 		bcopy(tp->ftt_instr, &scratch[i], tp->ftt_size);
15726e19f4deSRui Paulo 		i += tp->ftt_size;
15736e19f4deSRui Paulo 
15746e19f4deSRui Paulo #ifdef __amd64
15756e19f4deSRui Paulo 		if (tp->ftt_ripmode != 0) {
1576625564deSRui Paulo 			greg_t *reg = NULL;
15776e19f4deSRui Paulo 
15786e19f4deSRui Paulo 			ASSERT(p->p_model == DATAMODEL_LP64);
15796e19f4deSRui Paulo 			ASSERT(tp->ftt_ripmode &
15806e19f4deSRui Paulo 			    (FASTTRAP_RIP_1 | FASTTRAP_RIP_2));
15816e19f4deSRui Paulo 
15826e19f4deSRui Paulo 			/*
15836e19f4deSRui Paulo 			 * If this was a %rip-relative instruction, we change
15846e19f4deSRui Paulo 			 * it to be either a %rax- or %rcx-relative
15856e19f4deSRui Paulo 			 * instruction (depending on whether those registers
15866e19f4deSRui Paulo 			 * are used as another operand; or %r8- or %r9-
15876e19f4deSRui Paulo 			 * relative depending on the value of REX.B). We then
15886e19f4deSRui Paulo 			 * set that register and generate a movq instruction
15896e19f4deSRui Paulo 			 * to reset the value.
15906e19f4deSRui Paulo 			 */
15916e19f4deSRui Paulo 			if (tp->ftt_ripmode & FASTTRAP_RIP_X)
15926e19f4deSRui Paulo 				scratch[i++] = FASTTRAP_REX(1, 0, 0, 1);
15936e19f4deSRui Paulo 			else
15946e19f4deSRui Paulo 				scratch[i++] = FASTTRAP_REX(1, 0, 0, 0);
15956e19f4deSRui Paulo 
15966e19f4deSRui Paulo 			if (tp->ftt_ripmode & FASTTRAP_RIP_1)
15976e19f4deSRui Paulo 				scratch[i++] = FASTTRAP_MOV_EAX;
15986e19f4deSRui Paulo 			else
15996e19f4deSRui Paulo 				scratch[i++] = FASTTRAP_MOV_ECX;
16006e19f4deSRui Paulo 
16016e19f4deSRui Paulo 			switch (tp->ftt_ripmode) {
16026e19f4deSRui Paulo 			case FASTTRAP_RIP_1:
16036e19f4deSRui Paulo 				reg = &rp->r_rax;
16046e19f4deSRui Paulo 				curthread->t_dtrace_reg = REG_RAX;
16056e19f4deSRui Paulo 				break;
16066e19f4deSRui Paulo 			case FASTTRAP_RIP_2:
16076e19f4deSRui Paulo 				reg = &rp->r_rcx;
16086e19f4deSRui Paulo 				curthread->t_dtrace_reg = REG_RCX;
16096e19f4deSRui Paulo 				break;
16106e19f4deSRui Paulo 			case FASTTRAP_RIP_1 | FASTTRAP_RIP_X:
16116e19f4deSRui Paulo 				reg = &rp->r_r8;
16126e19f4deSRui Paulo 				curthread->t_dtrace_reg = REG_R8;
16136e19f4deSRui Paulo 				break;
16146e19f4deSRui Paulo 			case FASTTRAP_RIP_2 | FASTTRAP_RIP_X:
16156e19f4deSRui Paulo 				reg = &rp->r_r9;
16166e19f4deSRui Paulo 				curthread->t_dtrace_reg = REG_R9;
16176e19f4deSRui Paulo 				break;
16186e19f4deSRui Paulo 			}
16196e19f4deSRui Paulo 
16206e19f4deSRui Paulo 			/* LINTED - alignment */
16216e19f4deSRui Paulo 			*(uint64_t *)&scratch[i] = *reg;
16226e19f4deSRui Paulo 			curthread->t_dtrace_regv = *reg;
16236e19f4deSRui Paulo 			*reg = pc + tp->ftt_size;
16246e19f4deSRui Paulo 			i += sizeof (uint64_t);
16256e19f4deSRui Paulo 		}
16266e19f4deSRui Paulo #endif
16276e19f4deSRui Paulo 
16286e19f4deSRui Paulo 		/*
16296e19f4deSRui Paulo 		 * Generate the branch instruction to what would have
16306e19f4deSRui Paulo 		 * normally been the subsequent instruction. In 32-bit mode,
16316e19f4deSRui Paulo 		 * this is just a relative branch; in 64-bit mode this is a
16326e19f4deSRui Paulo 		 * %rip-relative branch that loads the 64-bit pc value
16336e19f4deSRui Paulo 		 * immediately after the jmp instruction.
16346e19f4deSRui Paulo 		 */
16356e19f4deSRui Paulo #ifdef __amd64
16366e19f4deSRui Paulo 		if (p->p_model == DATAMODEL_LP64) {
16376e19f4deSRui Paulo 			scratch[i++] = FASTTRAP_GROUP5_OP;
16386e19f4deSRui Paulo 			scratch[i++] = FASTTRAP_MODRM(0, 4, 5);
16396e19f4deSRui Paulo 			/* LINTED - alignment */
16406e19f4deSRui Paulo 			*(uint32_t *)&scratch[i] = 0;
16416e19f4deSRui Paulo 			i += sizeof (uint32_t);
16426e19f4deSRui Paulo 			/* LINTED - alignment */
16436e19f4deSRui Paulo 			*(uint64_t *)&scratch[i] = pc + tp->ftt_size;
16446e19f4deSRui Paulo 			i += sizeof (uint64_t);
16456e19f4deSRui Paulo 		} else {
16466e19f4deSRui Paulo #endif
16476e19f4deSRui Paulo 			/*
16486e19f4deSRui Paulo 			 * Set up the jmp to the next instruction; note that
16496e19f4deSRui Paulo 			 * the size of the traced instruction cancels out.
16506e19f4deSRui Paulo 			 */
16516e19f4deSRui Paulo 			scratch[i++] = FASTTRAP_JMP32;
16526e19f4deSRui Paulo 			/* LINTED - alignment */
16536e19f4deSRui Paulo 			*(uint32_t *)&scratch[i] = pc - addr - 5;
16546e19f4deSRui Paulo 			i += sizeof (uint32_t);
16556e19f4deSRui Paulo #ifdef __amd64
16566e19f4deSRui Paulo 		}
16576e19f4deSRui Paulo #endif
16586e19f4deSRui Paulo 
16596e19f4deSRui Paulo 		curthread->t_dtrace_astpc = addr + i;
16606e19f4deSRui Paulo 		bcopy(tp->ftt_instr, &scratch[i], tp->ftt_size);
16616e19f4deSRui Paulo 		i += tp->ftt_size;
16626e19f4deSRui Paulo 		scratch[i++] = FASTTRAP_INT;
16636e19f4deSRui Paulo 		scratch[i++] = T_DTRACE_RET;
16646e19f4deSRui Paulo 
16656e19f4deSRui Paulo 		ASSERT(i <= sizeof (scratch));
16666e19f4deSRui Paulo 
16673a56cfedSMark Johnston 		if (uwrite(curproc, scratch, i, addr) != 0) {
16686e19f4deSRui Paulo 			fasttrap_sigtrap(p, curthread, pc);
16696e19f4deSRui Paulo 			new_pc = pc;
16706e19f4deSRui Paulo 			break;
16716e19f4deSRui Paulo 		}
16726e19f4deSRui Paulo 		if (tp->ftt_retids != NULL) {
16736e19f4deSRui Paulo 			curthread->t_dtrace_step = 1;
16746e19f4deSRui Paulo 			curthread->t_dtrace_ret = 1;
16756e19f4deSRui Paulo 			new_pc = curthread->t_dtrace_astpc;
16766e19f4deSRui Paulo 		} else {
16776e19f4deSRui Paulo 			new_pc = curthread->t_dtrace_scrpc;
16786e19f4deSRui Paulo 		}
16796e19f4deSRui Paulo 
16806e19f4deSRui Paulo 		curthread->t_dtrace_pc = pc;
16816e19f4deSRui Paulo 		curthread->t_dtrace_npc = pc + tp->ftt_size;
16826e19f4deSRui Paulo 		curthread->t_dtrace_on = 1;
16836e19f4deSRui Paulo 		break;
16846e19f4deSRui Paulo 	}
16856e19f4deSRui Paulo 
16866e19f4deSRui Paulo 	default:
16876e19f4deSRui Paulo 		panic("fasttrap: mishandled an instruction");
16886e19f4deSRui Paulo 	}
16896e19f4deSRui Paulo 
16906e19f4deSRui Paulo done:
16916e19f4deSRui Paulo 	/*
16926e19f4deSRui Paulo 	 * If there were no return probes when we first found the tracepoint,
16936e19f4deSRui Paulo 	 * we should feel no obligation to honor any return probes that were
16946e19f4deSRui Paulo 	 * subsequently enabled -- they'll just have to wait until the next
16956e19f4deSRui Paulo 	 * time around.
16966e19f4deSRui Paulo 	 */
16976e19f4deSRui Paulo 	if (tp->ftt_retids != NULL) {
16986e19f4deSRui Paulo 		/*
16996e19f4deSRui Paulo 		 * We need to wait until the results of the instruction are
17006e19f4deSRui Paulo 		 * apparent before invoking any return probes. If this
17016e19f4deSRui Paulo 		 * instruction was emulated we can just call
17026e19f4deSRui Paulo 		 * fasttrap_return_common(); if it needs to be executed, we
17036e19f4deSRui Paulo 		 * need to wait until the user thread returns to the kernel.
17046e19f4deSRui Paulo 		 */
17056e19f4deSRui Paulo 		if (tp->ftt_type != FASTTRAP_T_COMMON) {
17066e19f4deSRui Paulo 			/*
17076e19f4deSRui Paulo 			 * Set the program counter to the address of the traced
17086e19f4deSRui Paulo 			 * instruction so that it looks right in ustack()
17096e19f4deSRui Paulo 			 * output. We had previously set it to the end of the
17106e19f4deSRui Paulo 			 * instruction to simplify %rip-relative addressing.
17116e19f4deSRui Paulo 			 */
1712625564deSRui Paulo 			rp->r_rip = pc;
17136e19f4deSRui Paulo 
17146e19f4deSRui Paulo 			fasttrap_return_common(rp, pc, pid, new_pc);
17156e19f4deSRui Paulo 		} else {
17166e19f4deSRui Paulo 			ASSERT(curthread->t_dtrace_ret != 0);
17176e19f4deSRui Paulo 			ASSERT(curthread->t_dtrace_pc == pc);
17186e19f4deSRui Paulo 			ASSERT(curthread->t_dtrace_scrpc != 0);
17196e19f4deSRui Paulo 			ASSERT(new_pc == curthread->t_dtrace_astpc);
17206e19f4deSRui Paulo 		}
17216e19f4deSRui Paulo 	}
17226e19f4deSRui Paulo 
1723625564deSRui Paulo 	rp->r_rip = new_pc;
17247e2a739fSJustin T. Gibbs 
17257e2a739fSJustin T. Gibbs 	PROC_LOCK(p);
17267e2a739fSJustin T. Gibbs 	proc_write_regs(curthread, rp);
17277e2a739fSJustin T. Gibbs 	PROC_UNLOCK(p);
17286e19f4deSRui Paulo 
17296e19f4deSRui Paulo 	return (0);
17306e19f4deSRui Paulo }
17316e19f4deSRui Paulo 
17326e19f4deSRui Paulo int
17335bab6234SMark Johnston fasttrap_return_probe(struct trapframe *tf)
17346e19f4deSRui Paulo {
17355bab6234SMark Johnston 	struct reg reg, *rp;
17366e19f4deSRui Paulo 	proc_t *p = curproc;
17376e19f4deSRui Paulo 	uintptr_t pc = curthread->t_dtrace_pc;
17386e19f4deSRui Paulo 	uintptr_t npc = curthread->t_dtrace_npc;
17396e19f4deSRui Paulo 
17405bab6234SMark Johnston 	fill_frame_regs(tf, &reg);
17415bab6234SMark Johnston 	rp = &reg;
17425bab6234SMark Johnston 
17436e19f4deSRui Paulo 	curthread->t_dtrace_pc = 0;
17446e19f4deSRui Paulo 	curthread->t_dtrace_npc = 0;
17456e19f4deSRui Paulo 	curthread->t_dtrace_scrpc = 0;
17466e19f4deSRui Paulo 	curthread->t_dtrace_astpc = 0;
17476e19f4deSRui Paulo 
1748bc96366cSSteven Hartland #ifdef illumos
17496e19f4deSRui Paulo 	/*
17506e19f4deSRui Paulo 	 * Treat a child created by a call to vfork(2) as if it were its
17516e19f4deSRui Paulo 	 * parent. We know that there's only one thread of control in such a
17526e19f4deSRui Paulo 	 * process: this one.
17536e19f4deSRui Paulo 	 */
17546e19f4deSRui Paulo 	while (p->p_flag & SVFORK) {
17556e19f4deSRui Paulo 		p = p->p_parent;
17566e19f4deSRui Paulo 	}
1757625564deSRui Paulo #endif
17586e19f4deSRui Paulo 
17596e19f4deSRui Paulo 	/*
1760625564deSRui Paulo 	 * We set rp->r_rip to the address of the traced instruction so
17616e19f4deSRui Paulo 	 * that it appears to dtrace_probe() that we're on the original
17625bab6234SMark Johnston 	 * instruction.
17636e19f4deSRui Paulo 	 */
1764625564deSRui Paulo 	rp->r_rip = pc;
17656e19f4deSRui Paulo 
17666e19f4deSRui Paulo 	fasttrap_return_common(rp, pc, p->p_pid, npc);
17676e19f4deSRui Paulo 
17686e19f4deSRui Paulo 	return (0);
17696e19f4deSRui Paulo }
17706e19f4deSRui Paulo 
17716e19f4deSRui Paulo /*ARGSUSED*/
17726e19f4deSRui Paulo uint64_t
17736e19f4deSRui Paulo fasttrap_pid_getarg(void *arg, dtrace_id_t id, void *parg, int argno,
17746e19f4deSRui Paulo     int aframes)
17756e19f4deSRui Paulo {
1776625564deSRui Paulo 	struct reg r;
1777625564deSRui Paulo 
1778625564deSRui Paulo 	fill_regs(curthread, &r);
1779625564deSRui Paulo 
1780625564deSRui Paulo 	return (fasttrap_anarg(&r, 1, argno));
17816e19f4deSRui Paulo }
17826e19f4deSRui Paulo 
17836e19f4deSRui Paulo /*ARGSUSED*/
17846e19f4deSRui Paulo uint64_t
17856e19f4deSRui Paulo fasttrap_usdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno,
17866e19f4deSRui Paulo     int aframes)
17876e19f4deSRui Paulo {
1788625564deSRui Paulo 	struct reg r;
1789625564deSRui Paulo 
1790625564deSRui Paulo 	fill_regs(curthread, &r);
1791625564deSRui Paulo 
1792625564deSRui Paulo 	return (fasttrap_anarg(&r, 0, argno));
17936e19f4deSRui Paulo }
17946e19f4deSRui Paulo 
17956e19f4deSRui Paulo static ulong_t
1796625564deSRui Paulo fasttrap_getreg(struct reg *rp, uint_t reg)
17976e19f4deSRui Paulo {
17986e19f4deSRui Paulo #ifdef __amd64
17996e19f4deSRui Paulo 	switch (reg) {
18006e19f4deSRui Paulo 	case REG_R15:		return (rp->r_r15);
18016e19f4deSRui Paulo 	case REG_R14:		return (rp->r_r14);
18026e19f4deSRui Paulo 	case REG_R13:		return (rp->r_r13);
18036e19f4deSRui Paulo 	case REG_R12:		return (rp->r_r12);
18046e19f4deSRui Paulo 	case REG_R11:		return (rp->r_r11);
18056e19f4deSRui Paulo 	case REG_R10:		return (rp->r_r10);
18066e19f4deSRui Paulo 	case REG_R9:		return (rp->r_r9);
18076e19f4deSRui Paulo 	case REG_R8:		return (rp->r_r8);
18086e19f4deSRui Paulo 	case REG_RDI:		return (rp->r_rdi);
18096e19f4deSRui Paulo 	case REG_RSI:		return (rp->r_rsi);
18106e19f4deSRui Paulo 	case REG_RBP:		return (rp->r_rbp);
18116e19f4deSRui Paulo 	case REG_RBX:		return (rp->r_rbx);
18126e19f4deSRui Paulo 	case REG_RDX:		return (rp->r_rdx);
18136e19f4deSRui Paulo 	case REG_RCX:		return (rp->r_rcx);
18146e19f4deSRui Paulo 	case REG_RAX:		return (rp->r_rax);
18156e19f4deSRui Paulo 	case REG_TRAPNO:	return (rp->r_trapno);
18166e19f4deSRui Paulo 	case REG_ERR:		return (rp->r_err);
18176e19f4deSRui Paulo 	case REG_RIP:		return (rp->r_rip);
18186e19f4deSRui Paulo 	case REG_CS:		return (rp->r_cs);
1819188011dbSMark Johnston 	case REG_RFL:		return (rp->r_rflags);
18206e19f4deSRui Paulo 	case REG_RSP:		return (rp->r_rsp);
18216e19f4deSRui Paulo 	case REG_SS:		return (rp->r_ss);
18226e19f4deSRui Paulo 	case REG_FS:		return (rp->r_fs);
18236e19f4deSRui Paulo 	case REG_GS:		return (rp->r_gs);
18246e19f4deSRui Paulo 	case REG_DS:		return (rp->r_ds);
18256e19f4deSRui Paulo 	case REG_ES:		return (rp->r_es);
1826625564deSRui Paulo 	case REG_FSBASE:	return (rdmsr(MSR_FSBASE));
1827625564deSRui Paulo 	case REG_GSBASE:	return (rdmsr(MSR_GSBASE));
18286e19f4deSRui Paulo 	}
18296e19f4deSRui Paulo 
18306e19f4deSRui Paulo 	panic("dtrace: illegal register constant");
18316e19f4deSRui Paulo 	/*NOTREACHED*/
18326e19f4deSRui Paulo #else
1833625564deSRui Paulo #define _NGREG 19
18346e19f4deSRui Paulo 	if (reg >= _NGREG)
18356e19f4deSRui Paulo 		panic("dtrace: illegal register constant");
18366e19f4deSRui Paulo 
18376e19f4deSRui Paulo 	return (((greg_t *)&rp->r_gs)[reg]);
18386e19f4deSRui Paulo #endif
18396e19f4deSRui Paulo }
1840