xref: /onnv-gate/usr/src/uts/sparc/dtrace/fbt.c (revision 8803:8c01b39012c9)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51677Sdp  * Common Development and Distribution License (the "License").
61677Sdp  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*8803SJonathan.Haslam@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #include <sys/errno.h>
280Sstevel@tonic-gate #include <sys/stat.h>
290Sstevel@tonic-gate #include <sys/modctl.h>
300Sstevel@tonic-gate #include <sys/conf.h>
310Sstevel@tonic-gate #include <sys/systm.h>
320Sstevel@tonic-gate #include <sys/ddi.h>
330Sstevel@tonic-gate #include <sys/sunddi.h>
340Sstevel@tonic-gate #include <sys/cpuvar.h>
350Sstevel@tonic-gate #include <sys/kmem.h>
360Sstevel@tonic-gate #include <sys/strsubr.h>
370Sstevel@tonic-gate #include <sys/dtrace.h>
380Sstevel@tonic-gate #include <sys/kobj.h>
390Sstevel@tonic-gate #include <sys/modctl.h>
400Sstevel@tonic-gate #include <sys/atomic.h>
410Sstevel@tonic-gate #include <vm/seg_kmem.h>
420Sstevel@tonic-gate #include <sys/stack.h>
430Sstevel@tonic-gate #include <sys/ctf_api.h>
440Sstevel@tonic-gate #include <sys/sysmacros.h>
450Sstevel@tonic-gate 
460Sstevel@tonic-gate static dev_info_t		*fbt_devi;
470Sstevel@tonic-gate static dtrace_provider_id_t	fbt_id;
480Sstevel@tonic-gate static uintptr_t		fbt_trampoline;
490Sstevel@tonic-gate static caddr_t			fbt_trampoline_window;
500Sstevel@tonic-gate static size_t			fbt_trampoline_size;
510Sstevel@tonic-gate static int			fbt_verbose = 0;
520Sstevel@tonic-gate 
530Sstevel@tonic-gate /*
540Sstevel@tonic-gate  * Various interesting bean counters.
550Sstevel@tonic-gate  */
560Sstevel@tonic-gate static int			fbt_entry;
570Sstevel@tonic-gate static int			fbt_ret;
580Sstevel@tonic-gate static int			fbt_retl;
590Sstevel@tonic-gate static int			fbt_retl_jmptab;
600Sstevel@tonic-gate static int			fbt_retl_twoinstr;
610Sstevel@tonic-gate static int			fbt_retl_tailcall;
620Sstevel@tonic-gate static int			fbt_retl_tailjmpl;
630Sstevel@tonic-gate static int			fbt_leaf_functions;
640Sstevel@tonic-gate 
650Sstevel@tonic-gate extern char			stubs_base[];
660Sstevel@tonic-gate extern char			stubs_end[];
670Sstevel@tonic-gate 
680Sstevel@tonic-gate #define	FBT_REG_G0		0
690Sstevel@tonic-gate #define	FBT_REG_G1		1
700Sstevel@tonic-gate #define	FBT_REG_O0		8
710Sstevel@tonic-gate #define	FBT_REG_O1		9
720Sstevel@tonic-gate #define	FBT_REG_O2		10
730Sstevel@tonic-gate #define	FBT_REG_O3		11
740Sstevel@tonic-gate #define	FBT_REG_O4		12
750Sstevel@tonic-gate #define	FBT_REG_O5		13
760Sstevel@tonic-gate #define	FBT_REG_O6		14
770Sstevel@tonic-gate #define	FBT_REG_O7		15
780Sstevel@tonic-gate #define	FBT_REG_I0		24
790Sstevel@tonic-gate #define	FBT_REG_I1		25
800Sstevel@tonic-gate #define	FBT_REG_I2		26
810Sstevel@tonic-gate #define	FBT_REG_I3		27
820Sstevel@tonic-gate #define	FBT_REG_I4		28
830Sstevel@tonic-gate #define	FBT_REG_I7		31
840Sstevel@tonic-gate #define	FBT_REG_L0		16
850Sstevel@tonic-gate #define	FBT_REG_L1		17
860Sstevel@tonic-gate #define	FBT_REG_L2		18
870Sstevel@tonic-gate #define	FBT_REG_L3		19
880Sstevel@tonic-gate #define	FBT_REG_PC		5
890Sstevel@tonic-gate 
900Sstevel@tonic-gate #define	FBT_REG_ISGLOBAL(r)	((r) < 8)
910Sstevel@tonic-gate #define	FBT_REG_ISOUTPUT(r)	((r) >= 8 && (r) < 16)
920Sstevel@tonic-gate #define	FBT_REG_ISLOCAL(r)	((r) >= 16 && (r) < 24)
930Sstevel@tonic-gate #define	FBT_REG_ISVOLATILE(r)	\
940Sstevel@tonic-gate 	((FBT_REG_ISGLOBAL(r) || FBT_REG_ISOUTPUT(r)) && (r) != FBT_REG_G0)
950Sstevel@tonic-gate #define	FBT_REG_NLOCALS		8
960Sstevel@tonic-gate 
970Sstevel@tonic-gate #define	FBT_REG_MARKLOCAL(locals, r)	\
980Sstevel@tonic-gate 	if (FBT_REG_ISLOCAL(r)) \
990Sstevel@tonic-gate 		(locals)[(r) - FBT_REG_L0] = 1;
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate #define	FBT_REG_INITLOCALS(local, locals)	\
1020Sstevel@tonic-gate 	for ((local) = 0; (local) < FBT_REG_NLOCALS; (local)++)  \
1030Sstevel@tonic-gate 		(locals)[(local)] = 0; \
1040Sstevel@tonic-gate 	(local) = FBT_REG_L0
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate #define	FBT_REG_ALLOCLOCAL(local, locals)	\
1070Sstevel@tonic-gate 	while ((locals)[(local) - FBT_REG_L0]) \
1080Sstevel@tonic-gate 		(local)++; \
1090Sstevel@tonic-gate 	(locals)[(local) - FBT_REG_L0] = 1;
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate #define	FBT_OP_MASK		0xc0000000
1120Sstevel@tonic-gate #define	FBT_OP_SHIFT		30
1130Sstevel@tonic-gate #define	FBT_OP(val)		((val) & FBT_FMT1_MASK)
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate #define	FBT_SIMM13_MASK		0x1fff
1160Sstevel@tonic-gate #define	FBT_SIMM13_MAX		((int32_t)0xfff)
1170Sstevel@tonic-gate #define	FBT_IMM22_MASK		0x3fffff
1180Sstevel@tonic-gate #define	FBT_IMM22_SHIFT		10
1190Sstevel@tonic-gate #define	FBT_IMM10_MASK		0x3ff
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate #define	FBT_DISP30_MASK		0x3fffffff
1220Sstevel@tonic-gate #define	FBT_DISP30(from, to)	\
1230Sstevel@tonic-gate 	(((uintptr_t)(to) - (uintptr_t)(from) >> 2) & FBT_DISP30_MASK)
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate #define	FBT_DISP22_MASK		0x3fffff
1260Sstevel@tonic-gate #define	FBT_DISP22(from, to)	\
1270Sstevel@tonic-gate 	(((uintptr_t)(to) - (uintptr_t)(from) >> 2) & FBT_DISP22_MASK)
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate #define	FBT_DISP19_MASK		0x7ffff
1300Sstevel@tonic-gate #define	FBT_DISP19(from, to)	\
1310Sstevel@tonic-gate 	(((uintptr_t)(to) - (uintptr_t)(from) >> 2) & FBT_DISP19_MASK)
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate #define	FBT_DISP16_HISHIFT	20
1340Sstevel@tonic-gate #define	FBT_DISP16_HIMASK	(0x3 << FBT_DISP16_HISHIFT)
1350Sstevel@tonic-gate #define	FBT_DISP16_LOMASK	(0x3fff)
1360Sstevel@tonic-gate #define	FBT_DISP16_MASK		(FBT_DISP16_HIMASK | FBT_DISP16_LOMASK)
1370Sstevel@tonic-gate #define	FBT_DISP16(val)	\
1380Sstevel@tonic-gate 	((((val) & FBT_DISP16_HIMASK) >> 6) | ((val) & FBT_DISP16_LOMASK))
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate #define	FBT_DISP14_MASK		0x3fff
1410Sstevel@tonic-gate #define	FBT_DISP14(from, to)	\
1420Sstevel@tonic-gate 	(((uintptr_t)(to) - (uintptr_t)(from) >> 2) & FBT_DISP14_MASK)
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate #define	FBT_OP0			(((uint32_t)0) << FBT_OP_SHIFT)
1450Sstevel@tonic-gate #define	FBT_OP1			(((uint32_t)1) << FBT_OP_SHIFT)
1460Sstevel@tonic-gate #define	FBT_OP2			(((uint32_t)2) << FBT_OP_SHIFT)
1470Sstevel@tonic-gate #define	FBT_ILLTRAP		0
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate #define	FBT_ANNUL_SHIFT		29
1500Sstevel@tonic-gate #define	FBT_ANNUL		(1 << FBT_ANNUL_SHIFT)
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate #define	FBT_FMT3_OP3_SHIFT	19
1530Sstevel@tonic-gate #define	FBT_FMT3_OP_MASK	0xc1f80000
1540Sstevel@tonic-gate #define	FBT_FMT3_OP(val)	((val) & FBT_FMT3_OP_MASK)
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate #define	FBT_FMT3_RD_SHIFT	25
1570Sstevel@tonic-gate #define	FBT_FMT3_RD_MASK	(0x1f << FBT_FMT3_RD_SHIFT)
1580Sstevel@tonic-gate #define	FBT_FMT3_RD(val)	\
1590Sstevel@tonic-gate 	(((val) & FBT_FMT3_RD_MASK) >> FBT_FMT3_RD_SHIFT)
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate #define	FBT_FMT3_RS1_SHIFT	14
1620Sstevel@tonic-gate #define	FBT_FMT3_RS1_MASK	(0x1f << FBT_FMT3_RS1_SHIFT)
1630Sstevel@tonic-gate #define	FBT_FMT3_RS1(val)	\
1640Sstevel@tonic-gate 	(((val) & FBT_FMT3_RS1_MASK) >> FBT_FMT3_RS1_SHIFT)
1650Sstevel@tonic-gate #define	FBT_FMT3_RS1_SET(val, rs1) \
1660Sstevel@tonic-gate 	(val) = ((val) & ~FBT_FMT3_RS1_MASK) | ((rs1) << FBT_FMT3_RS1_SHIFT)
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate #define	FBT_FMT3_RS2_SHIFT	0
1690Sstevel@tonic-gate #define	FBT_FMT3_RS2_MASK	(0x1f << FBT_FMT3_RS2_SHIFT)
1700Sstevel@tonic-gate #define	FBT_FMT3_RS2(val)	\
1710Sstevel@tonic-gate 	(((val) & FBT_FMT3_RS2_MASK) >> FBT_FMT3_RS2_SHIFT)
1720Sstevel@tonic-gate #define	FBT_FMT3_RS2_SET(val, rs2) \
1730Sstevel@tonic-gate 	(val) = ((val) & ~FBT_FMT3_RS2_MASK) | ((rs2) << FBT_FMT3_RS2_SHIFT)
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate #define	FBT_FMT3_IMM_SHIFT	13
1760Sstevel@tonic-gate #define	FBT_FMT3_IMM		(1 << FBT_FMT3_IMM_SHIFT)
1770Sstevel@tonic-gate #define	FBT_FMT3_SIMM13_MASK	FBT_SIMM13_MASK
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate #define	FBT_FMT3_ISIMM(val)	((val) & FBT_FMT3_IMM)
1800Sstevel@tonic-gate #define	FBT_FMT3_SIMM13(val)	((val) & FBT_FMT3_SIMM13_MASK)
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate #define	FBT_FMT2_OP2_SHIFT	22
1830Sstevel@tonic-gate #define	FBT_FMT2_OP2_MASK	(0x7 << FBT_FMT2_OP2_SHIFT)
1840Sstevel@tonic-gate #define	FBT_FMT2_RD_SHIFT	25
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate #define	FBT_FMT1_OP(val)	((val) & FBT_OP_MASK)
1870Sstevel@tonic-gate #define	FBT_FMT1_DISP30(val)	((val) & FBT_DISP30_MASK)
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate #define	FBT_FMT2_OP2_BPCC	(0x01 << FBT_FMT2_OP2_SHIFT)
1900Sstevel@tonic-gate #define	FBT_FMT2_OP2_BCC	(0x02 << FBT_FMT2_OP2_SHIFT)
1910Sstevel@tonic-gate #define	FBT_FMT2_OP2_BPR	(0x03 << FBT_FMT2_OP2_SHIFT)
1920Sstevel@tonic-gate #define	FBT_FMT2_OP2_SETHI	(0x04 << FBT_FMT2_OP2_SHIFT)
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate #define	FBT_FMT2_COND_SHIFT	25
1950Sstevel@tonic-gate #define	FBT_FMT2_COND_BA	(0x8 << FBT_FMT2_COND_SHIFT)
1960Sstevel@tonic-gate #define	FBT_FMT2_COND_BL	(0x3 << FBT_FMT2_COND_SHIFT)
1970Sstevel@tonic-gate #define	FBT_FMT2_COND_BGE	(0xb << FBT_FMT2_COND_SHIFT)
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate #define	FBT_OP_RESTORE		(FBT_OP2 | (0x3d << FBT_FMT3_OP3_SHIFT))
2000Sstevel@tonic-gate #define	FBT_OP_SAVE		(FBT_OP2 | (0x3c << FBT_FMT3_OP3_SHIFT))
2010Sstevel@tonic-gate #define	FBT_OP_JMPL		(FBT_OP2 | (0x38 << FBT_FMT3_OP3_SHIFT))
2020Sstevel@tonic-gate #define	FBT_OP_RETURN		(FBT_OP2 | (0x39 << FBT_FMT3_OP3_SHIFT))
2030Sstevel@tonic-gate #define	FBT_OP_CALL		FBT_OP1
2040Sstevel@tonic-gate #define	FBT_OP_SETHI		(FBT_OP0 | FBT_FMT2_OP2_SETHI)
2050Sstevel@tonic-gate #define	FBT_OP_ADD		(FBT_OP2 | (0x00 << FBT_FMT3_OP3_SHIFT))
2060Sstevel@tonic-gate #define	FBT_OP_OR		(FBT_OP2 | (0x02 << FBT_FMT3_OP3_SHIFT))
2070Sstevel@tonic-gate #define	FBT_OP_SUB		(FBT_OP2 | (0x04 << FBT_FMT3_OP3_SHIFT))
2080Sstevel@tonic-gate #define	FBT_OP_CC		(FBT_OP2 | (0x10 << FBT_FMT3_OP3_SHIFT))
2090Sstevel@tonic-gate #define	FBT_OP_BA		(FBT_OP0 | FBT_FMT2_OP2_BCC | FBT_FMT2_COND_BA)
2100Sstevel@tonic-gate #define	FBT_OP_BL		(FBT_OP0 | FBT_FMT2_OP2_BCC | FBT_FMT2_COND_BL)
2110Sstevel@tonic-gate #define	FBT_OP_BGE		(FBT_OP0 | FBT_FMT2_OP2_BCC | FBT_FMT2_COND_BGE)
2120Sstevel@tonic-gate #define	FBT_OP_BAPCC		(FBT_OP0 | FBT_FMT2_OP2_BPCC | FBT_FMT2_COND_BA)
2130Sstevel@tonic-gate #define	FBT_OP_RD		(FBT_OP2 | (0x28 << FBT_FMT3_OP3_SHIFT))
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate #define	FBT_ORLO(rs, val, rd) \
2160Sstevel@tonic-gate 	(FBT_OP_OR | ((rs) << FBT_FMT3_RS1_SHIFT) | \
2170Sstevel@tonic-gate 	((rd) << FBT_FMT3_RD_SHIFT) | FBT_FMT3_IMM | ((val) & FBT_IMM10_MASK))
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate #define	FBT_ORSIMM13(rs, val, rd) \
2200Sstevel@tonic-gate 	(FBT_OP_OR | ((rs) << FBT_FMT3_RS1_SHIFT) | \
2210Sstevel@tonic-gate 	((rd) << FBT_FMT3_RD_SHIFT) | FBT_FMT3_IMM | ((val) & FBT_SIMM13_MASK))
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate #define	FBT_ADDSIMM13(rs, val, rd) \
2240Sstevel@tonic-gate 	(FBT_OP_ADD | ((rs) << FBT_FMT3_RS1_SHIFT) | \
2250Sstevel@tonic-gate 	((rd) << FBT_FMT3_RD_SHIFT) | FBT_FMT3_IMM | ((val) & FBT_SIMM13_MASK))
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate #define	FBT_ADD(rs1, rs2, rd) \
2280Sstevel@tonic-gate 	(FBT_OP_ADD | ((rs1) << FBT_FMT3_RS1_SHIFT) | \
2290Sstevel@tonic-gate 	((rs2) << FBT_FMT3_RS2_SHIFT) | ((rd) << FBT_FMT3_RD_SHIFT))
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate #define	FBT_CMP(rs1, rs2) \
2320Sstevel@tonic-gate 	(FBT_OP_SUB | FBT_OP_CC | ((rs1) << FBT_FMT3_RS1_SHIFT) | \
2330Sstevel@tonic-gate 	((rs2) << FBT_FMT3_RS2_SHIFT) | (FBT_REG_G0 << FBT_FMT3_RD_SHIFT))
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate #define	FBT_MOV(rs, rd) \
2360Sstevel@tonic-gate 	(FBT_OP_OR | (FBT_REG_G0 << FBT_FMT3_RS1_SHIFT) | \
2370Sstevel@tonic-gate 	((rs) << FBT_FMT3_RS2_SHIFT) | ((rd) << FBT_FMT3_RD_SHIFT))
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate #define	FBT_SETHI(val, reg)	\
2400Sstevel@tonic-gate 	(FBT_OP_SETHI | (reg << FBT_FMT2_RD_SHIFT) | \
2410Sstevel@tonic-gate 	((val >> FBT_IMM22_SHIFT) & FBT_IMM22_MASK))
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate #define	FBT_CALL(orig, dest)	(FBT_OP_CALL | FBT_DISP30(orig, dest))
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate #define	FBT_RET \
2460Sstevel@tonic-gate 	(FBT_OP_JMPL | (FBT_REG_I7 << FBT_FMT3_RS1_SHIFT) | \
2470Sstevel@tonic-gate 	(FBT_REG_G0 << FBT_FMT3_RD_SHIFT) | FBT_FMT3_IMM | (sizeof (pc_t) << 1))
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate #define	FBT_SAVEIMM(rd, val, rs1)	\
2500Sstevel@tonic-gate 	(FBT_OP_SAVE | ((rs1) << FBT_FMT3_RS1_SHIFT) | \
2510Sstevel@tonic-gate 	((rd) << FBT_FMT3_RD_SHIFT) | FBT_FMT3_IMM | ((val) & FBT_SIMM13_MASK))
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate #define	FBT_RESTORE(rd, rs1, rs2)	\
2540Sstevel@tonic-gate 	(FBT_OP_RESTORE | ((rs1) << FBT_FMT3_RS1_SHIFT) | \
2550Sstevel@tonic-gate 	((rd) << FBT_FMT3_RD_SHIFT) | ((rs2) << FBT_FMT3_RS2_SHIFT))
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate #define	FBT_RETURN(rs1, val)		\
2580Sstevel@tonic-gate 	(FBT_OP_RETURN | ((rs1) << FBT_FMT3_RS1_SHIFT) | \
2590Sstevel@tonic-gate 	FBT_FMT3_IMM | ((val) & FBT_SIMM13_MASK))
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate #define	FBT_BA(orig, dest)	(FBT_OP_BA | FBT_DISP22(orig, dest))
2620Sstevel@tonic-gate #define	FBT_BAA(orig, dest)	(FBT_BA(orig, dest) | FBT_ANNUL)
2630Sstevel@tonic-gate #define	FBT_BL(orig, dest)	(FBT_OP_BL | FBT_DISP22(orig, dest))
2640Sstevel@tonic-gate #define	FBT_BGE(orig, dest)	(FBT_OP_BGE | FBT_DISP22(orig, dest))
2650Sstevel@tonic-gate #define	FBT_BDEST(va, instr)	((uintptr_t)(va) + \
2660Sstevel@tonic-gate 	(((int32_t)(((instr) & FBT_DISP22_MASK) << 10)) >> 8))
2670Sstevel@tonic-gate #define	FBT_BPCCDEST(va, instr)	((uintptr_t)(va) + \
2680Sstevel@tonic-gate 	(((int32_t)(((instr) & FBT_DISP19_MASK) << 13)) >> 11))
2690Sstevel@tonic-gate #define	FBT_BPRDEST(va, instr)	((uintptr_t)(va) + \
2700Sstevel@tonic-gate 	(((int32_t)((FBT_DISP16(instr)) << 16)) >> 14))
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate /*
2730Sstevel@tonic-gate  * We're only going to treat a save as safe if (a) both rs1 and rd are
2740Sstevel@tonic-gate  * %sp and (b) if the instruction has a simm, the value isn't 0.
2750Sstevel@tonic-gate  */
2760Sstevel@tonic-gate #define	FBT_IS_SAVE(instr)	\
2770Sstevel@tonic-gate 	(FBT_FMT3_OP(instr) == FBT_OP_SAVE && \
2780Sstevel@tonic-gate 	FBT_FMT3_RD(instr) == FBT_REG_O6 && \
2790Sstevel@tonic-gate 	FBT_FMT3_RS1(instr) == FBT_REG_O6 && \
2800Sstevel@tonic-gate 	!(FBT_FMT3_ISIMM(instr) && FBT_FMT3_SIMM13(instr) == 0))
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate #define	FBT_IS_BA(instr)	(((instr) & ~FBT_DISP22_MASK) == FBT_OP_BA)
2830Sstevel@tonic-gate #define	FBT_IS_BAPCC(instr)	(((instr) & ~FBT_DISP22_MASK) == FBT_OP_BAPCC)
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate #define	FBT_IS_RDPC(instr)	((FBT_FMT3_OP(instr) == FBT_OP_RD) && \
2860Sstevel@tonic-gate 	(FBT_FMT3_RD(instr) == FBT_REG_PC))
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate #define	FBT_IS_PCRELATIVE(instr)	\
2890Sstevel@tonic-gate 	((((instr) & FBT_OP_MASK) == FBT_OP0 && \
2900Sstevel@tonic-gate 	((instr) & FBT_FMT2_OP2_MASK) != FBT_FMT2_OP2_SETHI) || \
2910Sstevel@tonic-gate 	((instr) & FBT_OP_MASK) == FBT_OP1 || \
2920Sstevel@tonic-gate 	FBT_IS_RDPC(instr))
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate #define	FBT_IS_CTI(instr)	\
2950Sstevel@tonic-gate 	((((instr) & FBT_OP_MASK) == FBT_OP0 && \
2960Sstevel@tonic-gate 	((instr) & FBT_FMT2_OP2_MASK) != FBT_FMT2_OP2_SETHI) || \
2970Sstevel@tonic-gate 	((instr) & FBT_OP_MASK) == FBT_OP1 || \
2980Sstevel@tonic-gate 	(FBT_FMT3_OP(instr) == FBT_OP_JMPL) || \
2990Sstevel@tonic-gate 	(FBT_FMT3_OP(instr) == FBT_OP_RETURN))
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate #define	FBT_PROBENAME_ENTRY	"entry"
3020Sstevel@tonic-gate #define	FBT_PROBENAME_RETURN	"return"
3030Sstevel@tonic-gate #define	FBT_ESTIMATE_ID		(UINT32_MAX)
3040Sstevel@tonic-gate #define	FBT_COUNTER(id, count)	if ((id) != FBT_ESTIMATE_ID) (count)++
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate #define	FBT_ENTENT_MAXSIZE	(16 * sizeof (uint32_t))
3070Sstevel@tonic-gate #define	FBT_RETENT_MAXSIZE	(11 * sizeof (uint32_t))
3080Sstevel@tonic-gate #define	FBT_RETLENT_MAXSIZE	(23 * sizeof (uint32_t))
3090Sstevel@tonic-gate #define	FBT_ENT_MAXSIZE		\
3100Sstevel@tonic-gate 	MAX(MAX(FBT_ENTENT_MAXSIZE, FBT_RETENT_MAXSIZE), FBT_RETLENT_MAXSIZE)
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate typedef struct fbt_probe {
3130Sstevel@tonic-gate 	char		*fbtp_name;
3140Sstevel@tonic-gate 	dtrace_id_t	fbtp_id;
3150Sstevel@tonic-gate 	uintptr_t	fbtp_addr;
3160Sstevel@tonic-gate 	struct modctl	*fbtp_ctl;
3170Sstevel@tonic-gate 	int		fbtp_loadcnt;
3180Sstevel@tonic-gate 	int		fbtp_symndx;
3190Sstevel@tonic-gate 	int		fbtp_primary;
3200Sstevel@tonic-gate 	int		fbtp_return;
3210Sstevel@tonic-gate 	uint32_t	*fbtp_patchpoint;
3220Sstevel@tonic-gate 	uint32_t	fbtp_patchval;
3230Sstevel@tonic-gate 	uint32_t	fbtp_savedval;
3240Sstevel@tonic-gate 	struct fbt_probe *fbtp_next;
3250Sstevel@tonic-gate } fbt_probe_t;
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate typedef struct fbt_trampoline {
3280Sstevel@tonic-gate 	uintptr_t	fbtt_va;
3290Sstevel@tonic-gate 	uintptr_t	fbtt_limit;
3300Sstevel@tonic-gate 	uintptr_t	fbtt_next;
3310Sstevel@tonic-gate } fbt_trampoline_t;
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate static caddr_t
fbt_trampoline_map(uintptr_t tramp,size_t size)3340Sstevel@tonic-gate fbt_trampoline_map(uintptr_t tramp, size_t size)
3350Sstevel@tonic-gate {
3360Sstevel@tonic-gate 	uintptr_t offs;
3370Sstevel@tonic-gate 	page_t **ppl;
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	ASSERT(fbt_trampoline_window == NULL);
3400Sstevel@tonic-gate 	ASSERT(fbt_trampoline_size == 0);
3410Sstevel@tonic-gate 	ASSERT(fbt_trampoline == NULL);
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	size += tramp & PAGEOFFSET;
3440Sstevel@tonic-gate 	fbt_trampoline = tramp & PAGEMASK;
3450Sstevel@tonic-gate 	fbt_trampoline_size = (size + PAGESIZE - 1) & PAGEMASK;
3460Sstevel@tonic-gate 	fbt_trampoline_window =
3470Sstevel@tonic-gate 	    vmem_alloc(heap_arena, fbt_trampoline_size, VM_SLEEP);
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 	(void) as_pagelock(&kas, &ppl, (caddr_t)fbt_trampoline,
3500Sstevel@tonic-gate 	    fbt_trampoline_size, S_WRITE);
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	for (offs = 0; offs < fbt_trampoline_size; offs += PAGESIZE) {
3530Sstevel@tonic-gate 		hat_devload(kas.a_hat, fbt_trampoline_window + offs, PAGESIZE,
3540Sstevel@tonic-gate 		    hat_getpfnum(kas.a_hat, (caddr_t)fbt_trampoline + offs),
3550Sstevel@tonic-gate 		    PROT_READ | PROT_WRITE,
3560Sstevel@tonic-gate 		    HAT_LOAD_LOCK | HAT_LOAD_NOCONSIST);
3570Sstevel@tonic-gate 	}
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	as_pageunlock(&kas, ppl, (caddr_t)fbt_trampoline, fbt_trampoline_size,
3600Sstevel@tonic-gate 	    S_WRITE);
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	return (fbt_trampoline_window + (tramp & PAGEOFFSET));
3630Sstevel@tonic-gate }
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate static void
fbt_trampoline_unmap()3660Sstevel@tonic-gate fbt_trampoline_unmap()
3670Sstevel@tonic-gate {
3680Sstevel@tonic-gate 	ASSERT(fbt_trampoline_window != NULL);
3690Sstevel@tonic-gate 	ASSERT(fbt_trampoline_size != 0);
3700Sstevel@tonic-gate 	ASSERT(fbt_trampoline != NULL);
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 	membar_enter();
3730Sstevel@tonic-gate 	sync_icache((caddr_t)fbt_trampoline, fbt_trampoline_size);
3740Sstevel@tonic-gate 	sync_icache(fbt_trampoline_window, fbt_trampoline_size);
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	hat_unload(kas.a_hat, fbt_trampoline_window, fbt_trampoline_size,
3770Sstevel@tonic-gate 	    HAT_UNLOAD_UNLOCK);
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	vmem_free(heap_arena, fbt_trampoline_window, fbt_trampoline_size);
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	fbt_trampoline_window = NULL;
3820Sstevel@tonic-gate 	fbt_trampoline = NULL;
3830Sstevel@tonic-gate 	fbt_trampoline_size = 0;
3840Sstevel@tonic-gate }
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate static uintptr_t
fbt_patch_entry(uint32_t * instr,uint32_t id,fbt_trampoline_t * tramp,int nargs)3870Sstevel@tonic-gate fbt_patch_entry(uint32_t *instr, uint32_t id, fbt_trampoline_t *tramp,
3880Sstevel@tonic-gate     int nargs)
3890Sstevel@tonic-gate {
3900Sstevel@tonic-gate 	uint32_t *tinstr = (uint32_t *)tramp->fbtt_next;
3910Sstevel@tonic-gate 	uint32_t first = *instr;
3920Sstevel@tonic-gate 	uintptr_t va = tramp->fbtt_va;
3930Sstevel@tonic-gate 	uintptr_t base = tramp->fbtt_next;
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	if (tramp->fbtt_next + FBT_ENTENT_MAXSIZE > tramp->fbtt_limit) {
3960Sstevel@tonic-gate 		/*
3970Sstevel@tonic-gate 		 * There isn't sufficient room for this entry; return failure.
3980Sstevel@tonic-gate 		 */
3990Sstevel@tonic-gate 		return (0);
4000Sstevel@tonic-gate 	}
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	FBT_COUNTER(id, fbt_entry);
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 	if (FBT_IS_SAVE(first)) {
4050Sstevel@tonic-gate 		*tinstr++ = first;
4060Sstevel@tonic-gate 	} else {
4070Sstevel@tonic-gate 		*tinstr++ = FBT_SAVEIMM(FBT_REG_O6, -SA(MINFRAME), FBT_REG_O6);
4080Sstevel@tonic-gate 	}
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 	if (id > (uint32_t)FBT_SIMM13_MAX) {
4110Sstevel@tonic-gate 		*tinstr++ = FBT_SETHI(id, FBT_REG_O0);
4120Sstevel@tonic-gate 		*tinstr++ = FBT_ORLO(FBT_REG_O0, id, FBT_REG_O0);
4130Sstevel@tonic-gate 	} else {
4140Sstevel@tonic-gate 		*tinstr++ = FBT_ORSIMM13(FBT_REG_G0, id, FBT_REG_O0);
4150Sstevel@tonic-gate 	}
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 	if (nargs >= 1)
4180Sstevel@tonic-gate 		*tinstr++ = FBT_MOV(FBT_REG_I0, FBT_REG_O1);
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	if (nargs >= 2)
4210Sstevel@tonic-gate 		*tinstr++ = FBT_MOV(FBT_REG_I1, FBT_REG_O2);
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	if (nargs >= 3)
4240Sstevel@tonic-gate 		*tinstr++ = FBT_MOV(FBT_REG_I2, FBT_REG_O3);
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	if (nargs >= 4)
4270Sstevel@tonic-gate 		*tinstr++ = FBT_MOV(FBT_REG_I3, FBT_REG_O4);
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	if (nargs >= 5)
4300Sstevel@tonic-gate 		*tinstr++ = FBT_MOV(FBT_REG_I4, FBT_REG_O5);
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	if (FBT_IS_SAVE(first)) {
4330Sstevel@tonic-gate 		uintptr_t ret = (uintptr_t)instr - sizeof (uint32_t);
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 		*tinstr++ = FBT_SETHI(ret, FBT_REG_G1);
4360Sstevel@tonic-gate 		*tinstr = FBT_CALL((uintptr_t)tinstr - base + va, dtrace_probe);
4370Sstevel@tonic-gate 		tinstr++;
4380Sstevel@tonic-gate 		*tinstr++ = FBT_ORLO(FBT_REG_G1, ret, FBT_REG_O7);
4390Sstevel@tonic-gate 	} else {
4400Sstevel@tonic-gate 		uintptr_t slot = *--tinstr;
4410Sstevel@tonic-gate 		uintptr_t ret = (uintptr_t)instr + sizeof (uint32_t);
4420Sstevel@tonic-gate 		uint32_t delay = first;
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 		*tinstr = FBT_CALL((uintptr_t)tinstr - base + va, dtrace_probe);
4450Sstevel@tonic-gate 		tinstr++;
4460Sstevel@tonic-gate 		*tinstr++ = slot;
4470Sstevel@tonic-gate 		*tinstr++ = FBT_RESTORE(FBT_REG_G0, FBT_REG_G0, FBT_REG_G0);
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 		if (FBT_IS_BA(first) || FBT_IS_BAPCC(first)) {
4500Sstevel@tonic-gate 			/*
4510Sstevel@tonic-gate 			 * This is a special case:  we are instrumenting a
4520Sstevel@tonic-gate 			 * a non-annulled branch-always (or variant).  We'll
4530Sstevel@tonic-gate 			 * return directly to the destination of the branch,
4540Sstevel@tonic-gate 			 * copying the instruction in the delay slot here,
4550Sstevel@tonic-gate 			 * and then executing it in the slot of a ba.
4560Sstevel@tonic-gate 			 */
4570Sstevel@tonic-gate 			if (FBT_IS_BA(first)) {
4580Sstevel@tonic-gate 				ret = FBT_BDEST(instr, *instr);
4590Sstevel@tonic-gate 			} else {
4600Sstevel@tonic-gate 				ret = FBT_BPCCDEST(instr, *instr);
4610Sstevel@tonic-gate 			}
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 			delay = *(instr + 1);
4640Sstevel@tonic-gate 		}
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 		if ((first & FBT_OP_MASK) != FBT_OP0 ||
4670Sstevel@tonic-gate 		    (first & FBT_FMT2_OP2_MASK) != FBT_FMT2_OP2_BPR) {
4680Sstevel@tonic-gate 			*tinstr = FBT_BA((uintptr_t)tinstr - base + va, ret);
4690Sstevel@tonic-gate 			tinstr++;
4700Sstevel@tonic-gate 			*tinstr++ = delay;
4710Sstevel@tonic-gate 		} else {
4720Sstevel@tonic-gate 			/*
4730Sstevel@tonic-gate 			 * If this is a branch-on-register, we have a little
4740Sstevel@tonic-gate 			 * more work to do:  because the displacement is only
4750Sstevel@tonic-gate 			 * sixteen bits, we're going to thunk the branch into
4760Sstevel@tonic-gate 			 * the trampoline, and then ba,a to the appropriate
4770Sstevel@tonic-gate 			 * destination in the branch targets.  That is, we're
4780Sstevel@tonic-gate 			 * constructing this sequence in the trampoline:
4790Sstevel@tonic-gate 			 *
4800Sstevel@tonic-gate 			 *		br[cc]	%[rs], 1f
4810Sstevel@tonic-gate 			 *		<delay-instruction>
4820Sstevel@tonic-gate 			 *		ba,a	<not-taken-destination>
4830Sstevel@tonic-gate 			 *	1:	ba,a	<taken-destination>
4840Sstevel@tonic-gate 			 *
4850Sstevel@tonic-gate 			 */
4860Sstevel@tonic-gate 			uintptr_t targ = FBT_BPRDEST(instr, first);
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 			*tinstr = first & ~(FBT_DISP16_MASK);
4890Sstevel@tonic-gate 			*tinstr |= FBT_DISP14(tinstr, &tinstr[3]);
4900Sstevel@tonic-gate 			tinstr++;
4910Sstevel@tonic-gate 			*tinstr++ = *(instr + 1);
4920Sstevel@tonic-gate 			*tinstr = FBT_BAA((uintptr_t)tinstr - base + va,
4930Sstevel@tonic-gate 			    ret + sizeof (uint32_t));
4940Sstevel@tonic-gate 			tinstr++;
4950Sstevel@tonic-gate 			*tinstr = FBT_BAA((uintptr_t)tinstr - base + va, targ);
4960Sstevel@tonic-gate 			tinstr++;
4970Sstevel@tonic-gate 		}
4980Sstevel@tonic-gate 	}
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 	tramp->fbtt_va += (uintptr_t)tinstr - tramp->fbtt_next;
5010Sstevel@tonic-gate 	tramp->fbtt_next = (uintptr_t)tinstr;
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 	return (1);
5040Sstevel@tonic-gate }
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate /*
5070Sstevel@tonic-gate  * We are patching control-transfer/restore couplets.  There are three
5080Sstevel@tonic-gate  * variants of couplet:
5090Sstevel@tonic-gate  *
5100Sstevel@tonic-gate  * (a)	return		rs1 + imm
5110Sstevel@tonic-gate  *	delay
5120Sstevel@tonic-gate  *
5130Sstevel@tonic-gate  * (b)	jmpl		rs1 + (rs2 | offset), rd
5140Sstevel@tonic-gate  *	restore		rs1, rs2 | imm, rd
5150Sstevel@tonic-gate  *
5160Sstevel@tonic-gate  * (c)	call		displacement
5170Sstevel@tonic-gate  *	restore		rs1, rs2 | imm, rd
5180Sstevel@tonic-gate  *
5190Sstevel@tonic-gate  * If rs1 in (a) is anything other than %i7, or imm is anything other than 8,
5200Sstevel@tonic-gate  * or delay is a DCTI, we fail.  If rd from the jmpl in (b) is something other
5210Sstevel@tonic-gate  * than %g0 (a ret or a tail-call through a function pointer) or %o7 (a call
5220Sstevel@tonic-gate  * through a register), we fail.
5230Sstevel@tonic-gate  *
5240Sstevel@tonic-gate  * Note that rs1 and rs2 in the restore instructions in (b) and (c) are
5250Sstevel@tonic-gate  * potentially outputs and/or globals.  Because these registers cannot be
5260Sstevel@tonic-gate  * relied upon across the call to dtrace_probe(), we move rs1 into an unused
5270Sstevel@tonic-gate  * local, ls0, and rs2 into an unused local, ls1, and restructure the restore
5280Sstevel@tonic-gate  * to be:
5290Sstevel@tonic-gate  *
5300Sstevel@tonic-gate  *	restore		ls0, ls1, rd
5310Sstevel@tonic-gate  *
5320Sstevel@tonic-gate  * Likewise, rs1 and rs2 in the jmpl of case (b) may be outputs and/or globals.
5330Sstevel@tonic-gate  * If the jmpl uses outputs or globals, we restructure it to be:
5340Sstevel@tonic-gate  *
5350Sstevel@tonic-gate  * 	jmpl		ls2 + (ls3 | offset), (%g0 | %o7)
5360Sstevel@tonic-gate  *
5370Sstevel@tonic-gate  */
5380Sstevel@tonic-gate /*ARGSUSED*/
5390Sstevel@tonic-gate static int
fbt_canpatch_return(uint32_t * instr,int offset,const char * name)5400Sstevel@tonic-gate fbt_canpatch_return(uint32_t *instr, int offset, const char *name)
5410Sstevel@tonic-gate {
5420Sstevel@tonic-gate 	int rd;
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 	if (FBT_FMT3_OP(*instr) == FBT_OP_RETURN) {
5450Sstevel@tonic-gate 		uint32_t delay = *(instr + 1);
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 		if (*instr != FBT_RETURN(FBT_REG_I7, 8)) {
5480Sstevel@tonic-gate 			/*
5490Sstevel@tonic-gate 			 * It's unclear if we should warn about this or not.
5500Sstevel@tonic-gate 			 * We really wouldn't expect the compiler to generate
5510Sstevel@tonic-gate 			 * return instructions with something other than %i7
5520Sstevel@tonic-gate 			 * as rs1 and 8 as the simm13 -- it would just be
5530Sstevel@tonic-gate 			 * mean-spirited.  That said, such a construct isn't
5540Sstevel@tonic-gate 			 * necessarily incorrect.  Sill, we err on the side of
5550Sstevel@tonic-gate 			 * caution and warn about it...
5560Sstevel@tonic-gate 			 */
5570Sstevel@tonic-gate 			cmn_err(CE_NOTE, "cannot instrument return of %s at "
5580Sstevel@tonic-gate 			    "%p: non-canonical return instruction", name,
5590Sstevel@tonic-gate 			    (void *)instr);
5600Sstevel@tonic-gate 			return (0);
5610Sstevel@tonic-gate 		}
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 		if (FBT_IS_CTI(delay)) {
5640Sstevel@tonic-gate 			/*
5650Sstevel@tonic-gate 			 * This is even weirder -- a DCTI coupled with a
5660Sstevel@tonic-gate 			 * return instruction.  Similar constructs are used to
5670Sstevel@tonic-gate 			 * return from utraps, but these typically have the
5680Sstevel@tonic-gate 			 * return in the slot -- and we wouldn't expect to see
5690Sstevel@tonic-gate 			 * it in the kernel regardless.  At any rate, we don't
5700Sstevel@tonic-gate 			 * want to try to instrument this construct, whatever
5710Sstevel@tonic-gate 			 * it may be.
5720Sstevel@tonic-gate 			 */
5730Sstevel@tonic-gate 			cmn_err(CE_NOTE, "cannot instrument return of %s at "
5740Sstevel@tonic-gate 			    "%p: CTI in delay slot of return instruction",
5750Sstevel@tonic-gate 			    name, (void *)instr);
5760Sstevel@tonic-gate 			return (0);
5770Sstevel@tonic-gate 		}
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 		if (FBT_IS_PCRELATIVE(delay)) {
5800Sstevel@tonic-gate 			/*
5810Sstevel@tonic-gate 			 * This is also very weird, but might be correct code
5820Sstevel@tonic-gate 			 * if the function is (for example) returning the
5830Sstevel@tonic-gate 			 * address of the delay instruction of the return as
5840Sstevel@tonic-gate 			 * its return value (e.g. "rd %pc, %o0" in the slot).
5850Sstevel@tonic-gate 			 * Perhaps correct, but still too weird to not warn
5860Sstevel@tonic-gate 			 * about it...
5870Sstevel@tonic-gate 			 */
5880Sstevel@tonic-gate 			cmn_err(CE_NOTE, "cannot instrument return of %s at "
5890Sstevel@tonic-gate 			    "%p: PC-relative instruction in delay slot of "
5900Sstevel@tonic-gate 			    "return instruction", name, (void *)instr);
5910Sstevel@tonic-gate 			return (0);
5920Sstevel@tonic-gate 		}
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 		return (1);
5950Sstevel@tonic-gate 	}
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate 	if (FBT_FMT3_OP(*(instr + 1)) != FBT_OP_RESTORE)
5980Sstevel@tonic-gate 		return (0);
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	if (FBT_FMT1_OP(*instr) == FBT_OP_CALL)
6010Sstevel@tonic-gate 		return (1);
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	if (FBT_FMT3_OP(*instr) != FBT_OP_JMPL)
6040Sstevel@tonic-gate 		return (0);
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 	rd = FBT_FMT3_RD(*instr);
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	if (rd == FBT_REG_I7 || rd == FBT_REG_O7 || rd == FBT_REG_G0)
6090Sstevel@tonic-gate 		return (1);
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	/*
6120Sstevel@tonic-gate 	 * We have encountered a jmpl that is storing the calling %pc in
6130Sstevel@tonic-gate 	 * some register besides %i7, %o7 or %g0.  This is strange; emit
6140Sstevel@tonic-gate 	 * a warning and fail.
6150Sstevel@tonic-gate 	 */
6160Sstevel@tonic-gate 	cmn_err(CE_NOTE, "cannot instrument return of %s at %p: unexpected "
6170Sstevel@tonic-gate 	    "jmpl destination register", name, (void *)instr);
6180Sstevel@tonic-gate 	return (0);
6190Sstevel@tonic-gate }
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate static int
fbt_canpatch_retl(uint32_t * instr,int offset,const char * name)6220Sstevel@tonic-gate fbt_canpatch_retl(uint32_t *instr, int offset, const char *name)
6230Sstevel@tonic-gate {
6240Sstevel@tonic-gate 	if (FBT_FMT1_OP(*instr) == FBT_OP_CALL ||
6250Sstevel@tonic-gate 	    (FBT_FMT3_OP(*instr) == FBT_OP_JMPL &&
6260Sstevel@tonic-gate 	    FBT_FMT3_RD(*instr) == FBT_REG_O7)) {
6270Sstevel@tonic-gate 		/*
6280Sstevel@tonic-gate 		 * If this is a call (or a jmpl that links into %o7), we can
6290Sstevel@tonic-gate 		 * patch it iff the next instruction uses %o7 as a destination
6300Sstevel@tonic-gate 		 * register.  Because there is an ABI responsibility to
6310Sstevel@tonic-gate 		 * restore %o7 to the value before the call/jmpl, we don't
6320Sstevel@tonic-gate 		 * particularly care how this routine is managing to restore
6330Sstevel@tonic-gate 		 * it (mov, add, ld or divx for all we care).  If it doesn't
6340Sstevel@tonic-gate 		 * seem to be restoring it at all, however, we'll refuse
6350Sstevel@tonic-gate 		 * to patch it.
6360Sstevel@tonic-gate 		 */
6370Sstevel@tonic-gate 		uint32_t delay = *(instr + 1);
6380Sstevel@tonic-gate 		uint32_t op, rd;
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 		op = FBT_FMT1_OP(delay);
6410Sstevel@tonic-gate 		rd = FBT_FMT3_RD(delay);
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 		if (op != FBT_OP2 || rd != FBT_REG_O7) {
6440Sstevel@tonic-gate 			/*
6450Sstevel@tonic-gate 			 * This is odd.  Before we assume that we're looking
6460Sstevel@tonic-gate 			 * at something bizarre (and warn accordingly), we'll
6470Sstevel@tonic-gate 			 * check to see if it's obviously a jump table entry.
6480Sstevel@tonic-gate 			 */
6490Sstevel@tonic-gate 			if (*instr < (uintptr_t)instr &&
6500Sstevel@tonic-gate 			    *instr >= (uintptr_t)instr - offset)
6510Sstevel@tonic-gate 				return (0);
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate 			cmn_err(CE_NOTE, "cannot instrument return of %s at "
6540Sstevel@tonic-gate 			    "%p: leaf jmpl/call delay isn't restoring %%o7",
6550Sstevel@tonic-gate 			    name, (void *)instr);
6560Sstevel@tonic-gate 			return (0);
6570Sstevel@tonic-gate 		}
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 		return (1);
6600Sstevel@tonic-gate 	}
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 	if (offset == sizeof (uint32_t)) {
6630Sstevel@tonic-gate 		/*
6640Sstevel@tonic-gate 		 * If this is the second instruction in the function, we're
6650Sstevel@tonic-gate 		 * going to allow it to be patched if the first instruction
6660Sstevel@tonic-gate 		 * is a patchable return-from-leaf instruction.
6670Sstevel@tonic-gate 		 */
6680Sstevel@tonic-gate 		if (fbt_canpatch_retl(instr - 1, 0, name))
6690Sstevel@tonic-gate 			return (1);
6700Sstevel@tonic-gate 	}
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate 	if (FBT_FMT3_OP(*instr) != FBT_OP_JMPL)
6730Sstevel@tonic-gate 		return (0);
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	if (FBT_FMT3_RD(*instr) != FBT_REG_G0)
6760Sstevel@tonic-gate 		return (0);
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 	return (1);
6790Sstevel@tonic-gate }
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate /*ARGSUSED*/
6820Sstevel@tonic-gate static uint32_t
fbt_patch_return(uint32_t * instr,uint32_t * funcbase,uint32_t * funclim,int offset,uint32_t id,fbt_trampoline_t * tramp,const char * name)6830Sstevel@tonic-gate fbt_patch_return(uint32_t *instr, uint32_t *funcbase, uint32_t *funclim,
6840Sstevel@tonic-gate     int offset, uint32_t id, fbt_trampoline_t *tramp, const char *name)
6850Sstevel@tonic-gate {
6860Sstevel@tonic-gate 	uint32_t *tinstr = (uint32_t *)tramp->fbtt_next;
6870Sstevel@tonic-gate 	uint32_t cti = *instr, restore = *(instr + 1), rs1, dest;
6880Sstevel@tonic-gate 	uintptr_t va = tramp->fbtt_va;
6890Sstevel@tonic-gate 	uintptr_t base = tramp->fbtt_next;
6900Sstevel@tonic-gate 	uint32_t locals[FBT_REG_NLOCALS], local;
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	if (tramp->fbtt_next + FBT_RETENT_MAXSIZE > tramp->fbtt_limit) {
6930Sstevel@tonic-gate 		/*
6940Sstevel@tonic-gate 		 * There isn't sufficient room for this entry; return failure.
6950Sstevel@tonic-gate 		 */
6960Sstevel@tonic-gate 		return (FBT_ILLTRAP);
6970Sstevel@tonic-gate 	}
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	FBT_COUNTER(id, fbt_ret);
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 	if (FBT_FMT3_OP(*instr) == FBT_OP_RETURN) {
7020Sstevel@tonic-gate 		/*
7030Sstevel@tonic-gate 		 * To handle the case of the return instruction, we'll emit a
7040Sstevel@tonic-gate 		 * restore, followed by the instruction in the slot (which
7050Sstevel@tonic-gate 		 * we'll transplant here), and then another save.  While it
7060Sstevel@tonic-gate 		 * may seem intellectually unsatisfying to emit the additional
7070Sstevel@tonic-gate 		 * restore/save couplet, one can take solace in the fact that
7080Sstevel@tonic-gate 		 * we don't do this if the instruction in the return delay
7090Sstevel@tonic-gate 		 * slot is a nop -- which it is nearly 90% of the time with
7100Sstevel@tonic-gate 		 * gcc.  (And besides, this couplet can't induce unnecessary
7110Sstevel@tonic-gate 		 * spill/fill traps; rewriting the delay instruction to be
7120Sstevel@tonic-gate 		 * in terms of the current window hardly seems worth the
7130Sstevel@tonic-gate 		 * trouble -- let alone the risk.)
7140Sstevel@tonic-gate 		 */
7150Sstevel@tonic-gate 		uint32_t delay = *(instr + 1);
7160Sstevel@tonic-gate 		ASSERT(*instr == FBT_RETURN(FBT_REG_I7, 8));
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 		cti = FBT_RET;
7190Sstevel@tonic-gate 		restore = FBT_RESTORE(FBT_REG_G0, FBT_REG_G0, FBT_REG_G0);
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate 		if (delay != FBT_SETHI(0, FBT_REG_G0)) {
7220Sstevel@tonic-gate 			*tinstr++ = restore;
7230Sstevel@tonic-gate 			*tinstr++ = delay;
7240Sstevel@tonic-gate 			*tinstr++ = FBT_SAVEIMM(FBT_REG_O6,
7250Sstevel@tonic-gate 			    -SA(MINFRAME), FBT_REG_O6);
7260Sstevel@tonic-gate 		}
7270Sstevel@tonic-gate 	}
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 	FBT_REG_INITLOCALS(local, locals);
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 	/*
7320Sstevel@tonic-gate 	 * Mark the locals used in the jmpl.
7330Sstevel@tonic-gate 	 */
7340Sstevel@tonic-gate 	if (FBT_FMT3_OP(cti) == FBT_OP_JMPL) {
7350Sstevel@tonic-gate 		uint32_t rs1 = FBT_FMT3_RS1(cti);
7360Sstevel@tonic-gate 		FBT_REG_MARKLOCAL(locals, rs1);
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate 		if (!FBT_FMT3_ISIMM(cti)) {
7390Sstevel@tonic-gate 			uint32_t rs2 = FBT_FMT3_RS2(cti);
7400Sstevel@tonic-gate 			FBT_REG_MARKLOCAL(locals, rs2);
7410Sstevel@tonic-gate 		}
7420Sstevel@tonic-gate 	}
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 	/*
7450Sstevel@tonic-gate 	 * And mark the locals used in the restore.
7460Sstevel@tonic-gate 	 */
7470Sstevel@tonic-gate 	rs1 = FBT_FMT3_RS1(restore);
7480Sstevel@tonic-gate 	FBT_REG_MARKLOCAL(locals, rs1);
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	if (!FBT_FMT3_ISIMM(restore)) {
7510Sstevel@tonic-gate 		uint32_t rs2 = FBT_FMT3_RS2(restore);
7520Sstevel@tonic-gate 		FBT_REG_MARKLOCAL(locals, rs2);
7530Sstevel@tonic-gate 	}
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 	if (FBT_FMT3_OP(cti) == FBT_OP_JMPL) {
7560Sstevel@tonic-gate 		uint32_t rs1 = FBT_FMT3_RS1(cti);
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate 		if (FBT_REG_ISVOLATILE(rs1)) {
7590Sstevel@tonic-gate 			FBT_REG_ALLOCLOCAL(local, locals);
7600Sstevel@tonic-gate 			FBT_FMT3_RS1_SET(cti, local);
7610Sstevel@tonic-gate 			*tinstr++ = FBT_MOV(rs1, local);
7620Sstevel@tonic-gate 		}
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate 		if (!FBT_FMT3_ISIMM(cti)) {
7650Sstevel@tonic-gate 			uint32_t rs2 = FBT_FMT3_RS2(cti);
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 			if (FBT_REG_ISVOLATILE(rs2)) {
7680Sstevel@tonic-gate 				FBT_REG_ALLOCLOCAL(local, locals);
7690Sstevel@tonic-gate 				FBT_FMT3_RS2_SET(cti, local);
7700Sstevel@tonic-gate 				*tinstr++ = FBT_MOV(rs2, local);
7710Sstevel@tonic-gate 			}
7720Sstevel@tonic-gate 		}
7730Sstevel@tonic-gate 	}
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	rs1 = FBT_FMT3_RS1(restore);
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 	if (FBT_REG_ISVOLATILE(rs1)) {
7780Sstevel@tonic-gate 		FBT_REG_ALLOCLOCAL(local, locals);
7790Sstevel@tonic-gate 		FBT_FMT3_RS1_SET(restore, local);
7800Sstevel@tonic-gate 		*tinstr++ = FBT_MOV(rs1, local);
7810Sstevel@tonic-gate 	}
7820Sstevel@tonic-gate 
7830Sstevel@tonic-gate 	if (!FBT_FMT3_ISIMM(restore)) {
7840Sstevel@tonic-gate 		uint32_t rs2 = FBT_FMT3_RS2(restore);
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 		if (FBT_REG_ISVOLATILE(rs2)) {
7870Sstevel@tonic-gate 			FBT_REG_ALLOCLOCAL(local, locals);
7880Sstevel@tonic-gate 			FBT_FMT3_RS2_SET(restore, local);
7890Sstevel@tonic-gate 			*tinstr++ = FBT_MOV(rs2, local);
7900Sstevel@tonic-gate 		}
7910Sstevel@tonic-gate 	}
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	if (id > (uint32_t)FBT_SIMM13_MAX) {
7940Sstevel@tonic-gate 		*tinstr++ = FBT_SETHI(id, FBT_REG_O0);
7950Sstevel@tonic-gate 		*tinstr++ = FBT_ORLO(FBT_REG_O0, id, FBT_REG_O0);
7960Sstevel@tonic-gate 	} else {
7970Sstevel@tonic-gate 		*tinstr++ = FBT_ORSIMM13(FBT_REG_G0, id, FBT_REG_O0);
7980Sstevel@tonic-gate 	}
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 	if (offset > (uint32_t)FBT_SIMM13_MAX) {
8010Sstevel@tonic-gate 		*tinstr++ = FBT_SETHI(offset, FBT_REG_O1);
8020Sstevel@tonic-gate 		*tinstr++ = FBT_ORLO(FBT_REG_O1, offset, FBT_REG_O1);
8030Sstevel@tonic-gate 	} else {
8040Sstevel@tonic-gate 		*tinstr++ = FBT_ORSIMM13(FBT_REG_G0, offset, FBT_REG_O1);
8050Sstevel@tonic-gate 	}
8060Sstevel@tonic-gate 
8070Sstevel@tonic-gate 	*tinstr = FBT_CALL((uintptr_t)tinstr - base + va, dtrace_probe);
8080Sstevel@tonic-gate 	tinstr++;
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 	if (FBT_FMT3_RD(restore) == FBT_REG_O0) {
8110Sstevel@tonic-gate 		/*
8120Sstevel@tonic-gate 		 * If the destination register of the restore is %o0, we
8130Sstevel@tonic-gate 		 * need to perform the implied calculation to derive the
8140Sstevel@tonic-gate 		 * return value.
8150Sstevel@tonic-gate 		 */
8160Sstevel@tonic-gate 		uint32_t add = (restore & ~FBT_FMT3_OP_MASK) | FBT_OP_ADD;
8170Sstevel@tonic-gate 		add &= ~FBT_FMT3_RD_MASK;
8180Sstevel@tonic-gate 		*tinstr++ = add | (FBT_REG_O2 << FBT_FMT3_RD_SHIFT);
8190Sstevel@tonic-gate 	} else {
8200Sstevel@tonic-gate 		*tinstr++ = FBT_MOV(FBT_REG_I0, FBT_REG_O2);
8210Sstevel@tonic-gate 	}
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 	/*
8240Sstevel@tonic-gate 	 * If the control transfer instruction is %pc-relative (i.e. a
8250Sstevel@tonic-gate 	 * call), we need to reset it appropriately.
8260Sstevel@tonic-gate 	 */
8270Sstevel@tonic-gate 	if (FBT_FMT1_OP(cti) == FBT_OP_CALL) {
8280Sstevel@tonic-gate 		dest = (uintptr_t)instr + (FBT_FMT1_DISP30(cti) << 2);
8290Sstevel@tonic-gate 		*tinstr = FBT_CALL((uintptr_t)tinstr - base + va, dest);
8300Sstevel@tonic-gate 		tinstr++;
8310Sstevel@tonic-gate 	} else {
8320Sstevel@tonic-gate 		*tinstr++ = cti;
8330Sstevel@tonic-gate 	}
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 	*tinstr++ = restore;
8360Sstevel@tonic-gate 	tramp->fbtt_va += (uintptr_t)tinstr - tramp->fbtt_next;
8370Sstevel@tonic-gate 	tramp->fbtt_next = (uintptr_t)tinstr;
8380Sstevel@tonic-gate 
8390Sstevel@tonic-gate 	return (FBT_BAA(instr, va));
8400Sstevel@tonic-gate }
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate static uint32_t
fbt_patch_retl(uint32_t * instr,uint32_t * funcbase,uint32_t * funclim,int offset,uint32_t id,fbt_trampoline_t * tramp,const char * name)8430Sstevel@tonic-gate fbt_patch_retl(uint32_t *instr, uint32_t *funcbase, uint32_t *funclim,
8440Sstevel@tonic-gate     int offset, uint32_t id, fbt_trampoline_t *tramp, const char *name)
8450Sstevel@tonic-gate {
8460Sstevel@tonic-gate 	uint32_t *tinstr = (uint32_t *)tramp->fbtt_next;
8470Sstevel@tonic-gate 	uintptr_t va = tramp->fbtt_va;
8480Sstevel@tonic-gate 	uintptr_t base = tramp->fbtt_next;
8490Sstevel@tonic-gate 	uint32_t cti = *instr, dest;
8500Sstevel@tonic-gate 	int annul = 0;
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 	FBT_COUNTER(id, fbt_retl);
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 	if (tramp->fbtt_next + FBT_RETLENT_MAXSIZE > tramp->fbtt_limit) {
8550Sstevel@tonic-gate 		/*
8560Sstevel@tonic-gate 		 * There isn't sufficient room for this entry; return failure.
8570Sstevel@tonic-gate 		 */
8580Sstevel@tonic-gate 		return (FBT_ILLTRAP);
8590Sstevel@tonic-gate 	}
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 	if (offset == sizeof (uint32_t) &&
8620Sstevel@tonic-gate 	    fbt_canpatch_retl(instr - 1, 0, name)) {
8630Sstevel@tonic-gate 		*tinstr++ = *instr;
8640Sstevel@tonic-gate 		annul = 1;
8650Sstevel@tonic-gate 		FBT_COUNTER(id, fbt_retl_twoinstr);
8660Sstevel@tonic-gate 	} else {
8670Sstevel@tonic-gate 		if (FBT_FMT3_OP(cti) == FBT_OP_JMPL &&
8680Sstevel@tonic-gate 		    FBT_FMT3_RD(cti) != FBT_REG_O7 &&
8690Sstevel@tonic-gate 		    FBT_FMT3_RS1(cti) != FBT_REG_O7) {
8700Sstevel@tonic-gate 			annul = 1;
8710Sstevel@tonic-gate 			*tinstr++ = *(instr + 1);
8720Sstevel@tonic-gate 		}
8730Sstevel@tonic-gate 	}
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 	*tinstr++ = FBT_SAVEIMM(FBT_REG_O6, -SA(MINFRAME), FBT_REG_O6);
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 	if (FBT_FMT3_OP(cti) == FBT_OP_JMPL) {
8780Sstevel@tonic-gate 		uint32_t rs1, rs2, o2i = FBT_REG_I0 - FBT_REG_O0;
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 		/*
8810Sstevel@tonic-gate 		 * If we have a jmpl and it's in terms of output registers, we
8820Sstevel@tonic-gate 		 * need to rewrite it to be in terms of the corresponding input
8830Sstevel@tonic-gate 		 * registers.  If it's in terms of the globals, we'll rewrite
8840Sstevel@tonic-gate 		 * it to be in terms of locals.
8850Sstevel@tonic-gate 		 */
8860Sstevel@tonic-gate 		rs1 = FBT_FMT3_RS1(cti);
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate 		if (FBT_REG_ISOUTPUT(rs1))
8890Sstevel@tonic-gate 			rs1 += o2i;
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 		if (FBT_REG_ISGLOBAL(rs1)) {
8920Sstevel@tonic-gate 			*tinstr++ = FBT_MOV(rs1, FBT_REG_L0);
8930Sstevel@tonic-gate 			rs1 = FBT_REG_L0;
8940Sstevel@tonic-gate 		}
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 		FBT_FMT3_RS1_SET(cti, rs1);
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate 		if (!FBT_FMT3_ISIMM(cti)) {
8990Sstevel@tonic-gate 			rs2 = FBT_FMT3_RS2(cti);
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 			if (FBT_REG_ISOUTPUT(rs2))
9020Sstevel@tonic-gate 				rs2 += o2i;
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate 			if (FBT_REG_ISGLOBAL(rs2)) {
9050Sstevel@tonic-gate 				*tinstr++ = FBT_MOV(rs2, FBT_REG_L1);
9060Sstevel@tonic-gate 				rs2 = FBT_REG_L1;
9070Sstevel@tonic-gate 			}
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 			FBT_FMT3_RS2_SET(cti, rs2);
9100Sstevel@tonic-gate 		}
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 		/*
9130Sstevel@tonic-gate 		 * Now we need to check the rd and source register for the jmpl;
9140Sstevel@tonic-gate 		 * If neither rd nor the source register is %o7, then we might
9150Sstevel@tonic-gate 		 * have a jmp that is actually part of a jump table.  We need
9160Sstevel@tonic-gate 		 * to generate the code to compare it to the base and limit of
9170Sstevel@tonic-gate 		 * the function.
9180Sstevel@tonic-gate 		 */
9190Sstevel@tonic-gate 		if (FBT_FMT3_RD(cti) != FBT_REG_O7 && rs1 != FBT_REG_I7) {
9200Sstevel@tonic-gate 			uintptr_t base = (uintptr_t)funcbase;
9210Sstevel@tonic-gate 			uintptr_t limit = (uintptr_t)funclim;
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate 			FBT_COUNTER(id, fbt_retl_jmptab);
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 			if (FBT_FMT3_ISIMM(cti)) {
9260Sstevel@tonic-gate 				*tinstr++ = FBT_ADDSIMM13(rs1,
9270Sstevel@tonic-gate 				    FBT_FMT3_SIMM13(cti), FBT_REG_L2);
9280Sstevel@tonic-gate 			} else {
9290Sstevel@tonic-gate 				*tinstr++ = FBT_ADD(rs1, rs2, FBT_REG_L2);
9300Sstevel@tonic-gate 			}
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 			*tinstr++ = FBT_SETHI(base, FBT_REG_L3);
9330Sstevel@tonic-gate 			*tinstr++ = FBT_ORLO(FBT_REG_L3, base, FBT_REG_L3);
9340Sstevel@tonic-gate 			*tinstr++ = FBT_CMP(FBT_REG_L2, FBT_REG_L3);
9350Sstevel@tonic-gate 			*tinstr++ = FBT_BL(0, 8 * sizeof (uint32_t));
9360Sstevel@tonic-gate 			*tinstr++ = FBT_SETHI(limit, FBT_REG_L3);
9370Sstevel@tonic-gate 			*tinstr++ = FBT_ORLO(FBT_REG_L3, limit, FBT_REG_L3);
9380Sstevel@tonic-gate 			*tinstr++ = FBT_CMP(FBT_REG_L2, FBT_REG_L3);
9390Sstevel@tonic-gate 			*tinstr++ = FBT_BGE(0, 4 * sizeof (uint32_t));
9400Sstevel@tonic-gate 			*tinstr++ = FBT_SETHI(0, FBT_REG_G0);
9410Sstevel@tonic-gate 			*tinstr++ = cti;
9420Sstevel@tonic-gate 			*tinstr++ = FBT_RESTORE(FBT_REG_G0,
9430Sstevel@tonic-gate 			    FBT_REG_G0, FBT_REG_G0);
9440Sstevel@tonic-gate 		}
9450Sstevel@tonic-gate 	}
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 	if (id > (uint32_t)FBT_SIMM13_MAX) {
9480Sstevel@tonic-gate 		*tinstr++ = FBT_SETHI(id, FBT_REG_O0);
9490Sstevel@tonic-gate 		*tinstr++ = FBT_ORLO(FBT_REG_O0, id, FBT_REG_O0);
9500Sstevel@tonic-gate 	} else {
9510Sstevel@tonic-gate 		*tinstr++ = FBT_ORSIMM13(FBT_REG_G0, id, FBT_REG_O0);
9520Sstevel@tonic-gate 	}
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate 	if (offset > (uint32_t)FBT_SIMM13_MAX) {
9550Sstevel@tonic-gate 		*tinstr++ = FBT_SETHI(offset, FBT_REG_O1);
9560Sstevel@tonic-gate 		*tinstr++ = FBT_ORLO(FBT_REG_O1, offset, FBT_REG_O1);
9570Sstevel@tonic-gate 	} else {
9580Sstevel@tonic-gate 		*tinstr++ = FBT_ORSIMM13(FBT_REG_G0, offset, FBT_REG_O1);
9590Sstevel@tonic-gate 	}
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate 	*tinstr = FBT_CALL((uintptr_t)tinstr - base + va, dtrace_probe);
9620Sstevel@tonic-gate 	tinstr++;
9630Sstevel@tonic-gate 	*tinstr++ = FBT_MOV(FBT_REG_I0, FBT_REG_O2);
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 	/*
9660Sstevel@tonic-gate 	 * If the control transfer instruction is %pc-relative (i.e. a
9670Sstevel@tonic-gate 	 * call), we need to reset it appropriately.
9680Sstevel@tonic-gate 	 */
9690Sstevel@tonic-gate 	if (FBT_FMT1_OP(cti) == FBT_OP_CALL) {
9700Sstevel@tonic-gate 		FBT_COUNTER(id, fbt_retl_tailcall);
9710Sstevel@tonic-gate 		dest = (uintptr_t)instr + (FBT_FMT1_DISP30(cti) << 2);
9720Sstevel@tonic-gate 		*tinstr = FBT_CALL((uintptr_t)tinstr - base + va, dest);
9730Sstevel@tonic-gate 		tinstr++;
9740Sstevel@tonic-gate 		annul = 1;
9750Sstevel@tonic-gate 	} else {
9760Sstevel@tonic-gate 		if (FBT_FMT3_OP(cti) == FBT_OP_JMPL) {
9770Sstevel@tonic-gate 			*tinstr++ = cti;
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate 			if (FBT_FMT3_RD(cti) == FBT_REG_O7) {
9800Sstevel@tonic-gate 				FBT_COUNTER(id, fbt_retl_tailjmpl);
9810Sstevel@tonic-gate 				annul = 1;
9820Sstevel@tonic-gate 			}
9830Sstevel@tonic-gate 		} else {
9840Sstevel@tonic-gate 			*tinstr++ = FBT_RET;
9850Sstevel@tonic-gate 		}
9860Sstevel@tonic-gate 	}
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate 	*tinstr++ = FBT_RESTORE(FBT_REG_G0, FBT_REG_G0, FBT_REG_G0);
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate 	tramp->fbtt_va += (uintptr_t)tinstr - tramp->fbtt_next;
9910Sstevel@tonic-gate 	tramp->fbtt_next = (uintptr_t)tinstr;
9920Sstevel@tonic-gate 
9930Sstevel@tonic-gate 	return (annul ? FBT_BAA(instr, va) : FBT_BA(instr, va));
9940Sstevel@tonic-gate }
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate /*ARGSUSED*/
9970Sstevel@tonic-gate static void
fbt_provide_module(void * arg,struct modctl * ctl)9980Sstevel@tonic-gate fbt_provide_module(void *arg, struct modctl *ctl)
9990Sstevel@tonic-gate {
10000Sstevel@tonic-gate 	struct module *mp = ctl->mod_mp;
10010Sstevel@tonic-gate 	char *modname = ctl->mod_modname;
10020Sstevel@tonic-gate 	char *str = mp->strings;
10030Sstevel@tonic-gate 	int nsyms = mp->nsyms;
10040Sstevel@tonic-gate 	Shdr *symhdr = mp->symhdr;
10050Sstevel@tonic-gate 	size_t symsize;
10060Sstevel@tonic-gate 	char *name;
10070Sstevel@tonic-gate 	int i;
10080Sstevel@tonic-gate 	fbt_probe_t *fbt, *retfbt;
10090Sstevel@tonic-gate 	fbt_trampoline_t tramp;
10100Sstevel@tonic-gate 	uintptr_t offset;
10110Sstevel@tonic-gate 	int primary = 0;
10120Sstevel@tonic-gate 	ctf_file_t *fp = NULL;
10130Sstevel@tonic-gate 	int error;
10140Sstevel@tonic-gate 	int estimate = 1;
10150Sstevel@tonic-gate 	uint32_t faketramp[50];
10160Sstevel@tonic-gate 	size_t fbt_size = 0;
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 	/*
10190Sstevel@tonic-gate 	 * Employees of dtrace and their families are ineligible.  Void
10200Sstevel@tonic-gate 	 * where prohibited.
10210Sstevel@tonic-gate 	 */
10220Sstevel@tonic-gate 	if (strcmp(modname, "dtrace") == 0)
10230Sstevel@tonic-gate 		return;
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate 	if (ctl->mod_requisites != NULL) {
10260Sstevel@tonic-gate 		struct modctl_list *list;
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 		list = (struct modctl_list *)ctl->mod_requisites;
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate 		for (; list != NULL; list = list->modl_next) {
10310Sstevel@tonic-gate 			if (strcmp(list->modl_modp->mod_modname, "dtrace") == 0)
10320Sstevel@tonic-gate 				return;
10330Sstevel@tonic-gate 		}
10340Sstevel@tonic-gate 	}
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate 	/*
10370Sstevel@tonic-gate 	 * KMDB is ineligible for instrumentation -- it may execute in
10380Sstevel@tonic-gate 	 * any context, including probe context.
10390Sstevel@tonic-gate 	 */
10400Sstevel@tonic-gate 	if (strcmp(modname, "kmdbmod") == 0)
10410Sstevel@tonic-gate 		return;
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 	if (str == NULL || symhdr == NULL || symhdr->sh_addr == NULL) {
10440Sstevel@tonic-gate 		/*
10450Sstevel@tonic-gate 		 * If this module doesn't (yet) have its string or symbol
10460Sstevel@tonic-gate 		 * table allocated, clear out.
10470Sstevel@tonic-gate 		 */
10480Sstevel@tonic-gate 		return;
10490Sstevel@tonic-gate 	}
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	symsize = symhdr->sh_entsize;
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate 	if (mp->fbt_nentries) {
10540Sstevel@tonic-gate 		/*
10550Sstevel@tonic-gate 		 * This module has some FBT entries allocated; we're afraid
10560Sstevel@tonic-gate 		 * to screw with it.
10570Sstevel@tonic-gate 		 */
10580Sstevel@tonic-gate 		return;
10590Sstevel@tonic-gate 	}
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 	if (mp->fbt_tab != NULL)
10620Sstevel@tonic-gate 		estimate = 0;
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 	/*
10650Sstevel@tonic-gate 	 * This is a hack for unix/genunix/krtld.
10660Sstevel@tonic-gate 	 */
10670Sstevel@tonic-gate 	primary = vmem_contains(heap_arena, (void *)ctl,
10680Sstevel@tonic-gate 	    sizeof (struct modctl)) == 0;
10690Sstevel@tonic-gate 	kobj_textwin_alloc(mp);
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 	/*
10720Sstevel@tonic-gate 	 * Open the CTF data for the module.  We'll use this to determine the
10730Sstevel@tonic-gate 	 * functions that can be instrumented.  Note that this call can fail,
10740Sstevel@tonic-gate 	 * in which case we'll use heuristics to determine the functions that
10750Sstevel@tonic-gate 	 * can be instrumented.  (But in particular, leaf functions will not be
10760Sstevel@tonic-gate 	 * instrumented.)
10770Sstevel@tonic-gate 	 */
10780Sstevel@tonic-gate 	fp = ctf_modopen(mp, &error);
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate forreal:
10810Sstevel@tonic-gate 	if (!estimate) {
10820Sstevel@tonic-gate 		tramp.fbtt_next =
10830Sstevel@tonic-gate 		    (uintptr_t)fbt_trampoline_map((uintptr_t)mp->fbt_tab,
10840Sstevel@tonic-gate 		    mp->fbt_size);
10850Sstevel@tonic-gate 		tramp.fbtt_limit = tramp.fbtt_next + mp->fbt_size;
10860Sstevel@tonic-gate 		tramp.fbtt_va = (uintptr_t)mp->fbt_tab;
10870Sstevel@tonic-gate 	}
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate 	for (i = 1; i < nsyms; i++) {
10900Sstevel@tonic-gate 		ctf_funcinfo_t f;
10910Sstevel@tonic-gate 		uint32_t *instr, *base, *limit;
10920Sstevel@tonic-gate 		Sym *sym = (Sym *)(symhdr->sh_addr + i * symsize);
10930Sstevel@tonic-gate 		int have_ctf = 0, is_leaf = 0, nargs, cti = 0;
10940Sstevel@tonic-gate 		int (*canpatch)(uint32_t *, int, const char *);
10950Sstevel@tonic-gate 		uint32_t (*patch)(uint32_t *, uint32_t *, uint32_t *, int,
10960Sstevel@tonic-gate 		    uint32_t, fbt_trampoline_t *, const char *);
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 		if (ELF_ST_TYPE(sym->st_info) != STT_FUNC)
10990Sstevel@tonic-gate 			continue;
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 		/*
11020Sstevel@tonic-gate 		 * Weak symbols are not candidates.  This could be made to
11030Sstevel@tonic-gate 		 * work (where weak functions and their underlying function
11040Sstevel@tonic-gate 		 * appear as two disjoint probes), but it's not simple.
11050Sstevel@tonic-gate 		 */
11060Sstevel@tonic-gate 		if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
11070Sstevel@tonic-gate 			continue;
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate 		name = str + sym->st_name;
11100Sstevel@tonic-gate 
11110Sstevel@tonic-gate 		if (strstr(name, "dtrace_") == name &&
11120Sstevel@tonic-gate 		    strstr(name, "dtrace_safe_") != name) {
11130Sstevel@tonic-gate 			/*
11140Sstevel@tonic-gate 			 * Anything beginning with "dtrace_" may be called
11150Sstevel@tonic-gate 			 * from probe context unless it explitly indicates
11160Sstevel@tonic-gate 			 * that it won't be called from probe context by
11170Sstevel@tonic-gate 			 * using the prefix "dtrace_safe_".
11180Sstevel@tonic-gate 			 */
11190Sstevel@tonic-gate 			continue;
11200Sstevel@tonic-gate 		}
11210Sstevel@tonic-gate 
1122457Sbmc 		if (strstr(name, "kdi_") == name ||
1123457Sbmc 		    strstr(name, "_kdi_") != NULL) {
11240Sstevel@tonic-gate 			/*
1125457Sbmc 			 * Any function name beginning with "kdi_" or
1126457Sbmc 			 * containing the string "_kdi_" is a part of the
11270Sstevel@tonic-gate 			 * kernel debugger interface and may be called in
11280Sstevel@tonic-gate 			 * arbitrary context -- including probe context.
11290Sstevel@tonic-gate 			 */
11300Sstevel@tonic-gate 			continue;
11310Sstevel@tonic-gate 		}
11320Sstevel@tonic-gate 
11330Sstevel@tonic-gate 		if (strstr(name, "__relocatable") != NULL) {
11340Sstevel@tonic-gate 			/*
11350Sstevel@tonic-gate 			 * Anything with the string "__relocatable" anywhere
11360Sstevel@tonic-gate 			 * in the function name is considered to be a function
11370Sstevel@tonic-gate 			 * that may be manually relocated before execution.
11380Sstevel@tonic-gate 			 * Because FBT uses a PC-relative technique for
11390Sstevel@tonic-gate 			 * instrumentation, these functions cannot safely
11400Sstevel@tonic-gate 			 * be instrumented by us.
11410Sstevel@tonic-gate 			 */
11420Sstevel@tonic-gate 			continue;
11430Sstevel@tonic-gate 		}
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate 		if (strstr(name, "ip_ocsum") == name) {
11460Sstevel@tonic-gate 			/*
11470Sstevel@tonic-gate 			 * The ip_ocsum_* family of routines are all ABI
11480Sstevel@tonic-gate 			 * violators.  (They expect incoming arguments in the
11490Sstevel@tonic-gate 			 * globals!)  Break the ABI?  No soup for you!
11500Sstevel@tonic-gate 			 */
11510Sstevel@tonic-gate 			continue;
11520Sstevel@tonic-gate 		}
11530Sstevel@tonic-gate 
11540Sstevel@tonic-gate 		/*
11550Sstevel@tonic-gate 		 * We want to scan the function for one (and only one) save.
11560Sstevel@tonic-gate 		 * Any more indicates that something fancy is going on.
11570Sstevel@tonic-gate 		 */
11580Sstevel@tonic-gate 		base = (uint32_t *)sym->st_value;
11590Sstevel@tonic-gate 		limit = (uint32_t *)(sym->st_value + sym->st_size);
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 		/*
11620Sstevel@tonic-gate 		 * We don't want to interpose on the module stubs.
11630Sstevel@tonic-gate 		 */
11640Sstevel@tonic-gate 		if (base >= (uint32_t *)stubs_base &&
11650Sstevel@tonic-gate 		    base <= (uint32_t *)stubs_end)
11660Sstevel@tonic-gate 			continue;
11670Sstevel@tonic-gate 
11680Sstevel@tonic-gate 		/*
11690Sstevel@tonic-gate 		 * We can't safely trace a zero-length function...
11700Sstevel@tonic-gate 		 */
11710Sstevel@tonic-gate 		if (base == limit)
11720Sstevel@tonic-gate 			continue;
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate 		/*
11750Sstevel@tonic-gate 		 * Due to 4524008, _init and _fini may have a bloated st_size.
11760Sstevel@tonic-gate 		 * While this bug was fixed quite some time ago, old drivers
11770Sstevel@tonic-gate 		 * may be lurking.  We need to develop a better solution to
11780Sstevel@tonic-gate 		 * this problem, such that correct _init and _fini functions
11790Sstevel@tonic-gate 		 * (the vast majority) may be correctly traced.  One solution
11800Sstevel@tonic-gate 		 * may be to scan through the entire symbol table to see if
11810Sstevel@tonic-gate 		 * any symbol overlaps with _init.  If none does, set a bit in
11820Sstevel@tonic-gate 		 * the module structure that this module has correct _init and
11830Sstevel@tonic-gate 		 * _fini sizes.  This will cause some pain the first time a
11840Sstevel@tonic-gate 		 * module is scanned, but at least it would be O(N) instead of
11850Sstevel@tonic-gate 		 * O(N log N)...
11860Sstevel@tonic-gate 		 */
11870Sstevel@tonic-gate 		if (strcmp(name, "_init") == 0)
11880Sstevel@tonic-gate 			continue;
11890Sstevel@tonic-gate 
11900Sstevel@tonic-gate 		if (strcmp(name, "_fini") == 0)
11910Sstevel@tonic-gate 			continue;
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 		instr = base;
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate 		/*
11960Sstevel@tonic-gate 		 * While we try hard to only trace safe functions (that is,
11970Sstevel@tonic-gate 		 * functions at TL=0), one unsafe function manages to otherwise
11980Sstevel@tonic-gate 		 * appear safe:  prom_trap().  We could discover prom_trap()
11990Sstevel@tonic-gate 		 * if we added an additional rule:  in order to trace a
12000Sstevel@tonic-gate 		 * function, we must either (a) discover a restore or (b)
12010Sstevel@tonic-gate 		 * determine that the function does not have any unlinked
12020Sstevel@tonic-gate 		 * control transfers to another function (i.e., the function
12030Sstevel@tonic-gate 		 * never returns).  Unfortunately, as of this writing, one
12040Sstevel@tonic-gate 		 * legitimate function (resume_from_zombie()) transfers
12050Sstevel@tonic-gate 		 * control to a different function (_resume_from_idle())
12060Sstevel@tonic-gate 		 * without executing a restore.  Barring a rule to figure out
12070Sstevel@tonic-gate 		 * that resume_from_zombie() is safe while prom_trap() is not,
12080Sstevel@tonic-gate 		 * we resort to hard-coding prom_trap() here.
12090Sstevel@tonic-gate 		 */
12100Sstevel@tonic-gate 		if (strcmp(name, "prom_trap") == 0)
12110Sstevel@tonic-gate 			continue;
12120Sstevel@tonic-gate 
12130Sstevel@tonic-gate 		if (fp != NULL && ctf_func_info(fp, i, &f) != CTF_ERR) {
12140Sstevel@tonic-gate 			nargs = f.ctc_argc;
12150Sstevel@tonic-gate 			have_ctf = 1;
12160Sstevel@tonic-gate 		} else {
12170Sstevel@tonic-gate 			nargs = 32;
12180Sstevel@tonic-gate 		}
12190Sstevel@tonic-gate 
12200Sstevel@tonic-gate 		/*
12210Sstevel@tonic-gate 		 * If the first instruction of the function is a branch and
12220Sstevel@tonic-gate 		 * it's not a branch-always-not-annulled, we're going to refuse
12230Sstevel@tonic-gate 		 * to patch it.
12240Sstevel@tonic-gate 		 */
12250Sstevel@tonic-gate 		if ((*instr & FBT_OP_MASK) == FBT_OP0 &&
12260Sstevel@tonic-gate 		    (*instr & FBT_FMT2_OP2_MASK) != FBT_FMT2_OP2_SETHI &&
12270Sstevel@tonic-gate 		    (*instr & FBT_FMT2_OP2_MASK) != FBT_FMT2_OP2_BPR) {
12280Sstevel@tonic-gate 			if (!FBT_IS_BA(*instr) && !FBT_IS_BAPCC(*instr)) {
12290Sstevel@tonic-gate 				if (have_ctf) {
12300Sstevel@tonic-gate 					cmn_err(CE_NOTE, "cannot instrument %s:"
12310Sstevel@tonic-gate 					    " begins with non-ba, "
12320Sstevel@tonic-gate 					    "non-br CTI", name);
12330Sstevel@tonic-gate 				}
12340Sstevel@tonic-gate 				continue;
12350Sstevel@tonic-gate 			}
12360Sstevel@tonic-gate 		}
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 		while (!FBT_IS_SAVE(*instr)) {
12390Sstevel@tonic-gate 			/*
12400Sstevel@tonic-gate 			 * Before we assume that this is a leaf routine, check
12410Sstevel@tonic-gate 			 * forward in the basic block for a save.
12420Sstevel@tonic-gate 			 */
12430Sstevel@tonic-gate 			int op = *instr & FBT_OP_MASK;
12440Sstevel@tonic-gate 			int op2 = *instr & FBT_FMT2_OP2_MASK;
12450Sstevel@tonic-gate 
12460Sstevel@tonic-gate 			if (op == FBT_OP0 && op2 != FBT_FMT2_OP2_SETHI) {
12470Sstevel@tonic-gate 				/*
12480Sstevel@tonic-gate 				 * This is a CTI.  If we see a subsequent
12490Sstevel@tonic-gate 				 * save, we will refuse to process this
12500Sstevel@tonic-gate 				 * routine unless both of the following are
12510Sstevel@tonic-gate 				 * true:
12520Sstevel@tonic-gate 				 *
12530Sstevel@tonic-gate 				 *  (a)	The branch is not annulled
12540Sstevel@tonic-gate 				 *
12550Sstevel@tonic-gate 				 *  (b)	The subsequent save is in the delay
12560Sstevel@tonic-gate 				 *	slot of the branch
12570Sstevel@tonic-gate 				 */
12580Sstevel@tonic-gate 				if ((*instr & FBT_ANNUL) ||
12590Sstevel@tonic-gate 				    !FBT_IS_SAVE(*(instr + 1))) {
12600Sstevel@tonic-gate 					cti = 1;
12610Sstevel@tonic-gate 				} else {
12620Sstevel@tonic-gate 					instr++;
12630Sstevel@tonic-gate 					break;
12640Sstevel@tonic-gate 				}
12650Sstevel@tonic-gate 			}
12660Sstevel@tonic-gate 
12670Sstevel@tonic-gate 			if (op == FBT_OP1)
12680Sstevel@tonic-gate 				cti = 1;
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate 			if (++instr == limit)
12710Sstevel@tonic-gate 				break;
12720Sstevel@tonic-gate 		}
12730Sstevel@tonic-gate 
12740Sstevel@tonic-gate 		if (instr < limit && cti) {
12750Sstevel@tonic-gate 			/*
12760Sstevel@tonic-gate 			 * If we found a CTI before the save, we need to not
12770Sstevel@tonic-gate 			 * do anything.  But if we have CTF information, this
12780Sstevel@tonic-gate 			 * is weird enough that it merits a message.
12790Sstevel@tonic-gate 			 */
12800Sstevel@tonic-gate 			if (!have_ctf)
12810Sstevel@tonic-gate 				continue;
12820Sstevel@tonic-gate 
12830Sstevel@tonic-gate 			cmn_err(CE_NOTE, "cannot instrument %s: "
12840Sstevel@tonic-gate 			    "save not in first basic block", name);
12850Sstevel@tonic-gate 			continue;
12860Sstevel@tonic-gate 		}
12870Sstevel@tonic-gate 
12880Sstevel@tonic-gate 		if (instr == limit) {
12890Sstevel@tonic-gate 			if (!have_ctf)
12900Sstevel@tonic-gate 				continue;
12910Sstevel@tonic-gate 			is_leaf = 1;
12920Sstevel@tonic-gate 
12930Sstevel@tonic-gate 			if (!estimate)
12940Sstevel@tonic-gate 				fbt_leaf_functions++;
12950Sstevel@tonic-gate 
12960Sstevel@tonic-gate 			canpatch = fbt_canpatch_retl;
12970Sstevel@tonic-gate 			patch = fbt_patch_retl;
12980Sstevel@tonic-gate 		} else {
12990Sstevel@tonic-gate 			canpatch = fbt_canpatch_return;
13000Sstevel@tonic-gate 			patch = fbt_patch_return;
13010Sstevel@tonic-gate 		}
13020Sstevel@tonic-gate 
13030Sstevel@tonic-gate 		if (!have_ctf && !is_leaf) {
13040Sstevel@tonic-gate 			/*
13050Sstevel@tonic-gate 			 * Before we assume that this isn't something tricky,
13060Sstevel@tonic-gate 			 * look for other saves.  If we find them, there are
13070Sstevel@tonic-gate 			 * multiple entry points here (or something), and we'll
13080Sstevel@tonic-gate 			 * leave it alone.
13090Sstevel@tonic-gate 			 */
13100Sstevel@tonic-gate 			while (++instr < limit) {
13110Sstevel@tonic-gate 				if (FBT_IS_SAVE(*instr))
13120Sstevel@tonic-gate 					break;
13130Sstevel@tonic-gate 			}
13140Sstevel@tonic-gate 
13150Sstevel@tonic-gate 			if (instr != limit)
13160Sstevel@tonic-gate 				continue;
13170Sstevel@tonic-gate 		}
13180Sstevel@tonic-gate 
13190Sstevel@tonic-gate 		instr = base;
13200Sstevel@tonic-gate 
13210Sstevel@tonic-gate 		if (FBT_IS_CTI(*instr)) {
13220Sstevel@tonic-gate 			/*
13230Sstevel@tonic-gate 			 * If we have a CTI, we want to be sure that we don't
13240Sstevel@tonic-gate 			 * have a CTI or a PC-relative instruction in the
13250Sstevel@tonic-gate 			 * delay slot -- we want to be able to thunk the
13260Sstevel@tonic-gate 			 * instruction into the trampoline without worrying
13270Sstevel@tonic-gate 			 * about either DCTIs or relocations.  It would be
13280Sstevel@tonic-gate 			 * very odd for the compiler to generate this kind of
13290Sstevel@tonic-gate 			 * code, so we warn about it if we have CTF
13300Sstevel@tonic-gate 			 * information.
13310Sstevel@tonic-gate 			 */
13320Sstevel@tonic-gate 			if (FBT_IS_CTI(*(instr + 1))) {
13330Sstevel@tonic-gate 				if (!have_ctf)
13340Sstevel@tonic-gate 					continue;
13350Sstevel@tonic-gate 
13360Sstevel@tonic-gate 				cmn_err(CE_NOTE, "cannot instrument %s: "
13370Sstevel@tonic-gate 				    "CTI in delay slot of first instruction",
13380Sstevel@tonic-gate 				    name);
13390Sstevel@tonic-gate 				continue;
13400Sstevel@tonic-gate 			}
13410Sstevel@tonic-gate 
13420Sstevel@tonic-gate 			if (FBT_IS_PCRELATIVE(*(instr + 1))) {
13430Sstevel@tonic-gate 				if (!have_ctf)
13440Sstevel@tonic-gate 					continue;
13450Sstevel@tonic-gate 
13460Sstevel@tonic-gate 				cmn_err(CE_NOTE, "cannot instrument %s: "
13470Sstevel@tonic-gate 				    "PC-relative instruction in delay slot of"
13480Sstevel@tonic-gate 				    " first instruction", name);
13490Sstevel@tonic-gate 				continue;
13500Sstevel@tonic-gate 			}
13510Sstevel@tonic-gate 		}
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate 		if (estimate) {
13540Sstevel@tonic-gate 			tramp.fbtt_next = (uintptr_t)faketramp;
13550Sstevel@tonic-gate 			tramp.fbtt_limit = tramp.fbtt_next + sizeof (faketramp);
13560Sstevel@tonic-gate 			(void) fbt_patch_entry(instr, FBT_ESTIMATE_ID,
13570Sstevel@tonic-gate 			    &tramp, nargs);
13580Sstevel@tonic-gate 			fbt_size += tramp.fbtt_next - (uintptr_t)faketramp;
13590Sstevel@tonic-gate 		} else {
13600Sstevel@tonic-gate 			fbt = kmem_zalloc(sizeof (fbt_probe_t), KM_SLEEP);
13610Sstevel@tonic-gate 			fbt->fbtp_name = name;
13620Sstevel@tonic-gate 			fbt->fbtp_ctl = ctl;
13630Sstevel@tonic-gate 			fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
13640Sstevel@tonic-gate 			    name, FBT_PROBENAME_ENTRY, 1, fbt);
13650Sstevel@tonic-gate 			fbt->fbtp_patchval = FBT_BAA(instr, tramp.fbtt_va);
13660Sstevel@tonic-gate 
13670Sstevel@tonic-gate 			if (!fbt_patch_entry(instr, fbt->fbtp_id,
13680Sstevel@tonic-gate 			    &tramp, nargs)) {
13690Sstevel@tonic-gate 				cmn_err(CE_WARN, "unexpectedly short FBT table "
13700Sstevel@tonic-gate 				    "in module %s (sym %d of %d)", modname,
13710Sstevel@tonic-gate 				    i, nsyms);
13720Sstevel@tonic-gate 				break;
13730Sstevel@tonic-gate 			}
13740Sstevel@tonic-gate 
13750Sstevel@tonic-gate 			fbt->fbtp_patchpoint =
13760Sstevel@tonic-gate 			    (uint32_t *)((uintptr_t)mp->textwin +
13770Sstevel@tonic-gate 			    ((uintptr_t)instr - (uintptr_t)mp->text));
13780Sstevel@tonic-gate 			fbt->fbtp_savedval = *instr;
13790Sstevel@tonic-gate 
13800Sstevel@tonic-gate 			fbt->fbtp_loadcnt = ctl->mod_loadcnt;
13810Sstevel@tonic-gate 			fbt->fbtp_primary = primary;
13820Sstevel@tonic-gate 			fbt->fbtp_symndx = i;
13830Sstevel@tonic-gate 			mp->fbt_nentries++;
13840Sstevel@tonic-gate 		}
13850Sstevel@tonic-gate 
13860Sstevel@tonic-gate 		retfbt = NULL;
13870Sstevel@tonic-gate again:
13880Sstevel@tonic-gate 		if (++instr == limit)
13890Sstevel@tonic-gate 			continue;
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate 		offset = (uintptr_t)instr - (uintptr_t)base;
13920Sstevel@tonic-gate 
13930Sstevel@tonic-gate 		if (!(*canpatch)(instr, offset, name))
13940Sstevel@tonic-gate 			goto again;
13950Sstevel@tonic-gate 
13960Sstevel@tonic-gate 		if (estimate) {
13970Sstevel@tonic-gate 			tramp.fbtt_next = (uintptr_t)faketramp;
13980Sstevel@tonic-gate 			tramp.fbtt_limit = tramp.fbtt_next + sizeof (faketramp);
13990Sstevel@tonic-gate 			(void) (*patch)(instr, base, limit,
14000Sstevel@tonic-gate 			    offset, FBT_ESTIMATE_ID, &tramp, name);
14010Sstevel@tonic-gate 			fbt_size += tramp.fbtt_next - (uintptr_t)faketramp;
14020Sstevel@tonic-gate 
14030Sstevel@tonic-gate 			goto again;
14040Sstevel@tonic-gate 		}
14050Sstevel@tonic-gate 
14060Sstevel@tonic-gate 		fbt = kmem_zalloc(sizeof (fbt_probe_t), KM_SLEEP);
14070Sstevel@tonic-gate 		fbt->fbtp_name = name;
14080Sstevel@tonic-gate 		fbt->fbtp_ctl = ctl;
14090Sstevel@tonic-gate 
14100Sstevel@tonic-gate 		if (retfbt == NULL) {
14110Sstevel@tonic-gate 			fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
14120Sstevel@tonic-gate 			    name, FBT_PROBENAME_RETURN, 1, fbt);
14130Sstevel@tonic-gate 		} else {
14140Sstevel@tonic-gate 			retfbt->fbtp_next = fbt;
14150Sstevel@tonic-gate 			fbt->fbtp_id = retfbt->fbtp_id;
14160Sstevel@tonic-gate 		}
14170Sstevel@tonic-gate 
14180Sstevel@tonic-gate 		fbt->fbtp_return = 1;
14190Sstevel@tonic-gate 		retfbt = fbt;
14200Sstevel@tonic-gate 
14210Sstevel@tonic-gate 		if ((fbt->fbtp_patchval = (*patch)(instr, base, limit, offset,
14220Sstevel@tonic-gate 		    fbt->fbtp_id, &tramp, name)) == FBT_ILLTRAP) {
14230Sstevel@tonic-gate 			cmn_err(CE_WARN, "unexpectedly short FBT table "
14240Sstevel@tonic-gate 			    "in module %s (sym %d of %d)", modname, i, nsyms);
14250Sstevel@tonic-gate 			break;
14260Sstevel@tonic-gate 		}
14270Sstevel@tonic-gate 
14280Sstevel@tonic-gate 		fbt->fbtp_patchpoint = (uint32_t *)((uintptr_t)mp->textwin +
14290Sstevel@tonic-gate 		    ((uintptr_t)instr - (uintptr_t)mp->text));
14300Sstevel@tonic-gate 		fbt->fbtp_savedval = *instr;
14310Sstevel@tonic-gate 		fbt->fbtp_loadcnt = ctl->mod_loadcnt;
14320Sstevel@tonic-gate 		fbt->fbtp_primary = primary;
14330Sstevel@tonic-gate 		fbt->fbtp_symndx = i;
14340Sstevel@tonic-gate 		mp->fbt_nentries++;
14350Sstevel@tonic-gate 
14360Sstevel@tonic-gate 		goto again;
14370Sstevel@tonic-gate 	}
14380Sstevel@tonic-gate 
14390Sstevel@tonic-gate 	if (estimate) {
14400Sstevel@tonic-gate 		/*
14410Sstevel@tonic-gate 		 * Slosh on another entry's worth...
14420Sstevel@tonic-gate 		 */
14430Sstevel@tonic-gate 		fbt_size += FBT_ENT_MAXSIZE;
14440Sstevel@tonic-gate 		mp->fbt_size = fbt_size;
14450Sstevel@tonic-gate 		mp->fbt_tab = kobj_texthole_alloc(mp->text, fbt_size);
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate 		if (mp->fbt_tab == NULL) {
14480Sstevel@tonic-gate 			cmn_err(CE_WARN, "couldn't allocate FBT table "
14490Sstevel@tonic-gate 			    "for module %s", modname);
14500Sstevel@tonic-gate 		} else {
14510Sstevel@tonic-gate 			estimate = 0;
14520Sstevel@tonic-gate 			goto forreal;
14530Sstevel@tonic-gate 		}
14540Sstevel@tonic-gate 	} else {
14550Sstevel@tonic-gate 		fbt_trampoline_unmap();
14560Sstevel@tonic-gate 	}
14570Sstevel@tonic-gate 
14580Sstevel@tonic-gate error:
14590Sstevel@tonic-gate 	if (fp != NULL)
14600Sstevel@tonic-gate 		ctf_close(fp);
14610Sstevel@tonic-gate }
14620Sstevel@tonic-gate 
14630Sstevel@tonic-gate /*ARGSUSED*/
14640Sstevel@tonic-gate static void
fbt_destroy(void * arg,dtrace_id_t id,void * parg)14650Sstevel@tonic-gate fbt_destroy(void *arg, dtrace_id_t id, void *parg)
14660Sstevel@tonic-gate {
14670Sstevel@tonic-gate 	fbt_probe_t *fbt = parg, *next;
14680Sstevel@tonic-gate 	struct modctl *ctl = fbt->fbtp_ctl;
14690Sstevel@tonic-gate 
14700Sstevel@tonic-gate 	do {
14710Sstevel@tonic-gate 		if (ctl != NULL && ctl->mod_loadcnt == fbt->fbtp_loadcnt) {
14720Sstevel@tonic-gate 			if ((ctl->mod_loadcnt == fbt->fbtp_loadcnt &&
14730Sstevel@tonic-gate 			    ctl->mod_loaded) || fbt->fbtp_primary) {
14740Sstevel@tonic-gate 				((struct module *)
14750Sstevel@tonic-gate 				    (ctl->mod_mp))->fbt_nentries--;
14760Sstevel@tonic-gate 			}
14770Sstevel@tonic-gate 		}
14780Sstevel@tonic-gate 
14790Sstevel@tonic-gate 		next = fbt->fbtp_next;
14800Sstevel@tonic-gate 		kmem_free(fbt, sizeof (fbt_probe_t));
14810Sstevel@tonic-gate 		fbt = next;
14820Sstevel@tonic-gate 	} while (fbt != NULL);
14830Sstevel@tonic-gate }
14840Sstevel@tonic-gate 
14850Sstevel@tonic-gate /*ARGSUSED*/
1486*8803SJonathan.Haslam@Sun.COM static int
fbt_enable(void * arg,dtrace_id_t id,void * parg)14870Sstevel@tonic-gate fbt_enable(void *arg, dtrace_id_t id, void *parg)
14880Sstevel@tonic-gate {
14890Sstevel@tonic-gate 	fbt_probe_t *fbt = parg, *f;
14900Sstevel@tonic-gate 	struct modctl *ctl = fbt->fbtp_ctl;
14910Sstevel@tonic-gate 
14920Sstevel@tonic-gate 	ctl->mod_nenabled++;
14930Sstevel@tonic-gate 
14940Sstevel@tonic-gate 	for (f = fbt; f != NULL; f = f->fbtp_next) {
14950Sstevel@tonic-gate 		if (f->fbtp_patchpoint == NULL) {
14960Sstevel@tonic-gate 			/*
14970Sstevel@tonic-gate 			 * Due to a shortened FBT table, this entry was never
14980Sstevel@tonic-gate 			 * completed; refuse to enable it.
14990Sstevel@tonic-gate 			 */
15000Sstevel@tonic-gate 			if (fbt_verbose) {
15010Sstevel@tonic-gate 				cmn_err(CE_NOTE, "fbt is failing for probe %s "
15020Sstevel@tonic-gate 				    "(short FBT table in %s)",
15030Sstevel@tonic-gate 				    fbt->fbtp_name, ctl->mod_modname);
15040Sstevel@tonic-gate 			}
15050Sstevel@tonic-gate 
1506*8803SJonathan.Haslam@Sun.COM 			return (0);
15070Sstevel@tonic-gate 		}
15080Sstevel@tonic-gate 	}
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate 	/*
15110Sstevel@tonic-gate 	 * If this module has disappeared since we discovered its probes,
15120Sstevel@tonic-gate 	 * refuse to enable it.
15130Sstevel@tonic-gate 	 */
15140Sstevel@tonic-gate 	if (!fbt->fbtp_primary && !ctl->mod_loaded) {
15150Sstevel@tonic-gate 		if (fbt_verbose) {
15160Sstevel@tonic-gate 			cmn_err(CE_NOTE, "fbt is failing for probe %s "
15170Sstevel@tonic-gate 			    "(module %s unloaded)",
15180Sstevel@tonic-gate 			    fbt->fbtp_name, ctl->mod_modname);
15190Sstevel@tonic-gate 		}
15200Sstevel@tonic-gate 
1521*8803SJonathan.Haslam@Sun.COM 		return (0);
15220Sstevel@tonic-gate 	}
15230Sstevel@tonic-gate 
15240Sstevel@tonic-gate 	/*
15250Sstevel@tonic-gate 	 * Now check that our modctl has the expected load count.  If it
15260Sstevel@tonic-gate 	 * doesn't, this module must have been unloaded and reloaded -- and
15270Sstevel@tonic-gate 	 * we're not going to touch it.
15280Sstevel@tonic-gate 	 */
15290Sstevel@tonic-gate 	if (ctl->mod_loadcnt != fbt->fbtp_loadcnt) {
15300Sstevel@tonic-gate 		if (fbt_verbose) {
15310Sstevel@tonic-gate 			cmn_err(CE_NOTE, "fbt is failing for probe %s "
15320Sstevel@tonic-gate 			    "(module %s reloaded)",
15330Sstevel@tonic-gate 			    fbt->fbtp_name, ctl->mod_modname);
15340Sstevel@tonic-gate 		}
15350Sstevel@tonic-gate 
1536*8803SJonathan.Haslam@Sun.COM 		return (0);
15370Sstevel@tonic-gate 	}
15380Sstevel@tonic-gate 
15390Sstevel@tonic-gate 	for (; fbt != NULL; fbt = fbt->fbtp_next)
15400Sstevel@tonic-gate 		*fbt->fbtp_patchpoint = fbt->fbtp_patchval;
1541*8803SJonathan.Haslam@Sun.COM 
1542*8803SJonathan.Haslam@Sun.COM 	return (0);
15430Sstevel@tonic-gate }
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate /*ARGSUSED*/
15460Sstevel@tonic-gate static void
fbt_disable(void * arg,dtrace_id_t id,void * parg)15470Sstevel@tonic-gate fbt_disable(void *arg, dtrace_id_t id, void *parg)
15480Sstevel@tonic-gate {
15490Sstevel@tonic-gate 	fbt_probe_t *fbt = parg, *f;
15500Sstevel@tonic-gate 	struct modctl *ctl = fbt->fbtp_ctl;
15510Sstevel@tonic-gate 
15520Sstevel@tonic-gate 	ASSERT(ctl->mod_nenabled > 0);
15530Sstevel@tonic-gate 	ctl->mod_nenabled--;
15540Sstevel@tonic-gate 
15550Sstevel@tonic-gate 	for (f = fbt; f != NULL; f = f->fbtp_next) {
15560Sstevel@tonic-gate 		if (f->fbtp_patchpoint == NULL)
15570Sstevel@tonic-gate 			return;
15580Sstevel@tonic-gate 	}
15590Sstevel@tonic-gate 
15600Sstevel@tonic-gate 	if ((!fbt->fbtp_primary && !ctl->mod_loaded) ||
15610Sstevel@tonic-gate 	    (ctl->mod_loadcnt != fbt->fbtp_loadcnt))
15620Sstevel@tonic-gate 		return;
15630Sstevel@tonic-gate 
15640Sstevel@tonic-gate 	for (; fbt != NULL; fbt = fbt->fbtp_next)
15650Sstevel@tonic-gate 		*fbt->fbtp_patchpoint = fbt->fbtp_savedval;
15660Sstevel@tonic-gate }
15670Sstevel@tonic-gate 
15680Sstevel@tonic-gate /*ARGSUSED*/
15690Sstevel@tonic-gate static void
fbt_suspend(void * arg,dtrace_id_t id,void * parg)15700Sstevel@tonic-gate fbt_suspend(void *arg, dtrace_id_t id, void *parg)
15710Sstevel@tonic-gate {
15720Sstevel@tonic-gate 	fbt_probe_t *fbt = parg;
15730Sstevel@tonic-gate 	struct modctl *ctl = fbt->fbtp_ctl;
15740Sstevel@tonic-gate 
15750Sstevel@tonic-gate 	if (!fbt->fbtp_primary && !ctl->mod_loaded)
15760Sstevel@tonic-gate 		return;
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate 	if (ctl->mod_loadcnt != fbt->fbtp_loadcnt)
15790Sstevel@tonic-gate 		return;
15800Sstevel@tonic-gate 
15810Sstevel@tonic-gate 	ASSERT(ctl->mod_nenabled > 0);
15820Sstevel@tonic-gate 
15830Sstevel@tonic-gate 	for (; fbt != NULL; fbt = fbt->fbtp_next)
15840Sstevel@tonic-gate 		*fbt->fbtp_patchpoint = fbt->fbtp_savedval;
15850Sstevel@tonic-gate }
15860Sstevel@tonic-gate 
15870Sstevel@tonic-gate /*ARGSUSED*/
15880Sstevel@tonic-gate static void
fbt_resume(void * arg,dtrace_id_t id,void * parg)15890Sstevel@tonic-gate fbt_resume(void *arg, dtrace_id_t id, void *parg)
15900Sstevel@tonic-gate {
15910Sstevel@tonic-gate 	fbt_probe_t *fbt = parg;
15920Sstevel@tonic-gate 	struct modctl *ctl = fbt->fbtp_ctl;
15930Sstevel@tonic-gate 
15940Sstevel@tonic-gate 	if (!fbt->fbtp_primary && !ctl->mod_loaded)
15950Sstevel@tonic-gate 		return;
15960Sstevel@tonic-gate 
15970Sstevel@tonic-gate 	if (ctl->mod_loadcnt != fbt->fbtp_loadcnt)
15980Sstevel@tonic-gate 		return;
15990Sstevel@tonic-gate 
16000Sstevel@tonic-gate 	ASSERT(ctl->mod_nenabled > 0);
16010Sstevel@tonic-gate 
16020Sstevel@tonic-gate 	for (; fbt != NULL; fbt = fbt->fbtp_next)
16030Sstevel@tonic-gate 		*fbt->fbtp_patchpoint = fbt->fbtp_patchval;
16040Sstevel@tonic-gate }
16050Sstevel@tonic-gate 
16060Sstevel@tonic-gate /*ARGSUSED*/
16070Sstevel@tonic-gate static void
fbt_getargdesc(void * arg,dtrace_id_t id,void * parg,dtrace_argdesc_t * desc)16080Sstevel@tonic-gate fbt_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc)
16090Sstevel@tonic-gate {
16100Sstevel@tonic-gate 	fbt_probe_t *fbt = parg;
16110Sstevel@tonic-gate 	struct modctl *ctl = fbt->fbtp_ctl;
16120Sstevel@tonic-gate 	struct module *mp = ctl->mod_mp;
16130Sstevel@tonic-gate 	ctf_file_t *fp = NULL, *pfp;
16140Sstevel@tonic-gate 	ctf_funcinfo_t f;
16150Sstevel@tonic-gate 	int error;
16160Sstevel@tonic-gate 	ctf_id_t argv[32], type;
16170Sstevel@tonic-gate 	int argc = sizeof (argv) / sizeof (ctf_id_t);
16180Sstevel@tonic-gate 	const char *parent;
16190Sstevel@tonic-gate 
16200Sstevel@tonic-gate 	if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt))
16210Sstevel@tonic-gate 		goto err;
16220Sstevel@tonic-gate 
16230Sstevel@tonic-gate 	if (fbt->fbtp_return && desc->dtargd_ndx == 0) {
16240Sstevel@tonic-gate 		(void) strcpy(desc->dtargd_native, "int");
16250Sstevel@tonic-gate 		return;
16260Sstevel@tonic-gate 	}
16270Sstevel@tonic-gate 
16280Sstevel@tonic-gate 	if ((fp = ctf_modopen(mp, &error)) == NULL) {
16290Sstevel@tonic-gate 		/*
16300Sstevel@tonic-gate 		 * We have no CTF information for this module -- and therefore
16310Sstevel@tonic-gate 		 * no args[] information.
16320Sstevel@tonic-gate 		 */
16330Sstevel@tonic-gate 		goto err;
16340Sstevel@tonic-gate 	}
16350Sstevel@tonic-gate 
16360Sstevel@tonic-gate 	/*
16370Sstevel@tonic-gate 	 * If we have a parent container, we must manually import it.
16380Sstevel@tonic-gate 	 */
16390Sstevel@tonic-gate 	if ((parent = ctf_parent_name(fp)) != NULL) {
16403446Smrj 		struct modctl *mp = &modules;
16413446Smrj 		struct modctl *mod = NULL;
16420Sstevel@tonic-gate 
16430Sstevel@tonic-gate 		/*
16440Sstevel@tonic-gate 		 * We must iterate over all modules to find the module that
16450Sstevel@tonic-gate 		 * is our parent.
16460Sstevel@tonic-gate 		 */
16473446Smrj 		do {
16483446Smrj 			if (strcmp(mp->mod_modname, parent) == 0) {
16493446Smrj 				mod = mp;
16500Sstevel@tonic-gate 				break;
16513446Smrj 			}
16523446Smrj 		} while ((mp = mp->mod_next) != &modules);
16530Sstevel@tonic-gate 
16540Sstevel@tonic-gate 		if (mod == NULL)
16550Sstevel@tonic-gate 			goto err;
16560Sstevel@tonic-gate 
16570Sstevel@tonic-gate 		if ((pfp = ctf_modopen(mod->mod_mp, &error)) == NULL)
16580Sstevel@tonic-gate 			goto err;
16590Sstevel@tonic-gate 
16600Sstevel@tonic-gate 		if (ctf_import(fp, pfp) != 0) {
16610Sstevel@tonic-gate 			ctf_close(pfp);
16620Sstevel@tonic-gate 			goto err;
16630Sstevel@tonic-gate 		}
16640Sstevel@tonic-gate 
16650Sstevel@tonic-gate 		ctf_close(pfp);
16660Sstevel@tonic-gate 	}
16670Sstevel@tonic-gate 
16680Sstevel@tonic-gate 	if (ctf_func_info(fp, fbt->fbtp_symndx, &f) == CTF_ERR)
16690Sstevel@tonic-gate 		goto err;
16700Sstevel@tonic-gate 
16710Sstevel@tonic-gate 	if (fbt->fbtp_return) {
16720Sstevel@tonic-gate 		if (desc->dtargd_ndx > 1)
16730Sstevel@tonic-gate 			goto err;
16740Sstevel@tonic-gate 
16750Sstevel@tonic-gate 		ASSERT(desc->dtargd_ndx == 1);
16760Sstevel@tonic-gate 		type = f.ctc_return;
16770Sstevel@tonic-gate 	} else {
16780Sstevel@tonic-gate 		if (desc->dtargd_ndx + 1 > f.ctc_argc)
16790Sstevel@tonic-gate 			goto err;
16800Sstevel@tonic-gate 
16810Sstevel@tonic-gate 		if (ctf_func_args(fp, fbt->fbtp_symndx, argc, argv) == CTF_ERR)
16820Sstevel@tonic-gate 			goto err;
16830Sstevel@tonic-gate 
16840Sstevel@tonic-gate 		type = argv[desc->dtargd_ndx];
16850Sstevel@tonic-gate 	}
16860Sstevel@tonic-gate 
16870Sstevel@tonic-gate 	if (ctf_type_name(fp, type, desc->dtargd_native,
16880Sstevel@tonic-gate 	    DTRACE_ARGTYPELEN) != NULL) {
16890Sstevel@tonic-gate 		ctf_close(fp);
16900Sstevel@tonic-gate 		return;
16910Sstevel@tonic-gate 	}
16920Sstevel@tonic-gate err:
16930Sstevel@tonic-gate 	if (fp != NULL)
16940Sstevel@tonic-gate 		ctf_close(fp);
16950Sstevel@tonic-gate 
16960Sstevel@tonic-gate 	desc->dtargd_ndx = DTRACE_ARGNONE;
16970Sstevel@tonic-gate }
16980Sstevel@tonic-gate 
16990Sstevel@tonic-gate static dtrace_pattr_t fbt_attr = {
17000Sstevel@tonic-gate { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
17010Sstevel@tonic-gate { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
17020Sstevel@tonic-gate { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
17030Sstevel@tonic-gate { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
17040Sstevel@tonic-gate { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
17050Sstevel@tonic-gate };
17060Sstevel@tonic-gate 
17070Sstevel@tonic-gate static dtrace_pops_t fbt_pops = {
17080Sstevel@tonic-gate 	NULL,
17090Sstevel@tonic-gate 	fbt_provide_module,
17100Sstevel@tonic-gate 	fbt_enable,
17110Sstevel@tonic-gate 	fbt_disable,
17120Sstevel@tonic-gate 	fbt_suspend,
17130Sstevel@tonic-gate 	fbt_resume,
17140Sstevel@tonic-gate 	fbt_getargdesc,
17150Sstevel@tonic-gate 	NULL,
17160Sstevel@tonic-gate 	NULL,
17170Sstevel@tonic-gate 	fbt_destroy
17180Sstevel@tonic-gate };
17190Sstevel@tonic-gate 
17200Sstevel@tonic-gate static int
fbt_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)17210Sstevel@tonic-gate fbt_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
17220Sstevel@tonic-gate {
17230Sstevel@tonic-gate 	switch (cmd) {
17240Sstevel@tonic-gate 	case DDI_ATTACH:
17250Sstevel@tonic-gate 		break;
17260Sstevel@tonic-gate 	case DDI_RESUME:
17270Sstevel@tonic-gate 		return (DDI_SUCCESS);
17280Sstevel@tonic-gate 	default:
17290Sstevel@tonic-gate 		return (DDI_FAILURE);
17300Sstevel@tonic-gate 	}
17310Sstevel@tonic-gate 
17320Sstevel@tonic-gate 	if (ddi_create_minor_node(devi, "fbt", S_IFCHR, 0,
17330Sstevel@tonic-gate 	    DDI_PSEUDO, NULL) == DDI_FAILURE ||
17341677Sdp 	    dtrace_register("fbt", &fbt_attr, DTRACE_PRIV_KERNEL, NULL,
17350Sstevel@tonic-gate 	    &fbt_pops, NULL, &fbt_id) != 0) {
17360Sstevel@tonic-gate 		ddi_remove_minor_node(devi, NULL);
17370Sstevel@tonic-gate 		return (DDI_FAILURE);
17380Sstevel@tonic-gate 	}
17390Sstevel@tonic-gate 
17400Sstevel@tonic-gate 	ddi_report_dev(devi);
17410Sstevel@tonic-gate 	fbt_devi = devi;
17420Sstevel@tonic-gate 	return (DDI_SUCCESS);
17430Sstevel@tonic-gate }
17440Sstevel@tonic-gate 
17450Sstevel@tonic-gate static int
fbt_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)17460Sstevel@tonic-gate fbt_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
17470Sstevel@tonic-gate {
17480Sstevel@tonic-gate 	switch (cmd) {
17490Sstevel@tonic-gate 	case DDI_DETACH:
17500Sstevel@tonic-gate 		break;
17510Sstevel@tonic-gate 	case DDI_SUSPEND:
17520Sstevel@tonic-gate 		return (DDI_SUCCESS);
17530Sstevel@tonic-gate 	default:
17540Sstevel@tonic-gate 		return (DDI_FAILURE);
17550Sstevel@tonic-gate 	}
17560Sstevel@tonic-gate 
17570Sstevel@tonic-gate 	if (dtrace_unregister(fbt_id) != 0)
17580Sstevel@tonic-gate 		return (DDI_FAILURE);
17590Sstevel@tonic-gate 
17600Sstevel@tonic-gate 	ddi_remove_minor_node(devi, NULL);
17610Sstevel@tonic-gate 	return (DDI_SUCCESS);
17620Sstevel@tonic-gate }
17630Sstevel@tonic-gate 
17640Sstevel@tonic-gate /*ARGSUSED*/
17650Sstevel@tonic-gate static int
fbt_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)17660Sstevel@tonic-gate fbt_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
17670Sstevel@tonic-gate {
17680Sstevel@tonic-gate 	int error;
17690Sstevel@tonic-gate 
17700Sstevel@tonic-gate 	switch (infocmd) {
17710Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
17720Sstevel@tonic-gate 		*result = (void *)fbt_devi;
17730Sstevel@tonic-gate 		error = DDI_SUCCESS;
17740Sstevel@tonic-gate 		break;
17750Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
17760Sstevel@tonic-gate 		*result = (void *)0;
17770Sstevel@tonic-gate 		error = DDI_SUCCESS;
17780Sstevel@tonic-gate 		break;
17790Sstevel@tonic-gate 	default:
17800Sstevel@tonic-gate 		error = DDI_FAILURE;
17810Sstevel@tonic-gate 	}
17820Sstevel@tonic-gate 	return (error);
17830Sstevel@tonic-gate }
17840Sstevel@tonic-gate 
17850Sstevel@tonic-gate /*ARGSUSED*/
17860Sstevel@tonic-gate static int
fbt_open(dev_t * devp,int flag,int otyp,cred_t * cred_p)17870Sstevel@tonic-gate fbt_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
17880Sstevel@tonic-gate {
17890Sstevel@tonic-gate 	return (0);
17900Sstevel@tonic-gate }
17910Sstevel@tonic-gate 
17920Sstevel@tonic-gate static struct cb_ops fbt_cb_ops = {
17930Sstevel@tonic-gate 	fbt_open,		/* open */
17940Sstevel@tonic-gate 	nodev,			/* close */
17950Sstevel@tonic-gate 	nulldev,		/* strategy */
17960Sstevel@tonic-gate 	nulldev,		/* print */
17970Sstevel@tonic-gate 	nodev,			/* dump */
17980Sstevel@tonic-gate 	nodev,			/* read */
17990Sstevel@tonic-gate 	nodev,			/* write */
18000Sstevel@tonic-gate 	nodev,			/* ioctl */
18010Sstevel@tonic-gate 	nodev,			/* devmap */
18020Sstevel@tonic-gate 	nodev,			/* mmap */
18030Sstevel@tonic-gate 	nodev,			/* segmap */
18040Sstevel@tonic-gate 	nochpoll,		/* poll */
18050Sstevel@tonic-gate 	ddi_prop_op,		/* cb_prop_op */
18060Sstevel@tonic-gate 	0,			/* streamtab  */
18070Sstevel@tonic-gate 	D_NEW | D_MP		/* Driver compatibility flag */
18080Sstevel@tonic-gate };
18090Sstevel@tonic-gate 
18100Sstevel@tonic-gate static struct dev_ops fbt_ops = {
18110Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev */
18120Sstevel@tonic-gate 	0,			/* refcnt */
18130Sstevel@tonic-gate 	fbt_info,		/* get_dev_info */
18140Sstevel@tonic-gate 	nulldev,		/* identify */
18150Sstevel@tonic-gate 	nulldev,		/* probe */
18160Sstevel@tonic-gate 	fbt_attach,		/* attach */
18170Sstevel@tonic-gate 	fbt_detach,		/* detach */
18180Sstevel@tonic-gate 	nodev,			/* reset */
18190Sstevel@tonic-gate 	&fbt_cb_ops,		/* driver operations */
18200Sstevel@tonic-gate 	NULL,			/* bus operations */
18217656SSherry.Moore@Sun.COM 	nodev,			/* dev power */
18227656SSherry.Moore@Sun.COM 	ddi_quiesce_not_needed,		/* quiesce */
18230Sstevel@tonic-gate };
18240Sstevel@tonic-gate 
18250Sstevel@tonic-gate /*
18260Sstevel@tonic-gate  * Module linkage information for the kernel.
18270Sstevel@tonic-gate  */
18280Sstevel@tonic-gate static struct modldrv modldrv = {
18290Sstevel@tonic-gate 	&mod_driverops,		/* module type (this is a pseudo driver) */
18300Sstevel@tonic-gate 	"Function Boundary Tracing",	/* name of module */
18310Sstevel@tonic-gate 	&fbt_ops,		/* driver ops */
18320Sstevel@tonic-gate };
18330Sstevel@tonic-gate 
18340Sstevel@tonic-gate static struct modlinkage modlinkage = {
18350Sstevel@tonic-gate 	MODREV_1,
18360Sstevel@tonic-gate 	(void *)&modldrv,
18370Sstevel@tonic-gate 	NULL
18380Sstevel@tonic-gate };
18390Sstevel@tonic-gate 
18400Sstevel@tonic-gate int
_init(void)18410Sstevel@tonic-gate _init(void)
18420Sstevel@tonic-gate {
18430Sstevel@tonic-gate 	return (mod_install(&modlinkage));
18440Sstevel@tonic-gate }
18450Sstevel@tonic-gate 
18460Sstevel@tonic-gate int
_info(struct modinfo * modinfop)18470Sstevel@tonic-gate _info(struct modinfo *modinfop)
18480Sstevel@tonic-gate {
18490Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
18500Sstevel@tonic-gate }
18510Sstevel@tonic-gate 
18520Sstevel@tonic-gate int
_fini(void)18530Sstevel@tonic-gate _fini(void)
18540Sstevel@tonic-gate {
18550Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
18560Sstevel@tonic-gate }
1857