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