xref: /illumos-gate/usr/src/uts/sparc/dtrace/fbt.c (revision 7c478bd9)
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