1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/conf.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/dtrace.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/kobj.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/atomic.h> 43*7c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/stack.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/ctf_api.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate static dev_info_t *fbt_devi; 49*7c478bd9Sstevel@tonic-gate static dtrace_provider_id_t fbt_id; 50*7c478bd9Sstevel@tonic-gate static uintptr_t fbt_trampoline; 51*7c478bd9Sstevel@tonic-gate static caddr_t fbt_trampoline_window; 52*7c478bd9Sstevel@tonic-gate static size_t fbt_trampoline_size; 53*7c478bd9Sstevel@tonic-gate static int fbt_verbose = 0; 54*7c478bd9Sstevel@tonic-gate 55*7c478bd9Sstevel@tonic-gate /* 56*7c478bd9Sstevel@tonic-gate * Various interesting bean counters. 57*7c478bd9Sstevel@tonic-gate */ 58*7c478bd9Sstevel@tonic-gate static int fbt_entry; 59*7c478bd9Sstevel@tonic-gate static int fbt_ret; 60*7c478bd9Sstevel@tonic-gate static int fbt_retl; 61*7c478bd9Sstevel@tonic-gate static int fbt_retl_jmptab; 62*7c478bd9Sstevel@tonic-gate static int fbt_retl_twoinstr; 63*7c478bd9Sstevel@tonic-gate static int fbt_retl_tailcall; 64*7c478bd9Sstevel@tonic-gate static int fbt_retl_tailjmpl; 65*7c478bd9Sstevel@tonic-gate static int fbt_leaf_functions; 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate extern char stubs_base[]; 68*7c478bd9Sstevel@tonic-gate extern char stubs_end[]; 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate #define FBT_REG_G0 0 71*7c478bd9Sstevel@tonic-gate #define FBT_REG_G1 1 72*7c478bd9Sstevel@tonic-gate #define FBT_REG_O0 8 73*7c478bd9Sstevel@tonic-gate #define FBT_REG_O1 9 74*7c478bd9Sstevel@tonic-gate #define FBT_REG_O2 10 75*7c478bd9Sstevel@tonic-gate #define FBT_REG_O3 11 76*7c478bd9Sstevel@tonic-gate #define FBT_REG_O4 12 77*7c478bd9Sstevel@tonic-gate #define FBT_REG_O5 13 78*7c478bd9Sstevel@tonic-gate #define FBT_REG_O6 14 79*7c478bd9Sstevel@tonic-gate #define FBT_REG_O7 15 80*7c478bd9Sstevel@tonic-gate #define FBT_REG_I0 24 81*7c478bd9Sstevel@tonic-gate #define FBT_REG_I1 25 82*7c478bd9Sstevel@tonic-gate #define FBT_REG_I2 26 83*7c478bd9Sstevel@tonic-gate #define FBT_REG_I3 27 84*7c478bd9Sstevel@tonic-gate #define FBT_REG_I4 28 85*7c478bd9Sstevel@tonic-gate #define FBT_REG_I7 31 86*7c478bd9Sstevel@tonic-gate #define FBT_REG_L0 16 87*7c478bd9Sstevel@tonic-gate #define FBT_REG_L1 17 88*7c478bd9Sstevel@tonic-gate #define FBT_REG_L2 18 89*7c478bd9Sstevel@tonic-gate #define FBT_REG_L3 19 90*7c478bd9Sstevel@tonic-gate #define FBT_REG_PC 5 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate #define FBT_REG_ISGLOBAL(r) ((r) < 8) 93*7c478bd9Sstevel@tonic-gate #define FBT_REG_ISOUTPUT(r) ((r) >= 8 && (r) < 16) 94*7c478bd9Sstevel@tonic-gate #define FBT_REG_ISLOCAL(r) ((r) >= 16 && (r) < 24) 95*7c478bd9Sstevel@tonic-gate #define FBT_REG_ISVOLATILE(r) \ 96*7c478bd9Sstevel@tonic-gate ((FBT_REG_ISGLOBAL(r) || FBT_REG_ISOUTPUT(r)) && (r) != FBT_REG_G0) 97*7c478bd9Sstevel@tonic-gate #define FBT_REG_NLOCALS 8 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate #define FBT_REG_MARKLOCAL(locals, r) \ 100*7c478bd9Sstevel@tonic-gate if (FBT_REG_ISLOCAL(r)) \ 101*7c478bd9Sstevel@tonic-gate (locals)[(r) - FBT_REG_L0] = 1; 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate #define FBT_REG_INITLOCALS(local, locals) \ 104*7c478bd9Sstevel@tonic-gate for ((local) = 0; (local) < FBT_REG_NLOCALS; (local)++) \ 105*7c478bd9Sstevel@tonic-gate (locals)[(local)] = 0; \ 106*7c478bd9Sstevel@tonic-gate (local) = FBT_REG_L0 107*7c478bd9Sstevel@tonic-gate 108*7c478bd9Sstevel@tonic-gate #define FBT_REG_ALLOCLOCAL(local, locals) \ 109*7c478bd9Sstevel@tonic-gate while ((locals)[(local) - FBT_REG_L0]) \ 110*7c478bd9Sstevel@tonic-gate (local)++; \ 111*7c478bd9Sstevel@tonic-gate (locals)[(local) - FBT_REG_L0] = 1; 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate #define FBT_OP_MASK 0xc0000000 114*7c478bd9Sstevel@tonic-gate #define FBT_OP_SHIFT 30 115*7c478bd9Sstevel@tonic-gate #define FBT_OP(val) ((val) & FBT_FMT1_MASK) 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate #define FBT_SIMM13_MASK 0x1fff 118*7c478bd9Sstevel@tonic-gate #define FBT_SIMM13_MAX ((int32_t)0xfff) 119*7c478bd9Sstevel@tonic-gate #define FBT_IMM22_MASK 0x3fffff 120*7c478bd9Sstevel@tonic-gate #define FBT_IMM22_SHIFT 10 121*7c478bd9Sstevel@tonic-gate #define FBT_IMM10_MASK 0x3ff 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate #define FBT_DISP30_MASK 0x3fffffff 124*7c478bd9Sstevel@tonic-gate #define FBT_DISP30(from, to) \ 125*7c478bd9Sstevel@tonic-gate (((uintptr_t)(to) - (uintptr_t)(from) >> 2) & FBT_DISP30_MASK) 126*7c478bd9Sstevel@tonic-gate 127*7c478bd9Sstevel@tonic-gate #define FBT_DISP22_MASK 0x3fffff 128*7c478bd9Sstevel@tonic-gate #define FBT_DISP22(from, to) \ 129*7c478bd9Sstevel@tonic-gate (((uintptr_t)(to) - (uintptr_t)(from) >> 2) & FBT_DISP22_MASK) 130*7c478bd9Sstevel@tonic-gate 131*7c478bd9Sstevel@tonic-gate #define FBT_DISP19_MASK 0x7ffff 132*7c478bd9Sstevel@tonic-gate #define FBT_DISP19(from, to) \ 133*7c478bd9Sstevel@tonic-gate (((uintptr_t)(to) - (uintptr_t)(from) >> 2) & FBT_DISP19_MASK) 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate #define FBT_DISP16_HISHIFT 20 136*7c478bd9Sstevel@tonic-gate #define FBT_DISP16_HIMASK (0x3 << FBT_DISP16_HISHIFT) 137*7c478bd9Sstevel@tonic-gate #define FBT_DISP16_LOMASK (0x3fff) 138*7c478bd9Sstevel@tonic-gate #define FBT_DISP16_MASK (FBT_DISP16_HIMASK | FBT_DISP16_LOMASK) 139*7c478bd9Sstevel@tonic-gate #define FBT_DISP16(val) \ 140*7c478bd9Sstevel@tonic-gate ((((val) & FBT_DISP16_HIMASK) >> 6) | ((val) & FBT_DISP16_LOMASK)) 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate #define FBT_DISP14_MASK 0x3fff 143*7c478bd9Sstevel@tonic-gate #define FBT_DISP14(from, to) \ 144*7c478bd9Sstevel@tonic-gate (((uintptr_t)(to) - (uintptr_t)(from) >> 2) & FBT_DISP14_MASK) 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate #define FBT_OP0 (((uint32_t)0) << FBT_OP_SHIFT) 147*7c478bd9Sstevel@tonic-gate #define FBT_OP1 (((uint32_t)1) << FBT_OP_SHIFT) 148*7c478bd9Sstevel@tonic-gate #define FBT_OP2 (((uint32_t)2) << FBT_OP_SHIFT) 149*7c478bd9Sstevel@tonic-gate #define FBT_ILLTRAP 0 150*7c478bd9Sstevel@tonic-gate 151*7c478bd9Sstevel@tonic-gate #define FBT_ANNUL_SHIFT 29 152*7c478bd9Sstevel@tonic-gate #define FBT_ANNUL (1 << FBT_ANNUL_SHIFT) 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate #define FBT_FMT3_OP3_SHIFT 19 155*7c478bd9Sstevel@tonic-gate #define FBT_FMT3_OP_MASK 0xc1f80000 156*7c478bd9Sstevel@tonic-gate #define FBT_FMT3_OP(val) ((val) & FBT_FMT3_OP_MASK) 157*7c478bd9Sstevel@tonic-gate 158*7c478bd9Sstevel@tonic-gate #define FBT_FMT3_RD_SHIFT 25 159*7c478bd9Sstevel@tonic-gate #define FBT_FMT3_RD_MASK (0x1f << FBT_FMT3_RD_SHIFT) 160*7c478bd9Sstevel@tonic-gate #define FBT_FMT3_RD(val) \ 161*7c478bd9Sstevel@tonic-gate (((val) & FBT_FMT3_RD_MASK) >> FBT_FMT3_RD_SHIFT) 162*7c478bd9Sstevel@tonic-gate 163*7c478bd9Sstevel@tonic-gate #define FBT_FMT3_RS1_SHIFT 14 164*7c478bd9Sstevel@tonic-gate #define FBT_FMT3_RS1_MASK (0x1f << FBT_FMT3_RS1_SHIFT) 165*7c478bd9Sstevel@tonic-gate #define FBT_FMT3_RS1(val) \ 166*7c478bd9Sstevel@tonic-gate (((val) & FBT_FMT3_RS1_MASK) >> FBT_FMT3_RS1_SHIFT) 167*7c478bd9Sstevel@tonic-gate #define FBT_FMT3_RS1_SET(val, rs1) \ 168*7c478bd9Sstevel@tonic-gate (val) = ((val) & ~FBT_FMT3_RS1_MASK) | ((rs1) << FBT_FMT3_RS1_SHIFT) 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate #define FBT_FMT3_RS2_SHIFT 0 171*7c478bd9Sstevel@tonic-gate #define FBT_FMT3_RS2_MASK (0x1f << FBT_FMT3_RS2_SHIFT) 172*7c478bd9Sstevel@tonic-gate #define FBT_FMT3_RS2(val) \ 173*7c478bd9Sstevel@tonic-gate (((val) & FBT_FMT3_RS2_MASK) >> FBT_FMT3_RS2_SHIFT) 174*7c478bd9Sstevel@tonic-gate #define FBT_FMT3_RS2_SET(val, rs2) \ 175*7c478bd9Sstevel@tonic-gate (val) = ((val) & ~FBT_FMT3_RS2_MASK) | ((rs2) << FBT_FMT3_RS2_SHIFT) 176*7c478bd9Sstevel@tonic-gate 177*7c478bd9Sstevel@tonic-gate #define FBT_FMT3_IMM_SHIFT 13 178*7c478bd9Sstevel@tonic-gate #define FBT_FMT3_IMM (1 << FBT_FMT3_IMM_SHIFT) 179*7c478bd9Sstevel@tonic-gate #define FBT_FMT3_SIMM13_MASK FBT_SIMM13_MASK 180*7c478bd9Sstevel@tonic-gate 181*7c478bd9Sstevel@tonic-gate #define FBT_FMT3_ISIMM(val) ((val) & FBT_FMT3_IMM) 182*7c478bd9Sstevel@tonic-gate #define FBT_FMT3_SIMM13(val) ((val) & FBT_FMT3_SIMM13_MASK) 183*7c478bd9Sstevel@tonic-gate 184*7c478bd9Sstevel@tonic-gate #define FBT_FMT2_OP2_SHIFT 22 185*7c478bd9Sstevel@tonic-gate #define FBT_FMT2_OP2_MASK (0x7 << FBT_FMT2_OP2_SHIFT) 186*7c478bd9Sstevel@tonic-gate #define FBT_FMT2_RD_SHIFT 25 187*7c478bd9Sstevel@tonic-gate 188*7c478bd9Sstevel@tonic-gate #define FBT_FMT1_OP(val) ((val) & FBT_OP_MASK) 189*7c478bd9Sstevel@tonic-gate #define FBT_FMT1_DISP30(val) ((val) & FBT_DISP30_MASK) 190*7c478bd9Sstevel@tonic-gate 191*7c478bd9Sstevel@tonic-gate #define FBT_FMT2_OP2_BPCC (0x01 << FBT_FMT2_OP2_SHIFT) 192*7c478bd9Sstevel@tonic-gate #define FBT_FMT2_OP2_BCC (0x02 << FBT_FMT2_OP2_SHIFT) 193*7c478bd9Sstevel@tonic-gate #define FBT_FMT2_OP2_BPR (0x03 << FBT_FMT2_OP2_SHIFT) 194*7c478bd9Sstevel@tonic-gate #define FBT_FMT2_OP2_SETHI (0x04 << FBT_FMT2_OP2_SHIFT) 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate #define FBT_FMT2_COND_SHIFT 25 197*7c478bd9Sstevel@tonic-gate #define FBT_FMT2_COND_BA (0x8 << FBT_FMT2_COND_SHIFT) 198*7c478bd9Sstevel@tonic-gate #define FBT_FMT2_COND_BL (0x3 << FBT_FMT2_COND_SHIFT) 199*7c478bd9Sstevel@tonic-gate #define FBT_FMT2_COND_BGE (0xb << FBT_FMT2_COND_SHIFT) 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate #define FBT_OP_RESTORE (FBT_OP2 | (0x3d << FBT_FMT3_OP3_SHIFT)) 202*7c478bd9Sstevel@tonic-gate #define FBT_OP_SAVE (FBT_OP2 | (0x3c << FBT_FMT3_OP3_SHIFT)) 203*7c478bd9Sstevel@tonic-gate #define FBT_OP_JMPL (FBT_OP2 | (0x38 << FBT_FMT3_OP3_SHIFT)) 204*7c478bd9Sstevel@tonic-gate #define FBT_OP_RETURN (FBT_OP2 | (0x39 << FBT_FMT3_OP3_SHIFT)) 205*7c478bd9Sstevel@tonic-gate #define FBT_OP_CALL FBT_OP1 206*7c478bd9Sstevel@tonic-gate #define FBT_OP_SETHI (FBT_OP0 | FBT_FMT2_OP2_SETHI) 207*7c478bd9Sstevel@tonic-gate #define FBT_OP_ADD (FBT_OP2 | (0x00 << FBT_FMT3_OP3_SHIFT)) 208*7c478bd9Sstevel@tonic-gate #define FBT_OP_OR (FBT_OP2 | (0x02 << FBT_FMT3_OP3_SHIFT)) 209*7c478bd9Sstevel@tonic-gate #define FBT_OP_SUB (FBT_OP2 | (0x04 << FBT_FMT3_OP3_SHIFT)) 210*7c478bd9Sstevel@tonic-gate #define FBT_OP_CC (FBT_OP2 | (0x10 << FBT_FMT3_OP3_SHIFT)) 211*7c478bd9Sstevel@tonic-gate #define FBT_OP_BA (FBT_OP0 | FBT_FMT2_OP2_BCC | FBT_FMT2_COND_BA) 212*7c478bd9Sstevel@tonic-gate #define FBT_OP_BL (FBT_OP0 | FBT_FMT2_OP2_BCC | FBT_FMT2_COND_BL) 213*7c478bd9Sstevel@tonic-gate #define FBT_OP_BGE (FBT_OP0 | FBT_FMT2_OP2_BCC | FBT_FMT2_COND_BGE) 214*7c478bd9Sstevel@tonic-gate #define FBT_OP_BAPCC (FBT_OP0 | FBT_FMT2_OP2_BPCC | FBT_FMT2_COND_BA) 215*7c478bd9Sstevel@tonic-gate #define FBT_OP_RD (FBT_OP2 | (0x28 << FBT_FMT3_OP3_SHIFT)) 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate #define FBT_ORLO(rs, val, rd) \ 218*7c478bd9Sstevel@tonic-gate (FBT_OP_OR | ((rs) << FBT_FMT3_RS1_SHIFT) | \ 219*7c478bd9Sstevel@tonic-gate ((rd) << FBT_FMT3_RD_SHIFT) | FBT_FMT3_IMM | ((val) & FBT_IMM10_MASK)) 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate #define FBT_ORSIMM13(rs, val, rd) \ 222*7c478bd9Sstevel@tonic-gate (FBT_OP_OR | ((rs) << FBT_FMT3_RS1_SHIFT) | \ 223*7c478bd9Sstevel@tonic-gate ((rd) << FBT_FMT3_RD_SHIFT) | FBT_FMT3_IMM | ((val) & FBT_SIMM13_MASK)) 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate #define FBT_ADDSIMM13(rs, val, rd) \ 226*7c478bd9Sstevel@tonic-gate (FBT_OP_ADD | ((rs) << FBT_FMT3_RS1_SHIFT) | \ 227*7c478bd9Sstevel@tonic-gate ((rd) << FBT_FMT3_RD_SHIFT) | FBT_FMT3_IMM | ((val) & FBT_SIMM13_MASK)) 228*7c478bd9Sstevel@tonic-gate 229*7c478bd9Sstevel@tonic-gate #define FBT_ADD(rs1, rs2, rd) \ 230*7c478bd9Sstevel@tonic-gate (FBT_OP_ADD | ((rs1) << FBT_FMT3_RS1_SHIFT) | \ 231*7c478bd9Sstevel@tonic-gate ((rs2) << FBT_FMT3_RS2_SHIFT) | ((rd) << FBT_FMT3_RD_SHIFT)) 232*7c478bd9Sstevel@tonic-gate 233*7c478bd9Sstevel@tonic-gate #define FBT_CMP(rs1, rs2) \ 234*7c478bd9Sstevel@tonic-gate (FBT_OP_SUB | FBT_OP_CC | ((rs1) << FBT_FMT3_RS1_SHIFT) | \ 235*7c478bd9Sstevel@tonic-gate ((rs2) << FBT_FMT3_RS2_SHIFT) | (FBT_REG_G0 << FBT_FMT3_RD_SHIFT)) 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate #define FBT_MOV(rs, rd) \ 238*7c478bd9Sstevel@tonic-gate (FBT_OP_OR | (FBT_REG_G0 << FBT_FMT3_RS1_SHIFT) | \ 239*7c478bd9Sstevel@tonic-gate ((rs) << FBT_FMT3_RS2_SHIFT) | ((rd) << FBT_FMT3_RD_SHIFT)) 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate #define FBT_SETHI(val, reg) \ 242*7c478bd9Sstevel@tonic-gate (FBT_OP_SETHI | (reg << FBT_FMT2_RD_SHIFT) | \ 243*7c478bd9Sstevel@tonic-gate ((val >> FBT_IMM22_SHIFT) & FBT_IMM22_MASK)) 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate #define FBT_CALL(orig, dest) (FBT_OP_CALL | FBT_DISP30(orig, dest)) 246*7c478bd9Sstevel@tonic-gate 247*7c478bd9Sstevel@tonic-gate #define FBT_RET \ 248*7c478bd9Sstevel@tonic-gate (FBT_OP_JMPL | (FBT_REG_I7 << FBT_FMT3_RS1_SHIFT) | \ 249*7c478bd9Sstevel@tonic-gate (FBT_REG_G0 << FBT_FMT3_RD_SHIFT) | FBT_FMT3_IMM | (sizeof (pc_t) << 1)) 250*7c478bd9Sstevel@tonic-gate 251*7c478bd9Sstevel@tonic-gate #define FBT_SAVEIMM(rd, val, rs1) \ 252*7c478bd9Sstevel@tonic-gate (FBT_OP_SAVE | ((rs1) << FBT_FMT3_RS1_SHIFT) | \ 253*7c478bd9Sstevel@tonic-gate ((rd) << FBT_FMT3_RD_SHIFT) | FBT_FMT3_IMM | ((val) & FBT_SIMM13_MASK)) 254*7c478bd9Sstevel@tonic-gate 255*7c478bd9Sstevel@tonic-gate #define FBT_RESTORE(rd, rs1, rs2) \ 256*7c478bd9Sstevel@tonic-gate (FBT_OP_RESTORE | ((rs1) << FBT_FMT3_RS1_SHIFT) | \ 257*7c478bd9Sstevel@tonic-gate ((rd) << FBT_FMT3_RD_SHIFT) | ((rs2) << FBT_FMT3_RS2_SHIFT)) 258*7c478bd9Sstevel@tonic-gate 259*7c478bd9Sstevel@tonic-gate #define FBT_RETURN(rs1, val) \ 260*7c478bd9Sstevel@tonic-gate (FBT_OP_RETURN | ((rs1) << FBT_FMT3_RS1_SHIFT) | \ 261*7c478bd9Sstevel@tonic-gate FBT_FMT3_IMM | ((val) & FBT_SIMM13_MASK)) 262*7c478bd9Sstevel@tonic-gate 263*7c478bd9Sstevel@tonic-gate #define FBT_BA(orig, dest) (FBT_OP_BA | FBT_DISP22(orig, dest)) 264*7c478bd9Sstevel@tonic-gate #define FBT_BAA(orig, dest) (FBT_BA(orig, dest) | FBT_ANNUL) 265*7c478bd9Sstevel@tonic-gate #define FBT_BL(orig, dest) (FBT_OP_BL | FBT_DISP22(orig, dest)) 266*7c478bd9Sstevel@tonic-gate #define FBT_BGE(orig, dest) (FBT_OP_BGE | FBT_DISP22(orig, dest)) 267*7c478bd9Sstevel@tonic-gate #define FBT_BDEST(va, instr) ((uintptr_t)(va) + \ 268*7c478bd9Sstevel@tonic-gate (((int32_t)(((instr) & FBT_DISP22_MASK) << 10)) >> 8)) 269*7c478bd9Sstevel@tonic-gate #define FBT_BPCCDEST(va, instr) ((uintptr_t)(va) + \ 270*7c478bd9Sstevel@tonic-gate (((int32_t)(((instr) & FBT_DISP19_MASK) << 13)) >> 11)) 271*7c478bd9Sstevel@tonic-gate #define FBT_BPRDEST(va, instr) ((uintptr_t)(va) + \ 272*7c478bd9Sstevel@tonic-gate (((int32_t)((FBT_DISP16(instr)) << 16)) >> 14)) 273*7c478bd9Sstevel@tonic-gate 274*7c478bd9Sstevel@tonic-gate /* 275*7c478bd9Sstevel@tonic-gate * We're only going to treat a save as safe if (a) both rs1 and rd are 276*7c478bd9Sstevel@tonic-gate * %sp and (b) if the instruction has a simm, the value isn't 0. 277*7c478bd9Sstevel@tonic-gate */ 278*7c478bd9Sstevel@tonic-gate #define FBT_IS_SAVE(instr) \ 279*7c478bd9Sstevel@tonic-gate (FBT_FMT3_OP(instr) == FBT_OP_SAVE && \ 280*7c478bd9Sstevel@tonic-gate FBT_FMT3_RD(instr) == FBT_REG_O6 && \ 281*7c478bd9Sstevel@tonic-gate FBT_FMT3_RS1(instr) == FBT_REG_O6 && \ 282*7c478bd9Sstevel@tonic-gate !(FBT_FMT3_ISIMM(instr) && FBT_FMT3_SIMM13(instr) == 0)) 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate #define FBT_IS_BA(instr) (((instr) & ~FBT_DISP22_MASK) == FBT_OP_BA) 285*7c478bd9Sstevel@tonic-gate #define FBT_IS_BAPCC(instr) (((instr) & ~FBT_DISP22_MASK) == FBT_OP_BAPCC) 286*7c478bd9Sstevel@tonic-gate 287*7c478bd9Sstevel@tonic-gate #define FBT_IS_RDPC(instr) ((FBT_FMT3_OP(instr) == FBT_OP_RD) && \ 288*7c478bd9Sstevel@tonic-gate (FBT_FMT3_RD(instr) == FBT_REG_PC)) 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate #define FBT_IS_PCRELATIVE(instr) \ 291*7c478bd9Sstevel@tonic-gate ((((instr) & FBT_OP_MASK) == FBT_OP0 && \ 292*7c478bd9Sstevel@tonic-gate ((instr) & FBT_FMT2_OP2_MASK) != FBT_FMT2_OP2_SETHI) || \ 293*7c478bd9Sstevel@tonic-gate ((instr) & FBT_OP_MASK) == FBT_OP1 || \ 294*7c478bd9Sstevel@tonic-gate FBT_IS_RDPC(instr)) 295*7c478bd9Sstevel@tonic-gate 296*7c478bd9Sstevel@tonic-gate #define FBT_IS_CTI(instr) \ 297*7c478bd9Sstevel@tonic-gate ((((instr) & FBT_OP_MASK) == FBT_OP0 && \ 298*7c478bd9Sstevel@tonic-gate ((instr) & FBT_FMT2_OP2_MASK) != FBT_FMT2_OP2_SETHI) || \ 299*7c478bd9Sstevel@tonic-gate ((instr) & FBT_OP_MASK) == FBT_OP1 || \ 300*7c478bd9Sstevel@tonic-gate (FBT_FMT3_OP(instr) == FBT_OP_JMPL) || \ 301*7c478bd9Sstevel@tonic-gate (FBT_FMT3_OP(instr) == FBT_OP_RETURN)) 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate #define FBT_PROBENAME_ENTRY "entry" 304*7c478bd9Sstevel@tonic-gate #define FBT_PROBENAME_RETURN "return" 305*7c478bd9Sstevel@tonic-gate #define FBT_ESTIMATE_ID (UINT32_MAX) 306*7c478bd9Sstevel@tonic-gate #define FBT_COUNTER(id, count) if ((id) != FBT_ESTIMATE_ID) (count)++ 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate #define FBT_ENTENT_MAXSIZE (16 * sizeof (uint32_t)) 309*7c478bd9Sstevel@tonic-gate #define FBT_RETENT_MAXSIZE (11 * sizeof (uint32_t)) 310*7c478bd9Sstevel@tonic-gate #define FBT_RETLENT_MAXSIZE (23 * sizeof (uint32_t)) 311*7c478bd9Sstevel@tonic-gate #define FBT_ENT_MAXSIZE \ 312*7c478bd9Sstevel@tonic-gate MAX(MAX(FBT_ENTENT_MAXSIZE, FBT_RETENT_MAXSIZE), FBT_RETLENT_MAXSIZE) 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate typedef struct fbt_probe { 315*7c478bd9Sstevel@tonic-gate char *fbtp_name; 316*7c478bd9Sstevel@tonic-gate dtrace_id_t fbtp_id; 317*7c478bd9Sstevel@tonic-gate uintptr_t fbtp_addr; 318*7c478bd9Sstevel@tonic-gate struct modctl *fbtp_ctl; 319*7c478bd9Sstevel@tonic-gate int fbtp_loadcnt; 320*7c478bd9Sstevel@tonic-gate int fbtp_symndx; 321*7c478bd9Sstevel@tonic-gate int fbtp_primary; 322*7c478bd9Sstevel@tonic-gate int fbtp_return; 323*7c478bd9Sstevel@tonic-gate uint32_t *fbtp_patchpoint; 324*7c478bd9Sstevel@tonic-gate uint32_t fbtp_patchval; 325*7c478bd9Sstevel@tonic-gate uint32_t fbtp_savedval; 326*7c478bd9Sstevel@tonic-gate struct fbt_probe *fbtp_next; 327*7c478bd9Sstevel@tonic-gate } fbt_probe_t; 328*7c478bd9Sstevel@tonic-gate 329*7c478bd9Sstevel@tonic-gate typedef struct fbt_trampoline { 330*7c478bd9Sstevel@tonic-gate uintptr_t fbtt_va; 331*7c478bd9Sstevel@tonic-gate uintptr_t fbtt_limit; 332*7c478bd9Sstevel@tonic-gate uintptr_t fbtt_next; 333*7c478bd9Sstevel@tonic-gate } fbt_trampoline_t; 334*7c478bd9Sstevel@tonic-gate 335*7c478bd9Sstevel@tonic-gate static caddr_t 336*7c478bd9Sstevel@tonic-gate fbt_trampoline_map(uintptr_t tramp, size_t size) 337*7c478bd9Sstevel@tonic-gate { 338*7c478bd9Sstevel@tonic-gate uintptr_t offs; 339*7c478bd9Sstevel@tonic-gate page_t **ppl; 340*7c478bd9Sstevel@tonic-gate 341*7c478bd9Sstevel@tonic-gate ASSERT(fbt_trampoline_window == NULL); 342*7c478bd9Sstevel@tonic-gate ASSERT(fbt_trampoline_size == 0); 343*7c478bd9Sstevel@tonic-gate ASSERT(fbt_trampoline == NULL); 344*7c478bd9Sstevel@tonic-gate 345*7c478bd9Sstevel@tonic-gate size += tramp & PAGEOFFSET; 346*7c478bd9Sstevel@tonic-gate fbt_trampoline = tramp & PAGEMASK; 347*7c478bd9Sstevel@tonic-gate fbt_trampoline_size = (size + PAGESIZE - 1) & PAGEMASK; 348*7c478bd9Sstevel@tonic-gate fbt_trampoline_window = 349*7c478bd9Sstevel@tonic-gate vmem_alloc(heap_arena, fbt_trampoline_size, VM_SLEEP); 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate (void) as_pagelock(&kas, &ppl, (caddr_t)fbt_trampoline, 352*7c478bd9Sstevel@tonic-gate fbt_trampoline_size, S_WRITE); 353*7c478bd9Sstevel@tonic-gate 354*7c478bd9Sstevel@tonic-gate for (offs = 0; offs < fbt_trampoline_size; offs += PAGESIZE) { 355*7c478bd9Sstevel@tonic-gate hat_devload(kas.a_hat, fbt_trampoline_window + offs, PAGESIZE, 356*7c478bd9Sstevel@tonic-gate hat_getpfnum(kas.a_hat, (caddr_t)fbt_trampoline + offs), 357*7c478bd9Sstevel@tonic-gate PROT_READ | PROT_WRITE, 358*7c478bd9Sstevel@tonic-gate HAT_LOAD_LOCK | HAT_LOAD_NOCONSIST); 359*7c478bd9Sstevel@tonic-gate } 360*7c478bd9Sstevel@tonic-gate 361*7c478bd9Sstevel@tonic-gate as_pageunlock(&kas, ppl, (caddr_t)fbt_trampoline, fbt_trampoline_size, 362*7c478bd9Sstevel@tonic-gate S_WRITE); 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate return (fbt_trampoline_window + (tramp & PAGEOFFSET)); 365*7c478bd9Sstevel@tonic-gate } 366*7c478bd9Sstevel@tonic-gate 367*7c478bd9Sstevel@tonic-gate static void 368*7c478bd9Sstevel@tonic-gate fbt_trampoline_unmap() 369*7c478bd9Sstevel@tonic-gate { 370*7c478bd9Sstevel@tonic-gate ASSERT(fbt_trampoline_window != NULL); 371*7c478bd9Sstevel@tonic-gate ASSERT(fbt_trampoline_size != 0); 372*7c478bd9Sstevel@tonic-gate ASSERT(fbt_trampoline != NULL); 373*7c478bd9Sstevel@tonic-gate 374*7c478bd9Sstevel@tonic-gate membar_enter(); 375*7c478bd9Sstevel@tonic-gate sync_icache((caddr_t)fbt_trampoline, fbt_trampoline_size); 376*7c478bd9Sstevel@tonic-gate sync_icache(fbt_trampoline_window, fbt_trampoline_size); 377*7c478bd9Sstevel@tonic-gate 378*7c478bd9Sstevel@tonic-gate hat_unload(kas.a_hat, fbt_trampoline_window, fbt_trampoline_size, 379*7c478bd9Sstevel@tonic-gate HAT_UNLOAD_UNLOCK); 380*7c478bd9Sstevel@tonic-gate 381*7c478bd9Sstevel@tonic-gate vmem_free(heap_arena, fbt_trampoline_window, fbt_trampoline_size); 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate fbt_trampoline_window = NULL; 384*7c478bd9Sstevel@tonic-gate fbt_trampoline = NULL; 385*7c478bd9Sstevel@tonic-gate fbt_trampoline_size = 0; 386*7c478bd9Sstevel@tonic-gate } 387*7c478bd9Sstevel@tonic-gate 388*7c478bd9Sstevel@tonic-gate static uintptr_t 389*7c478bd9Sstevel@tonic-gate fbt_patch_entry(uint32_t *instr, uint32_t id, fbt_trampoline_t *tramp, 390*7c478bd9Sstevel@tonic-gate int nargs) 391*7c478bd9Sstevel@tonic-gate { 392*7c478bd9Sstevel@tonic-gate uint32_t *tinstr = (uint32_t *)tramp->fbtt_next; 393*7c478bd9Sstevel@tonic-gate uint32_t first = *instr; 394*7c478bd9Sstevel@tonic-gate uintptr_t va = tramp->fbtt_va; 395*7c478bd9Sstevel@tonic-gate uintptr_t base = tramp->fbtt_next; 396*7c478bd9Sstevel@tonic-gate 397*7c478bd9Sstevel@tonic-gate if (tramp->fbtt_next + FBT_ENTENT_MAXSIZE > tramp->fbtt_limit) { 398*7c478bd9Sstevel@tonic-gate /* 399*7c478bd9Sstevel@tonic-gate * There isn't sufficient room for this entry; return failure. 400*7c478bd9Sstevel@tonic-gate */ 401*7c478bd9Sstevel@tonic-gate return (0); 402*7c478bd9Sstevel@tonic-gate } 403*7c478bd9Sstevel@tonic-gate 404*7c478bd9Sstevel@tonic-gate FBT_COUNTER(id, fbt_entry); 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate if (FBT_IS_SAVE(first)) { 407*7c478bd9Sstevel@tonic-gate *tinstr++ = first; 408*7c478bd9Sstevel@tonic-gate } else { 409*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_SAVEIMM(FBT_REG_O6, -SA(MINFRAME), FBT_REG_O6); 410*7c478bd9Sstevel@tonic-gate } 411*7c478bd9Sstevel@tonic-gate 412*7c478bd9Sstevel@tonic-gate if (id > (uint32_t)FBT_SIMM13_MAX) { 413*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_SETHI(id, FBT_REG_O0); 414*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_ORLO(FBT_REG_O0, id, FBT_REG_O0); 415*7c478bd9Sstevel@tonic-gate } else { 416*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_ORSIMM13(FBT_REG_G0, id, FBT_REG_O0); 417*7c478bd9Sstevel@tonic-gate } 418*7c478bd9Sstevel@tonic-gate 419*7c478bd9Sstevel@tonic-gate if (nargs >= 1) 420*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_MOV(FBT_REG_I0, FBT_REG_O1); 421*7c478bd9Sstevel@tonic-gate 422*7c478bd9Sstevel@tonic-gate if (nargs >= 2) 423*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_MOV(FBT_REG_I1, FBT_REG_O2); 424*7c478bd9Sstevel@tonic-gate 425*7c478bd9Sstevel@tonic-gate if (nargs >= 3) 426*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_MOV(FBT_REG_I2, FBT_REG_O3); 427*7c478bd9Sstevel@tonic-gate 428*7c478bd9Sstevel@tonic-gate if (nargs >= 4) 429*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_MOV(FBT_REG_I3, FBT_REG_O4); 430*7c478bd9Sstevel@tonic-gate 431*7c478bd9Sstevel@tonic-gate if (nargs >= 5) 432*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_MOV(FBT_REG_I4, FBT_REG_O5); 433*7c478bd9Sstevel@tonic-gate 434*7c478bd9Sstevel@tonic-gate if (FBT_IS_SAVE(first)) { 435*7c478bd9Sstevel@tonic-gate uintptr_t ret = (uintptr_t)instr - sizeof (uint32_t); 436*7c478bd9Sstevel@tonic-gate 437*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_SETHI(ret, FBT_REG_G1); 438*7c478bd9Sstevel@tonic-gate *tinstr = FBT_CALL((uintptr_t)tinstr - base + va, dtrace_probe); 439*7c478bd9Sstevel@tonic-gate tinstr++; 440*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_ORLO(FBT_REG_G1, ret, FBT_REG_O7); 441*7c478bd9Sstevel@tonic-gate } else { 442*7c478bd9Sstevel@tonic-gate uintptr_t slot = *--tinstr; 443*7c478bd9Sstevel@tonic-gate uintptr_t ret = (uintptr_t)instr + sizeof (uint32_t); 444*7c478bd9Sstevel@tonic-gate uint32_t delay = first; 445*7c478bd9Sstevel@tonic-gate 446*7c478bd9Sstevel@tonic-gate *tinstr = FBT_CALL((uintptr_t)tinstr - base + va, dtrace_probe); 447*7c478bd9Sstevel@tonic-gate tinstr++; 448*7c478bd9Sstevel@tonic-gate *tinstr++ = slot; 449*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_RESTORE(FBT_REG_G0, FBT_REG_G0, FBT_REG_G0); 450*7c478bd9Sstevel@tonic-gate 451*7c478bd9Sstevel@tonic-gate if (FBT_IS_BA(first) || FBT_IS_BAPCC(first)) { 452*7c478bd9Sstevel@tonic-gate /* 453*7c478bd9Sstevel@tonic-gate * This is a special case: we are instrumenting a 454*7c478bd9Sstevel@tonic-gate * a non-annulled branch-always (or variant). We'll 455*7c478bd9Sstevel@tonic-gate * return directly to the destination of the branch, 456*7c478bd9Sstevel@tonic-gate * copying the instruction in the delay slot here, 457*7c478bd9Sstevel@tonic-gate * and then executing it in the slot of a ba. 458*7c478bd9Sstevel@tonic-gate */ 459*7c478bd9Sstevel@tonic-gate if (FBT_IS_BA(first)) { 460*7c478bd9Sstevel@tonic-gate ret = FBT_BDEST(instr, *instr); 461*7c478bd9Sstevel@tonic-gate } else { 462*7c478bd9Sstevel@tonic-gate ret = FBT_BPCCDEST(instr, *instr); 463*7c478bd9Sstevel@tonic-gate } 464*7c478bd9Sstevel@tonic-gate 465*7c478bd9Sstevel@tonic-gate delay = *(instr + 1); 466*7c478bd9Sstevel@tonic-gate } 467*7c478bd9Sstevel@tonic-gate 468*7c478bd9Sstevel@tonic-gate if ((first & FBT_OP_MASK) != FBT_OP0 || 469*7c478bd9Sstevel@tonic-gate (first & FBT_FMT2_OP2_MASK) != FBT_FMT2_OP2_BPR) { 470*7c478bd9Sstevel@tonic-gate *tinstr = FBT_BA((uintptr_t)tinstr - base + va, ret); 471*7c478bd9Sstevel@tonic-gate tinstr++; 472*7c478bd9Sstevel@tonic-gate *tinstr++ = delay; 473*7c478bd9Sstevel@tonic-gate } else { 474*7c478bd9Sstevel@tonic-gate /* 475*7c478bd9Sstevel@tonic-gate * If this is a branch-on-register, we have a little 476*7c478bd9Sstevel@tonic-gate * more work to do: because the displacement is only 477*7c478bd9Sstevel@tonic-gate * sixteen bits, we're going to thunk the branch into 478*7c478bd9Sstevel@tonic-gate * the trampoline, and then ba,a to the appropriate 479*7c478bd9Sstevel@tonic-gate * destination in the branch targets. That is, we're 480*7c478bd9Sstevel@tonic-gate * constructing this sequence in the trampoline: 481*7c478bd9Sstevel@tonic-gate * 482*7c478bd9Sstevel@tonic-gate * br[cc] %[rs], 1f 483*7c478bd9Sstevel@tonic-gate * <delay-instruction> 484*7c478bd9Sstevel@tonic-gate * ba,a <not-taken-destination> 485*7c478bd9Sstevel@tonic-gate * 1: ba,a <taken-destination> 486*7c478bd9Sstevel@tonic-gate * 487*7c478bd9Sstevel@tonic-gate */ 488*7c478bd9Sstevel@tonic-gate uintptr_t targ = FBT_BPRDEST(instr, first); 489*7c478bd9Sstevel@tonic-gate 490*7c478bd9Sstevel@tonic-gate *tinstr = first & ~(FBT_DISP16_MASK); 491*7c478bd9Sstevel@tonic-gate *tinstr |= FBT_DISP14(tinstr, &tinstr[3]); 492*7c478bd9Sstevel@tonic-gate tinstr++; 493*7c478bd9Sstevel@tonic-gate *tinstr++ = *(instr + 1); 494*7c478bd9Sstevel@tonic-gate *tinstr = FBT_BAA((uintptr_t)tinstr - base + va, 495*7c478bd9Sstevel@tonic-gate ret + sizeof (uint32_t)); 496*7c478bd9Sstevel@tonic-gate tinstr++; 497*7c478bd9Sstevel@tonic-gate *tinstr = FBT_BAA((uintptr_t)tinstr - base + va, targ); 498*7c478bd9Sstevel@tonic-gate tinstr++; 499*7c478bd9Sstevel@tonic-gate } 500*7c478bd9Sstevel@tonic-gate } 501*7c478bd9Sstevel@tonic-gate 502*7c478bd9Sstevel@tonic-gate tramp->fbtt_va += (uintptr_t)tinstr - tramp->fbtt_next; 503*7c478bd9Sstevel@tonic-gate tramp->fbtt_next = (uintptr_t)tinstr; 504*7c478bd9Sstevel@tonic-gate 505*7c478bd9Sstevel@tonic-gate return (1); 506*7c478bd9Sstevel@tonic-gate } 507*7c478bd9Sstevel@tonic-gate 508*7c478bd9Sstevel@tonic-gate /* 509*7c478bd9Sstevel@tonic-gate * We are patching control-transfer/restore couplets. There are three 510*7c478bd9Sstevel@tonic-gate * variants of couplet: 511*7c478bd9Sstevel@tonic-gate * 512*7c478bd9Sstevel@tonic-gate * (a) return rs1 + imm 513*7c478bd9Sstevel@tonic-gate * delay 514*7c478bd9Sstevel@tonic-gate * 515*7c478bd9Sstevel@tonic-gate * (b) jmpl rs1 + (rs2 | offset), rd 516*7c478bd9Sstevel@tonic-gate * restore rs1, rs2 | imm, rd 517*7c478bd9Sstevel@tonic-gate * 518*7c478bd9Sstevel@tonic-gate * (c) call displacement 519*7c478bd9Sstevel@tonic-gate * restore rs1, rs2 | imm, rd 520*7c478bd9Sstevel@tonic-gate * 521*7c478bd9Sstevel@tonic-gate * If rs1 in (a) is anything other than %i7, or imm is anything other than 8, 522*7c478bd9Sstevel@tonic-gate * or delay is a DCTI, we fail. If rd from the jmpl in (b) is something other 523*7c478bd9Sstevel@tonic-gate * than %g0 (a ret or a tail-call through a function pointer) or %o7 (a call 524*7c478bd9Sstevel@tonic-gate * through a register), we fail. 525*7c478bd9Sstevel@tonic-gate * 526*7c478bd9Sstevel@tonic-gate * Note that rs1 and rs2 in the restore instructions in (b) and (c) are 527*7c478bd9Sstevel@tonic-gate * potentially outputs and/or globals. Because these registers cannot be 528*7c478bd9Sstevel@tonic-gate * relied upon across the call to dtrace_probe(), we move rs1 into an unused 529*7c478bd9Sstevel@tonic-gate * local, ls0, and rs2 into an unused local, ls1, and restructure the restore 530*7c478bd9Sstevel@tonic-gate * to be: 531*7c478bd9Sstevel@tonic-gate * 532*7c478bd9Sstevel@tonic-gate * restore ls0, ls1, rd 533*7c478bd9Sstevel@tonic-gate * 534*7c478bd9Sstevel@tonic-gate * Likewise, rs1 and rs2 in the jmpl of case (b) may be outputs and/or globals. 535*7c478bd9Sstevel@tonic-gate * If the jmpl uses outputs or globals, we restructure it to be: 536*7c478bd9Sstevel@tonic-gate * 537*7c478bd9Sstevel@tonic-gate * jmpl ls2 + (ls3 | offset), (%g0 | %o7) 538*7c478bd9Sstevel@tonic-gate * 539*7c478bd9Sstevel@tonic-gate */ 540*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 541*7c478bd9Sstevel@tonic-gate static int 542*7c478bd9Sstevel@tonic-gate fbt_canpatch_return(uint32_t *instr, int offset, const char *name) 543*7c478bd9Sstevel@tonic-gate { 544*7c478bd9Sstevel@tonic-gate int rd; 545*7c478bd9Sstevel@tonic-gate 546*7c478bd9Sstevel@tonic-gate if (FBT_FMT3_OP(*instr) == FBT_OP_RETURN) { 547*7c478bd9Sstevel@tonic-gate uint32_t delay = *(instr + 1); 548*7c478bd9Sstevel@tonic-gate 549*7c478bd9Sstevel@tonic-gate if (*instr != FBT_RETURN(FBT_REG_I7, 8)) { 550*7c478bd9Sstevel@tonic-gate /* 551*7c478bd9Sstevel@tonic-gate * It's unclear if we should warn about this or not. 552*7c478bd9Sstevel@tonic-gate * We really wouldn't expect the compiler to generate 553*7c478bd9Sstevel@tonic-gate * return instructions with something other than %i7 554*7c478bd9Sstevel@tonic-gate * as rs1 and 8 as the simm13 -- it would just be 555*7c478bd9Sstevel@tonic-gate * mean-spirited. That said, such a construct isn't 556*7c478bd9Sstevel@tonic-gate * necessarily incorrect. Sill, we err on the side of 557*7c478bd9Sstevel@tonic-gate * caution and warn about it... 558*7c478bd9Sstevel@tonic-gate */ 559*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "cannot instrument return of %s at " 560*7c478bd9Sstevel@tonic-gate "%p: non-canonical return instruction", name, 561*7c478bd9Sstevel@tonic-gate (void *)instr); 562*7c478bd9Sstevel@tonic-gate return (0); 563*7c478bd9Sstevel@tonic-gate } 564*7c478bd9Sstevel@tonic-gate 565*7c478bd9Sstevel@tonic-gate if (FBT_IS_CTI(delay)) { 566*7c478bd9Sstevel@tonic-gate /* 567*7c478bd9Sstevel@tonic-gate * This is even weirder -- a DCTI coupled with a 568*7c478bd9Sstevel@tonic-gate * return instruction. Similar constructs are used to 569*7c478bd9Sstevel@tonic-gate * return from utraps, but these typically have the 570*7c478bd9Sstevel@tonic-gate * return in the slot -- and we wouldn't expect to see 571*7c478bd9Sstevel@tonic-gate * it in the kernel regardless. At any rate, we don't 572*7c478bd9Sstevel@tonic-gate * want to try to instrument this construct, whatever 573*7c478bd9Sstevel@tonic-gate * it may be. 574*7c478bd9Sstevel@tonic-gate */ 575*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "cannot instrument return of %s at " 576*7c478bd9Sstevel@tonic-gate "%p: CTI in delay slot of return instruction", 577*7c478bd9Sstevel@tonic-gate name, (void *)instr); 578*7c478bd9Sstevel@tonic-gate return (0); 579*7c478bd9Sstevel@tonic-gate } 580*7c478bd9Sstevel@tonic-gate 581*7c478bd9Sstevel@tonic-gate if (FBT_IS_PCRELATIVE(delay)) { 582*7c478bd9Sstevel@tonic-gate /* 583*7c478bd9Sstevel@tonic-gate * This is also very weird, but might be correct code 584*7c478bd9Sstevel@tonic-gate * if the function is (for example) returning the 585*7c478bd9Sstevel@tonic-gate * address of the delay instruction of the return as 586*7c478bd9Sstevel@tonic-gate * its return value (e.g. "rd %pc, %o0" in the slot). 587*7c478bd9Sstevel@tonic-gate * Perhaps correct, but still too weird to not warn 588*7c478bd9Sstevel@tonic-gate * about it... 589*7c478bd9Sstevel@tonic-gate */ 590*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "cannot instrument return of %s at " 591*7c478bd9Sstevel@tonic-gate "%p: PC-relative instruction in delay slot of " 592*7c478bd9Sstevel@tonic-gate "return instruction", name, (void *)instr); 593*7c478bd9Sstevel@tonic-gate return (0); 594*7c478bd9Sstevel@tonic-gate } 595*7c478bd9Sstevel@tonic-gate 596*7c478bd9Sstevel@tonic-gate return (1); 597*7c478bd9Sstevel@tonic-gate } 598*7c478bd9Sstevel@tonic-gate 599*7c478bd9Sstevel@tonic-gate if (FBT_FMT3_OP(*(instr + 1)) != FBT_OP_RESTORE) 600*7c478bd9Sstevel@tonic-gate return (0); 601*7c478bd9Sstevel@tonic-gate 602*7c478bd9Sstevel@tonic-gate if (FBT_FMT1_OP(*instr) == FBT_OP_CALL) 603*7c478bd9Sstevel@tonic-gate return (1); 604*7c478bd9Sstevel@tonic-gate 605*7c478bd9Sstevel@tonic-gate if (FBT_FMT3_OP(*instr) != FBT_OP_JMPL) 606*7c478bd9Sstevel@tonic-gate return (0); 607*7c478bd9Sstevel@tonic-gate 608*7c478bd9Sstevel@tonic-gate rd = FBT_FMT3_RD(*instr); 609*7c478bd9Sstevel@tonic-gate 610*7c478bd9Sstevel@tonic-gate if (rd == FBT_REG_I7 || rd == FBT_REG_O7 || rd == FBT_REG_G0) 611*7c478bd9Sstevel@tonic-gate return (1); 612*7c478bd9Sstevel@tonic-gate 613*7c478bd9Sstevel@tonic-gate /* 614*7c478bd9Sstevel@tonic-gate * We have encountered a jmpl that is storing the calling %pc in 615*7c478bd9Sstevel@tonic-gate * some register besides %i7, %o7 or %g0. This is strange; emit 616*7c478bd9Sstevel@tonic-gate * a warning and fail. 617*7c478bd9Sstevel@tonic-gate */ 618*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "cannot instrument return of %s at %p: unexpected " 619*7c478bd9Sstevel@tonic-gate "jmpl destination register", name, (void *)instr); 620*7c478bd9Sstevel@tonic-gate return (0); 621*7c478bd9Sstevel@tonic-gate } 622*7c478bd9Sstevel@tonic-gate 623*7c478bd9Sstevel@tonic-gate static int 624*7c478bd9Sstevel@tonic-gate fbt_canpatch_retl(uint32_t *instr, int offset, const char *name) 625*7c478bd9Sstevel@tonic-gate { 626*7c478bd9Sstevel@tonic-gate if (FBT_FMT1_OP(*instr) == FBT_OP_CALL || 627*7c478bd9Sstevel@tonic-gate (FBT_FMT3_OP(*instr) == FBT_OP_JMPL && 628*7c478bd9Sstevel@tonic-gate FBT_FMT3_RD(*instr) == FBT_REG_O7)) { 629*7c478bd9Sstevel@tonic-gate /* 630*7c478bd9Sstevel@tonic-gate * If this is a call (or a jmpl that links into %o7), we can 631*7c478bd9Sstevel@tonic-gate * patch it iff the next instruction uses %o7 as a destination 632*7c478bd9Sstevel@tonic-gate * register. Because there is an ABI responsibility to 633*7c478bd9Sstevel@tonic-gate * restore %o7 to the value before the call/jmpl, we don't 634*7c478bd9Sstevel@tonic-gate * particularly care how this routine is managing to restore 635*7c478bd9Sstevel@tonic-gate * it (mov, add, ld or divx for all we care). If it doesn't 636*7c478bd9Sstevel@tonic-gate * seem to be restoring it at all, however, we'll refuse 637*7c478bd9Sstevel@tonic-gate * to patch it. 638*7c478bd9Sstevel@tonic-gate */ 639*7c478bd9Sstevel@tonic-gate uint32_t delay = *(instr + 1); 640*7c478bd9Sstevel@tonic-gate uint32_t op, rd; 641*7c478bd9Sstevel@tonic-gate 642*7c478bd9Sstevel@tonic-gate op = FBT_FMT1_OP(delay); 643*7c478bd9Sstevel@tonic-gate rd = FBT_FMT3_RD(delay); 644*7c478bd9Sstevel@tonic-gate 645*7c478bd9Sstevel@tonic-gate if (op != FBT_OP2 || rd != FBT_REG_O7) { 646*7c478bd9Sstevel@tonic-gate /* 647*7c478bd9Sstevel@tonic-gate * This is odd. Before we assume that we're looking 648*7c478bd9Sstevel@tonic-gate * at something bizarre (and warn accordingly), we'll 649*7c478bd9Sstevel@tonic-gate * check to see if it's obviously a jump table entry. 650*7c478bd9Sstevel@tonic-gate */ 651*7c478bd9Sstevel@tonic-gate if (*instr < (uintptr_t)instr && 652*7c478bd9Sstevel@tonic-gate *instr >= (uintptr_t)instr - offset) 653*7c478bd9Sstevel@tonic-gate return (0); 654*7c478bd9Sstevel@tonic-gate 655*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "cannot instrument return of %s at " 656*7c478bd9Sstevel@tonic-gate "%p: leaf jmpl/call delay isn't restoring %%o7", 657*7c478bd9Sstevel@tonic-gate name, (void *)instr); 658*7c478bd9Sstevel@tonic-gate return (0); 659*7c478bd9Sstevel@tonic-gate } 660*7c478bd9Sstevel@tonic-gate 661*7c478bd9Sstevel@tonic-gate return (1); 662*7c478bd9Sstevel@tonic-gate } 663*7c478bd9Sstevel@tonic-gate 664*7c478bd9Sstevel@tonic-gate if (offset == sizeof (uint32_t)) { 665*7c478bd9Sstevel@tonic-gate /* 666*7c478bd9Sstevel@tonic-gate * If this is the second instruction in the function, we're 667*7c478bd9Sstevel@tonic-gate * going to allow it to be patched if the first instruction 668*7c478bd9Sstevel@tonic-gate * is a patchable return-from-leaf instruction. 669*7c478bd9Sstevel@tonic-gate */ 670*7c478bd9Sstevel@tonic-gate if (fbt_canpatch_retl(instr - 1, 0, name)) 671*7c478bd9Sstevel@tonic-gate return (1); 672*7c478bd9Sstevel@tonic-gate } 673*7c478bd9Sstevel@tonic-gate 674*7c478bd9Sstevel@tonic-gate if (FBT_FMT3_OP(*instr) != FBT_OP_JMPL) 675*7c478bd9Sstevel@tonic-gate return (0); 676*7c478bd9Sstevel@tonic-gate 677*7c478bd9Sstevel@tonic-gate if (FBT_FMT3_RD(*instr) != FBT_REG_G0) 678*7c478bd9Sstevel@tonic-gate return (0); 679*7c478bd9Sstevel@tonic-gate 680*7c478bd9Sstevel@tonic-gate return (1); 681*7c478bd9Sstevel@tonic-gate } 682*7c478bd9Sstevel@tonic-gate 683*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 684*7c478bd9Sstevel@tonic-gate static uint32_t 685*7c478bd9Sstevel@tonic-gate fbt_patch_return(uint32_t *instr, uint32_t *funcbase, uint32_t *funclim, 686*7c478bd9Sstevel@tonic-gate int offset, uint32_t id, fbt_trampoline_t *tramp, const char *name) 687*7c478bd9Sstevel@tonic-gate { 688*7c478bd9Sstevel@tonic-gate uint32_t *tinstr = (uint32_t *)tramp->fbtt_next; 689*7c478bd9Sstevel@tonic-gate uint32_t cti = *instr, restore = *(instr + 1), rs1, dest; 690*7c478bd9Sstevel@tonic-gate uintptr_t va = tramp->fbtt_va; 691*7c478bd9Sstevel@tonic-gate uintptr_t base = tramp->fbtt_next; 692*7c478bd9Sstevel@tonic-gate uint32_t locals[FBT_REG_NLOCALS], local; 693*7c478bd9Sstevel@tonic-gate 694*7c478bd9Sstevel@tonic-gate if (tramp->fbtt_next + FBT_RETENT_MAXSIZE > tramp->fbtt_limit) { 695*7c478bd9Sstevel@tonic-gate /* 696*7c478bd9Sstevel@tonic-gate * There isn't sufficient room for this entry; return failure. 697*7c478bd9Sstevel@tonic-gate */ 698*7c478bd9Sstevel@tonic-gate return (FBT_ILLTRAP); 699*7c478bd9Sstevel@tonic-gate } 700*7c478bd9Sstevel@tonic-gate 701*7c478bd9Sstevel@tonic-gate FBT_COUNTER(id, fbt_ret); 702*7c478bd9Sstevel@tonic-gate 703*7c478bd9Sstevel@tonic-gate if (FBT_FMT3_OP(*instr) == FBT_OP_RETURN) { 704*7c478bd9Sstevel@tonic-gate /* 705*7c478bd9Sstevel@tonic-gate * To handle the case of the return instruction, we'll emit a 706*7c478bd9Sstevel@tonic-gate * restore, followed by the instruction in the slot (which 707*7c478bd9Sstevel@tonic-gate * we'll transplant here), and then another save. While it 708*7c478bd9Sstevel@tonic-gate * may seem intellectually unsatisfying to emit the additional 709*7c478bd9Sstevel@tonic-gate * restore/save couplet, one can take solace in the fact that 710*7c478bd9Sstevel@tonic-gate * we don't do this if the instruction in the return delay 711*7c478bd9Sstevel@tonic-gate * slot is a nop -- which it is nearly 90% of the time with 712*7c478bd9Sstevel@tonic-gate * gcc. (And besides, this couplet can't induce unnecessary 713*7c478bd9Sstevel@tonic-gate * spill/fill traps; rewriting the delay instruction to be 714*7c478bd9Sstevel@tonic-gate * in terms of the current window hardly seems worth the 715*7c478bd9Sstevel@tonic-gate * trouble -- let alone the risk.) 716*7c478bd9Sstevel@tonic-gate */ 717*7c478bd9Sstevel@tonic-gate uint32_t delay = *(instr + 1); 718*7c478bd9Sstevel@tonic-gate ASSERT(*instr == FBT_RETURN(FBT_REG_I7, 8)); 719*7c478bd9Sstevel@tonic-gate 720*7c478bd9Sstevel@tonic-gate cti = FBT_RET; 721*7c478bd9Sstevel@tonic-gate restore = FBT_RESTORE(FBT_REG_G0, FBT_REG_G0, FBT_REG_G0); 722*7c478bd9Sstevel@tonic-gate 723*7c478bd9Sstevel@tonic-gate if (delay != FBT_SETHI(0, FBT_REG_G0)) { 724*7c478bd9Sstevel@tonic-gate *tinstr++ = restore; 725*7c478bd9Sstevel@tonic-gate *tinstr++ = delay; 726*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_SAVEIMM(FBT_REG_O6, 727*7c478bd9Sstevel@tonic-gate -SA(MINFRAME), FBT_REG_O6); 728*7c478bd9Sstevel@tonic-gate } 729*7c478bd9Sstevel@tonic-gate } 730*7c478bd9Sstevel@tonic-gate 731*7c478bd9Sstevel@tonic-gate FBT_REG_INITLOCALS(local, locals); 732*7c478bd9Sstevel@tonic-gate 733*7c478bd9Sstevel@tonic-gate /* 734*7c478bd9Sstevel@tonic-gate * Mark the locals used in the jmpl. 735*7c478bd9Sstevel@tonic-gate */ 736*7c478bd9Sstevel@tonic-gate if (FBT_FMT3_OP(cti) == FBT_OP_JMPL) { 737*7c478bd9Sstevel@tonic-gate uint32_t rs1 = FBT_FMT3_RS1(cti); 738*7c478bd9Sstevel@tonic-gate FBT_REG_MARKLOCAL(locals, rs1); 739*7c478bd9Sstevel@tonic-gate 740*7c478bd9Sstevel@tonic-gate if (!FBT_FMT3_ISIMM(cti)) { 741*7c478bd9Sstevel@tonic-gate uint32_t rs2 = FBT_FMT3_RS2(cti); 742*7c478bd9Sstevel@tonic-gate FBT_REG_MARKLOCAL(locals, rs2); 743*7c478bd9Sstevel@tonic-gate } 744*7c478bd9Sstevel@tonic-gate } 745*7c478bd9Sstevel@tonic-gate 746*7c478bd9Sstevel@tonic-gate /* 747*7c478bd9Sstevel@tonic-gate * And mark the locals used in the restore. 748*7c478bd9Sstevel@tonic-gate */ 749*7c478bd9Sstevel@tonic-gate rs1 = FBT_FMT3_RS1(restore); 750*7c478bd9Sstevel@tonic-gate FBT_REG_MARKLOCAL(locals, rs1); 751*7c478bd9Sstevel@tonic-gate 752*7c478bd9Sstevel@tonic-gate if (!FBT_FMT3_ISIMM(restore)) { 753*7c478bd9Sstevel@tonic-gate uint32_t rs2 = FBT_FMT3_RS2(restore); 754*7c478bd9Sstevel@tonic-gate FBT_REG_MARKLOCAL(locals, rs2); 755*7c478bd9Sstevel@tonic-gate } 756*7c478bd9Sstevel@tonic-gate 757*7c478bd9Sstevel@tonic-gate if (FBT_FMT3_OP(cti) == FBT_OP_JMPL) { 758*7c478bd9Sstevel@tonic-gate uint32_t rs1 = FBT_FMT3_RS1(cti); 759*7c478bd9Sstevel@tonic-gate 760*7c478bd9Sstevel@tonic-gate if (FBT_REG_ISVOLATILE(rs1)) { 761*7c478bd9Sstevel@tonic-gate FBT_REG_ALLOCLOCAL(local, locals); 762*7c478bd9Sstevel@tonic-gate FBT_FMT3_RS1_SET(cti, local); 763*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_MOV(rs1, local); 764*7c478bd9Sstevel@tonic-gate } 765*7c478bd9Sstevel@tonic-gate 766*7c478bd9Sstevel@tonic-gate if (!FBT_FMT3_ISIMM(cti)) { 767*7c478bd9Sstevel@tonic-gate uint32_t rs2 = FBT_FMT3_RS2(cti); 768*7c478bd9Sstevel@tonic-gate 769*7c478bd9Sstevel@tonic-gate if (FBT_REG_ISVOLATILE(rs2)) { 770*7c478bd9Sstevel@tonic-gate FBT_REG_ALLOCLOCAL(local, locals); 771*7c478bd9Sstevel@tonic-gate FBT_FMT3_RS2_SET(cti, local); 772*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_MOV(rs2, local); 773*7c478bd9Sstevel@tonic-gate } 774*7c478bd9Sstevel@tonic-gate } 775*7c478bd9Sstevel@tonic-gate } 776*7c478bd9Sstevel@tonic-gate 777*7c478bd9Sstevel@tonic-gate rs1 = FBT_FMT3_RS1(restore); 778*7c478bd9Sstevel@tonic-gate 779*7c478bd9Sstevel@tonic-gate if (FBT_REG_ISVOLATILE(rs1)) { 780*7c478bd9Sstevel@tonic-gate FBT_REG_ALLOCLOCAL(local, locals); 781*7c478bd9Sstevel@tonic-gate FBT_FMT3_RS1_SET(restore, local); 782*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_MOV(rs1, local); 783*7c478bd9Sstevel@tonic-gate } 784*7c478bd9Sstevel@tonic-gate 785*7c478bd9Sstevel@tonic-gate if (!FBT_FMT3_ISIMM(restore)) { 786*7c478bd9Sstevel@tonic-gate uint32_t rs2 = FBT_FMT3_RS2(restore); 787*7c478bd9Sstevel@tonic-gate 788*7c478bd9Sstevel@tonic-gate if (FBT_REG_ISVOLATILE(rs2)) { 789*7c478bd9Sstevel@tonic-gate FBT_REG_ALLOCLOCAL(local, locals); 790*7c478bd9Sstevel@tonic-gate FBT_FMT3_RS2_SET(restore, local); 791*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_MOV(rs2, local); 792*7c478bd9Sstevel@tonic-gate } 793*7c478bd9Sstevel@tonic-gate } 794*7c478bd9Sstevel@tonic-gate 795*7c478bd9Sstevel@tonic-gate if (id > (uint32_t)FBT_SIMM13_MAX) { 796*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_SETHI(id, FBT_REG_O0); 797*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_ORLO(FBT_REG_O0, id, FBT_REG_O0); 798*7c478bd9Sstevel@tonic-gate } else { 799*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_ORSIMM13(FBT_REG_G0, id, FBT_REG_O0); 800*7c478bd9Sstevel@tonic-gate } 801*7c478bd9Sstevel@tonic-gate 802*7c478bd9Sstevel@tonic-gate if (offset > (uint32_t)FBT_SIMM13_MAX) { 803*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_SETHI(offset, FBT_REG_O1); 804*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_ORLO(FBT_REG_O1, offset, FBT_REG_O1); 805*7c478bd9Sstevel@tonic-gate } else { 806*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_ORSIMM13(FBT_REG_G0, offset, FBT_REG_O1); 807*7c478bd9Sstevel@tonic-gate } 808*7c478bd9Sstevel@tonic-gate 809*7c478bd9Sstevel@tonic-gate *tinstr = FBT_CALL((uintptr_t)tinstr - base + va, dtrace_probe); 810*7c478bd9Sstevel@tonic-gate tinstr++; 811*7c478bd9Sstevel@tonic-gate 812*7c478bd9Sstevel@tonic-gate if (FBT_FMT3_RD(restore) == FBT_REG_O0) { 813*7c478bd9Sstevel@tonic-gate /* 814*7c478bd9Sstevel@tonic-gate * If the destination register of the restore is %o0, we 815*7c478bd9Sstevel@tonic-gate * need to perform the implied calculation to derive the 816*7c478bd9Sstevel@tonic-gate * return value. 817*7c478bd9Sstevel@tonic-gate */ 818*7c478bd9Sstevel@tonic-gate uint32_t add = (restore & ~FBT_FMT3_OP_MASK) | FBT_OP_ADD; 819*7c478bd9Sstevel@tonic-gate add &= ~FBT_FMT3_RD_MASK; 820*7c478bd9Sstevel@tonic-gate *tinstr++ = add | (FBT_REG_O2 << FBT_FMT3_RD_SHIFT); 821*7c478bd9Sstevel@tonic-gate } else { 822*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_MOV(FBT_REG_I0, FBT_REG_O2); 823*7c478bd9Sstevel@tonic-gate } 824*7c478bd9Sstevel@tonic-gate 825*7c478bd9Sstevel@tonic-gate /* 826*7c478bd9Sstevel@tonic-gate * If the control transfer instruction is %pc-relative (i.e. a 827*7c478bd9Sstevel@tonic-gate * call), we need to reset it appropriately. 828*7c478bd9Sstevel@tonic-gate */ 829*7c478bd9Sstevel@tonic-gate if (FBT_FMT1_OP(cti) == FBT_OP_CALL) { 830*7c478bd9Sstevel@tonic-gate dest = (uintptr_t)instr + (FBT_FMT1_DISP30(cti) << 2); 831*7c478bd9Sstevel@tonic-gate *tinstr = FBT_CALL((uintptr_t)tinstr - base + va, dest); 832*7c478bd9Sstevel@tonic-gate tinstr++; 833*7c478bd9Sstevel@tonic-gate } else { 834*7c478bd9Sstevel@tonic-gate *tinstr++ = cti; 835*7c478bd9Sstevel@tonic-gate } 836*7c478bd9Sstevel@tonic-gate 837*7c478bd9Sstevel@tonic-gate *tinstr++ = restore; 838*7c478bd9Sstevel@tonic-gate tramp->fbtt_va += (uintptr_t)tinstr - tramp->fbtt_next; 839*7c478bd9Sstevel@tonic-gate tramp->fbtt_next = (uintptr_t)tinstr; 840*7c478bd9Sstevel@tonic-gate 841*7c478bd9Sstevel@tonic-gate return (FBT_BAA(instr, va)); 842*7c478bd9Sstevel@tonic-gate } 843*7c478bd9Sstevel@tonic-gate 844*7c478bd9Sstevel@tonic-gate static uint32_t 845*7c478bd9Sstevel@tonic-gate fbt_patch_retl(uint32_t *instr, uint32_t *funcbase, uint32_t *funclim, 846*7c478bd9Sstevel@tonic-gate int offset, uint32_t id, fbt_trampoline_t *tramp, const char *name) 847*7c478bd9Sstevel@tonic-gate { 848*7c478bd9Sstevel@tonic-gate uint32_t *tinstr = (uint32_t *)tramp->fbtt_next; 849*7c478bd9Sstevel@tonic-gate uintptr_t va = tramp->fbtt_va; 850*7c478bd9Sstevel@tonic-gate uintptr_t base = tramp->fbtt_next; 851*7c478bd9Sstevel@tonic-gate uint32_t cti = *instr, dest; 852*7c478bd9Sstevel@tonic-gate int annul = 0; 853*7c478bd9Sstevel@tonic-gate 854*7c478bd9Sstevel@tonic-gate FBT_COUNTER(id, fbt_retl); 855*7c478bd9Sstevel@tonic-gate 856*7c478bd9Sstevel@tonic-gate if (tramp->fbtt_next + FBT_RETLENT_MAXSIZE > tramp->fbtt_limit) { 857*7c478bd9Sstevel@tonic-gate /* 858*7c478bd9Sstevel@tonic-gate * There isn't sufficient room for this entry; return failure. 859*7c478bd9Sstevel@tonic-gate */ 860*7c478bd9Sstevel@tonic-gate return (FBT_ILLTRAP); 861*7c478bd9Sstevel@tonic-gate } 862*7c478bd9Sstevel@tonic-gate 863*7c478bd9Sstevel@tonic-gate if (offset == sizeof (uint32_t) && 864*7c478bd9Sstevel@tonic-gate fbt_canpatch_retl(instr - 1, 0, name)) { 865*7c478bd9Sstevel@tonic-gate *tinstr++ = *instr; 866*7c478bd9Sstevel@tonic-gate annul = 1; 867*7c478bd9Sstevel@tonic-gate FBT_COUNTER(id, fbt_retl_twoinstr); 868*7c478bd9Sstevel@tonic-gate } else { 869*7c478bd9Sstevel@tonic-gate if (FBT_FMT3_OP(cti) == FBT_OP_JMPL && 870*7c478bd9Sstevel@tonic-gate FBT_FMT3_RD(cti) != FBT_REG_O7 && 871*7c478bd9Sstevel@tonic-gate FBT_FMT3_RS1(cti) != FBT_REG_O7) { 872*7c478bd9Sstevel@tonic-gate annul = 1; 873*7c478bd9Sstevel@tonic-gate *tinstr++ = *(instr + 1); 874*7c478bd9Sstevel@tonic-gate } 875*7c478bd9Sstevel@tonic-gate } 876*7c478bd9Sstevel@tonic-gate 877*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_SAVEIMM(FBT_REG_O6, -SA(MINFRAME), FBT_REG_O6); 878*7c478bd9Sstevel@tonic-gate 879*7c478bd9Sstevel@tonic-gate if (FBT_FMT3_OP(cti) == FBT_OP_JMPL) { 880*7c478bd9Sstevel@tonic-gate uint32_t rs1, rs2, o2i = FBT_REG_I0 - FBT_REG_O0; 881*7c478bd9Sstevel@tonic-gate 882*7c478bd9Sstevel@tonic-gate /* 883*7c478bd9Sstevel@tonic-gate * If we have a jmpl and it's in terms of output registers, we 884*7c478bd9Sstevel@tonic-gate * need to rewrite it to be in terms of the corresponding input 885*7c478bd9Sstevel@tonic-gate * registers. If it's in terms of the globals, we'll rewrite 886*7c478bd9Sstevel@tonic-gate * it to be in terms of locals. 887*7c478bd9Sstevel@tonic-gate */ 888*7c478bd9Sstevel@tonic-gate rs1 = FBT_FMT3_RS1(cti); 889*7c478bd9Sstevel@tonic-gate 890*7c478bd9Sstevel@tonic-gate if (FBT_REG_ISOUTPUT(rs1)) 891*7c478bd9Sstevel@tonic-gate rs1 += o2i; 892*7c478bd9Sstevel@tonic-gate 893*7c478bd9Sstevel@tonic-gate if (FBT_REG_ISGLOBAL(rs1)) { 894*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_MOV(rs1, FBT_REG_L0); 895*7c478bd9Sstevel@tonic-gate rs1 = FBT_REG_L0; 896*7c478bd9Sstevel@tonic-gate } 897*7c478bd9Sstevel@tonic-gate 898*7c478bd9Sstevel@tonic-gate FBT_FMT3_RS1_SET(cti, rs1); 899*7c478bd9Sstevel@tonic-gate 900*7c478bd9Sstevel@tonic-gate if (!FBT_FMT3_ISIMM(cti)) { 901*7c478bd9Sstevel@tonic-gate rs2 = FBT_FMT3_RS2(cti); 902*7c478bd9Sstevel@tonic-gate 903*7c478bd9Sstevel@tonic-gate if (FBT_REG_ISOUTPUT(rs2)) 904*7c478bd9Sstevel@tonic-gate rs2 += o2i; 905*7c478bd9Sstevel@tonic-gate 906*7c478bd9Sstevel@tonic-gate if (FBT_REG_ISGLOBAL(rs2)) { 907*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_MOV(rs2, FBT_REG_L1); 908*7c478bd9Sstevel@tonic-gate rs2 = FBT_REG_L1; 909*7c478bd9Sstevel@tonic-gate } 910*7c478bd9Sstevel@tonic-gate 911*7c478bd9Sstevel@tonic-gate FBT_FMT3_RS2_SET(cti, rs2); 912*7c478bd9Sstevel@tonic-gate } 913*7c478bd9Sstevel@tonic-gate 914*7c478bd9Sstevel@tonic-gate /* 915*7c478bd9Sstevel@tonic-gate * Now we need to check the rd and source register for the jmpl; 916*7c478bd9Sstevel@tonic-gate * If neither rd nor the source register is %o7, then we might 917*7c478bd9Sstevel@tonic-gate * have a jmp that is actually part of a jump table. We need 918*7c478bd9Sstevel@tonic-gate * to generate the code to compare it to the base and limit of 919*7c478bd9Sstevel@tonic-gate * the function. 920*7c478bd9Sstevel@tonic-gate */ 921*7c478bd9Sstevel@tonic-gate if (FBT_FMT3_RD(cti) != FBT_REG_O7 && rs1 != FBT_REG_I7) { 922*7c478bd9Sstevel@tonic-gate uintptr_t base = (uintptr_t)funcbase; 923*7c478bd9Sstevel@tonic-gate uintptr_t limit = (uintptr_t)funclim; 924*7c478bd9Sstevel@tonic-gate 925*7c478bd9Sstevel@tonic-gate FBT_COUNTER(id, fbt_retl_jmptab); 926*7c478bd9Sstevel@tonic-gate 927*7c478bd9Sstevel@tonic-gate if (FBT_FMT3_ISIMM(cti)) { 928*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_ADDSIMM13(rs1, 929*7c478bd9Sstevel@tonic-gate FBT_FMT3_SIMM13(cti), FBT_REG_L2); 930*7c478bd9Sstevel@tonic-gate } else { 931*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_ADD(rs1, rs2, FBT_REG_L2); 932*7c478bd9Sstevel@tonic-gate } 933*7c478bd9Sstevel@tonic-gate 934*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_SETHI(base, FBT_REG_L3); 935*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_ORLO(FBT_REG_L3, base, FBT_REG_L3); 936*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_CMP(FBT_REG_L2, FBT_REG_L3); 937*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_BL(0, 8 * sizeof (uint32_t)); 938*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_SETHI(limit, FBT_REG_L3); 939*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_ORLO(FBT_REG_L3, limit, FBT_REG_L3); 940*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_CMP(FBT_REG_L2, FBT_REG_L3); 941*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_BGE(0, 4 * sizeof (uint32_t)); 942*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_SETHI(0, FBT_REG_G0); 943*7c478bd9Sstevel@tonic-gate *tinstr++ = cti; 944*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_RESTORE(FBT_REG_G0, 945*7c478bd9Sstevel@tonic-gate FBT_REG_G0, FBT_REG_G0); 946*7c478bd9Sstevel@tonic-gate } 947*7c478bd9Sstevel@tonic-gate } 948*7c478bd9Sstevel@tonic-gate 949*7c478bd9Sstevel@tonic-gate if (id > (uint32_t)FBT_SIMM13_MAX) { 950*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_SETHI(id, FBT_REG_O0); 951*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_ORLO(FBT_REG_O0, id, FBT_REG_O0); 952*7c478bd9Sstevel@tonic-gate } else { 953*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_ORSIMM13(FBT_REG_G0, id, FBT_REG_O0); 954*7c478bd9Sstevel@tonic-gate } 955*7c478bd9Sstevel@tonic-gate 956*7c478bd9Sstevel@tonic-gate if (offset > (uint32_t)FBT_SIMM13_MAX) { 957*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_SETHI(offset, FBT_REG_O1); 958*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_ORLO(FBT_REG_O1, offset, FBT_REG_O1); 959*7c478bd9Sstevel@tonic-gate } else { 960*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_ORSIMM13(FBT_REG_G0, offset, FBT_REG_O1); 961*7c478bd9Sstevel@tonic-gate } 962*7c478bd9Sstevel@tonic-gate 963*7c478bd9Sstevel@tonic-gate *tinstr = FBT_CALL((uintptr_t)tinstr - base + va, dtrace_probe); 964*7c478bd9Sstevel@tonic-gate tinstr++; 965*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_MOV(FBT_REG_I0, FBT_REG_O2); 966*7c478bd9Sstevel@tonic-gate 967*7c478bd9Sstevel@tonic-gate /* 968*7c478bd9Sstevel@tonic-gate * If the control transfer instruction is %pc-relative (i.e. a 969*7c478bd9Sstevel@tonic-gate * call), we need to reset it appropriately. 970*7c478bd9Sstevel@tonic-gate */ 971*7c478bd9Sstevel@tonic-gate if (FBT_FMT1_OP(cti) == FBT_OP_CALL) { 972*7c478bd9Sstevel@tonic-gate FBT_COUNTER(id, fbt_retl_tailcall); 973*7c478bd9Sstevel@tonic-gate dest = (uintptr_t)instr + (FBT_FMT1_DISP30(cti) << 2); 974*7c478bd9Sstevel@tonic-gate *tinstr = FBT_CALL((uintptr_t)tinstr - base + va, dest); 975*7c478bd9Sstevel@tonic-gate tinstr++; 976*7c478bd9Sstevel@tonic-gate annul = 1; 977*7c478bd9Sstevel@tonic-gate } else { 978*7c478bd9Sstevel@tonic-gate if (FBT_FMT3_OP(cti) == FBT_OP_JMPL) { 979*7c478bd9Sstevel@tonic-gate *tinstr++ = cti; 980*7c478bd9Sstevel@tonic-gate 981*7c478bd9Sstevel@tonic-gate if (FBT_FMT3_RD(cti) == FBT_REG_O7) { 982*7c478bd9Sstevel@tonic-gate FBT_COUNTER(id, fbt_retl_tailjmpl); 983*7c478bd9Sstevel@tonic-gate annul = 1; 984*7c478bd9Sstevel@tonic-gate } 985*7c478bd9Sstevel@tonic-gate } else { 986*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_RET; 987*7c478bd9Sstevel@tonic-gate } 988*7c478bd9Sstevel@tonic-gate } 989*7c478bd9Sstevel@tonic-gate 990*7c478bd9Sstevel@tonic-gate *tinstr++ = FBT_RESTORE(FBT_REG_G0, FBT_REG_G0, FBT_REG_G0); 991*7c478bd9Sstevel@tonic-gate 992*7c478bd9Sstevel@tonic-gate tramp->fbtt_va += (uintptr_t)tinstr - tramp->fbtt_next; 993*7c478bd9Sstevel@tonic-gate tramp->fbtt_next = (uintptr_t)tinstr; 994*7c478bd9Sstevel@tonic-gate 995*7c478bd9Sstevel@tonic-gate return (annul ? FBT_BAA(instr, va) : FBT_BA(instr, va)); 996*7c478bd9Sstevel@tonic-gate } 997*7c478bd9Sstevel@tonic-gate 998*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 999*7c478bd9Sstevel@tonic-gate static void 1000*7c478bd9Sstevel@tonic-gate fbt_provide_module(void *arg, struct modctl *ctl) 1001*7c478bd9Sstevel@tonic-gate { 1002*7c478bd9Sstevel@tonic-gate struct module *mp = ctl->mod_mp; 1003*7c478bd9Sstevel@tonic-gate char *modname = ctl->mod_modname; 1004*7c478bd9Sstevel@tonic-gate char *str = mp->strings; 1005*7c478bd9Sstevel@tonic-gate int nsyms = mp->nsyms; 1006*7c478bd9Sstevel@tonic-gate Shdr *symhdr = mp->symhdr; 1007*7c478bd9Sstevel@tonic-gate size_t symsize; 1008*7c478bd9Sstevel@tonic-gate char *name; 1009*7c478bd9Sstevel@tonic-gate int i; 1010*7c478bd9Sstevel@tonic-gate fbt_probe_t *fbt, *retfbt; 1011*7c478bd9Sstevel@tonic-gate fbt_trampoline_t tramp; 1012*7c478bd9Sstevel@tonic-gate uintptr_t offset; 1013*7c478bd9Sstevel@tonic-gate int primary = 0; 1014*7c478bd9Sstevel@tonic-gate ctf_file_t *fp = NULL; 1015*7c478bd9Sstevel@tonic-gate int error; 1016*7c478bd9Sstevel@tonic-gate int estimate = 1; 1017*7c478bd9Sstevel@tonic-gate uint32_t faketramp[50]; 1018*7c478bd9Sstevel@tonic-gate size_t fbt_size = 0; 1019*7c478bd9Sstevel@tonic-gate 1020*7c478bd9Sstevel@tonic-gate /* 1021*7c478bd9Sstevel@tonic-gate * Employees of dtrace and their families are ineligible. Void 1022*7c478bd9Sstevel@tonic-gate * where prohibited. 1023*7c478bd9Sstevel@tonic-gate */ 1024*7c478bd9Sstevel@tonic-gate if (strcmp(modname, "dtrace") == 0) 1025*7c478bd9Sstevel@tonic-gate return; 1026*7c478bd9Sstevel@tonic-gate 1027*7c478bd9Sstevel@tonic-gate if (ctl->mod_requisites != NULL) { 1028*7c478bd9Sstevel@tonic-gate struct modctl_list *list; 1029*7c478bd9Sstevel@tonic-gate 1030*7c478bd9Sstevel@tonic-gate list = (struct modctl_list *)ctl->mod_requisites; 1031*7c478bd9Sstevel@tonic-gate 1032*7c478bd9Sstevel@tonic-gate for (; list != NULL; list = list->modl_next) { 1033*7c478bd9Sstevel@tonic-gate if (strcmp(list->modl_modp->mod_modname, "dtrace") == 0) 1034*7c478bd9Sstevel@tonic-gate return; 1035*7c478bd9Sstevel@tonic-gate } 1036*7c478bd9Sstevel@tonic-gate } 1037*7c478bd9Sstevel@tonic-gate 1038*7c478bd9Sstevel@tonic-gate /* 1039*7c478bd9Sstevel@tonic-gate * KMDB is ineligible for instrumentation -- it may execute in 1040*7c478bd9Sstevel@tonic-gate * any context, including probe context. 1041*7c478bd9Sstevel@tonic-gate */ 1042*7c478bd9Sstevel@tonic-gate if (strcmp(modname, "kmdbmod") == 0) 1043*7c478bd9Sstevel@tonic-gate return; 1044*7c478bd9Sstevel@tonic-gate 1045*7c478bd9Sstevel@tonic-gate if (str == NULL || symhdr == NULL || symhdr->sh_addr == NULL) { 1046*7c478bd9Sstevel@tonic-gate /* 1047*7c478bd9Sstevel@tonic-gate * If this module doesn't (yet) have its string or symbol 1048*7c478bd9Sstevel@tonic-gate * table allocated, clear out. 1049*7c478bd9Sstevel@tonic-gate */ 1050*7c478bd9Sstevel@tonic-gate return; 1051*7c478bd9Sstevel@tonic-gate } 1052*7c478bd9Sstevel@tonic-gate 1053*7c478bd9Sstevel@tonic-gate symsize = symhdr->sh_entsize; 1054*7c478bd9Sstevel@tonic-gate 1055*7c478bd9Sstevel@tonic-gate if (mp->fbt_nentries) { 1056*7c478bd9Sstevel@tonic-gate /* 1057*7c478bd9Sstevel@tonic-gate * This module has some FBT entries allocated; we're afraid 1058*7c478bd9Sstevel@tonic-gate * to screw with it. 1059*7c478bd9Sstevel@tonic-gate */ 1060*7c478bd9Sstevel@tonic-gate return; 1061*7c478bd9Sstevel@tonic-gate } 1062*7c478bd9Sstevel@tonic-gate 1063*7c478bd9Sstevel@tonic-gate if (mp->fbt_tab != NULL) 1064*7c478bd9Sstevel@tonic-gate estimate = 0; 1065*7c478bd9Sstevel@tonic-gate 1066*7c478bd9Sstevel@tonic-gate /* 1067*7c478bd9Sstevel@tonic-gate * This is a hack for unix/genunix/krtld. 1068*7c478bd9Sstevel@tonic-gate */ 1069*7c478bd9Sstevel@tonic-gate primary = vmem_contains(heap_arena, (void *)ctl, 1070*7c478bd9Sstevel@tonic-gate sizeof (struct modctl)) == 0; 1071*7c478bd9Sstevel@tonic-gate kobj_textwin_alloc(mp); 1072*7c478bd9Sstevel@tonic-gate 1073*7c478bd9Sstevel@tonic-gate /* 1074*7c478bd9Sstevel@tonic-gate * Open the CTF data for the module. We'll use this to determine the 1075*7c478bd9Sstevel@tonic-gate * functions that can be instrumented. Note that this call can fail, 1076*7c478bd9Sstevel@tonic-gate * in which case we'll use heuristics to determine the functions that 1077*7c478bd9Sstevel@tonic-gate * can be instrumented. (But in particular, leaf functions will not be 1078*7c478bd9Sstevel@tonic-gate * instrumented.) 1079*7c478bd9Sstevel@tonic-gate */ 1080*7c478bd9Sstevel@tonic-gate fp = ctf_modopen(mp, &error); 1081*7c478bd9Sstevel@tonic-gate 1082*7c478bd9Sstevel@tonic-gate forreal: 1083*7c478bd9Sstevel@tonic-gate if (!estimate) { 1084*7c478bd9Sstevel@tonic-gate tramp.fbtt_next = 1085*7c478bd9Sstevel@tonic-gate (uintptr_t)fbt_trampoline_map((uintptr_t)mp->fbt_tab, 1086*7c478bd9Sstevel@tonic-gate mp->fbt_size); 1087*7c478bd9Sstevel@tonic-gate tramp.fbtt_limit = tramp.fbtt_next + mp->fbt_size; 1088*7c478bd9Sstevel@tonic-gate tramp.fbtt_va = (uintptr_t)mp->fbt_tab; 1089*7c478bd9Sstevel@tonic-gate } 1090*7c478bd9Sstevel@tonic-gate 1091*7c478bd9Sstevel@tonic-gate for (i = 1; i < nsyms; i++) { 1092*7c478bd9Sstevel@tonic-gate ctf_funcinfo_t f; 1093*7c478bd9Sstevel@tonic-gate uint32_t *instr, *base, *limit; 1094*7c478bd9Sstevel@tonic-gate Sym *sym = (Sym *)(symhdr->sh_addr + i * symsize); 1095*7c478bd9Sstevel@tonic-gate int have_ctf = 0, is_leaf = 0, nargs, cti = 0; 1096*7c478bd9Sstevel@tonic-gate int (*canpatch)(uint32_t *, int, const char *); 1097*7c478bd9Sstevel@tonic-gate uint32_t (*patch)(uint32_t *, uint32_t *, uint32_t *, int, 1098*7c478bd9Sstevel@tonic-gate uint32_t, fbt_trampoline_t *, const char *); 1099*7c478bd9Sstevel@tonic-gate 1100*7c478bd9Sstevel@tonic-gate if (ELF_ST_TYPE(sym->st_info) != STT_FUNC) 1101*7c478bd9Sstevel@tonic-gate continue; 1102*7c478bd9Sstevel@tonic-gate 1103*7c478bd9Sstevel@tonic-gate /* 1104*7c478bd9Sstevel@tonic-gate * Weak symbols are not candidates. This could be made to 1105*7c478bd9Sstevel@tonic-gate * work (where weak functions and their underlying function 1106*7c478bd9Sstevel@tonic-gate * appear as two disjoint probes), but it's not simple. 1107*7c478bd9Sstevel@tonic-gate */ 1108*7c478bd9Sstevel@tonic-gate if (ELF_ST_BIND(sym->st_info) == STB_WEAK) 1109*7c478bd9Sstevel@tonic-gate continue; 1110*7c478bd9Sstevel@tonic-gate 1111*7c478bd9Sstevel@tonic-gate name = str + sym->st_name; 1112*7c478bd9Sstevel@tonic-gate 1113*7c478bd9Sstevel@tonic-gate if (strstr(name, "dtrace_") == name && 1114*7c478bd9Sstevel@tonic-gate strstr(name, "dtrace_safe_") != name) { 1115*7c478bd9Sstevel@tonic-gate /* 1116*7c478bd9Sstevel@tonic-gate * Anything beginning with "dtrace_" may be called 1117*7c478bd9Sstevel@tonic-gate * from probe context unless it explitly indicates 1118*7c478bd9Sstevel@tonic-gate * that it won't be called from probe context by 1119*7c478bd9Sstevel@tonic-gate * using the prefix "dtrace_safe_". 1120*7c478bd9Sstevel@tonic-gate */ 1121*7c478bd9Sstevel@tonic-gate continue; 1122*7c478bd9Sstevel@tonic-gate } 1123*7c478bd9Sstevel@tonic-gate 1124*7c478bd9Sstevel@tonic-gate if (strstr(name, "kdi_") == name) { 1125*7c478bd9Sstevel@tonic-gate /* 1126*7c478bd9Sstevel@tonic-gate * Anything beginning with "kdi_" is a part of the 1127*7c478bd9Sstevel@tonic-gate * kernel debugger interface and may be called in 1128*7c478bd9Sstevel@tonic-gate * arbitrary context -- including probe context. 1129*7c478bd9Sstevel@tonic-gate */ 1130*7c478bd9Sstevel@tonic-gate continue; 1131*7c478bd9Sstevel@tonic-gate } 1132*7c478bd9Sstevel@tonic-gate 1133*7c478bd9Sstevel@tonic-gate if (strstr(name, "__relocatable") != NULL) { 1134*7c478bd9Sstevel@tonic-gate /* 1135*7c478bd9Sstevel@tonic-gate * Anything with the string "__relocatable" anywhere 1136*7c478bd9Sstevel@tonic-gate * in the function name is considered to be a function 1137*7c478bd9Sstevel@tonic-gate * that may be manually relocated before execution. 1138*7c478bd9Sstevel@tonic-gate * Because FBT uses a PC-relative technique for 1139*7c478bd9Sstevel@tonic-gate * instrumentation, these functions cannot safely 1140*7c478bd9Sstevel@tonic-gate * be instrumented by us. 1141*7c478bd9Sstevel@tonic-gate */ 1142*7c478bd9Sstevel@tonic-gate continue; 1143*7c478bd9Sstevel@tonic-gate } 1144*7c478bd9Sstevel@tonic-gate 1145*7c478bd9Sstevel@tonic-gate if (strstr(name, "ip_ocsum") == name) { 1146*7c478bd9Sstevel@tonic-gate /* 1147*7c478bd9Sstevel@tonic-gate * The ip_ocsum_* family of routines are all ABI 1148*7c478bd9Sstevel@tonic-gate * violators. (They expect incoming arguments in the 1149*7c478bd9Sstevel@tonic-gate * globals!) Break the ABI? No soup for you! 1150*7c478bd9Sstevel@tonic-gate */ 1151*7c478bd9Sstevel@tonic-gate continue; 1152*7c478bd9Sstevel@tonic-gate } 1153*7c478bd9Sstevel@tonic-gate 1154*7c478bd9Sstevel@tonic-gate /* 1155*7c478bd9Sstevel@tonic-gate * We want to scan the function for one (and only one) save. 1156*7c478bd9Sstevel@tonic-gate * Any more indicates that something fancy is going on. 1157*7c478bd9Sstevel@tonic-gate */ 1158*7c478bd9Sstevel@tonic-gate base = (uint32_t *)sym->st_value; 1159*7c478bd9Sstevel@tonic-gate limit = (uint32_t *)(sym->st_value + sym->st_size); 1160*7c478bd9Sstevel@tonic-gate 1161*7c478bd9Sstevel@tonic-gate /* 1162*7c478bd9Sstevel@tonic-gate * We don't want to interpose on the module stubs. 1163*7c478bd9Sstevel@tonic-gate */ 1164*7c478bd9Sstevel@tonic-gate if (base >= (uint32_t *)stubs_base && 1165*7c478bd9Sstevel@tonic-gate base <= (uint32_t *)stubs_end) 1166*7c478bd9Sstevel@tonic-gate continue; 1167*7c478bd9Sstevel@tonic-gate 1168*7c478bd9Sstevel@tonic-gate /* 1169*7c478bd9Sstevel@tonic-gate * We can't safely trace a zero-length function... 1170*7c478bd9Sstevel@tonic-gate */ 1171*7c478bd9Sstevel@tonic-gate if (base == limit) 1172*7c478bd9Sstevel@tonic-gate continue; 1173*7c478bd9Sstevel@tonic-gate 1174*7c478bd9Sstevel@tonic-gate /* 1175*7c478bd9Sstevel@tonic-gate * Due to 4524008, _init and _fini may have a bloated st_size. 1176*7c478bd9Sstevel@tonic-gate * While this bug was fixed quite some time ago, old drivers 1177*7c478bd9Sstevel@tonic-gate * may be lurking. We need to develop a better solution to 1178*7c478bd9Sstevel@tonic-gate * this problem, such that correct _init and _fini functions 1179*7c478bd9Sstevel@tonic-gate * (the vast majority) may be correctly traced. One solution 1180*7c478bd9Sstevel@tonic-gate * may be to scan through the entire symbol table to see if 1181*7c478bd9Sstevel@tonic-gate * any symbol overlaps with _init. If none does, set a bit in 1182*7c478bd9Sstevel@tonic-gate * the module structure that this module has correct _init and 1183*7c478bd9Sstevel@tonic-gate * _fini sizes. This will cause some pain the first time a 1184*7c478bd9Sstevel@tonic-gate * module is scanned, but at least it would be O(N) instead of 1185*7c478bd9Sstevel@tonic-gate * O(N log N)... 1186*7c478bd9Sstevel@tonic-gate */ 1187*7c478bd9Sstevel@tonic-gate if (strcmp(name, "_init") == 0) 1188*7c478bd9Sstevel@tonic-gate continue; 1189*7c478bd9Sstevel@tonic-gate 1190*7c478bd9Sstevel@tonic-gate if (strcmp(name, "_fini") == 0) 1191*7c478bd9Sstevel@tonic-gate continue; 1192*7c478bd9Sstevel@tonic-gate 1193*7c478bd9Sstevel@tonic-gate instr = base; 1194*7c478bd9Sstevel@tonic-gate 1195*7c478bd9Sstevel@tonic-gate /* 1196*7c478bd9Sstevel@tonic-gate * While we try hard to only trace safe functions (that is, 1197*7c478bd9Sstevel@tonic-gate * functions at TL=0), one unsafe function manages to otherwise 1198*7c478bd9Sstevel@tonic-gate * appear safe: prom_trap(). We could discover prom_trap() 1199*7c478bd9Sstevel@tonic-gate * if we added an additional rule: in order to trace a 1200*7c478bd9Sstevel@tonic-gate * function, we must either (a) discover a restore or (b) 1201*7c478bd9Sstevel@tonic-gate * determine that the function does not have any unlinked 1202*7c478bd9Sstevel@tonic-gate * control transfers to another function (i.e., the function 1203*7c478bd9Sstevel@tonic-gate * never returns). Unfortunately, as of this writing, one 1204*7c478bd9Sstevel@tonic-gate * legitimate function (resume_from_zombie()) transfers 1205*7c478bd9Sstevel@tonic-gate * control to a different function (_resume_from_idle()) 1206*7c478bd9Sstevel@tonic-gate * without executing a restore. Barring a rule to figure out 1207*7c478bd9Sstevel@tonic-gate * that resume_from_zombie() is safe while prom_trap() is not, 1208*7c478bd9Sstevel@tonic-gate * we resort to hard-coding prom_trap() here. 1209*7c478bd9Sstevel@tonic-gate */ 1210*7c478bd9Sstevel@tonic-gate if (strcmp(name, "prom_trap") == 0) 1211*7c478bd9Sstevel@tonic-gate continue; 1212*7c478bd9Sstevel@tonic-gate 1213*7c478bd9Sstevel@tonic-gate if (fp != NULL && ctf_func_info(fp, i, &f) != CTF_ERR) { 1214*7c478bd9Sstevel@tonic-gate nargs = f.ctc_argc; 1215*7c478bd9Sstevel@tonic-gate have_ctf = 1; 1216*7c478bd9Sstevel@tonic-gate } else { 1217*7c478bd9Sstevel@tonic-gate nargs = 32; 1218*7c478bd9Sstevel@tonic-gate } 1219*7c478bd9Sstevel@tonic-gate 1220*7c478bd9Sstevel@tonic-gate /* 1221*7c478bd9Sstevel@tonic-gate * If the first instruction of the function is a branch and 1222*7c478bd9Sstevel@tonic-gate * it's not a branch-always-not-annulled, we're going to refuse 1223*7c478bd9Sstevel@tonic-gate * to patch it. 1224*7c478bd9Sstevel@tonic-gate */ 1225*7c478bd9Sstevel@tonic-gate if ((*instr & FBT_OP_MASK) == FBT_OP0 && 1226*7c478bd9Sstevel@tonic-gate (*instr & FBT_FMT2_OP2_MASK) != FBT_FMT2_OP2_SETHI && 1227*7c478bd9Sstevel@tonic-gate (*instr & FBT_FMT2_OP2_MASK) != FBT_FMT2_OP2_BPR) { 1228*7c478bd9Sstevel@tonic-gate if (!FBT_IS_BA(*instr) && !FBT_IS_BAPCC(*instr)) { 1229*7c478bd9Sstevel@tonic-gate if (have_ctf) { 1230*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "cannot instrument %s:" 1231*7c478bd9Sstevel@tonic-gate " begins with non-ba, " 1232*7c478bd9Sstevel@tonic-gate "non-br CTI", name); 1233*7c478bd9Sstevel@tonic-gate } 1234*7c478bd9Sstevel@tonic-gate continue; 1235*7c478bd9Sstevel@tonic-gate } 1236*7c478bd9Sstevel@tonic-gate } 1237*7c478bd9Sstevel@tonic-gate 1238*7c478bd9Sstevel@tonic-gate while (!FBT_IS_SAVE(*instr)) { 1239*7c478bd9Sstevel@tonic-gate /* 1240*7c478bd9Sstevel@tonic-gate * Before we assume that this is a leaf routine, check 1241*7c478bd9Sstevel@tonic-gate * forward in the basic block for a save. 1242*7c478bd9Sstevel@tonic-gate */ 1243*7c478bd9Sstevel@tonic-gate int op = *instr & FBT_OP_MASK; 1244*7c478bd9Sstevel@tonic-gate int op2 = *instr & FBT_FMT2_OP2_MASK; 1245*7c478bd9Sstevel@tonic-gate 1246*7c478bd9Sstevel@tonic-gate if (op == FBT_OP0 && op2 != FBT_FMT2_OP2_SETHI) { 1247*7c478bd9Sstevel@tonic-gate /* 1248*7c478bd9Sstevel@tonic-gate * This is a CTI. If we see a subsequent 1249*7c478bd9Sstevel@tonic-gate * save, we will refuse to process this 1250*7c478bd9Sstevel@tonic-gate * routine unless both of the following are 1251*7c478bd9Sstevel@tonic-gate * true: 1252*7c478bd9Sstevel@tonic-gate * 1253*7c478bd9Sstevel@tonic-gate * (a) The branch is not annulled 1254*7c478bd9Sstevel@tonic-gate * 1255*7c478bd9Sstevel@tonic-gate * (b) The subsequent save is in the delay 1256*7c478bd9Sstevel@tonic-gate * slot of the branch 1257*7c478bd9Sstevel@tonic-gate */ 1258*7c478bd9Sstevel@tonic-gate if ((*instr & FBT_ANNUL) || 1259*7c478bd9Sstevel@tonic-gate !FBT_IS_SAVE(*(instr + 1))) { 1260*7c478bd9Sstevel@tonic-gate cti = 1; 1261*7c478bd9Sstevel@tonic-gate } else { 1262*7c478bd9Sstevel@tonic-gate instr++; 1263*7c478bd9Sstevel@tonic-gate break; 1264*7c478bd9Sstevel@tonic-gate } 1265*7c478bd9Sstevel@tonic-gate } 1266*7c478bd9Sstevel@tonic-gate 1267*7c478bd9Sstevel@tonic-gate if (op == FBT_OP1) 1268*7c478bd9Sstevel@tonic-gate cti = 1; 1269*7c478bd9Sstevel@tonic-gate 1270*7c478bd9Sstevel@tonic-gate if (++instr == limit) 1271*7c478bd9Sstevel@tonic-gate break; 1272*7c478bd9Sstevel@tonic-gate } 1273*7c478bd9Sstevel@tonic-gate 1274*7c478bd9Sstevel@tonic-gate if (instr < limit && cti) { 1275*7c478bd9Sstevel@tonic-gate /* 1276*7c478bd9Sstevel@tonic-gate * If we found a CTI before the save, we need to not 1277*7c478bd9Sstevel@tonic-gate * do anything. But if we have CTF information, this 1278*7c478bd9Sstevel@tonic-gate * is weird enough that it merits a message. 1279*7c478bd9Sstevel@tonic-gate */ 1280*7c478bd9Sstevel@tonic-gate if (!have_ctf) 1281*7c478bd9Sstevel@tonic-gate continue; 1282*7c478bd9Sstevel@tonic-gate 1283*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "cannot instrument %s: " 1284*7c478bd9Sstevel@tonic-gate "save not in first basic block", name); 1285*7c478bd9Sstevel@tonic-gate continue; 1286*7c478bd9Sstevel@tonic-gate } 1287*7c478bd9Sstevel@tonic-gate 1288*7c478bd9Sstevel@tonic-gate if (instr == limit) { 1289*7c478bd9Sstevel@tonic-gate if (!have_ctf) 1290*7c478bd9Sstevel@tonic-gate continue; 1291*7c478bd9Sstevel@tonic-gate is_leaf = 1; 1292*7c478bd9Sstevel@tonic-gate 1293*7c478bd9Sstevel@tonic-gate if (!estimate) 1294*7c478bd9Sstevel@tonic-gate fbt_leaf_functions++; 1295*7c478bd9Sstevel@tonic-gate 1296*7c478bd9Sstevel@tonic-gate canpatch = fbt_canpatch_retl; 1297*7c478bd9Sstevel@tonic-gate patch = fbt_patch_retl; 1298*7c478bd9Sstevel@tonic-gate } else { 1299*7c478bd9Sstevel@tonic-gate canpatch = fbt_canpatch_return; 1300*7c478bd9Sstevel@tonic-gate patch = fbt_patch_return; 1301*7c478bd9Sstevel@tonic-gate } 1302*7c478bd9Sstevel@tonic-gate 1303*7c478bd9Sstevel@tonic-gate if (!have_ctf && !is_leaf) { 1304*7c478bd9Sstevel@tonic-gate /* 1305*7c478bd9Sstevel@tonic-gate * Before we assume that this isn't something tricky, 1306*7c478bd9Sstevel@tonic-gate * look for other saves. If we find them, there are 1307*7c478bd9Sstevel@tonic-gate * multiple entry points here (or something), and we'll 1308*7c478bd9Sstevel@tonic-gate * leave it alone. 1309*7c478bd9Sstevel@tonic-gate */ 1310*7c478bd9Sstevel@tonic-gate while (++instr < limit) { 1311*7c478bd9Sstevel@tonic-gate if (FBT_IS_SAVE(*instr)) 1312*7c478bd9Sstevel@tonic-gate break; 1313*7c478bd9Sstevel@tonic-gate } 1314*7c478bd9Sstevel@tonic-gate 1315*7c478bd9Sstevel@tonic-gate if (instr != limit) 1316*7c478bd9Sstevel@tonic-gate continue; 1317*7c478bd9Sstevel@tonic-gate } 1318*7c478bd9Sstevel@tonic-gate 1319*7c478bd9Sstevel@tonic-gate instr = base; 1320*7c478bd9Sstevel@tonic-gate 1321*7c478bd9Sstevel@tonic-gate if (FBT_IS_CTI(*instr)) { 1322*7c478bd9Sstevel@tonic-gate /* 1323*7c478bd9Sstevel@tonic-gate * If we have a CTI, we want to be sure that we don't 1324*7c478bd9Sstevel@tonic-gate * have a CTI or a PC-relative instruction in the 1325*7c478bd9Sstevel@tonic-gate * delay slot -- we want to be able to thunk the 1326*7c478bd9Sstevel@tonic-gate * instruction into the trampoline without worrying 1327*7c478bd9Sstevel@tonic-gate * about either DCTIs or relocations. It would be 1328*7c478bd9Sstevel@tonic-gate * very odd for the compiler to generate this kind of 1329*7c478bd9Sstevel@tonic-gate * code, so we warn about it if we have CTF 1330*7c478bd9Sstevel@tonic-gate * information. 1331*7c478bd9Sstevel@tonic-gate */ 1332*7c478bd9Sstevel@tonic-gate if (FBT_IS_CTI(*(instr + 1))) { 1333*7c478bd9Sstevel@tonic-gate if (!have_ctf) 1334*7c478bd9Sstevel@tonic-gate continue; 1335*7c478bd9Sstevel@tonic-gate 1336*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "cannot instrument %s: " 1337*7c478bd9Sstevel@tonic-gate "CTI in delay slot of first instruction", 1338*7c478bd9Sstevel@tonic-gate name); 1339*7c478bd9Sstevel@tonic-gate continue; 1340*7c478bd9Sstevel@tonic-gate } 1341*7c478bd9Sstevel@tonic-gate 1342*7c478bd9Sstevel@tonic-gate if (FBT_IS_PCRELATIVE(*(instr + 1))) { 1343*7c478bd9Sstevel@tonic-gate if (!have_ctf) 1344*7c478bd9Sstevel@tonic-gate continue; 1345*7c478bd9Sstevel@tonic-gate 1346*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "cannot instrument %s: " 1347*7c478bd9Sstevel@tonic-gate "PC-relative instruction in delay slot of" 1348*7c478bd9Sstevel@tonic-gate " first instruction", name); 1349*7c478bd9Sstevel@tonic-gate continue; 1350*7c478bd9Sstevel@tonic-gate } 1351*7c478bd9Sstevel@tonic-gate } 1352*7c478bd9Sstevel@tonic-gate 1353*7c478bd9Sstevel@tonic-gate if (estimate) { 1354*7c478bd9Sstevel@tonic-gate tramp.fbtt_next = (uintptr_t)faketramp; 1355*7c478bd9Sstevel@tonic-gate tramp.fbtt_limit = tramp.fbtt_next + sizeof (faketramp); 1356*7c478bd9Sstevel@tonic-gate (void) fbt_patch_entry(instr, FBT_ESTIMATE_ID, 1357*7c478bd9Sstevel@tonic-gate &tramp, nargs); 1358*7c478bd9Sstevel@tonic-gate fbt_size += tramp.fbtt_next - (uintptr_t)faketramp; 1359*7c478bd9Sstevel@tonic-gate } else { 1360*7c478bd9Sstevel@tonic-gate fbt = kmem_zalloc(sizeof (fbt_probe_t), KM_SLEEP); 1361*7c478bd9Sstevel@tonic-gate fbt->fbtp_name = name; 1362*7c478bd9Sstevel@tonic-gate fbt->fbtp_ctl = ctl; 1363*7c478bd9Sstevel@tonic-gate fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, 1364*7c478bd9Sstevel@tonic-gate name, FBT_PROBENAME_ENTRY, 1, fbt); 1365*7c478bd9Sstevel@tonic-gate fbt->fbtp_patchval = FBT_BAA(instr, tramp.fbtt_va); 1366*7c478bd9Sstevel@tonic-gate 1367*7c478bd9Sstevel@tonic-gate if (!fbt_patch_entry(instr, fbt->fbtp_id, 1368*7c478bd9Sstevel@tonic-gate &tramp, nargs)) { 1369*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "unexpectedly short FBT table " 1370*7c478bd9Sstevel@tonic-gate "in module %s (sym %d of %d)", modname, 1371*7c478bd9Sstevel@tonic-gate i, nsyms); 1372*7c478bd9Sstevel@tonic-gate break; 1373*7c478bd9Sstevel@tonic-gate } 1374*7c478bd9Sstevel@tonic-gate 1375*7c478bd9Sstevel@tonic-gate fbt->fbtp_patchpoint = 1376*7c478bd9Sstevel@tonic-gate (uint32_t *)((uintptr_t)mp->textwin + 1377*7c478bd9Sstevel@tonic-gate ((uintptr_t)instr - (uintptr_t)mp->text)); 1378*7c478bd9Sstevel@tonic-gate fbt->fbtp_savedval = *instr; 1379*7c478bd9Sstevel@tonic-gate 1380*7c478bd9Sstevel@tonic-gate fbt->fbtp_loadcnt = ctl->mod_loadcnt; 1381*7c478bd9Sstevel@tonic-gate fbt->fbtp_primary = primary; 1382*7c478bd9Sstevel@tonic-gate fbt->fbtp_symndx = i; 1383*7c478bd9Sstevel@tonic-gate mp->fbt_nentries++; 1384*7c478bd9Sstevel@tonic-gate } 1385*7c478bd9Sstevel@tonic-gate 1386*7c478bd9Sstevel@tonic-gate retfbt = NULL; 1387*7c478bd9Sstevel@tonic-gate again: 1388*7c478bd9Sstevel@tonic-gate if (++instr == limit) 1389*7c478bd9Sstevel@tonic-gate continue; 1390*7c478bd9Sstevel@tonic-gate 1391*7c478bd9Sstevel@tonic-gate offset = (uintptr_t)instr - (uintptr_t)base; 1392*7c478bd9Sstevel@tonic-gate 1393*7c478bd9Sstevel@tonic-gate if (!(*canpatch)(instr, offset, name)) 1394*7c478bd9Sstevel@tonic-gate goto again; 1395*7c478bd9Sstevel@tonic-gate 1396*7c478bd9Sstevel@tonic-gate if (estimate) { 1397*7c478bd9Sstevel@tonic-gate tramp.fbtt_next = (uintptr_t)faketramp; 1398*7c478bd9Sstevel@tonic-gate tramp.fbtt_limit = tramp.fbtt_next + sizeof (faketramp); 1399*7c478bd9Sstevel@tonic-gate (void) (*patch)(instr, base, limit, 1400*7c478bd9Sstevel@tonic-gate offset, FBT_ESTIMATE_ID, &tramp, name); 1401*7c478bd9Sstevel@tonic-gate fbt_size += tramp.fbtt_next - (uintptr_t)faketramp; 1402*7c478bd9Sstevel@tonic-gate 1403*7c478bd9Sstevel@tonic-gate goto again; 1404*7c478bd9Sstevel@tonic-gate } 1405*7c478bd9Sstevel@tonic-gate 1406*7c478bd9Sstevel@tonic-gate fbt = kmem_zalloc(sizeof (fbt_probe_t), KM_SLEEP); 1407*7c478bd9Sstevel@tonic-gate fbt->fbtp_name = name; 1408*7c478bd9Sstevel@tonic-gate fbt->fbtp_ctl = ctl; 1409*7c478bd9Sstevel@tonic-gate 1410*7c478bd9Sstevel@tonic-gate if (retfbt == NULL) { 1411*7c478bd9Sstevel@tonic-gate fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, 1412*7c478bd9Sstevel@tonic-gate name, FBT_PROBENAME_RETURN, 1, fbt); 1413*7c478bd9Sstevel@tonic-gate } else { 1414*7c478bd9Sstevel@tonic-gate retfbt->fbtp_next = fbt; 1415*7c478bd9Sstevel@tonic-gate fbt->fbtp_id = retfbt->fbtp_id; 1416*7c478bd9Sstevel@tonic-gate } 1417*7c478bd9Sstevel@tonic-gate 1418*7c478bd9Sstevel@tonic-gate fbt->fbtp_return = 1; 1419*7c478bd9Sstevel@tonic-gate retfbt = fbt; 1420*7c478bd9Sstevel@tonic-gate 1421*7c478bd9Sstevel@tonic-gate if ((fbt->fbtp_patchval = (*patch)(instr, base, limit, offset, 1422*7c478bd9Sstevel@tonic-gate fbt->fbtp_id, &tramp, name)) == FBT_ILLTRAP) { 1423*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "unexpectedly short FBT table " 1424*7c478bd9Sstevel@tonic-gate "in module %s (sym %d of %d)", modname, i, nsyms); 1425*7c478bd9Sstevel@tonic-gate break; 1426*7c478bd9Sstevel@tonic-gate } 1427*7c478bd9Sstevel@tonic-gate 1428*7c478bd9Sstevel@tonic-gate fbt->fbtp_patchpoint = (uint32_t *)((uintptr_t)mp->textwin + 1429*7c478bd9Sstevel@tonic-gate ((uintptr_t)instr - (uintptr_t)mp->text)); 1430*7c478bd9Sstevel@tonic-gate fbt->fbtp_savedval = *instr; 1431*7c478bd9Sstevel@tonic-gate fbt->fbtp_loadcnt = ctl->mod_loadcnt; 1432*7c478bd9Sstevel@tonic-gate fbt->fbtp_primary = primary; 1433*7c478bd9Sstevel@tonic-gate fbt->fbtp_symndx = i; 1434*7c478bd9Sstevel@tonic-gate mp->fbt_nentries++; 1435*7c478bd9Sstevel@tonic-gate 1436*7c478bd9Sstevel@tonic-gate goto again; 1437*7c478bd9Sstevel@tonic-gate } 1438*7c478bd9Sstevel@tonic-gate 1439*7c478bd9Sstevel@tonic-gate if (estimate) { 1440*7c478bd9Sstevel@tonic-gate /* 1441*7c478bd9Sstevel@tonic-gate * Slosh on another entry's worth... 1442*7c478bd9Sstevel@tonic-gate */ 1443*7c478bd9Sstevel@tonic-gate fbt_size += FBT_ENT_MAXSIZE; 1444*7c478bd9Sstevel@tonic-gate mp->fbt_size = fbt_size; 1445*7c478bd9Sstevel@tonic-gate mp->fbt_tab = kobj_texthole_alloc(mp->text, fbt_size); 1446*7c478bd9Sstevel@tonic-gate 1447*7c478bd9Sstevel@tonic-gate if (mp->fbt_tab == NULL) { 1448*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "couldn't allocate FBT table " 1449*7c478bd9Sstevel@tonic-gate "for module %s", modname); 1450*7c478bd9Sstevel@tonic-gate } else { 1451*7c478bd9Sstevel@tonic-gate estimate = 0; 1452*7c478bd9Sstevel@tonic-gate goto forreal; 1453*7c478bd9Sstevel@tonic-gate } 1454*7c478bd9Sstevel@tonic-gate } else { 1455*7c478bd9Sstevel@tonic-gate fbt_trampoline_unmap(); 1456*7c478bd9Sstevel@tonic-gate } 1457*7c478bd9Sstevel@tonic-gate 1458*7c478bd9Sstevel@tonic-gate error: 1459*7c478bd9Sstevel@tonic-gate if (fp != NULL) 1460*7c478bd9Sstevel@tonic-gate ctf_close(fp); 1461*7c478bd9Sstevel@tonic-gate } 1462*7c478bd9Sstevel@tonic-gate 1463*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1464*7c478bd9Sstevel@tonic-gate static void 1465*7c478bd9Sstevel@tonic-gate fbt_destroy(void *arg, dtrace_id_t id, void *parg) 1466*7c478bd9Sstevel@tonic-gate { 1467*7c478bd9Sstevel@tonic-gate fbt_probe_t *fbt = parg, *next; 1468*7c478bd9Sstevel@tonic-gate struct modctl *ctl = fbt->fbtp_ctl; 1469*7c478bd9Sstevel@tonic-gate 1470*7c478bd9Sstevel@tonic-gate do { 1471*7c478bd9Sstevel@tonic-gate if (ctl != NULL && ctl->mod_loadcnt == fbt->fbtp_loadcnt) { 1472*7c478bd9Sstevel@tonic-gate if ((ctl->mod_loadcnt == fbt->fbtp_loadcnt && 1473*7c478bd9Sstevel@tonic-gate ctl->mod_loaded) || fbt->fbtp_primary) { 1474*7c478bd9Sstevel@tonic-gate ((struct module *) 1475*7c478bd9Sstevel@tonic-gate (ctl->mod_mp))->fbt_nentries--; 1476*7c478bd9Sstevel@tonic-gate } 1477*7c478bd9Sstevel@tonic-gate } 1478*7c478bd9Sstevel@tonic-gate 1479*7c478bd9Sstevel@tonic-gate next = fbt->fbtp_next; 1480*7c478bd9Sstevel@tonic-gate kmem_free(fbt, sizeof (fbt_probe_t)); 1481*7c478bd9Sstevel@tonic-gate fbt = next; 1482*7c478bd9Sstevel@tonic-gate } while (fbt != NULL); 1483*7c478bd9Sstevel@tonic-gate } 1484*7c478bd9Sstevel@tonic-gate 1485*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1486*7c478bd9Sstevel@tonic-gate static void 1487*7c478bd9Sstevel@tonic-gate fbt_enable(void *arg, dtrace_id_t id, void *parg) 1488*7c478bd9Sstevel@tonic-gate { 1489*7c478bd9Sstevel@tonic-gate fbt_probe_t *fbt = parg, *f; 1490*7c478bd9Sstevel@tonic-gate struct modctl *ctl = fbt->fbtp_ctl; 1491*7c478bd9Sstevel@tonic-gate 1492*7c478bd9Sstevel@tonic-gate ctl->mod_nenabled++; 1493*7c478bd9Sstevel@tonic-gate 1494*7c478bd9Sstevel@tonic-gate for (f = fbt; f != NULL; f = f->fbtp_next) { 1495*7c478bd9Sstevel@tonic-gate if (f->fbtp_patchpoint == NULL) { 1496*7c478bd9Sstevel@tonic-gate /* 1497*7c478bd9Sstevel@tonic-gate * Due to a shortened FBT table, this entry was never 1498*7c478bd9Sstevel@tonic-gate * completed; refuse to enable it. 1499*7c478bd9Sstevel@tonic-gate */ 1500*7c478bd9Sstevel@tonic-gate if (fbt_verbose) { 1501*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "fbt is failing for probe %s " 1502*7c478bd9Sstevel@tonic-gate "(short FBT table in %s)", 1503*7c478bd9Sstevel@tonic-gate fbt->fbtp_name, ctl->mod_modname); 1504*7c478bd9Sstevel@tonic-gate } 1505*7c478bd9Sstevel@tonic-gate 1506*7c478bd9Sstevel@tonic-gate return; 1507*7c478bd9Sstevel@tonic-gate } 1508*7c478bd9Sstevel@tonic-gate } 1509*7c478bd9Sstevel@tonic-gate 1510*7c478bd9Sstevel@tonic-gate /* 1511*7c478bd9Sstevel@tonic-gate * If this module has disappeared since we discovered its probes, 1512*7c478bd9Sstevel@tonic-gate * refuse to enable it. 1513*7c478bd9Sstevel@tonic-gate */ 1514*7c478bd9Sstevel@tonic-gate if (!fbt->fbtp_primary && !ctl->mod_loaded) { 1515*7c478bd9Sstevel@tonic-gate if (fbt_verbose) { 1516*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "fbt is failing for probe %s " 1517*7c478bd9Sstevel@tonic-gate "(module %s unloaded)", 1518*7c478bd9Sstevel@tonic-gate fbt->fbtp_name, ctl->mod_modname); 1519*7c478bd9Sstevel@tonic-gate } 1520*7c478bd9Sstevel@tonic-gate 1521*7c478bd9Sstevel@tonic-gate return; 1522*7c478bd9Sstevel@tonic-gate } 1523*7c478bd9Sstevel@tonic-gate 1524*7c478bd9Sstevel@tonic-gate /* 1525*7c478bd9Sstevel@tonic-gate * Now check that our modctl has the expected load count. If it 1526*7c478bd9Sstevel@tonic-gate * doesn't, this module must have been unloaded and reloaded -- and 1527*7c478bd9Sstevel@tonic-gate * we're not going to touch it. 1528*7c478bd9Sstevel@tonic-gate */ 1529*7c478bd9Sstevel@tonic-gate if (ctl->mod_loadcnt != fbt->fbtp_loadcnt) { 1530*7c478bd9Sstevel@tonic-gate if (fbt_verbose) { 1531*7c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "fbt is failing for probe %s " 1532*7c478bd9Sstevel@tonic-gate "(module %s reloaded)", 1533*7c478bd9Sstevel@tonic-gate fbt->fbtp_name, ctl->mod_modname); 1534*7c478bd9Sstevel@tonic-gate } 1535*7c478bd9Sstevel@tonic-gate 1536*7c478bd9Sstevel@tonic-gate return; 1537*7c478bd9Sstevel@tonic-gate } 1538*7c478bd9Sstevel@tonic-gate 1539*7c478bd9Sstevel@tonic-gate for (; fbt != NULL; fbt = fbt->fbtp_next) 1540*7c478bd9Sstevel@tonic-gate *fbt->fbtp_patchpoint = fbt->fbtp_patchval; 1541*7c478bd9Sstevel@tonic-gate } 1542*7c478bd9Sstevel@tonic-gate 1543*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1544*7c478bd9Sstevel@tonic-gate static void 1545*7c478bd9Sstevel@tonic-gate fbt_disable(void *arg, dtrace_id_t id, void *parg) 1546*7c478bd9Sstevel@tonic-gate { 1547*7c478bd9Sstevel@tonic-gate fbt_probe_t *fbt = parg, *f; 1548*7c478bd9Sstevel@tonic-gate struct modctl *ctl = fbt->fbtp_ctl; 1549*7c478bd9Sstevel@tonic-gate 1550*7c478bd9Sstevel@tonic-gate ASSERT(ctl->mod_nenabled > 0); 1551*7c478bd9Sstevel@tonic-gate ctl->mod_nenabled--; 1552*7c478bd9Sstevel@tonic-gate 1553*7c478bd9Sstevel@tonic-gate for (f = fbt; f != NULL; f = f->fbtp_next) { 1554*7c478bd9Sstevel@tonic-gate if (f->fbtp_patchpoint == NULL) 1555*7c478bd9Sstevel@tonic-gate return; 1556*7c478bd9Sstevel@tonic-gate } 1557*7c478bd9Sstevel@tonic-gate 1558*7c478bd9Sstevel@tonic-gate if ((!fbt->fbtp_primary && !ctl->mod_loaded) || 1559*7c478bd9Sstevel@tonic-gate (ctl->mod_loadcnt != fbt->fbtp_loadcnt)) 1560*7c478bd9Sstevel@tonic-gate return; 1561*7c478bd9Sstevel@tonic-gate 1562*7c478bd9Sstevel@tonic-gate for (; fbt != NULL; fbt = fbt->fbtp_next) 1563*7c478bd9Sstevel@tonic-gate *fbt->fbtp_patchpoint = fbt->fbtp_savedval; 1564*7c478bd9Sstevel@tonic-gate } 1565*7c478bd9Sstevel@tonic-gate 1566*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1567*7c478bd9Sstevel@tonic-gate static void 1568*7c478bd9Sstevel@tonic-gate fbt_suspend(void *arg, dtrace_id_t id, void *parg) 1569*7c478bd9Sstevel@tonic-gate { 1570*7c478bd9Sstevel@tonic-gate fbt_probe_t *fbt = parg; 1571*7c478bd9Sstevel@tonic-gate struct modctl *ctl = fbt->fbtp_ctl; 1572*7c478bd9Sstevel@tonic-gate 1573*7c478bd9Sstevel@tonic-gate if (!fbt->fbtp_primary && !ctl->mod_loaded) 1574*7c478bd9Sstevel@tonic-gate return; 1575*7c478bd9Sstevel@tonic-gate 1576*7c478bd9Sstevel@tonic-gate if (ctl->mod_loadcnt != fbt->fbtp_loadcnt) 1577*7c478bd9Sstevel@tonic-gate return; 1578*7c478bd9Sstevel@tonic-gate 1579*7c478bd9Sstevel@tonic-gate ASSERT(ctl->mod_nenabled > 0); 1580*7c478bd9Sstevel@tonic-gate 1581*7c478bd9Sstevel@tonic-gate for (; fbt != NULL; fbt = fbt->fbtp_next) 1582*7c478bd9Sstevel@tonic-gate *fbt->fbtp_patchpoint = fbt->fbtp_savedval; 1583*7c478bd9Sstevel@tonic-gate } 1584*7c478bd9Sstevel@tonic-gate 1585*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1586*7c478bd9Sstevel@tonic-gate static void 1587*7c478bd9Sstevel@tonic-gate fbt_resume(void *arg, dtrace_id_t id, void *parg) 1588*7c478bd9Sstevel@tonic-gate { 1589*7c478bd9Sstevel@tonic-gate fbt_probe_t *fbt = parg; 1590*7c478bd9Sstevel@tonic-gate struct modctl *ctl = fbt->fbtp_ctl; 1591*7c478bd9Sstevel@tonic-gate 1592*7c478bd9Sstevel@tonic-gate if (!fbt->fbtp_primary && !ctl->mod_loaded) 1593*7c478bd9Sstevel@tonic-gate return; 1594*7c478bd9Sstevel@tonic-gate 1595*7c478bd9Sstevel@tonic-gate if (ctl->mod_loadcnt != fbt->fbtp_loadcnt) 1596*7c478bd9Sstevel@tonic-gate return; 1597*7c478bd9Sstevel@tonic-gate 1598*7c478bd9Sstevel@tonic-gate ASSERT(ctl->mod_nenabled > 0); 1599*7c478bd9Sstevel@tonic-gate 1600*7c478bd9Sstevel@tonic-gate for (; fbt != NULL; fbt = fbt->fbtp_next) 1601*7c478bd9Sstevel@tonic-gate *fbt->fbtp_patchpoint = fbt->fbtp_patchval; 1602*7c478bd9Sstevel@tonic-gate } 1603*7c478bd9Sstevel@tonic-gate 1604*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1605*7c478bd9Sstevel@tonic-gate static void 1606*7c478bd9Sstevel@tonic-gate fbt_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc) 1607*7c478bd9Sstevel@tonic-gate { 1608*7c478bd9Sstevel@tonic-gate fbt_probe_t *fbt = parg; 1609*7c478bd9Sstevel@tonic-gate struct modctl *ctl = fbt->fbtp_ctl; 1610*7c478bd9Sstevel@tonic-gate struct module *mp = ctl->mod_mp; 1611*7c478bd9Sstevel@tonic-gate ctf_file_t *fp = NULL, *pfp; 1612*7c478bd9Sstevel@tonic-gate ctf_funcinfo_t f; 1613*7c478bd9Sstevel@tonic-gate int error; 1614*7c478bd9Sstevel@tonic-gate ctf_id_t argv[32], type; 1615*7c478bd9Sstevel@tonic-gate int argc = sizeof (argv) / sizeof (ctf_id_t); 1616*7c478bd9Sstevel@tonic-gate const char *parent; 1617*7c478bd9Sstevel@tonic-gate 1618*7c478bd9Sstevel@tonic-gate if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt)) 1619*7c478bd9Sstevel@tonic-gate goto err; 1620*7c478bd9Sstevel@tonic-gate 1621*7c478bd9Sstevel@tonic-gate if (fbt->fbtp_return && desc->dtargd_ndx == 0) { 1622*7c478bd9Sstevel@tonic-gate (void) strcpy(desc->dtargd_native, "int"); 1623*7c478bd9Sstevel@tonic-gate return; 1624*7c478bd9Sstevel@tonic-gate } 1625*7c478bd9Sstevel@tonic-gate 1626*7c478bd9Sstevel@tonic-gate if ((fp = ctf_modopen(mp, &error)) == NULL) { 1627*7c478bd9Sstevel@tonic-gate /* 1628*7c478bd9Sstevel@tonic-gate * We have no CTF information for this module -- and therefore 1629*7c478bd9Sstevel@tonic-gate * no args[] information. 1630*7c478bd9Sstevel@tonic-gate */ 1631*7c478bd9Sstevel@tonic-gate goto err; 1632*7c478bd9Sstevel@tonic-gate } 1633*7c478bd9Sstevel@tonic-gate 1634*7c478bd9Sstevel@tonic-gate /* 1635*7c478bd9Sstevel@tonic-gate * If we have a parent container, we must manually import it. 1636*7c478bd9Sstevel@tonic-gate */ 1637*7c478bd9Sstevel@tonic-gate if ((parent = ctf_parent_name(fp)) != NULL) { 1638*7c478bd9Sstevel@tonic-gate struct modctl *mod; 1639*7c478bd9Sstevel@tonic-gate 1640*7c478bd9Sstevel@tonic-gate /* 1641*7c478bd9Sstevel@tonic-gate * We must iterate over all modules to find the module that 1642*7c478bd9Sstevel@tonic-gate * is our parent. 1643*7c478bd9Sstevel@tonic-gate */ 1644*7c478bd9Sstevel@tonic-gate for (mod = &modules; mod != NULL; mod = mod->mod_next) { 1645*7c478bd9Sstevel@tonic-gate if (strcmp(mod->mod_filename, parent) == 0) 1646*7c478bd9Sstevel@tonic-gate break; 1647*7c478bd9Sstevel@tonic-gate } 1648*7c478bd9Sstevel@tonic-gate 1649*7c478bd9Sstevel@tonic-gate if (mod == NULL) 1650*7c478bd9Sstevel@tonic-gate goto err; 1651*7c478bd9Sstevel@tonic-gate 1652*7c478bd9Sstevel@tonic-gate if ((pfp = ctf_modopen(mod->mod_mp, &error)) == NULL) 1653*7c478bd9Sstevel@tonic-gate goto err; 1654*7c478bd9Sstevel@tonic-gate 1655*7c478bd9Sstevel@tonic-gate if (ctf_import(fp, pfp) != 0) { 1656*7c478bd9Sstevel@tonic-gate ctf_close(pfp); 1657*7c478bd9Sstevel@tonic-gate goto err; 1658*7c478bd9Sstevel@tonic-gate } 1659*7c478bd9Sstevel@tonic-gate 1660*7c478bd9Sstevel@tonic-gate ctf_close(pfp); 1661*7c478bd9Sstevel@tonic-gate } 1662*7c478bd9Sstevel@tonic-gate 1663*7c478bd9Sstevel@tonic-gate if (ctf_func_info(fp, fbt->fbtp_symndx, &f) == CTF_ERR) 1664*7c478bd9Sstevel@tonic-gate goto err; 1665*7c478bd9Sstevel@tonic-gate 1666*7c478bd9Sstevel@tonic-gate if (fbt->fbtp_return) { 1667*7c478bd9Sstevel@tonic-gate if (desc->dtargd_ndx > 1) 1668*7c478bd9Sstevel@tonic-gate goto err; 1669*7c478bd9Sstevel@tonic-gate 1670*7c478bd9Sstevel@tonic-gate ASSERT(desc->dtargd_ndx == 1); 1671*7c478bd9Sstevel@tonic-gate type = f.ctc_return; 1672*7c478bd9Sstevel@tonic-gate } else { 1673*7c478bd9Sstevel@tonic-gate if (desc->dtargd_ndx + 1 > f.ctc_argc) 1674*7c478bd9Sstevel@tonic-gate goto err; 1675*7c478bd9Sstevel@tonic-gate 1676*7c478bd9Sstevel@tonic-gate if (ctf_func_args(fp, fbt->fbtp_symndx, argc, argv) == CTF_ERR) 1677*7c478bd9Sstevel@tonic-gate goto err; 1678*7c478bd9Sstevel@tonic-gate 1679*7c478bd9Sstevel@tonic-gate type = argv[desc->dtargd_ndx]; 1680*7c478bd9Sstevel@tonic-gate } 1681*7c478bd9Sstevel@tonic-gate 1682*7c478bd9Sstevel@tonic-gate if (ctf_type_name(fp, type, desc->dtargd_native, 1683*7c478bd9Sstevel@tonic-gate DTRACE_ARGTYPELEN) != NULL) { 1684*7c478bd9Sstevel@tonic-gate ctf_close(fp); 1685*7c478bd9Sstevel@tonic-gate return; 1686*7c478bd9Sstevel@tonic-gate } 1687*7c478bd9Sstevel@tonic-gate err: 1688*7c478bd9Sstevel@tonic-gate if (fp != NULL) 1689*7c478bd9Sstevel@tonic-gate ctf_close(fp); 1690*7c478bd9Sstevel@tonic-gate 1691*7c478bd9Sstevel@tonic-gate desc->dtargd_ndx = DTRACE_ARGNONE; 1692*7c478bd9Sstevel@tonic-gate } 1693*7c478bd9Sstevel@tonic-gate 1694*7c478bd9Sstevel@tonic-gate static dtrace_pattr_t fbt_attr = { 1695*7c478bd9Sstevel@tonic-gate { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, 1696*7c478bd9Sstevel@tonic-gate { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, 1697*7c478bd9Sstevel@tonic-gate { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, 1698*7c478bd9Sstevel@tonic-gate { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, 1699*7c478bd9Sstevel@tonic-gate { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, 1700*7c478bd9Sstevel@tonic-gate }; 1701*7c478bd9Sstevel@tonic-gate 1702*7c478bd9Sstevel@tonic-gate static dtrace_pops_t fbt_pops = { 1703*7c478bd9Sstevel@tonic-gate NULL, 1704*7c478bd9Sstevel@tonic-gate fbt_provide_module, 1705*7c478bd9Sstevel@tonic-gate fbt_enable, 1706*7c478bd9Sstevel@tonic-gate fbt_disable, 1707*7c478bd9Sstevel@tonic-gate fbt_suspend, 1708*7c478bd9Sstevel@tonic-gate fbt_resume, 1709*7c478bd9Sstevel@tonic-gate fbt_getargdesc, 1710*7c478bd9Sstevel@tonic-gate NULL, 1711*7c478bd9Sstevel@tonic-gate NULL, 1712*7c478bd9Sstevel@tonic-gate fbt_destroy 1713*7c478bd9Sstevel@tonic-gate }; 1714*7c478bd9Sstevel@tonic-gate 1715*7c478bd9Sstevel@tonic-gate static int 1716*7c478bd9Sstevel@tonic-gate fbt_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 1717*7c478bd9Sstevel@tonic-gate { 1718*7c478bd9Sstevel@tonic-gate switch (cmd) { 1719*7c478bd9Sstevel@tonic-gate case DDI_ATTACH: 1720*7c478bd9Sstevel@tonic-gate break; 1721*7c478bd9Sstevel@tonic-gate case DDI_RESUME: 1722*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1723*7c478bd9Sstevel@tonic-gate default: 1724*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1725*7c478bd9Sstevel@tonic-gate } 1726*7c478bd9Sstevel@tonic-gate 1727*7c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(devi, "fbt", S_IFCHR, 0, 1728*7c478bd9Sstevel@tonic-gate DDI_PSEUDO, NULL) == DDI_FAILURE || 1729*7c478bd9Sstevel@tonic-gate dtrace_register("fbt", &fbt_attr, DTRACE_PRIV_KERNEL, 0, 1730*7c478bd9Sstevel@tonic-gate &fbt_pops, NULL, &fbt_id) != 0) { 1731*7c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 1732*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1733*7c478bd9Sstevel@tonic-gate } 1734*7c478bd9Sstevel@tonic-gate 1735*7c478bd9Sstevel@tonic-gate ddi_report_dev(devi); 1736*7c478bd9Sstevel@tonic-gate fbt_devi = devi; 1737*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1738*7c478bd9Sstevel@tonic-gate } 1739*7c478bd9Sstevel@tonic-gate 1740*7c478bd9Sstevel@tonic-gate static int 1741*7c478bd9Sstevel@tonic-gate fbt_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 1742*7c478bd9Sstevel@tonic-gate { 1743*7c478bd9Sstevel@tonic-gate switch (cmd) { 1744*7c478bd9Sstevel@tonic-gate case DDI_DETACH: 1745*7c478bd9Sstevel@tonic-gate break; 1746*7c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 1747*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1748*7c478bd9Sstevel@tonic-gate default: 1749*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1750*7c478bd9Sstevel@tonic-gate } 1751*7c478bd9Sstevel@tonic-gate 1752*7c478bd9Sstevel@tonic-gate if (dtrace_unregister(fbt_id) != 0) 1753*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1754*7c478bd9Sstevel@tonic-gate 1755*7c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 1756*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 1757*7c478bd9Sstevel@tonic-gate } 1758*7c478bd9Sstevel@tonic-gate 1759*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1760*7c478bd9Sstevel@tonic-gate static int 1761*7c478bd9Sstevel@tonic-gate fbt_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 1762*7c478bd9Sstevel@tonic-gate { 1763*7c478bd9Sstevel@tonic-gate int error; 1764*7c478bd9Sstevel@tonic-gate 1765*7c478bd9Sstevel@tonic-gate switch (infocmd) { 1766*7c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 1767*7c478bd9Sstevel@tonic-gate *result = (void *)fbt_devi; 1768*7c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 1769*7c478bd9Sstevel@tonic-gate break; 1770*7c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 1771*7c478bd9Sstevel@tonic-gate *result = (void *)0; 1772*7c478bd9Sstevel@tonic-gate error = DDI_SUCCESS; 1773*7c478bd9Sstevel@tonic-gate break; 1774*7c478bd9Sstevel@tonic-gate default: 1775*7c478bd9Sstevel@tonic-gate error = DDI_FAILURE; 1776*7c478bd9Sstevel@tonic-gate } 1777*7c478bd9Sstevel@tonic-gate return (error); 1778*7c478bd9Sstevel@tonic-gate } 1779*7c478bd9Sstevel@tonic-gate 1780*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1781*7c478bd9Sstevel@tonic-gate static int 1782*7c478bd9Sstevel@tonic-gate fbt_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) 1783*7c478bd9Sstevel@tonic-gate { 1784*7c478bd9Sstevel@tonic-gate return (0); 1785*7c478bd9Sstevel@tonic-gate } 1786*7c478bd9Sstevel@tonic-gate 1787*7c478bd9Sstevel@tonic-gate static struct cb_ops fbt_cb_ops = { 1788*7c478bd9Sstevel@tonic-gate fbt_open, /* open */ 1789*7c478bd9Sstevel@tonic-gate nodev, /* close */ 1790*7c478bd9Sstevel@tonic-gate nulldev, /* strategy */ 1791*7c478bd9Sstevel@tonic-gate nulldev, /* print */ 1792*7c478bd9Sstevel@tonic-gate nodev, /* dump */ 1793*7c478bd9Sstevel@tonic-gate nodev, /* read */ 1794*7c478bd9Sstevel@tonic-gate nodev, /* write */ 1795*7c478bd9Sstevel@tonic-gate nodev, /* ioctl */ 1796*7c478bd9Sstevel@tonic-gate nodev, /* devmap */ 1797*7c478bd9Sstevel@tonic-gate nodev, /* mmap */ 1798*7c478bd9Sstevel@tonic-gate nodev, /* segmap */ 1799*7c478bd9Sstevel@tonic-gate nochpoll, /* poll */ 1800*7c478bd9Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 1801*7c478bd9Sstevel@tonic-gate 0, /* streamtab */ 1802*7c478bd9Sstevel@tonic-gate D_NEW | D_MP /* Driver compatibility flag */ 1803*7c478bd9Sstevel@tonic-gate }; 1804*7c478bd9Sstevel@tonic-gate 1805*7c478bd9Sstevel@tonic-gate static struct dev_ops fbt_ops = { 1806*7c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev */ 1807*7c478bd9Sstevel@tonic-gate 0, /* refcnt */ 1808*7c478bd9Sstevel@tonic-gate fbt_info, /* get_dev_info */ 1809*7c478bd9Sstevel@tonic-gate nulldev, /* identify */ 1810*7c478bd9Sstevel@tonic-gate nulldev, /* probe */ 1811*7c478bd9Sstevel@tonic-gate fbt_attach, /* attach */ 1812*7c478bd9Sstevel@tonic-gate fbt_detach, /* detach */ 1813*7c478bd9Sstevel@tonic-gate nodev, /* reset */ 1814*7c478bd9Sstevel@tonic-gate &fbt_cb_ops, /* driver operations */ 1815*7c478bd9Sstevel@tonic-gate NULL, /* bus operations */ 1816*7c478bd9Sstevel@tonic-gate nodev /* dev power */ 1817*7c478bd9Sstevel@tonic-gate }; 1818*7c478bd9Sstevel@tonic-gate 1819*7c478bd9Sstevel@tonic-gate /* 1820*7c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 1821*7c478bd9Sstevel@tonic-gate */ 1822*7c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 1823*7c478bd9Sstevel@tonic-gate &mod_driverops, /* module type (this is a pseudo driver) */ 1824*7c478bd9Sstevel@tonic-gate "Function Boundary Tracing", /* name of module */ 1825*7c478bd9Sstevel@tonic-gate &fbt_ops, /* driver ops */ 1826*7c478bd9Sstevel@tonic-gate }; 1827*7c478bd9Sstevel@tonic-gate 1828*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 1829*7c478bd9Sstevel@tonic-gate MODREV_1, 1830*7c478bd9Sstevel@tonic-gate (void *)&modldrv, 1831*7c478bd9Sstevel@tonic-gate NULL 1832*7c478bd9Sstevel@tonic-gate }; 1833*7c478bd9Sstevel@tonic-gate 1834*7c478bd9Sstevel@tonic-gate int 1835*7c478bd9Sstevel@tonic-gate _init(void) 1836*7c478bd9Sstevel@tonic-gate { 1837*7c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage)); 1838*7c478bd9Sstevel@tonic-gate } 1839*7c478bd9Sstevel@tonic-gate 1840*7c478bd9Sstevel@tonic-gate int 1841*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 1842*7c478bd9Sstevel@tonic-gate { 1843*7c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1844*7c478bd9Sstevel@tonic-gate } 1845*7c478bd9Sstevel@tonic-gate 1846*7c478bd9Sstevel@tonic-gate int 1847*7c478bd9Sstevel@tonic-gate _fini(void) 1848*7c478bd9Sstevel@tonic-gate { 1849*7c478bd9Sstevel@tonic-gate return (mod_remove(&modlinkage)); 1850*7c478bd9Sstevel@tonic-gate } 1851