10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51710Sahl * Common Development and Distribution License (the "License"). 61710Sahl * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 211710Sahl 220Sstevel@tonic-gate /* 231710Sahl * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include <sys/fasttrap_isa.h> 300Sstevel@tonic-gate #include <sys/fasttrap_impl.h> 310Sstevel@tonic-gate #include <sys/dtrace.h> 320Sstevel@tonic-gate #include <sys/dtrace_impl.h> 330Sstevel@tonic-gate #include <sys/cmn_err.h> 340Sstevel@tonic-gate #include <sys/regset.h> 350Sstevel@tonic-gate #include <sys/privregs.h> 360Sstevel@tonic-gate #include <sys/segments.h> 370Sstevel@tonic-gate #include <sys/sysmacros.h> 380Sstevel@tonic-gate #include <sys/trap.h> 392712Snn35248 #include <sys/archsystm.h> 400Sstevel@tonic-gate 410Sstevel@tonic-gate /* 420Sstevel@tonic-gate * Lossless User-Land Tracing on x86 430Sstevel@tonic-gate * --------------------------------- 440Sstevel@tonic-gate * 451710Sahl * The execution of most instructions is not dependent on the address; for 461710Sahl * these instructions it is sufficient to copy them into the user process's 471710Sahl * address space and execute them. To effectively single-step an instruction 481710Sahl * in user-land, we copy out the following sequence of instructions to scratch 490Sstevel@tonic-gate * space in the user thread's ulwp_t structure. 500Sstevel@tonic-gate * 510Sstevel@tonic-gate * We then set the program counter (%eip or %rip) to point to this scratch 520Sstevel@tonic-gate * space. Once execution resumes, the original instruction is executed and 530Sstevel@tonic-gate * then control flow is redirected to what was originally the subsequent 540Sstevel@tonic-gate * instruction. If the kernel attemps to deliver a signal while single- 550Sstevel@tonic-gate * stepping, the signal is deferred and the program counter is moved into the 560Sstevel@tonic-gate * second sequence of instructions. The second sequence ends in a trap into 570Sstevel@tonic-gate * the kernel where the deferred signal is then properly handled and delivered. 580Sstevel@tonic-gate * 590Sstevel@tonic-gate * For instructions whose execute is position dependent, we perform simple 600Sstevel@tonic-gate * emulation. These instructions are limited to control transfer 610Sstevel@tonic-gate * instructions in 32-bit mode, but in 64-bit mode there's the added wrinkle 620Sstevel@tonic-gate * of %rip-relative addressing that means that almost any instruction can be 630Sstevel@tonic-gate * position dependent. For all the details on how we emulate generic 640Sstevel@tonic-gate * instructions included %rip-relative instructions, see the code in 650Sstevel@tonic-gate * fasttrap_pid_probe() below where we handle instructions of type 660Sstevel@tonic-gate * FASTTRAP_T_COMMON (under the header: Generic Instruction Tracing). 670Sstevel@tonic-gate */ 680Sstevel@tonic-gate 690Sstevel@tonic-gate #define FASTTRAP_MODRM_MOD(modrm) (((modrm) >> 6) & 0x3) 700Sstevel@tonic-gate #define FASTTRAP_MODRM_REG(modrm) (((modrm) >> 3) & 0x7) 710Sstevel@tonic-gate #define FASTTRAP_MODRM_RM(modrm) ((modrm) & 0x7) 720Sstevel@tonic-gate #define FASTTRAP_MODRM(mod, reg, rm) (((mod) << 6) | ((reg) << 3) | (rm)) 730Sstevel@tonic-gate 740Sstevel@tonic-gate #define FASTTRAP_SIB_SCALE(sib) (((sib) >> 6) & 0x3) 750Sstevel@tonic-gate #define FASTTRAP_SIB_INDEX(sib) (((sib) >> 3) & 0x7) 760Sstevel@tonic-gate #define FASTTRAP_SIB_BASE(sib) ((sib) & 0x7) 770Sstevel@tonic-gate 780Sstevel@tonic-gate #define FASTTRAP_REX_W(rex) (((rex) >> 3) & 1) 790Sstevel@tonic-gate #define FASTTRAP_REX_R(rex) (((rex) >> 2) & 1) 800Sstevel@tonic-gate #define FASTTRAP_REX_X(rex) (((rex) >> 1) & 1) 810Sstevel@tonic-gate #define FASTTRAP_REX_B(rex) ((rex) & 1) 820Sstevel@tonic-gate #define FASTTRAP_REX(w, r, x, b) \ 830Sstevel@tonic-gate (0x40 | ((w) << 3) | ((r) << 2) | ((x) << 1) | (b)) 840Sstevel@tonic-gate 850Sstevel@tonic-gate /* 860Sstevel@tonic-gate * Single-byte op-codes. 870Sstevel@tonic-gate */ 880Sstevel@tonic-gate #define FASTTRAP_PUSHL_EBP 0x55 890Sstevel@tonic-gate 900Sstevel@tonic-gate #define FASTTRAP_JO 0x70 910Sstevel@tonic-gate #define FASTTRAP_JNO 0x71 920Sstevel@tonic-gate #define FASTTRAP_JB 0x72 930Sstevel@tonic-gate #define FASTTRAP_JAE 0x73 940Sstevel@tonic-gate #define FASTTRAP_JE 0x74 950Sstevel@tonic-gate #define FASTTRAP_JNE 0x75 960Sstevel@tonic-gate #define FASTTRAP_JBE 0x76 970Sstevel@tonic-gate #define FASTTRAP_JA 0x77 980Sstevel@tonic-gate #define FASTTRAP_JS 0x78 990Sstevel@tonic-gate #define FASTTRAP_JNS 0x79 1000Sstevel@tonic-gate #define FASTTRAP_JP 0x7a 1010Sstevel@tonic-gate #define FASTTRAP_JNP 0x7b 1020Sstevel@tonic-gate #define FASTTRAP_JL 0x7c 1030Sstevel@tonic-gate #define FASTTRAP_JGE 0x7d 1040Sstevel@tonic-gate #define FASTTRAP_JLE 0x7e 1050Sstevel@tonic-gate #define FASTTRAP_JG 0x7f 1060Sstevel@tonic-gate 107*2769Sahl #define FASTTRAP_NOP 0x90 108*2769Sahl 1090Sstevel@tonic-gate #define FASTTRAP_MOV_EAX 0xb8 1100Sstevel@tonic-gate #define FASTTRAP_MOV_ECX 0xb9 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate #define FASTTRAP_RET16 0xc2 1130Sstevel@tonic-gate #define FASTTRAP_RET 0xc3 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate #define FASTTRAP_LOOPNZ 0xe0 1160Sstevel@tonic-gate #define FASTTRAP_LOOPZ 0xe1 1170Sstevel@tonic-gate #define FASTTRAP_LOOP 0xe2 1180Sstevel@tonic-gate #define FASTTRAP_JCXZ 0xe3 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate #define FASTTRAP_CALL 0xe8 1210Sstevel@tonic-gate #define FASTTRAP_JMP32 0xe9 1220Sstevel@tonic-gate #define FASTTRAP_JMP8 0xeb 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate #define FASTTRAP_INT3 0xcc 1250Sstevel@tonic-gate #define FASTTRAP_INT 0xcd 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate #define FASTTRAP_2_BYTE_OP 0x0f 1280Sstevel@tonic-gate #define FASTTRAP_GROUP5_OP 0xff 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate /* 1310Sstevel@tonic-gate * Two-byte op-codes (second byte only). 1320Sstevel@tonic-gate */ 1330Sstevel@tonic-gate #define FASTTRAP_0F_JO 0x80 1340Sstevel@tonic-gate #define FASTTRAP_0F_JNO 0x81 1350Sstevel@tonic-gate #define FASTTRAP_0F_JB 0x82 1360Sstevel@tonic-gate #define FASTTRAP_0F_JAE 0x83 1370Sstevel@tonic-gate #define FASTTRAP_0F_JE 0x84 1380Sstevel@tonic-gate #define FASTTRAP_0F_JNE 0x85 1390Sstevel@tonic-gate #define FASTTRAP_0F_JBE 0x86 1400Sstevel@tonic-gate #define FASTTRAP_0F_JA 0x87 1410Sstevel@tonic-gate #define FASTTRAP_0F_JS 0x88 1420Sstevel@tonic-gate #define FASTTRAP_0F_JNS 0x89 1430Sstevel@tonic-gate #define FASTTRAP_0F_JP 0x8a 1440Sstevel@tonic-gate #define FASTTRAP_0F_JNP 0x8b 1450Sstevel@tonic-gate #define FASTTRAP_0F_JL 0x8c 1460Sstevel@tonic-gate #define FASTTRAP_0F_JGE 0x8d 1470Sstevel@tonic-gate #define FASTTRAP_0F_JLE 0x8e 1480Sstevel@tonic-gate #define FASTTRAP_0F_JG 0x8f 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate #define FASTTRAP_EFLAGS_OF 0x800 1510Sstevel@tonic-gate #define FASTTRAP_EFLAGS_DF 0x400 1520Sstevel@tonic-gate #define FASTTRAP_EFLAGS_SF 0x080 1530Sstevel@tonic-gate #define FASTTRAP_EFLAGS_ZF 0x040 1540Sstevel@tonic-gate #define FASTTRAP_EFLAGS_AF 0x010 1550Sstevel@tonic-gate #define FASTTRAP_EFLAGS_PF 0x004 1560Sstevel@tonic-gate #define FASTTRAP_EFLAGS_CF 0x001 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate /* 1590Sstevel@tonic-gate * Instruction prefixes. 1600Sstevel@tonic-gate */ 1610Sstevel@tonic-gate #define FASTTRAP_PREFIX_OPERAND 0x66 1620Sstevel@tonic-gate #define FASTTRAP_PREFIX_ADDRESS 0x67 1630Sstevel@tonic-gate #define FASTTRAP_PREFIX_CS 0x2E 1640Sstevel@tonic-gate #define FASTTRAP_PREFIX_DS 0x3E 1650Sstevel@tonic-gate #define FASTTRAP_PREFIX_ES 0x26 1660Sstevel@tonic-gate #define FASTTRAP_PREFIX_FS 0x64 1670Sstevel@tonic-gate #define FASTTRAP_PREFIX_GS 0x65 1680Sstevel@tonic-gate #define FASTTRAP_PREFIX_SS 0x36 1690Sstevel@tonic-gate #define FASTTRAP_PREFIX_LOCK 0xF0 1700Sstevel@tonic-gate #define FASTTRAP_PREFIX_REP 0xF3 1710Sstevel@tonic-gate #define FASTTRAP_PREFIX_REPNE 0xF2 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate #define FASTTRAP_NOREG 0xff 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate /* 1760Sstevel@tonic-gate * Map between instruction register encodings and the kernel constants which 1770Sstevel@tonic-gate * correspond to indicies into struct regs. 1780Sstevel@tonic-gate */ 1790Sstevel@tonic-gate #ifdef __amd64 1800Sstevel@tonic-gate static const uint8_t regmap[16] = { 1810Sstevel@tonic-gate REG_RAX, REG_RCX, REG_RDX, REG_RBX, REG_RSP, REG_RBP, REG_RSI, REG_RDI, 1820Sstevel@tonic-gate REG_R8, REG_R9, REG_R10, REG_R11, REG_R12, REG_R13, REG_R14, REG_R15, 1830Sstevel@tonic-gate }; 1840Sstevel@tonic-gate #else 1850Sstevel@tonic-gate static const uint8_t regmap[8] = { 1860Sstevel@tonic-gate EAX, ECX, EDX, EBX, UESP, EBP, ESI, EDI 1870Sstevel@tonic-gate }; 1880Sstevel@tonic-gate #endif 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate static ulong_t fasttrap_getreg(struct regs *, uint_t); 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate static uint64_t 1930Sstevel@tonic-gate fasttrap_anarg(struct regs *rp, int function_entry, int argno) 1940Sstevel@tonic-gate { 1950Sstevel@tonic-gate uint64_t value; 1960Sstevel@tonic-gate int shift = function_entry ? 1 : 0; 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate #ifdef __amd64 1990Sstevel@tonic-gate if (curproc->p_model == DATAMODEL_LP64) { 2000Sstevel@tonic-gate uintptr_t *stack; 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate /* 2030Sstevel@tonic-gate * In 64-bit mode, the first six arguments are stored in 2040Sstevel@tonic-gate * registers. 2050Sstevel@tonic-gate */ 2060Sstevel@tonic-gate if (argno < 6) 2070Sstevel@tonic-gate return ((&rp->r_rdi)[argno]); 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate stack = (uintptr_t *)rp->r_sp; 2100Sstevel@tonic-gate DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); 2110Sstevel@tonic-gate value = dtrace_fulword(&stack[argno - 6 + shift]); 2120Sstevel@tonic-gate DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR); 2130Sstevel@tonic-gate } else { 2140Sstevel@tonic-gate #endif 2150Sstevel@tonic-gate uint32_t *stack = (uint32_t *)rp->r_sp; 2160Sstevel@tonic-gate DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); 2170Sstevel@tonic-gate value = dtrace_fuword32(&stack[argno + shift]); 2180Sstevel@tonic-gate DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR); 2190Sstevel@tonic-gate #ifdef __amd64 2200Sstevel@tonic-gate } 2210Sstevel@tonic-gate #endif 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate return (value); 2240Sstevel@tonic-gate } 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate /*ARGSUSED*/ 2270Sstevel@tonic-gate int 2281710Sahl fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, uintptr_t pc, 2291710Sahl fasttrap_probe_type_t type) 2300Sstevel@tonic-gate { 2310Sstevel@tonic-gate uint8_t instr[FASTTRAP_MAX_INSTR_SIZE + 10]; 2320Sstevel@tonic-gate size_t len = FASTTRAP_MAX_INSTR_SIZE; 2330Sstevel@tonic-gate size_t first = MIN(len, PAGESIZE - (pc & PAGEOFFSET)); 2340Sstevel@tonic-gate uint_t start = 0; 235*2769Sahl int rmindex, size; 2362712Snn35248 uint8_t seg, rex = 0; 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate /* 2390Sstevel@tonic-gate * Read the instruction at the given address out of the process's 2400Sstevel@tonic-gate * address space. We don't have to worry about a debugger 2410Sstevel@tonic-gate * changing this instruction before we overwrite it with our trap 2420Sstevel@tonic-gate * instruction since P_PR_LOCK is set. Since instructions can span 2430Sstevel@tonic-gate * pages, we potentially read the instruction in two parts. If the 2440Sstevel@tonic-gate * second part fails, we just zero out that part of the instruction. 2450Sstevel@tonic-gate */ 2460Sstevel@tonic-gate if (uread(p, &instr[0], first, pc) != 0) 2470Sstevel@tonic-gate return (-1); 2480Sstevel@tonic-gate if (len > first && 2490Sstevel@tonic-gate uread(p, &instr[first], len - first, pc + first) != 0) { 2500Sstevel@tonic-gate bzero(&instr[first], len - first); 2510Sstevel@tonic-gate len = first; 2520Sstevel@tonic-gate } 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate /* 2550Sstevel@tonic-gate * If the disassembly fails, then we have a malformed instruction. 2560Sstevel@tonic-gate */ 257*2769Sahl if ((size = dtrace_instr_size_isa(instr, p->p_model, &rmindex)) <= 0) 2580Sstevel@tonic-gate return (-1); 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate /* 2610Sstevel@tonic-gate * Make sure the disassembler isn't completely broken. 2620Sstevel@tonic-gate */ 263*2769Sahl ASSERT(-1 <= rmindex && rmindex < size); 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate /* 2660Sstevel@tonic-gate * If the computed size is greater than the number of bytes read, 2670Sstevel@tonic-gate * then it was a malformed instruction possibly because it fell on a 2680Sstevel@tonic-gate * page boundary and the subsequent page was missing or because of 2690Sstevel@tonic-gate * some malicious user. 2700Sstevel@tonic-gate */ 271*2769Sahl if (size > len) 2720Sstevel@tonic-gate return (-1); 2730Sstevel@tonic-gate 274*2769Sahl tp->ftt_size = (uint8_t)size; 2752712Snn35248 tp->ftt_segment = FASTTRAP_SEG_NONE; 2762712Snn35248 2770Sstevel@tonic-gate /* 2780Sstevel@tonic-gate * Find the start of the instruction's opcode by processing any 2790Sstevel@tonic-gate * legacy prefixes. 2800Sstevel@tonic-gate */ 2810Sstevel@tonic-gate for (;;) { 2822712Snn35248 seg = 0; 2830Sstevel@tonic-gate switch (instr[start]) { 2842712Snn35248 case FASTTRAP_PREFIX_SS: 2852712Snn35248 seg++; 2862712Snn35248 /*FALLTHRU*/ 2872712Snn35248 case FASTTRAP_PREFIX_GS: 2882712Snn35248 seg++; 2892712Snn35248 /*FALLTHRU*/ 2902712Snn35248 case FASTTRAP_PREFIX_FS: 2912712Snn35248 seg++; 2922712Snn35248 /*FALLTHRU*/ 2932712Snn35248 case FASTTRAP_PREFIX_ES: 2942712Snn35248 seg++; 2952712Snn35248 /*FALLTHRU*/ 2962712Snn35248 case FASTTRAP_PREFIX_DS: 2972712Snn35248 seg++; 2982712Snn35248 /*FALLTHRU*/ 2992712Snn35248 case FASTTRAP_PREFIX_CS: 3002712Snn35248 seg++; 3012712Snn35248 /*FALLTHRU*/ 3020Sstevel@tonic-gate case FASTTRAP_PREFIX_OPERAND: 3030Sstevel@tonic-gate case FASTTRAP_PREFIX_ADDRESS: 3040Sstevel@tonic-gate case FASTTRAP_PREFIX_LOCK: 3050Sstevel@tonic-gate case FASTTRAP_PREFIX_REP: 3060Sstevel@tonic-gate case FASTTRAP_PREFIX_REPNE: 3072712Snn35248 if (seg != 0) { 3082712Snn35248 /* 3092712Snn35248 * It's illegal for an instruction to specify 3102712Snn35248 * two segment prefixes -- give up on this 3112712Snn35248 * illegal instruction. 3122712Snn35248 */ 3132712Snn35248 if (tp->ftt_segment != FASTTRAP_SEG_NONE) 3142712Snn35248 return (-1); 3152712Snn35248 3162712Snn35248 tp->ftt_segment = seg; 3172712Snn35248 } 3180Sstevel@tonic-gate start++; 3190Sstevel@tonic-gate continue; 3200Sstevel@tonic-gate } 3210Sstevel@tonic-gate break; 3220Sstevel@tonic-gate } 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate #ifdef __amd64 3250Sstevel@tonic-gate /* 3260Sstevel@tonic-gate * Identify the REX prefix on 64-bit processes. 3270Sstevel@tonic-gate */ 3280Sstevel@tonic-gate if (p->p_model == DATAMODEL_LP64 && (instr[start] & 0xf0) == 0x40) 3290Sstevel@tonic-gate rex = instr[start++]; 3300Sstevel@tonic-gate #endif 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate /* 3330Sstevel@tonic-gate * Now that we're pretty sure that the instruction is okay, copy the 3340Sstevel@tonic-gate * valid part to the tracepoint. 3350Sstevel@tonic-gate */ 3360Sstevel@tonic-gate bcopy(instr, tp->ftt_instr, FASTTRAP_MAX_INSTR_SIZE); 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate tp->ftt_type = FASTTRAP_T_COMMON; 3390Sstevel@tonic-gate if (instr[start] == FASTTRAP_2_BYTE_OP) { 3400Sstevel@tonic-gate switch (instr[start + 1]) { 3410Sstevel@tonic-gate case FASTTRAP_0F_JO: 3420Sstevel@tonic-gate case FASTTRAP_0F_JNO: 3430Sstevel@tonic-gate case FASTTRAP_0F_JB: 3440Sstevel@tonic-gate case FASTTRAP_0F_JAE: 3450Sstevel@tonic-gate case FASTTRAP_0F_JE: 3460Sstevel@tonic-gate case FASTTRAP_0F_JNE: 3470Sstevel@tonic-gate case FASTTRAP_0F_JBE: 3480Sstevel@tonic-gate case FASTTRAP_0F_JA: 3490Sstevel@tonic-gate case FASTTRAP_0F_JS: 3500Sstevel@tonic-gate case FASTTRAP_0F_JNS: 3510Sstevel@tonic-gate case FASTTRAP_0F_JP: 3520Sstevel@tonic-gate case FASTTRAP_0F_JNP: 3530Sstevel@tonic-gate case FASTTRAP_0F_JL: 3540Sstevel@tonic-gate case FASTTRAP_0F_JGE: 3550Sstevel@tonic-gate case FASTTRAP_0F_JLE: 3560Sstevel@tonic-gate case FASTTRAP_0F_JG: 3570Sstevel@tonic-gate tp->ftt_type = FASTTRAP_T_JCC; 3580Sstevel@tonic-gate tp->ftt_code = (instr[start + 1] & 0x0f) | FASTTRAP_JO; 3590Sstevel@tonic-gate tp->ftt_dest = pc + tp->ftt_size + 3600Sstevel@tonic-gate *(int32_t *)&instr[start + 2]; 3610Sstevel@tonic-gate break; 3620Sstevel@tonic-gate } 3630Sstevel@tonic-gate } else if (instr[start] == FASTTRAP_GROUP5_OP) { 3640Sstevel@tonic-gate uint_t mod = FASTTRAP_MODRM_MOD(instr[start + 1]); 3650Sstevel@tonic-gate uint_t reg = FASTTRAP_MODRM_REG(instr[start + 1]); 3660Sstevel@tonic-gate uint_t rm = FASTTRAP_MODRM_RM(instr[start + 1]); 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate if (reg == 2 || reg == 4) { 3690Sstevel@tonic-gate uint_t i, sz; 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate if (reg == 2) 3720Sstevel@tonic-gate tp->ftt_type = FASTTRAP_T_CALL; 3730Sstevel@tonic-gate else 3740Sstevel@tonic-gate tp->ftt_type = FASTTRAP_T_JMP; 3750Sstevel@tonic-gate 3760Sstevel@tonic-gate if (mod == 3) 3770Sstevel@tonic-gate tp->ftt_code = 2; 3780Sstevel@tonic-gate else 3790Sstevel@tonic-gate tp->ftt_code = 1; 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate ASSERT(p->p_model == DATAMODEL_LP64 || rex == 0); 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate /* 3840Sstevel@tonic-gate * See AMD x86-64 Architecture Programmer's Manual 3850Sstevel@tonic-gate * Volume 3, Section 1.2.7, Table 1-12, and 3860Sstevel@tonic-gate * Appendix A.3.1, Table A-15. 3870Sstevel@tonic-gate */ 3880Sstevel@tonic-gate if (mod != 3 && rm == 4) { 3890Sstevel@tonic-gate uint8_t sib = instr[start + 2]; 3900Sstevel@tonic-gate uint_t index = FASTTRAP_SIB_INDEX(sib); 3910Sstevel@tonic-gate uint_t base = FASTTRAP_SIB_BASE(sib); 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate tp->ftt_scale = FASTTRAP_SIB_SCALE(sib); 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate tp->ftt_index = (index == 4) ? 3960Sstevel@tonic-gate FASTTRAP_NOREG : 3970Sstevel@tonic-gate regmap[index | (FASTTRAP_REX_X(rex) << 3)]; 3980Sstevel@tonic-gate tp->ftt_base = (mod == 0 && base == 5) ? 3990Sstevel@tonic-gate FASTTRAP_NOREG : 4000Sstevel@tonic-gate regmap[base | (FASTTRAP_REX_B(rex) << 3)]; 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate i = 3; 4030Sstevel@tonic-gate sz = mod == 1 ? 1 : 4; 4040Sstevel@tonic-gate } else { 4050Sstevel@tonic-gate /* 4060Sstevel@tonic-gate * In 64-bit mode, mod == 0 and r/m == 5 4070Sstevel@tonic-gate * denotes %rip-relative addressing; in 32-bit 4080Sstevel@tonic-gate * mode, the base register isn't used. In both 4090Sstevel@tonic-gate * modes, there is a 32-bit operand. 4100Sstevel@tonic-gate */ 4110Sstevel@tonic-gate if (mod == 0 && rm == 5) { 4120Sstevel@tonic-gate #ifdef __amd64 4130Sstevel@tonic-gate if (p->p_model == DATAMODEL_LP64) 4140Sstevel@tonic-gate tp->ftt_base = REG_RIP; 4150Sstevel@tonic-gate else 4160Sstevel@tonic-gate #endif 4170Sstevel@tonic-gate tp->ftt_base = FASTTRAP_NOREG; 4180Sstevel@tonic-gate sz = 4; 4190Sstevel@tonic-gate } else { 4200Sstevel@tonic-gate uint8_t base = rm | 4210Sstevel@tonic-gate (FASTTRAP_REX_B(rex) << 3); 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate tp->ftt_base = regmap[base]; 4240Sstevel@tonic-gate sz = mod == 1 ? 1 : mod == 2 ? 4 : 0; 4250Sstevel@tonic-gate } 4260Sstevel@tonic-gate tp->ftt_index = FASTTRAP_NOREG; 4270Sstevel@tonic-gate i = 2; 4280Sstevel@tonic-gate } 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate if (sz == 1) 4310Sstevel@tonic-gate tp->ftt_dest = *(int8_t *)&instr[start + i]; 4320Sstevel@tonic-gate else if (sz == 4) 4330Sstevel@tonic-gate tp->ftt_dest = *(int32_t *)&instr[start + i]; 4340Sstevel@tonic-gate else 4350Sstevel@tonic-gate tp->ftt_dest = 0; 4360Sstevel@tonic-gate } 4370Sstevel@tonic-gate } else { 4380Sstevel@tonic-gate switch (instr[start]) { 4390Sstevel@tonic-gate case FASTTRAP_RET: 4400Sstevel@tonic-gate tp->ftt_type = FASTTRAP_T_RET; 4410Sstevel@tonic-gate break; 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate case FASTTRAP_RET16: 4440Sstevel@tonic-gate tp->ftt_type = FASTTRAP_T_RET16; 4450Sstevel@tonic-gate tp->ftt_dest = *(uint16_t *)&instr[start + 1]; 4460Sstevel@tonic-gate break; 4470Sstevel@tonic-gate 4480Sstevel@tonic-gate case FASTTRAP_JO: 4490Sstevel@tonic-gate case FASTTRAP_JNO: 4500Sstevel@tonic-gate case FASTTRAP_JB: 4510Sstevel@tonic-gate case FASTTRAP_JAE: 4520Sstevel@tonic-gate case FASTTRAP_JE: 4530Sstevel@tonic-gate case FASTTRAP_JNE: 4540Sstevel@tonic-gate case FASTTRAP_JBE: 4550Sstevel@tonic-gate case FASTTRAP_JA: 4560Sstevel@tonic-gate case FASTTRAP_JS: 4570Sstevel@tonic-gate case FASTTRAP_JNS: 4580Sstevel@tonic-gate case FASTTRAP_JP: 4590Sstevel@tonic-gate case FASTTRAP_JNP: 4600Sstevel@tonic-gate case FASTTRAP_JL: 4610Sstevel@tonic-gate case FASTTRAP_JGE: 4620Sstevel@tonic-gate case FASTTRAP_JLE: 4630Sstevel@tonic-gate case FASTTRAP_JG: 4640Sstevel@tonic-gate tp->ftt_type = FASTTRAP_T_JCC; 4650Sstevel@tonic-gate tp->ftt_code = instr[start]; 4660Sstevel@tonic-gate tp->ftt_dest = pc + tp->ftt_size + 4670Sstevel@tonic-gate (int8_t)instr[start + 1]; 4680Sstevel@tonic-gate break; 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate case FASTTRAP_LOOPNZ: 4710Sstevel@tonic-gate case FASTTRAP_LOOPZ: 4720Sstevel@tonic-gate case FASTTRAP_LOOP: 4730Sstevel@tonic-gate tp->ftt_type = FASTTRAP_T_LOOP; 4740Sstevel@tonic-gate tp->ftt_code = instr[start]; 4750Sstevel@tonic-gate tp->ftt_dest = pc + tp->ftt_size + 4760Sstevel@tonic-gate (int8_t)instr[start + 1]; 4770Sstevel@tonic-gate break; 4780Sstevel@tonic-gate 4790Sstevel@tonic-gate case FASTTRAP_JCXZ: 4800Sstevel@tonic-gate tp->ftt_type = FASTTRAP_T_JCXZ; 4810Sstevel@tonic-gate tp->ftt_dest = pc + tp->ftt_size + 4820Sstevel@tonic-gate (int8_t)instr[start + 1]; 4830Sstevel@tonic-gate break; 4840Sstevel@tonic-gate 4850Sstevel@tonic-gate case FASTTRAP_CALL: 4860Sstevel@tonic-gate tp->ftt_type = FASTTRAP_T_CALL; 4870Sstevel@tonic-gate tp->ftt_dest = pc + tp->ftt_size + 4880Sstevel@tonic-gate *(int32_t *)&instr[start + 1]; 4890Sstevel@tonic-gate tp->ftt_code = 0; 4900Sstevel@tonic-gate break; 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate case FASTTRAP_JMP32: 4930Sstevel@tonic-gate tp->ftt_type = FASTTRAP_T_JMP; 4940Sstevel@tonic-gate tp->ftt_dest = pc + tp->ftt_size + 4950Sstevel@tonic-gate *(int32_t *)&instr[start + 1]; 4960Sstevel@tonic-gate break; 4970Sstevel@tonic-gate case FASTTRAP_JMP8: 4980Sstevel@tonic-gate tp->ftt_type = FASTTRAP_T_JMP; 4990Sstevel@tonic-gate tp->ftt_dest = pc + tp->ftt_size + 5000Sstevel@tonic-gate (int8_t)instr[start + 1]; 5010Sstevel@tonic-gate break; 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate case FASTTRAP_PUSHL_EBP: 5040Sstevel@tonic-gate if (start == 0) 5050Sstevel@tonic-gate tp->ftt_type = FASTTRAP_T_PUSHL_EBP; 5060Sstevel@tonic-gate break; 5070Sstevel@tonic-gate 508*2769Sahl case FASTTRAP_NOP: 509*2769Sahl #ifdef __amd64 510*2769Sahl ASSERT(p->p_model == DATAMODEL_LP64 || rex == 0); 511*2769Sahl 512*2769Sahl /* 513*2769Sahl * On amd64 we have to be careful not to confuse a nop 514*2769Sahl * (actually xchgl %eax, %eax) with an instruction using 515*2769Sahl * the same opcode, but that does something different 516*2769Sahl * (e.g. xchgl %r8d, %eax or xcghq %r8, %rax). 517*2769Sahl */ 518*2769Sahl if (FASTTRAP_REX_B(rex) == 0) 519*2769Sahl #endif 520*2769Sahl tp->ftt_type = FASTTRAP_T_NOP; 521*2769Sahl break; 522*2769Sahl 5230Sstevel@tonic-gate case FASTTRAP_INT3: 5240Sstevel@tonic-gate /* 5250Sstevel@tonic-gate * The pid provider shares the int3 trap with debugger 5260Sstevel@tonic-gate * breakpoints so we can't instrument them. 5270Sstevel@tonic-gate */ 5280Sstevel@tonic-gate ASSERT(instr[start] == FASTTRAP_INSTR); 5290Sstevel@tonic-gate return (-1); 5302712Snn35248 5312712Snn35248 case FASTTRAP_INT: 5322712Snn35248 /* 5332712Snn35248 * Interrupts seem like they could be traced with 5342712Snn35248 * no negative implications, but it's possible that 5352712Snn35248 * a thread could be redirected by the trap handling 5362712Snn35248 * code which would eventually return to the 5372712Snn35248 * instruction after the interrupt. If the interrupt 5382712Snn35248 * were in our scratch space, the subsequent 5392712Snn35248 * instruction might be overwritten before we return. 5402712Snn35248 * Accordingly we refuse to instrument any interrupt. 5412712Snn35248 */ 5422712Snn35248 return (-1); 5430Sstevel@tonic-gate } 5440Sstevel@tonic-gate } 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate #ifdef __amd64 5470Sstevel@tonic-gate if (p->p_model == DATAMODEL_LP64 && tp->ftt_type == FASTTRAP_T_COMMON) { 5480Sstevel@tonic-gate /* 5490Sstevel@tonic-gate * If the process is 64-bit and the instruction type is still 5500Sstevel@tonic-gate * FASTTRAP_T_COMMON -- meaning we're going to copy it out an 5510Sstevel@tonic-gate * execute it -- we need to watch for %rip-relative 5520Sstevel@tonic-gate * addressing mode. See the portion of fasttrap_pid_probe() 5530Sstevel@tonic-gate * below where we handle tracepoints with type 5540Sstevel@tonic-gate * FASTTRAP_T_COMMON for how we emulate instructions that 5550Sstevel@tonic-gate * employ %rip-relative addressing. 5560Sstevel@tonic-gate */ 5570Sstevel@tonic-gate if (rmindex != -1) { 5580Sstevel@tonic-gate uint_t mod = FASTTRAP_MODRM_MOD(instr[rmindex]); 5590Sstevel@tonic-gate uint_t reg = FASTTRAP_MODRM_REG(instr[rmindex]); 5600Sstevel@tonic-gate uint_t rm = FASTTRAP_MODRM_RM(instr[rmindex]); 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate ASSERT(rmindex > start); 5630Sstevel@tonic-gate 5640Sstevel@tonic-gate if (mod == 0 && rm == 5) { 5650Sstevel@tonic-gate /* 5660Sstevel@tonic-gate * We need to be sure to avoid other 5670Sstevel@tonic-gate * registers used by this instruction. While 5680Sstevel@tonic-gate * the reg field may determine the op code 5690Sstevel@tonic-gate * rather than denoting a register, assuming 5700Sstevel@tonic-gate * that it denotes a register is always safe. 5710Sstevel@tonic-gate * We leave the REX field intact and use 5720Sstevel@tonic-gate * whatever value's there for simplicity. 5730Sstevel@tonic-gate */ 5740Sstevel@tonic-gate if (reg != 0) { 5750Sstevel@tonic-gate tp->ftt_ripmode = FASTTRAP_RIP_1 | 5760Sstevel@tonic-gate (FASTTRAP_RIP_X * 5770Sstevel@tonic-gate FASTTRAP_REX_B(rex)); 5780Sstevel@tonic-gate rm = 0; 5790Sstevel@tonic-gate } else { 5800Sstevel@tonic-gate tp->ftt_ripmode = FASTTRAP_RIP_2 | 5810Sstevel@tonic-gate (FASTTRAP_RIP_X * 5820Sstevel@tonic-gate FASTTRAP_REX_B(rex)); 5830Sstevel@tonic-gate rm = 1; 5840Sstevel@tonic-gate } 5850Sstevel@tonic-gate 5860Sstevel@tonic-gate tp->ftt_modrm = tp->ftt_instr[rmindex]; 5870Sstevel@tonic-gate tp->ftt_instr[rmindex] = 5880Sstevel@tonic-gate FASTTRAP_MODRM(2, reg, rm); 5890Sstevel@tonic-gate } 5900Sstevel@tonic-gate } 5910Sstevel@tonic-gate } 5920Sstevel@tonic-gate #endif 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate return (0); 5950Sstevel@tonic-gate } 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate int 5980Sstevel@tonic-gate fasttrap_tracepoint_install(proc_t *p, fasttrap_tracepoint_t *tp) 5990Sstevel@tonic-gate { 6000Sstevel@tonic-gate fasttrap_instr_t instr = FASTTRAP_INSTR; 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate if (uwrite(p, &instr, 1, tp->ftt_pc) != 0) 6030Sstevel@tonic-gate return (-1); 6040Sstevel@tonic-gate 6050Sstevel@tonic-gate return (0); 6060Sstevel@tonic-gate } 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate int 6090Sstevel@tonic-gate fasttrap_tracepoint_remove(proc_t *p, fasttrap_tracepoint_t *tp) 6100Sstevel@tonic-gate { 6110Sstevel@tonic-gate uint8_t instr; 6120Sstevel@tonic-gate 6130Sstevel@tonic-gate /* 6140Sstevel@tonic-gate * Distinguish between read or write failures and a changed 6150Sstevel@tonic-gate * instruction. 6160Sstevel@tonic-gate */ 6170Sstevel@tonic-gate if (uread(p, &instr, 1, tp->ftt_pc) != 0) 6180Sstevel@tonic-gate return (0); 6190Sstevel@tonic-gate if (instr != FASTTRAP_INSTR) 6200Sstevel@tonic-gate return (0); 6210Sstevel@tonic-gate if (uwrite(p, &tp->ftt_instr[0], 1, tp->ftt_pc) != 0) 6220Sstevel@tonic-gate return (-1); 6230Sstevel@tonic-gate 6240Sstevel@tonic-gate return (0); 6250Sstevel@tonic-gate } 6260Sstevel@tonic-gate 6270Sstevel@tonic-gate static uintptr_t 6280Sstevel@tonic-gate fasttrap_fulword_noerr(const void *uaddr) 6290Sstevel@tonic-gate { 6300Sstevel@tonic-gate uintptr_t ret; 6310Sstevel@tonic-gate 6320Sstevel@tonic-gate if (fasttrap_fulword(uaddr, &ret) == 0) 6330Sstevel@tonic-gate return (ret); 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate return (0); 6360Sstevel@tonic-gate } 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate static uint32_t 6390Sstevel@tonic-gate fasttrap_fuword32_noerr(const void *uaddr) 6400Sstevel@tonic-gate { 6410Sstevel@tonic-gate uint32_t ret; 6420Sstevel@tonic-gate 6430Sstevel@tonic-gate if (fasttrap_fuword32(uaddr, &ret) == 0) 6440Sstevel@tonic-gate return (ret); 6450Sstevel@tonic-gate 6460Sstevel@tonic-gate return (0); 6470Sstevel@tonic-gate } 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate static void 6500Sstevel@tonic-gate fasttrap_return_common(struct regs *rp, uintptr_t pc, pid_t pid, 6510Sstevel@tonic-gate uintptr_t new_pc) 6520Sstevel@tonic-gate { 6530Sstevel@tonic-gate fasttrap_tracepoint_t *tp; 6540Sstevel@tonic-gate fasttrap_bucket_t *bucket; 6550Sstevel@tonic-gate fasttrap_id_t *id; 6560Sstevel@tonic-gate kmutex_t *pid_mtx; 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate pid_mtx = &cpu_core[CPU->cpu_id].cpuc_pid_lock; 6590Sstevel@tonic-gate mutex_enter(pid_mtx); 6600Sstevel@tonic-gate bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)]; 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) { 6630Sstevel@tonic-gate if (pid == tp->ftt_pid && pc == tp->ftt_pc && 664532Sahl !tp->ftt_proc->ftpc_defunct) 6650Sstevel@tonic-gate break; 6660Sstevel@tonic-gate } 6670Sstevel@tonic-gate 6680Sstevel@tonic-gate /* 6690Sstevel@tonic-gate * Don't sweat it if we can't find the tracepoint again; unlike 6700Sstevel@tonic-gate * when we're in fasttrap_pid_probe(), finding the tracepoint here 6710Sstevel@tonic-gate * is not essential to the correct execution of the process. 6720Sstevel@tonic-gate */ 6730Sstevel@tonic-gate if (tp == NULL) { 6740Sstevel@tonic-gate mutex_exit(pid_mtx); 6750Sstevel@tonic-gate return; 6760Sstevel@tonic-gate } 6770Sstevel@tonic-gate 6780Sstevel@tonic-gate for (id = tp->ftt_retids; id != NULL; id = id->fti_next) { 6790Sstevel@tonic-gate /* 6800Sstevel@tonic-gate * If there's a branch that could act as a return site, we 6810Sstevel@tonic-gate * need to trace it, and check here if the program counter is 6820Sstevel@tonic-gate * external to the function. 6830Sstevel@tonic-gate */ 6840Sstevel@tonic-gate if (tp->ftt_type != FASTTRAP_T_RET && 6850Sstevel@tonic-gate tp->ftt_type != FASTTRAP_T_RET16 && 6860Sstevel@tonic-gate new_pc - id->fti_probe->ftp_faddr < 6870Sstevel@tonic-gate id->fti_probe->ftp_fsize) 6880Sstevel@tonic-gate continue; 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate dtrace_probe(id->fti_probe->ftp_id, 6910Sstevel@tonic-gate pc - id->fti_probe->ftp_faddr, 6920Sstevel@tonic-gate rp->r_r0, rp->r_r1, 0, 0); 6930Sstevel@tonic-gate } 6940Sstevel@tonic-gate 6950Sstevel@tonic-gate mutex_exit(pid_mtx); 6960Sstevel@tonic-gate } 6970Sstevel@tonic-gate 6980Sstevel@tonic-gate static void 6990Sstevel@tonic-gate fasttrap_sigsegv(proc_t *p, kthread_t *t, uintptr_t addr) 7000Sstevel@tonic-gate { 7010Sstevel@tonic-gate sigqueue_t *sqp = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP); 7020Sstevel@tonic-gate 7030Sstevel@tonic-gate sqp->sq_info.si_signo = SIGSEGV; 7040Sstevel@tonic-gate sqp->sq_info.si_code = SEGV_MAPERR; 7050Sstevel@tonic-gate sqp->sq_info.si_addr = (caddr_t)addr; 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate mutex_enter(&p->p_lock); 7080Sstevel@tonic-gate sigaddqa(p, t, sqp); 7090Sstevel@tonic-gate mutex_exit(&p->p_lock); 7100Sstevel@tonic-gate 7110Sstevel@tonic-gate if (t != NULL) 7120Sstevel@tonic-gate aston(t); 7130Sstevel@tonic-gate } 7140Sstevel@tonic-gate 7150Sstevel@tonic-gate #ifdef __amd64 7160Sstevel@tonic-gate static void 7170Sstevel@tonic-gate fasttrap_usdt_args64(fasttrap_probe_t *probe, struct regs *rp, int argc, 7180Sstevel@tonic-gate uintptr_t *argv) 7190Sstevel@tonic-gate { 7200Sstevel@tonic-gate int i, x, cap = MIN(argc, probe->ftp_nargs); 7210Sstevel@tonic-gate uintptr_t *stack = (uintptr_t *)rp->r_sp; 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate for (i = 0; i < cap; i++) { 7240Sstevel@tonic-gate x = probe->ftp_argmap[i]; 7250Sstevel@tonic-gate 7260Sstevel@tonic-gate if (x < 6) 7270Sstevel@tonic-gate argv[i] = (&rp->r_rdi)[x]; 7280Sstevel@tonic-gate else 7290Sstevel@tonic-gate argv[i] = fasttrap_fulword_noerr(&stack[x]); 7300Sstevel@tonic-gate } 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate for (; i < argc; i++) { 7330Sstevel@tonic-gate argv[i] = 0; 7340Sstevel@tonic-gate } 7350Sstevel@tonic-gate } 7360Sstevel@tonic-gate #endif 7370Sstevel@tonic-gate 7380Sstevel@tonic-gate static void 7390Sstevel@tonic-gate fasttrap_usdt_args32(fasttrap_probe_t *probe, struct regs *rp, int argc, 7400Sstevel@tonic-gate uint32_t *argv) 7410Sstevel@tonic-gate { 7420Sstevel@tonic-gate int i, x, cap = MIN(argc, probe->ftp_nargs); 7430Sstevel@tonic-gate uint32_t *stack = (uint32_t *)rp->r_sp; 7440Sstevel@tonic-gate 7450Sstevel@tonic-gate for (i = 0; i < cap; i++) { 7460Sstevel@tonic-gate x = probe->ftp_argmap[i]; 7470Sstevel@tonic-gate 7480Sstevel@tonic-gate argv[i] = fasttrap_fuword32_noerr(&stack[x]); 7490Sstevel@tonic-gate } 7500Sstevel@tonic-gate 7510Sstevel@tonic-gate for (; i < argc; i++) { 7520Sstevel@tonic-gate argv[i] = 0; 7530Sstevel@tonic-gate } 7540Sstevel@tonic-gate } 7550Sstevel@tonic-gate 7562712Snn35248 static int 7572712Snn35248 fasttrap_do_seg(fasttrap_tracepoint_t *tp, struct regs *rp, uintptr_t *addr) 7582712Snn35248 { 7592712Snn35248 proc_t *p = curproc; 7602712Snn35248 user_desc_t *desc; 7612712Snn35248 uint16_t sel, ndx, type; 7622712Snn35248 uintptr_t limit; 7632712Snn35248 7642712Snn35248 switch (tp->ftt_segment) { 7652712Snn35248 case FASTTRAP_SEG_CS: 7662712Snn35248 sel = rp->r_cs; 7672712Snn35248 break; 7682712Snn35248 case FASTTRAP_SEG_DS: 7692712Snn35248 sel = rp->r_ds; 7702712Snn35248 break; 7712712Snn35248 case FASTTRAP_SEG_ES: 7722712Snn35248 sel = rp->r_es; 7732712Snn35248 break; 7742712Snn35248 case FASTTRAP_SEG_FS: 7752712Snn35248 sel = rp->r_fs; 7762712Snn35248 break; 7772712Snn35248 case FASTTRAP_SEG_GS: 7782712Snn35248 sel = rp->r_gs; 7792712Snn35248 break; 7802712Snn35248 case FASTTRAP_SEG_SS: 7812712Snn35248 sel = rp->r_ss; 7822712Snn35248 break; 7832712Snn35248 } 7842712Snn35248 7852712Snn35248 /* 7862712Snn35248 * Make sure the given segment register specifies a user priority 7872712Snn35248 * selector rather than a kernel selector. 7882712Snn35248 */ 7892712Snn35248 if (!SELISUPL(sel)) 7902712Snn35248 return (-1); 7912712Snn35248 7922712Snn35248 ndx = SELTOIDX(sel); 7932712Snn35248 7942712Snn35248 /* 7952712Snn35248 * Check the bounds and grab the descriptor out of the specified 7962712Snn35248 * descriptor table. 7972712Snn35248 */ 7982712Snn35248 if (SELISLDT(sel)) { 7992712Snn35248 if (ndx > p->p_ldtlimit) 8002712Snn35248 return (-1); 8012712Snn35248 8022712Snn35248 desc = p->p_ldt + ndx; 8032712Snn35248 8042712Snn35248 } else { 8052712Snn35248 if (ndx >= NGDT) 8062712Snn35248 return (-1); 8072712Snn35248 8082712Snn35248 desc = cpu_get_gdt() + ndx; 8092712Snn35248 } 8102712Snn35248 8112712Snn35248 /* 8122712Snn35248 * The descriptor must have user privilege level and it must be 8132712Snn35248 * present in memory. 8142712Snn35248 */ 8152712Snn35248 if (desc->usd_dpl != SEL_UPL || desc->usd_p != 1) 8162712Snn35248 return (-1); 8172712Snn35248 8182712Snn35248 type = desc->usd_type; 8192712Snn35248 8202712Snn35248 /* 8212712Snn35248 * If the S bit in the type field is not set, this descriptor can 8222712Snn35248 * only be used in system context. 8232712Snn35248 */ 8242712Snn35248 if ((type & 0x10) != 0x10) 8252712Snn35248 return (-1); 8262712Snn35248 8272712Snn35248 limit = USEGD_GETLIMIT(desc) * (desc->usd_gran ? PAGESIZE : 1); 8282712Snn35248 8292712Snn35248 if (tp->ftt_segment == FASTTRAP_SEG_CS) { 8302712Snn35248 /* 8312712Snn35248 * The code/data bit and readable bit must both be set. 8322712Snn35248 */ 8332712Snn35248 if ((type & 0xa) != 0xa) 8342712Snn35248 return (-1); 8352712Snn35248 8362712Snn35248 if (*addr > limit) 8372712Snn35248 return (-1); 8382712Snn35248 } else { 8392712Snn35248 /* 8402712Snn35248 * The code/data bit must be clear. 8412712Snn35248 */ 8422712Snn35248 if ((type & 0x8) != 0) 8432712Snn35248 return (-1); 8442712Snn35248 8452712Snn35248 /* 8462712Snn35248 * If the expand-down bit is clear, we just check the limit as 8472712Snn35248 * it would naturally be applied. Otherwise, we need to check 8482712Snn35248 * that the address is the range [limit + 1 .. 0xffff] or 8492712Snn35248 * [limit + 1 ... 0xffffffff] depending on if the default 8502712Snn35248 * operand size bit is set. 8512712Snn35248 */ 8522712Snn35248 if ((type & 0x4) == 0) { 8532712Snn35248 if (*addr > limit) 8542712Snn35248 return (-1); 8552712Snn35248 } else if (desc->usd_def32) { 8562712Snn35248 if (*addr < limit + 1 || 0xffff < *addr) 8572712Snn35248 return (-1); 8582712Snn35248 } else { 8592712Snn35248 if (*addr < limit + 1 || 0xffffffff < *addr) 8602712Snn35248 return (-1); 8612712Snn35248 } 8622712Snn35248 } 8632712Snn35248 8642712Snn35248 *addr += USEGD_GETBASE(desc); 8652712Snn35248 8662712Snn35248 return (0); 8672712Snn35248 } 8682712Snn35248 8690Sstevel@tonic-gate int 8700Sstevel@tonic-gate fasttrap_pid_probe(struct regs *rp) 8710Sstevel@tonic-gate { 8720Sstevel@tonic-gate proc_t *p = curproc; 8730Sstevel@tonic-gate uintptr_t pc = rp->r_pc - 1, new_pc = 0; 8740Sstevel@tonic-gate fasttrap_bucket_t *bucket; 8750Sstevel@tonic-gate kmutex_t *pid_mtx; 8760Sstevel@tonic-gate fasttrap_tracepoint_t *tp, tp_local; 8770Sstevel@tonic-gate pid_t pid; 8780Sstevel@tonic-gate dtrace_icookie_t cookie; 8791710Sahl uint_t is_enabled = 0; 8800Sstevel@tonic-gate 8810Sstevel@tonic-gate /* 8820Sstevel@tonic-gate * It's possible that a user (in a veritable orgy of bad planning) 8830Sstevel@tonic-gate * could redirect this thread's flow of control before it reached the 8840Sstevel@tonic-gate * return probe fasttrap. In this case we need to kill the process 8850Sstevel@tonic-gate * since it's in a unrecoverable state. 8860Sstevel@tonic-gate */ 8870Sstevel@tonic-gate if (curthread->t_dtrace_step) { 8880Sstevel@tonic-gate ASSERT(curthread->t_dtrace_on); 8890Sstevel@tonic-gate fasttrap_sigtrap(p, curthread, pc); 8900Sstevel@tonic-gate return (0); 8910Sstevel@tonic-gate } 8920Sstevel@tonic-gate 8930Sstevel@tonic-gate /* 8940Sstevel@tonic-gate * Clear all user tracing flags. 8950Sstevel@tonic-gate */ 8960Sstevel@tonic-gate curthread->t_dtrace_ft = 0; 8970Sstevel@tonic-gate curthread->t_dtrace_pc = 0; 8980Sstevel@tonic-gate curthread->t_dtrace_npc = 0; 8990Sstevel@tonic-gate curthread->t_dtrace_scrpc = 0; 9000Sstevel@tonic-gate curthread->t_dtrace_astpc = 0; 9010Sstevel@tonic-gate #ifdef __amd64 9020Sstevel@tonic-gate curthread->t_dtrace_regv = 0; 9030Sstevel@tonic-gate #endif 9040Sstevel@tonic-gate 9050Sstevel@tonic-gate /* 9060Sstevel@tonic-gate * Treat a child created by a call to vfork(2) as if it were its 9070Sstevel@tonic-gate * parent. We know that there's only one thread of control in such a 9080Sstevel@tonic-gate * process: this one. 9090Sstevel@tonic-gate */ 9100Sstevel@tonic-gate while (p->p_flag & SVFORK) { 9110Sstevel@tonic-gate p = p->p_parent; 9120Sstevel@tonic-gate } 9130Sstevel@tonic-gate 9140Sstevel@tonic-gate pid = p->p_pid; 9150Sstevel@tonic-gate pid_mtx = &cpu_core[CPU->cpu_id].cpuc_pid_lock; 9160Sstevel@tonic-gate mutex_enter(pid_mtx); 9170Sstevel@tonic-gate bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)]; 9180Sstevel@tonic-gate 9190Sstevel@tonic-gate /* 9200Sstevel@tonic-gate * Lookup the tracepoint that the process just hit. 9210Sstevel@tonic-gate */ 9220Sstevel@tonic-gate for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) { 9230Sstevel@tonic-gate if (pid == tp->ftt_pid && pc == tp->ftt_pc && 924532Sahl !tp->ftt_proc->ftpc_defunct) 9250Sstevel@tonic-gate break; 9260Sstevel@tonic-gate } 9270Sstevel@tonic-gate 9280Sstevel@tonic-gate /* 9290Sstevel@tonic-gate * If we couldn't find a matching tracepoint, either a tracepoint has 9300Sstevel@tonic-gate * been inserted without using the pid<pid> ioctl interface (see 9310Sstevel@tonic-gate * fasttrap_ioctl), or somehow we have mislaid this tracepoint. 9320Sstevel@tonic-gate */ 9330Sstevel@tonic-gate if (tp == NULL) { 9340Sstevel@tonic-gate mutex_exit(pid_mtx); 9350Sstevel@tonic-gate return (-1); 9360Sstevel@tonic-gate } 9370Sstevel@tonic-gate 9380Sstevel@tonic-gate /* 9390Sstevel@tonic-gate * Set the program counter to the address of the traced instruction 9400Sstevel@tonic-gate * so that it looks right in ustack() output. 9410Sstevel@tonic-gate */ 9420Sstevel@tonic-gate rp->r_pc = pc; 9430Sstevel@tonic-gate 9440Sstevel@tonic-gate if (tp->ftt_ids != NULL) { 9450Sstevel@tonic-gate fasttrap_id_t *id; 9460Sstevel@tonic-gate 9470Sstevel@tonic-gate #ifdef __amd64 9480Sstevel@tonic-gate if (p->p_model == DATAMODEL_LP64) { 9490Sstevel@tonic-gate for (id = tp->ftt_ids; id != NULL; id = id->fti_next) { 9500Sstevel@tonic-gate fasttrap_probe_t *probe = id->fti_probe; 9510Sstevel@tonic-gate 9521710Sahl if (id->fti_ptype == DTFTP_ENTRY) { 9530Sstevel@tonic-gate /* 9540Sstevel@tonic-gate * We note that this was an entry 9550Sstevel@tonic-gate * probe to help ustack() find the 9560Sstevel@tonic-gate * first caller. 9570Sstevel@tonic-gate */ 9580Sstevel@tonic-gate cookie = dtrace_interrupt_disable(); 9590Sstevel@tonic-gate DTRACE_CPUFLAG_SET(CPU_DTRACE_ENTRY); 9600Sstevel@tonic-gate dtrace_probe(probe->ftp_id, rp->r_rdi, 9610Sstevel@tonic-gate rp->r_rsi, rp->r_rdx, rp->r_rcx, 9620Sstevel@tonic-gate rp->r_r8); 9630Sstevel@tonic-gate DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_ENTRY); 9640Sstevel@tonic-gate dtrace_interrupt_enable(cookie); 9651710Sahl } else if (id->fti_ptype == DTFTP_IS_ENABLED) { 9661710Sahl /* 9671710Sahl * Note that in this case, we don't 9681710Sahl * call dtrace_probe() since it's only 9691710Sahl * an artificial probe meant to change 9701710Sahl * the flow of control so that it 9711710Sahl * encounters the true probe. 9721710Sahl */ 9731710Sahl is_enabled = 1; 9740Sstevel@tonic-gate } else if (probe->ftp_argmap == NULL) { 9750Sstevel@tonic-gate dtrace_probe(probe->ftp_id, rp->r_rdi, 9760Sstevel@tonic-gate rp->r_rsi, rp->r_rdx, rp->r_rcx, 9770Sstevel@tonic-gate rp->r_r8); 9780Sstevel@tonic-gate } else { 9790Sstevel@tonic-gate uintptr_t t[5]; 9800Sstevel@tonic-gate 9810Sstevel@tonic-gate fasttrap_usdt_args64(probe, rp, 9820Sstevel@tonic-gate sizeof (t) / sizeof (t[0]), t); 9830Sstevel@tonic-gate 9840Sstevel@tonic-gate dtrace_probe(probe->ftp_id, t[0], t[1], 9850Sstevel@tonic-gate t[2], t[3], t[4]); 9860Sstevel@tonic-gate } 9870Sstevel@tonic-gate } 9880Sstevel@tonic-gate } else { 9890Sstevel@tonic-gate #endif 9900Sstevel@tonic-gate uintptr_t s0, s1, s2, s3, s4, s5; 9910Sstevel@tonic-gate uint32_t *stack = (uint32_t *)rp->r_sp; 9920Sstevel@tonic-gate 9930Sstevel@tonic-gate /* 9940Sstevel@tonic-gate * In 32-bit mode, all arguments are passed on the 9950Sstevel@tonic-gate * stack. If this is a function entry probe, we need 9960Sstevel@tonic-gate * to skip the first entry on the stack as it 9970Sstevel@tonic-gate * represents the return address rather than a 9980Sstevel@tonic-gate * parameter to the function. 9990Sstevel@tonic-gate */ 10000Sstevel@tonic-gate s0 = fasttrap_fuword32_noerr(&stack[0]); 10010Sstevel@tonic-gate s1 = fasttrap_fuword32_noerr(&stack[1]); 10020Sstevel@tonic-gate s2 = fasttrap_fuword32_noerr(&stack[2]); 10030Sstevel@tonic-gate s3 = fasttrap_fuword32_noerr(&stack[3]); 10040Sstevel@tonic-gate s4 = fasttrap_fuword32_noerr(&stack[4]); 10050Sstevel@tonic-gate s5 = fasttrap_fuword32_noerr(&stack[5]); 10060Sstevel@tonic-gate 10070Sstevel@tonic-gate for (id = tp->ftt_ids; id != NULL; id = id->fti_next) { 10080Sstevel@tonic-gate fasttrap_probe_t *probe = id->fti_probe; 10090Sstevel@tonic-gate 10101710Sahl if (id->fti_ptype == DTFTP_ENTRY) { 10110Sstevel@tonic-gate /* 10120Sstevel@tonic-gate * We note that this was an entry 10130Sstevel@tonic-gate * probe to help ustack() find the 10140Sstevel@tonic-gate * first caller. 10150Sstevel@tonic-gate */ 10160Sstevel@tonic-gate cookie = dtrace_interrupt_disable(); 10170Sstevel@tonic-gate DTRACE_CPUFLAG_SET(CPU_DTRACE_ENTRY); 10180Sstevel@tonic-gate dtrace_probe(probe->ftp_id, s1, s2, 10190Sstevel@tonic-gate s3, s4, s5); 10200Sstevel@tonic-gate DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_ENTRY); 10210Sstevel@tonic-gate dtrace_interrupt_enable(cookie); 10221710Sahl } else if (id->fti_ptype == DTFTP_IS_ENABLED) { 10231710Sahl /* 10241710Sahl * Note that in this case, we don't 10251710Sahl * call dtrace_probe() since it's only 10261710Sahl * an artificial probe meant to change 10271710Sahl * the flow of control so that it 10281710Sahl * encounters the true probe. 10291710Sahl */ 10301710Sahl is_enabled = 1; 10310Sstevel@tonic-gate } else if (probe->ftp_argmap == NULL) { 10320Sstevel@tonic-gate dtrace_probe(probe->ftp_id, s0, s1, 10330Sstevel@tonic-gate s2, s3, s4); 10340Sstevel@tonic-gate } else { 10350Sstevel@tonic-gate uint32_t t[5]; 10360Sstevel@tonic-gate 10370Sstevel@tonic-gate fasttrap_usdt_args32(probe, rp, 10380Sstevel@tonic-gate sizeof (t) / sizeof (t[0]), t); 10390Sstevel@tonic-gate 10400Sstevel@tonic-gate dtrace_probe(probe->ftp_id, t[0], t[1], 10410Sstevel@tonic-gate t[2], t[3], t[4]); 10420Sstevel@tonic-gate } 10430Sstevel@tonic-gate } 10440Sstevel@tonic-gate #ifdef __amd64 10450Sstevel@tonic-gate } 10460Sstevel@tonic-gate #endif 10470Sstevel@tonic-gate } 10480Sstevel@tonic-gate 10490Sstevel@tonic-gate /* 10500Sstevel@tonic-gate * We're about to do a bunch of work so we cache a local copy of 10510Sstevel@tonic-gate * the tracepoint to emulate the instruction, and then find the 10520Sstevel@tonic-gate * tracepoint again later if we need to light up any return probes. 10530Sstevel@tonic-gate */ 10540Sstevel@tonic-gate tp_local = *tp; 10550Sstevel@tonic-gate mutex_exit(pid_mtx); 10560Sstevel@tonic-gate tp = &tp_local; 10570Sstevel@tonic-gate 10580Sstevel@tonic-gate /* 10590Sstevel@tonic-gate * Set the program counter to appear as though the traced instruction 10600Sstevel@tonic-gate * had completely executed. This ensures that fasttrap_getreg() will 10610Sstevel@tonic-gate * report the expected value for REG_RIP. 10620Sstevel@tonic-gate */ 10630Sstevel@tonic-gate rp->r_pc = pc + tp->ftt_size; 10640Sstevel@tonic-gate 10651710Sahl /* 10661710Sahl * If there's an is-enabled probe connected to this tracepoint it 10671710Sahl * means that there was a 'xorl %eax, %eax' or 'xorq %rax, %rax' 10681710Sahl * instruction that was placed there by DTrace when the binary was 10691710Sahl * linked. As this probe is, in fact, enabled, we need to stuff 1 10701710Sahl * into %eax or %rax. Accordingly, we can bypass all the instruction 10711710Sahl * emulation logic since we know the inevitable result. It's possible 10721710Sahl * that a user could construct a scenario where the 'is-enabled' 10731710Sahl * probe was on some other instruction, but that would be a rather 10741710Sahl * exotic way to shoot oneself in the foot. 10751710Sahl */ 10761710Sahl if (is_enabled) { 10771710Sahl rp->r_r0 = 1; 10781710Sahl new_pc = rp->r_pc; 10791710Sahl goto done; 10801710Sahl } 10811710Sahl 10821710Sahl /* 10831710Sahl * We emulate certain types of instructions to ensure correctness 10841710Sahl * (in the case of position dependent instructions) or optimize 10851710Sahl * common cases. The rest we have the thread execute back in user- 10861710Sahl * land. 10871710Sahl */ 10880Sstevel@tonic-gate switch (tp->ftt_type) { 10890Sstevel@tonic-gate case FASTTRAP_T_RET: 10900Sstevel@tonic-gate case FASTTRAP_T_RET16: 10910Sstevel@tonic-gate { 10920Sstevel@tonic-gate uintptr_t dst; 10930Sstevel@tonic-gate uintptr_t addr; 10940Sstevel@tonic-gate int ret; 10950Sstevel@tonic-gate 10960Sstevel@tonic-gate /* 10970Sstevel@tonic-gate * We have to emulate _every_ facet of the behavior of a ret 10980Sstevel@tonic-gate * instruction including what happens if the load from %esp 10990Sstevel@tonic-gate * fails; in that case, we send a SIGSEGV. 11000Sstevel@tonic-gate */ 11010Sstevel@tonic-gate #ifdef __amd64 11020Sstevel@tonic-gate if (p->p_model == DATAMODEL_NATIVE) { 11030Sstevel@tonic-gate #endif 11040Sstevel@tonic-gate ret = fasttrap_fulword((void *)rp->r_sp, &dst); 11050Sstevel@tonic-gate addr = rp->r_sp + sizeof (uintptr_t); 11060Sstevel@tonic-gate #ifdef __amd64 11070Sstevel@tonic-gate } else { 11080Sstevel@tonic-gate uint32_t dst32; 11090Sstevel@tonic-gate ret = fasttrap_fuword32((void *)rp->r_sp, &dst32); 11100Sstevel@tonic-gate dst = dst32; 11110Sstevel@tonic-gate addr = rp->r_sp + sizeof (uint32_t); 11120Sstevel@tonic-gate } 11130Sstevel@tonic-gate #endif 11140Sstevel@tonic-gate 11150Sstevel@tonic-gate if (ret == -1) { 11160Sstevel@tonic-gate fasttrap_sigsegv(p, curthread, rp->r_sp); 11170Sstevel@tonic-gate new_pc = pc; 11180Sstevel@tonic-gate break; 11190Sstevel@tonic-gate } 11200Sstevel@tonic-gate 11210Sstevel@tonic-gate if (tp->ftt_type == FASTTRAP_T_RET16) 11220Sstevel@tonic-gate addr += tp->ftt_dest; 11230Sstevel@tonic-gate 11240Sstevel@tonic-gate rp->r_sp = addr; 11250Sstevel@tonic-gate new_pc = dst; 11260Sstevel@tonic-gate break; 11270Sstevel@tonic-gate } 11280Sstevel@tonic-gate 11290Sstevel@tonic-gate case FASTTRAP_T_JCC: 11300Sstevel@tonic-gate { 11310Sstevel@tonic-gate uint_t taken; 11320Sstevel@tonic-gate 11330Sstevel@tonic-gate switch (tp->ftt_code) { 11340Sstevel@tonic-gate case FASTTRAP_JO: 11350Sstevel@tonic-gate taken = (rp->r_ps & FASTTRAP_EFLAGS_OF) != 0; 11360Sstevel@tonic-gate break; 11370Sstevel@tonic-gate case FASTTRAP_JNO: 11380Sstevel@tonic-gate taken = (rp->r_ps & FASTTRAP_EFLAGS_OF) == 0; 11390Sstevel@tonic-gate break; 11400Sstevel@tonic-gate case FASTTRAP_JB: 11410Sstevel@tonic-gate taken = (rp->r_ps & FASTTRAP_EFLAGS_CF) != 0; 11420Sstevel@tonic-gate break; 11430Sstevel@tonic-gate case FASTTRAP_JAE: 11440Sstevel@tonic-gate taken = (rp->r_ps & FASTTRAP_EFLAGS_CF) == 0; 11450Sstevel@tonic-gate break; 11460Sstevel@tonic-gate case FASTTRAP_JE: 11470Sstevel@tonic-gate taken = (rp->r_ps & FASTTRAP_EFLAGS_ZF) != 0; 11480Sstevel@tonic-gate break; 11490Sstevel@tonic-gate case FASTTRAP_JNE: 11500Sstevel@tonic-gate taken = (rp->r_ps & FASTTRAP_EFLAGS_ZF) == 0; 11510Sstevel@tonic-gate break; 11520Sstevel@tonic-gate case FASTTRAP_JBE: 11530Sstevel@tonic-gate taken = (rp->r_ps & FASTTRAP_EFLAGS_CF) != 0 || 11540Sstevel@tonic-gate (rp->r_ps & FASTTRAP_EFLAGS_ZF) != 0; 11550Sstevel@tonic-gate break; 11560Sstevel@tonic-gate case FASTTRAP_JA: 11570Sstevel@tonic-gate taken = (rp->r_ps & FASTTRAP_EFLAGS_CF) == 0 && 11580Sstevel@tonic-gate (rp->r_ps & FASTTRAP_EFLAGS_ZF) == 0; 11590Sstevel@tonic-gate break; 11600Sstevel@tonic-gate case FASTTRAP_JS: 11610Sstevel@tonic-gate taken = (rp->r_ps & FASTTRAP_EFLAGS_SF) != 0; 11620Sstevel@tonic-gate break; 11630Sstevel@tonic-gate case FASTTRAP_JNS: 11640Sstevel@tonic-gate taken = (rp->r_ps & FASTTRAP_EFLAGS_SF) == 0; 11650Sstevel@tonic-gate break; 11660Sstevel@tonic-gate case FASTTRAP_JP: 11670Sstevel@tonic-gate taken = (rp->r_ps & FASTTRAP_EFLAGS_PF) != 0; 11680Sstevel@tonic-gate break; 11690Sstevel@tonic-gate case FASTTRAP_JNP: 11700Sstevel@tonic-gate taken = (rp->r_ps & FASTTRAP_EFLAGS_PF) == 0; 11710Sstevel@tonic-gate break; 11720Sstevel@tonic-gate case FASTTRAP_JL: 11730Sstevel@tonic-gate taken = ((rp->r_ps & FASTTRAP_EFLAGS_SF) == 0) != 11740Sstevel@tonic-gate ((rp->r_ps & FASTTRAP_EFLAGS_OF) == 0); 11750Sstevel@tonic-gate break; 11760Sstevel@tonic-gate case FASTTRAP_JGE: 11770Sstevel@tonic-gate taken = ((rp->r_ps & FASTTRAP_EFLAGS_SF) == 0) == 11780Sstevel@tonic-gate ((rp->r_ps & FASTTRAP_EFLAGS_OF) == 0); 11790Sstevel@tonic-gate break; 11800Sstevel@tonic-gate case FASTTRAP_JLE: 11810Sstevel@tonic-gate taken = (rp->r_ps & FASTTRAP_EFLAGS_ZF) != 0 || 11820Sstevel@tonic-gate ((rp->r_ps & FASTTRAP_EFLAGS_SF) == 0) != 11830Sstevel@tonic-gate ((rp->r_ps & FASTTRAP_EFLAGS_OF) == 0); 11840Sstevel@tonic-gate break; 11850Sstevel@tonic-gate case FASTTRAP_JG: 11860Sstevel@tonic-gate taken = (rp->r_ps & FASTTRAP_EFLAGS_ZF) == 0 && 11870Sstevel@tonic-gate ((rp->r_ps & FASTTRAP_EFLAGS_SF) == 0) == 11880Sstevel@tonic-gate ((rp->r_ps & FASTTRAP_EFLAGS_OF) == 0); 11890Sstevel@tonic-gate break; 11900Sstevel@tonic-gate 11910Sstevel@tonic-gate } 11920Sstevel@tonic-gate 11930Sstevel@tonic-gate if (taken) 11940Sstevel@tonic-gate new_pc = tp->ftt_dest; 11950Sstevel@tonic-gate else 11960Sstevel@tonic-gate new_pc = pc + tp->ftt_size; 11970Sstevel@tonic-gate break; 11980Sstevel@tonic-gate } 11990Sstevel@tonic-gate 12000Sstevel@tonic-gate case FASTTRAP_T_LOOP: 12010Sstevel@tonic-gate { 12020Sstevel@tonic-gate uint_t taken; 12030Sstevel@tonic-gate #ifdef __amd64 12040Sstevel@tonic-gate greg_t cx = rp->r_rcx--; 12050Sstevel@tonic-gate #else 12060Sstevel@tonic-gate greg_t cx = rp->r_ecx--; 12070Sstevel@tonic-gate #endif 12080Sstevel@tonic-gate 12090Sstevel@tonic-gate switch (tp->ftt_code) { 12100Sstevel@tonic-gate case FASTTRAP_LOOPNZ: 12110Sstevel@tonic-gate taken = (rp->r_ps & FASTTRAP_EFLAGS_ZF) == 0 && 12120Sstevel@tonic-gate cx != 0; 12130Sstevel@tonic-gate break; 12140Sstevel@tonic-gate case FASTTRAP_LOOPZ: 12150Sstevel@tonic-gate taken = (rp->r_ps & FASTTRAP_EFLAGS_ZF) != 0 && 12160Sstevel@tonic-gate cx != 0; 12170Sstevel@tonic-gate break; 12180Sstevel@tonic-gate case FASTTRAP_LOOP: 12190Sstevel@tonic-gate taken = (cx != 0); 12200Sstevel@tonic-gate break; 12210Sstevel@tonic-gate } 12220Sstevel@tonic-gate 12230Sstevel@tonic-gate if (taken) 12240Sstevel@tonic-gate new_pc = tp->ftt_dest; 12250Sstevel@tonic-gate else 12260Sstevel@tonic-gate new_pc = pc + tp->ftt_size; 12270Sstevel@tonic-gate break; 12280Sstevel@tonic-gate } 12290Sstevel@tonic-gate 12300Sstevel@tonic-gate case FASTTRAP_T_JCXZ: 12310Sstevel@tonic-gate { 12320Sstevel@tonic-gate #ifdef __amd64 12330Sstevel@tonic-gate greg_t cx = rp->r_rcx; 12340Sstevel@tonic-gate #else 12350Sstevel@tonic-gate greg_t cx = rp->r_ecx; 12360Sstevel@tonic-gate #endif 12370Sstevel@tonic-gate 12380Sstevel@tonic-gate if (cx == 0) 12390Sstevel@tonic-gate new_pc = tp->ftt_dest; 12400Sstevel@tonic-gate else 12410Sstevel@tonic-gate new_pc = pc + tp->ftt_size; 12420Sstevel@tonic-gate break; 12430Sstevel@tonic-gate } 12440Sstevel@tonic-gate 12450Sstevel@tonic-gate case FASTTRAP_T_PUSHL_EBP: 12460Sstevel@tonic-gate { 12470Sstevel@tonic-gate int ret; 12480Sstevel@tonic-gate uintptr_t addr; 12490Sstevel@tonic-gate #ifdef __amd64 12500Sstevel@tonic-gate if (p->p_model == DATAMODEL_NATIVE) { 12510Sstevel@tonic-gate #endif 12520Sstevel@tonic-gate addr = rp->r_sp - sizeof (uintptr_t); 12530Sstevel@tonic-gate ret = fasttrap_sulword((void *)addr, rp->r_fp); 12540Sstevel@tonic-gate #ifdef __amd64 12550Sstevel@tonic-gate } else { 12560Sstevel@tonic-gate addr = rp->r_sp - sizeof (uint32_t); 12570Sstevel@tonic-gate ret = fasttrap_suword32((void *)addr, 12580Sstevel@tonic-gate (uint32_t)rp->r_fp); 12590Sstevel@tonic-gate } 12600Sstevel@tonic-gate #endif 12610Sstevel@tonic-gate 12620Sstevel@tonic-gate if (ret == -1) { 12630Sstevel@tonic-gate fasttrap_sigsegv(p, curthread, addr); 12640Sstevel@tonic-gate new_pc = pc; 12650Sstevel@tonic-gate break; 12660Sstevel@tonic-gate } 12670Sstevel@tonic-gate 12680Sstevel@tonic-gate rp->r_sp = addr; 12690Sstevel@tonic-gate new_pc = pc + tp->ftt_size; 12700Sstevel@tonic-gate break; 12710Sstevel@tonic-gate } 12720Sstevel@tonic-gate 1273*2769Sahl case FASTTRAP_T_NOP: 1274*2769Sahl new_pc = pc + tp->ftt_size; 1275*2769Sahl break; 1276*2769Sahl 12770Sstevel@tonic-gate case FASTTRAP_T_JMP: 12780Sstevel@tonic-gate case FASTTRAP_T_CALL: 12790Sstevel@tonic-gate if (tp->ftt_code == 0) { 12800Sstevel@tonic-gate new_pc = tp->ftt_dest; 12810Sstevel@tonic-gate } else { 12822712Snn35248 uintptr_t value, addr = tp->ftt_dest; 12830Sstevel@tonic-gate 12840Sstevel@tonic-gate if (tp->ftt_base != FASTTRAP_NOREG) 12850Sstevel@tonic-gate addr += fasttrap_getreg(rp, tp->ftt_base); 12860Sstevel@tonic-gate if (tp->ftt_index != FASTTRAP_NOREG) 12870Sstevel@tonic-gate addr += fasttrap_getreg(rp, tp->ftt_index) << 12880Sstevel@tonic-gate tp->ftt_scale; 12890Sstevel@tonic-gate 12900Sstevel@tonic-gate if (tp->ftt_code == 1) { 12912712Snn35248 /* 12922712Snn35248 * If there's a segment prefix for this 12932712Snn35248 * instruction, we'll need to check permissions 12942712Snn35248 * and bounds on the given selector, and adjust 12952712Snn35248 * the address accordingly. 12962712Snn35248 */ 12972712Snn35248 if (tp->ftt_segment != FASTTRAP_SEG_NONE && 12982712Snn35248 fasttrap_do_seg(tp, rp, &addr) != 0) { 12992712Snn35248 fasttrap_sigsegv(p, curthread, addr); 13002712Snn35248 new_pc = pc; 13012712Snn35248 break; 13022712Snn35248 } 13032712Snn35248 13040Sstevel@tonic-gate #ifdef __amd64 13050Sstevel@tonic-gate if (p->p_model == DATAMODEL_NATIVE) { 13060Sstevel@tonic-gate #endif 13070Sstevel@tonic-gate if (fasttrap_fulword((void *)addr, 13080Sstevel@tonic-gate &value) == -1) { 13090Sstevel@tonic-gate fasttrap_sigsegv(p, curthread, 13100Sstevel@tonic-gate addr); 13110Sstevel@tonic-gate new_pc = pc; 13120Sstevel@tonic-gate break; 13130Sstevel@tonic-gate } 13140Sstevel@tonic-gate new_pc = value; 13150Sstevel@tonic-gate #ifdef __amd64 13160Sstevel@tonic-gate } else { 13172712Snn35248 uint32_t value32; 13182712Snn35248 addr = (uintptr_t)(uint32_t)addr; 13190Sstevel@tonic-gate if (fasttrap_fuword32((void *)addr, 13202712Snn35248 &value32) == -1) { 13210Sstevel@tonic-gate fasttrap_sigsegv(p, curthread, 13220Sstevel@tonic-gate addr); 13230Sstevel@tonic-gate new_pc = pc; 13240Sstevel@tonic-gate break; 13250Sstevel@tonic-gate } 13262712Snn35248 new_pc = value32; 13270Sstevel@tonic-gate } 13280Sstevel@tonic-gate #endif 13290Sstevel@tonic-gate } else { 13300Sstevel@tonic-gate new_pc = addr; 13310Sstevel@tonic-gate } 13320Sstevel@tonic-gate } 13330Sstevel@tonic-gate 13340Sstevel@tonic-gate /* 13350Sstevel@tonic-gate * If this is a call instruction, we need to push the return 13360Sstevel@tonic-gate * address onto the stack. If this fails, we send the process 13370Sstevel@tonic-gate * a SIGSEGV and reset the pc to emulate what would happen if 13380Sstevel@tonic-gate * this instruction weren't traced. 13390Sstevel@tonic-gate */ 13400Sstevel@tonic-gate if (tp->ftt_type == FASTTRAP_T_CALL) { 13410Sstevel@tonic-gate int ret; 13420Sstevel@tonic-gate uintptr_t addr; 13430Sstevel@tonic-gate #ifdef __amd64 13440Sstevel@tonic-gate if (p->p_model == DATAMODEL_NATIVE) { 13450Sstevel@tonic-gate addr = rp->r_sp - sizeof (uintptr_t); 13460Sstevel@tonic-gate ret = fasttrap_sulword((void *)addr, 13470Sstevel@tonic-gate pc + tp->ftt_size); 13480Sstevel@tonic-gate } else { 13490Sstevel@tonic-gate #endif 13500Sstevel@tonic-gate addr = rp->r_sp - sizeof (uint32_t); 13510Sstevel@tonic-gate ret = fasttrap_suword32((void *)addr, 13520Sstevel@tonic-gate (uint32_t)(pc + tp->ftt_size)); 13530Sstevel@tonic-gate #ifdef __amd64 13540Sstevel@tonic-gate } 13550Sstevel@tonic-gate #endif 13560Sstevel@tonic-gate 13570Sstevel@tonic-gate if (ret == -1) { 13580Sstevel@tonic-gate fasttrap_sigsegv(p, curthread, addr); 13590Sstevel@tonic-gate new_pc = pc; 13600Sstevel@tonic-gate break; 13610Sstevel@tonic-gate } 13620Sstevel@tonic-gate 13630Sstevel@tonic-gate rp->r_sp = addr; 13640Sstevel@tonic-gate } 13650Sstevel@tonic-gate 13660Sstevel@tonic-gate break; 13670Sstevel@tonic-gate 13680Sstevel@tonic-gate case FASTTRAP_T_COMMON: 13690Sstevel@tonic-gate { 13700Sstevel@tonic-gate uintptr_t addr; 13710Sstevel@tonic-gate uint8_t scratch[2 * FASTTRAP_MAX_INSTR_SIZE + 5 + 2]; 13720Sstevel@tonic-gate uint_t i = 0; 13730Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 13740Sstevel@tonic-gate 13750Sstevel@tonic-gate /* 13760Sstevel@tonic-gate * Compute the address of the ulwp_t and step over the 13770Sstevel@tonic-gate * ul_self pointer. The method used to store the user-land 13780Sstevel@tonic-gate * thread pointer is very different on 32- and 64-bit 13790Sstevel@tonic-gate * kernels. 13800Sstevel@tonic-gate */ 13810Sstevel@tonic-gate #if defined(__amd64) 13820Sstevel@tonic-gate if (p->p_model == DATAMODEL_LP64) { 13830Sstevel@tonic-gate addr = lwp->lwp_pcb.pcb_fsbase; 13840Sstevel@tonic-gate addr += sizeof (void *); 13850Sstevel@tonic-gate } else { 13860Sstevel@tonic-gate addr = lwp->lwp_pcb.pcb_gsbase; 13870Sstevel@tonic-gate addr += sizeof (caddr32_t); 13880Sstevel@tonic-gate } 13890Sstevel@tonic-gate #elif defined(__i386) 13900Sstevel@tonic-gate addr = USEGD_GETBASE(&lwp->lwp_pcb.pcb_gsdesc); 13910Sstevel@tonic-gate addr += sizeof (void *); 13920Sstevel@tonic-gate #endif 13930Sstevel@tonic-gate 13940Sstevel@tonic-gate /* 13950Sstevel@tonic-gate * Generic Instruction Tracing 13960Sstevel@tonic-gate * --------------------------- 13970Sstevel@tonic-gate * 13980Sstevel@tonic-gate * This is the layout of the scratch space in the user-land 13990Sstevel@tonic-gate * thread structure for our generated instructions. 14000Sstevel@tonic-gate * 14010Sstevel@tonic-gate * 32-bit mode bytes 14020Sstevel@tonic-gate * ------------------------ ----- 14030Sstevel@tonic-gate * a: <original instruction> <= 15 14040Sstevel@tonic-gate * jmp <pc + tp->ftt_size> 5 14050Sstevel@tonic-gate * b: <original instrction> <= 15 14060Sstevel@tonic-gate * int T_DTRACE_RET 2 14070Sstevel@tonic-gate * ----- 14080Sstevel@tonic-gate * <= 37 14090Sstevel@tonic-gate * 14100Sstevel@tonic-gate * 64-bit mode bytes 14110Sstevel@tonic-gate * ------------------------ ----- 14120Sstevel@tonic-gate * a: <original instruction> <= 15 14130Sstevel@tonic-gate * jmp 0(%rip) 6 14140Sstevel@tonic-gate * <pc + tp->ftt_size> 8 14150Sstevel@tonic-gate * b: <original instruction> <= 15 14160Sstevel@tonic-gate * int T_DTRACE_RET 2 14170Sstevel@tonic-gate * ----- 14180Sstevel@tonic-gate * <= 46 14190Sstevel@tonic-gate * 14200Sstevel@tonic-gate * The %pc is set to a, and curthread->t_dtrace_astpc is set 14210Sstevel@tonic-gate * to b. If we encounter a signal on the way out of the 14220Sstevel@tonic-gate * kernel, trap() will set %pc to curthread->t_dtrace_astpc 14230Sstevel@tonic-gate * so that we execute the original instruction and re-enter 14240Sstevel@tonic-gate * the kernel rather than redirecting to the next instruction. 14250Sstevel@tonic-gate * 14260Sstevel@tonic-gate * If there are return probes (so we know that we're going to 14270Sstevel@tonic-gate * need to reenter the kernel after executing the original 14280Sstevel@tonic-gate * instruction), the scratch space will just contain the 14290Sstevel@tonic-gate * original instruction followed by an interrupt -- the same 14300Sstevel@tonic-gate * data as at b. 14310Sstevel@tonic-gate * 14320Sstevel@tonic-gate * %rip-relative Addressing 14330Sstevel@tonic-gate * ------------------------ 14340Sstevel@tonic-gate * 14350Sstevel@tonic-gate * There's a further complication in 64-bit mode due to %rip- 14360Sstevel@tonic-gate * relative addressing. While this is clearly a beneficial 14370Sstevel@tonic-gate * architectural decision for position independent code, it's 14380Sstevel@tonic-gate * hard not to see it as a personal attack against the pid 14390Sstevel@tonic-gate * provider since before there was a relatively small set of 14400Sstevel@tonic-gate * instructions to emulate; with %rip-relative addressing, 14410Sstevel@tonic-gate * almost every instruction can potentially depend on the 14420Sstevel@tonic-gate * address at which it's executed. Rather than emulating 14430Sstevel@tonic-gate * the broad spectrum of instructions that can now be 14440Sstevel@tonic-gate * position dependent, we emulate jumps and others as in 14450Sstevel@tonic-gate * 32-bit mode, and take a different tack for instructions 14460Sstevel@tonic-gate * using %rip-relative addressing. 14470Sstevel@tonic-gate * 14480Sstevel@tonic-gate * For every instruction that uses the ModRM byte, the 14490Sstevel@tonic-gate * in-kernel disassembler reports its location. We use the 14500Sstevel@tonic-gate * ModRM byte to identify that an instruction uses 14510Sstevel@tonic-gate * %rip-relative addressing and to see what other registers 14520Sstevel@tonic-gate * the instruction uses. To emulate those instructions, 14530Sstevel@tonic-gate * we modify the instruction to be %rax-relative rather than 14540Sstevel@tonic-gate * %rip-relative (or %rcx-relative if the instruction uses 14550Sstevel@tonic-gate * %rax; or %r8- or %r9-relative if the REX.B is present so 14560Sstevel@tonic-gate * we don't have to rewrite the REX prefix). We then load 14570Sstevel@tonic-gate * the value that %rip would have been into the scratch 14580Sstevel@tonic-gate * register and generate an instruction to reset the scratch 14590Sstevel@tonic-gate * register back to its original value. The instruction 14600Sstevel@tonic-gate * sequence looks like this: 14610Sstevel@tonic-gate * 14620Sstevel@tonic-gate * 64-mode %rip-relative bytes 14630Sstevel@tonic-gate * ------------------------ ----- 14640Sstevel@tonic-gate * a: <modified instruction> <= 15 14650Sstevel@tonic-gate * movq $<value>, %<scratch> 6 14660Sstevel@tonic-gate * jmp 0(%rip) 6 14670Sstevel@tonic-gate * <pc + tp->ftt_size> 8 14680Sstevel@tonic-gate * b: <modified instruction> <= 15 14690Sstevel@tonic-gate * int T_DTRACE_RET 2 14700Sstevel@tonic-gate * ----- 14710Sstevel@tonic-gate * 52 14720Sstevel@tonic-gate * 14730Sstevel@tonic-gate * We set curthread->t_dtrace_regv so that upon receiving 14740Sstevel@tonic-gate * a signal we can reset the value of the scratch register. 14750Sstevel@tonic-gate */ 14760Sstevel@tonic-gate 14770Sstevel@tonic-gate ASSERT(tp->ftt_size < FASTTRAP_MAX_INSTR_SIZE); 14780Sstevel@tonic-gate 14790Sstevel@tonic-gate curthread->t_dtrace_scrpc = addr; 14800Sstevel@tonic-gate bcopy(tp->ftt_instr, &scratch[i], tp->ftt_size); 14810Sstevel@tonic-gate i += tp->ftt_size; 14820Sstevel@tonic-gate 14830Sstevel@tonic-gate #ifdef __amd64 14840Sstevel@tonic-gate if (tp->ftt_ripmode != 0) { 14850Sstevel@tonic-gate greg_t *reg; 14860Sstevel@tonic-gate 14870Sstevel@tonic-gate ASSERT(p->p_model == DATAMODEL_LP64); 14880Sstevel@tonic-gate ASSERT(tp->ftt_ripmode & 14890Sstevel@tonic-gate (FASTTRAP_RIP_1 | FASTTRAP_RIP_2)); 14900Sstevel@tonic-gate 14910Sstevel@tonic-gate /* 14920Sstevel@tonic-gate * If this was a %rip-relative instruction, we change 14930Sstevel@tonic-gate * it to be either a %rax- or %rcx-relative 14940Sstevel@tonic-gate * instruction (depending on whether those registers 14950Sstevel@tonic-gate * are used as another operand; or %r8- or %r9- 14960Sstevel@tonic-gate * relative depending on the value of REX.B). We then 14970Sstevel@tonic-gate * set that register and generate a movq instruction 14980Sstevel@tonic-gate * to reset the value. 14990Sstevel@tonic-gate */ 15000Sstevel@tonic-gate if (tp->ftt_ripmode & FASTTRAP_RIP_X) 15010Sstevel@tonic-gate scratch[i++] = FASTTRAP_REX(1, 0, 0, 1); 15020Sstevel@tonic-gate else 15030Sstevel@tonic-gate scratch[i++] = FASTTRAP_REX(1, 0, 0, 0); 15040Sstevel@tonic-gate 15050Sstevel@tonic-gate if (tp->ftt_ripmode & FASTTRAP_RIP_1) 15060Sstevel@tonic-gate scratch[i++] = FASTTRAP_MOV_EAX; 15070Sstevel@tonic-gate else 15080Sstevel@tonic-gate scratch[i++] = FASTTRAP_MOV_ECX; 15090Sstevel@tonic-gate 15100Sstevel@tonic-gate switch (tp->ftt_ripmode) { 15110Sstevel@tonic-gate case FASTTRAP_RIP_1: 15120Sstevel@tonic-gate reg = &rp->r_rax; 15130Sstevel@tonic-gate curthread->t_dtrace_reg = REG_RAX; 15140Sstevel@tonic-gate break; 15150Sstevel@tonic-gate case FASTTRAP_RIP_2: 15160Sstevel@tonic-gate reg = &rp->r_rcx; 15170Sstevel@tonic-gate curthread->t_dtrace_reg = REG_RCX; 15180Sstevel@tonic-gate break; 15190Sstevel@tonic-gate case FASTTRAP_RIP_1 | FASTTRAP_RIP_X: 15200Sstevel@tonic-gate reg = &rp->r_r8; 15210Sstevel@tonic-gate curthread->t_dtrace_reg = REG_R8; 15220Sstevel@tonic-gate break; 15230Sstevel@tonic-gate case FASTTRAP_RIP_2 | FASTTRAP_RIP_X: 15240Sstevel@tonic-gate reg = &rp->r_r9; 15250Sstevel@tonic-gate curthread->t_dtrace_reg = REG_R9; 15260Sstevel@tonic-gate break; 15270Sstevel@tonic-gate } 15280Sstevel@tonic-gate 15290Sstevel@tonic-gate *(uint64_t *)&scratch[i] = *reg; 15300Sstevel@tonic-gate curthread->t_dtrace_regv = *reg; 15310Sstevel@tonic-gate *reg = pc + tp->ftt_size; 15320Sstevel@tonic-gate i += sizeof (uint64_t); 15330Sstevel@tonic-gate } 15340Sstevel@tonic-gate #endif 15350Sstevel@tonic-gate 15360Sstevel@tonic-gate /* 15370Sstevel@tonic-gate * Generate the branch instruction to what would have 15380Sstevel@tonic-gate * normally been the subsequent instruction. In 32-bit mode, 15390Sstevel@tonic-gate * this is just a relative branch; in 64-bit mode this is a 15400Sstevel@tonic-gate * %rip-relative branch that loads the 64-bit pc value 15410Sstevel@tonic-gate * immediately after the jmp instruction. 15420Sstevel@tonic-gate */ 15430Sstevel@tonic-gate #ifdef __amd64 15440Sstevel@tonic-gate if (p->p_model == DATAMODEL_LP64) { 15450Sstevel@tonic-gate scratch[i++] = FASTTRAP_GROUP5_OP; 15460Sstevel@tonic-gate scratch[i++] = FASTTRAP_MODRM(0, 4, 5); 15470Sstevel@tonic-gate *(uint32_t *)&scratch[i] = 0; 15480Sstevel@tonic-gate i += sizeof (uint32_t); 15490Sstevel@tonic-gate *(uint64_t *)&scratch[i] = pc + tp->ftt_size; 15500Sstevel@tonic-gate i += sizeof (uint64_t); 15510Sstevel@tonic-gate } else { 15520Sstevel@tonic-gate #endif 15530Sstevel@tonic-gate /* 15540Sstevel@tonic-gate * Set up the jmp to the next instruction; note that 15550Sstevel@tonic-gate * the size of the traced instruction cancels out. 15560Sstevel@tonic-gate */ 15570Sstevel@tonic-gate scratch[i++] = FASTTRAP_JMP32; 15580Sstevel@tonic-gate *(uint32_t *)&scratch[i] = pc - addr - 5; 15590Sstevel@tonic-gate i += sizeof (uint32_t); 15600Sstevel@tonic-gate #ifdef __amd64 15610Sstevel@tonic-gate } 15620Sstevel@tonic-gate #endif 15630Sstevel@tonic-gate 15640Sstevel@tonic-gate curthread->t_dtrace_astpc = addr + i; 15650Sstevel@tonic-gate bcopy(tp->ftt_instr, &scratch[i], tp->ftt_size); 15660Sstevel@tonic-gate i += tp->ftt_size; 15670Sstevel@tonic-gate scratch[i++] = FASTTRAP_INT; 15680Sstevel@tonic-gate scratch[i++] = T_DTRACE_RET; 15690Sstevel@tonic-gate 15700Sstevel@tonic-gate if (fasttrap_copyout(scratch, (char *)addr, i)) { 15710Sstevel@tonic-gate fasttrap_sigtrap(p, curthread, pc); 15720Sstevel@tonic-gate new_pc = pc; 15730Sstevel@tonic-gate break; 15740Sstevel@tonic-gate } 15750Sstevel@tonic-gate 15760Sstevel@tonic-gate if (tp->ftt_retids != NULL) { 15770Sstevel@tonic-gate curthread->t_dtrace_step = 1; 15780Sstevel@tonic-gate curthread->t_dtrace_ret = 1; 15790Sstevel@tonic-gate new_pc = curthread->t_dtrace_astpc; 15800Sstevel@tonic-gate } else { 15810Sstevel@tonic-gate new_pc = curthread->t_dtrace_scrpc; 15820Sstevel@tonic-gate } 15830Sstevel@tonic-gate 15840Sstevel@tonic-gate curthread->t_dtrace_pc = pc; 15850Sstevel@tonic-gate curthread->t_dtrace_npc = pc + tp->ftt_size; 15860Sstevel@tonic-gate curthread->t_dtrace_on = 1; 15870Sstevel@tonic-gate break; 15880Sstevel@tonic-gate } 15890Sstevel@tonic-gate 15900Sstevel@tonic-gate default: 15910Sstevel@tonic-gate panic("fasttrap: mishandled an instruction"); 15920Sstevel@tonic-gate } 15930Sstevel@tonic-gate 15941710Sahl done: 15950Sstevel@tonic-gate /* 15960Sstevel@tonic-gate * If there were no return probes when we first found the tracepoint, 15970Sstevel@tonic-gate * we should feel no obligation to honor any return probes that were 15980Sstevel@tonic-gate * subsequently enabled -- they'll just have to wait until the next 15990Sstevel@tonic-gate * time around. 16000Sstevel@tonic-gate */ 16010Sstevel@tonic-gate if (tp->ftt_retids != NULL) { 16020Sstevel@tonic-gate /* 16030Sstevel@tonic-gate * We need to wait until the results of the instruction are 16040Sstevel@tonic-gate * apparent before invoking any return probes. If this 16050Sstevel@tonic-gate * instruction was emulated we can just call 16060Sstevel@tonic-gate * fasttrap_return_common(); if it needs to be executed, we 16070Sstevel@tonic-gate * need to wait until the user thread returns to the kernel. 16080Sstevel@tonic-gate */ 16090Sstevel@tonic-gate if (tp->ftt_type != FASTTRAP_T_COMMON) { 16100Sstevel@tonic-gate /* 16110Sstevel@tonic-gate * Set the program counter to the address of the traced 16120Sstevel@tonic-gate * instruction so that it looks right in ustack() 16130Sstevel@tonic-gate * output. We had previously set it to the end of the 16140Sstevel@tonic-gate * instruction to simplify %rip-relative addressing. 16150Sstevel@tonic-gate */ 16160Sstevel@tonic-gate rp->r_pc = pc; 16170Sstevel@tonic-gate 16180Sstevel@tonic-gate fasttrap_return_common(rp, pc, pid, new_pc); 16190Sstevel@tonic-gate } else { 16200Sstevel@tonic-gate ASSERT(curthread->t_dtrace_ret != 0); 16210Sstevel@tonic-gate ASSERT(curthread->t_dtrace_pc == pc); 16220Sstevel@tonic-gate ASSERT(curthread->t_dtrace_scrpc != 0); 16230Sstevel@tonic-gate ASSERT(new_pc == curthread->t_dtrace_astpc); 16240Sstevel@tonic-gate } 16250Sstevel@tonic-gate } 16260Sstevel@tonic-gate 16270Sstevel@tonic-gate rp->r_pc = new_pc; 16280Sstevel@tonic-gate 16290Sstevel@tonic-gate return (0); 16300Sstevel@tonic-gate } 16310Sstevel@tonic-gate 16320Sstevel@tonic-gate int 16330Sstevel@tonic-gate fasttrap_return_probe(struct regs *rp) 16340Sstevel@tonic-gate { 16350Sstevel@tonic-gate proc_t *p = curproc; 16360Sstevel@tonic-gate uintptr_t pc = curthread->t_dtrace_pc; 16370Sstevel@tonic-gate uintptr_t npc = curthread->t_dtrace_npc; 16380Sstevel@tonic-gate 16390Sstevel@tonic-gate curthread->t_dtrace_pc = 0; 16400Sstevel@tonic-gate curthread->t_dtrace_npc = 0; 16410Sstevel@tonic-gate curthread->t_dtrace_scrpc = 0; 16420Sstevel@tonic-gate curthread->t_dtrace_astpc = 0; 16430Sstevel@tonic-gate 16440Sstevel@tonic-gate /* 16450Sstevel@tonic-gate * Treat a child created by a call to vfork(2) as if it were its 16460Sstevel@tonic-gate * parent. We know that there's only one thread of control in such a 16470Sstevel@tonic-gate * process: this one. 16480Sstevel@tonic-gate */ 16490Sstevel@tonic-gate while (p->p_flag & SVFORK) { 16500Sstevel@tonic-gate p = p->p_parent; 16510Sstevel@tonic-gate } 16520Sstevel@tonic-gate 16530Sstevel@tonic-gate /* 16540Sstevel@tonic-gate * We set rp->r_pc to the address of the traced instruction so 16550Sstevel@tonic-gate * that it appears to dtrace_probe() that we're on the original 16560Sstevel@tonic-gate * instruction, and so that the user can't easily detect our 16570Sstevel@tonic-gate * complex web of lies. dtrace_return_probe() (our caller) 16580Sstevel@tonic-gate * will correctly set %pc after we return. 16590Sstevel@tonic-gate */ 16600Sstevel@tonic-gate rp->r_pc = pc; 16610Sstevel@tonic-gate 16620Sstevel@tonic-gate fasttrap_return_common(rp, pc, p->p_pid, npc); 16630Sstevel@tonic-gate 16640Sstevel@tonic-gate return (0); 16650Sstevel@tonic-gate } 16660Sstevel@tonic-gate 16670Sstevel@tonic-gate /*ARGSUSED*/ 16680Sstevel@tonic-gate uint64_t 16692179Sahl fasttrap_pid_getarg(void *arg, dtrace_id_t id, void *parg, int argno, 16702179Sahl int aframes) 16710Sstevel@tonic-gate { 16720Sstevel@tonic-gate return (fasttrap_anarg(ttolwp(curthread)->lwp_regs, 1, argno)); 16730Sstevel@tonic-gate } 16740Sstevel@tonic-gate 16750Sstevel@tonic-gate /*ARGSUSED*/ 16760Sstevel@tonic-gate uint64_t 16770Sstevel@tonic-gate fasttrap_usdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, 16780Sstevel@tonic-gate int aframes) 16790Sstevel@tonic-gate { 16800Sstevel@tonic-gate return (fasttrap_anarg(ttolwp(curthread)->lwp_regs, 0, argno)); 16810Sstevel@tonic-gate } 16820Sstevel@tonic-gate 16830Sstevel@tonic-gate static ulong_t 16840Sstevel@tonic-gate fasttrap_getreg(struct regs *rp, uint_t reg) 16850Sstevel@tonic-gate { 16860Sstevel@tonic-gate #ifdef __amd64 16870Sstevel@tonic-gate switch (reg) { 16880Sstevel@tonic-gate case REG_R15: return (rp->r_r15); 16890Sstevel@tonic-gate case REG_R14: return (rp->r_r14); 16900Sstevel@tonic-gate case REG_R13: return (rp->r_r13); 16910Sstevel@tonic-gate case REG_R12: return (rp->r_r12); 16920Sstevel@tonic-gate case REG_R11: return (rp->r_r11); 16930Sstevel@tonic-gate case REG_R10: return (rp->r_r10); 16940Sstevel@tonic-gate case REG_R9: return (rp->r_r9); 16950Sstevel@tonic-gate case REG_R8: return (rp->r_r8); 16960Sstevel@tonic-gate case REG_RDI: return (rp->r_rdi); 16970Sstevel@tonic-gate case REG_RSI: return (rp->r_rsi); 16980Sstevel@tonic-gate case REG_RBP: return (rp->r_rbp); 16990Sstevel@tonic-gate case REG_RBX: return (rp->r_rbx); 17000Sstevel@tonic-gate case REG_RDX: return (rp->r_rdx); 17010Sstevel@tonic-gate case REG_RCX: return (rp->r_rcx); 17020Sstevel@tonic-gate case REG_RAX: return (rp->r_rax); 17030Sstevel@tonic-gate case REG_TRAPNO: return (rp->r_trapno); 17040Sstevel@tonic-gate case REG_ERR: return (rp->r_err); 17050Sstevel@tonic-gate case REG_RIP: return (rp->r_rip); 17060Sstevel@tonic-gate case REG_CS: return (rp->r_cs); 17070Sstevel@tonic-gate case REG_RFL: return (rp->r_rfl); 17080Sstevel@tonic-gate case REG_RSP: return (rp->r_rsp); 17090Sstevel@tonic-gate case REG_SS: return (rp->r_ss); 17100Sstevel@tonic-gate case REG_FS: return (rp->r_fs); 17110Sstevel@tonic-gate case REG_GS: return (rp->r_gs); 17120Sstevel@tonic-gate case REG_DS: return (rp->r_ds); 17130Sstevel@tonic-gate case REG_ES: return (rp->r_es); 17140Sstevel@tonic-gate case REG_FSBASE: return (rp->r_fsbase); 17150Sstevel@tonic-gate case REG_GSBASE: return (rp->r_gsbase); 17160Sstevel@tonic-gate } 17170Sstevel@tonic-gate 17180Sstevel@tonic-gate panic("dtrace: illegal register constant"); 17190Sstevel@tonic-gate /*NOTREACHED*/ 17200Sstevel@tonic-gate #else 17210Sstevel@tonic-gate if (reg >= _NGREG) 17220Sstevel@tonic-gate panic("dtrace: illegal register constant"); 17230Sstevel@tonic-gate 17240Sstevel@tonic-gate return (((greg_t *)&rp->r_gs)[reg]); 17250Sstevel@tonic-gate #endif 17260Sstevel@tonic-gate } 1727