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, ®); 9345bab6234SMark Johnston rp = ® 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, ®); 17415bab6234SMark Johnston rp = ® 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