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