xref: /xnu-8796.121.2/bsd/dev/dtrace/fasttrap.c (revision c54f35ca767986246321eb901baf8f5ff7923f6a)
1*c54f35caSApple OSS Distributions /*
2*c54f35caSApple OSS Distributions  * CDDL HEADER START
3*c54f35caSApple OSS Distributions  *
4*c54f35caSApple OSS Distributions  * The contents of this file are subject to the terms of the
5*c54f35caSApple OSS Distributions  * Common Development and Distribution License (the "License").
6*c54f35caSApple OSS Distributions  * You may not use this file except in compliance with the License.
7*c54f35caSApple OSS Distributions  *
8*c54f35caSApple OSS Distributions  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*c54f35caSApple OSS Distributions  * or http://www.opensolaris.org/os/licensing.
10*c54f35caSApple OSS Distributions  * See the License for the specific language governing permissions
11*c54f35caSApple OSS Distributions  * and limitations under the License.
12*c54f35caSApple OSS Distributions  *
13*c54f35caSApple OSS Distributions  * When distributing Covered Code, include this CDDL HEADER in each
14*c54f35caSApple OSS Distributions  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*c54f35caSApple OSS Distributions  * If applicable, add the following below this CDDL HEADER, with the
16*c54f35caSApple OSS Distributions  * fields enclosed by brackets "[]" replaced with your own identifying
17*c54f35caSApple OSS Distributions  * information: Portions Copyright [yyyy] [name of copyright owner]
18*c54f35caSApple OSS Distributions  *
19*c54f35caSApple OSS Distributions  * CDDL HEADER END
20*c54f35caSApple OSS Distributions  */
21*c54f35caSApple OSS Distributions 
22*c54f35caSApple OSS Distributions /*
23*c54f35caSApple OSS Distributions  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*c54f35caSApple OSS Distributions  * Use is subject to license terms.
25*c54f35caSApple OSS Distributions  */
26*c54f35caSApple OSS Distributions 
27*c54f35caSApple OSS Distributions #include <sys/types.h>
28*c54f35caSApple OSS Distributions #include <sys/time.h>
29*c54f35caSApple OSS Distributions 
30*c54f35caSApple OSS Distributions #include <sys/codesign.h>
31*c54f35caSApple OSS Distributions #include <sys/errno.h>
32*c54f35caSApple OSS Distributions #include <sys/stat.h>
33*c54f35caSApple OSS Distributions #include <sys/conf.h>
34*c54f35caSApple OSS Distributions #include <sys/systm.h>
35*c54f35caSApple OSS Distributions #include <sys/kauth.h>
36*c54f35caSApple OSS Distributions #include <sys/utfconv.h>
37*c54f35caSApple OSS Distributions 
38*c54f35caSApple OSS Distributions #include <sys/fasttrap.h>
39*c54f35caSApple OSS Distributions #include <sys/fasttrap_impl.h>
40*c54f35caSApple OSS Distributions #include <sys/fasttrap_isa.h>
41*c54f35caSApple OSS Distributions #include <sys/dtrace.h>
42*c54f35caSApple OSS Distributions #include <sys/dtrace_impl.h>
43*c54f35caSApple OSS Distributions #include <sys/proc.h>
44*c54f35caSApple OSS Distributions 
45*c54f35caSApple OSS Distributions #include <security/mac_framework.h>
46*c54f35caSApple OSS Distributions 
47*c54f35caSApple OSS Distributions #include <miscfs/devfs/devfs.h>
48*c54f35caSApple OSS Distributions #include <sys/proc_internal.h>
49*c54f35caSApple OSS Distributions #include <sys/dtrace_glue.h>
50*c54f35caSApple OSS Distributions #include <sys/dtrace_ptss.h>
51*c54f35caSApple OSS Distributions 
52*c54f35caSApple OSS Distributions #include <kern/cs_blobs.h>
53*c54f35caSApple OSS Distributions #include <kern/thread.h>
54*c54f35caSApple OSS Distributions #include <kern/zalloc.h>
55*c54f35caSApple OSS Distributions 
56*c54f35caSApple OSS Distributions #include <mach/thread_act.h>
57*c54f35caSApple OSS Distributions 
58*c54f35caSApple OSS Distributions extern kern_return_t kernel_thread_start_priority(thread_continue_t continuation, void *parameter, integer_t priority, thread_t *new_thread);
59*c54f35caSApple OSS Distributions 
60*c54f35caSApple OSS Distributions /* Solaris proc_t is the struct. Darwin's proc_t is a pointer to it. */
61*c54f35caSApple OSS Distributions #define proc_t struct proc /* Steer clear of the Darwin typedef for proc_t */
62*c54f35caSApple OSS Distributions 
63*c54f35caSApple OSS Distributions __private_extern__
64*c54f35caSApple OSS Distributions void
65*c54f35caSApple OSS Distributions qsort(void *a, size_t n, size_t es, int (*cmp)(const void *, const void *));
66*c54f35caSApple OSS Distributions 
67*c54f35caSApple OSS Distributions /*
68*c54f35caSApple OSS Distributions  * User-Land Trap-Based Tracing
69*c54f35caSApple OSS Distributions  * ----------------------------
70*c54f35caSApple OSS Distributions  *
71*c54f35caSApple OSS Distributions  * The fasttrap provider allows DTrace consumers to instrument any user-level
72*c54f35caSApple OSS Distributions  * instruction to gather data; this includes probes with semantic
73*c54f35caSApple OSS Distributions  * signifigance like entry and return as well as simple offsets into the
74*c54f35caSApple OSS Distributions  * function. While the specific techniques used are very ISA specific, the
75*c54f35caSApple OSS Distributions  * methodology is generalizable to any architecture.
76*c54f35caSApple OSS Distributions  *
77*c54f35caSApple OSS Distributions  *
78*c54f35caSApple OSS Distributions  * The General Methodology
79*c54f35caSApple OSS Distributions  * -----------------------
80*c54f35caSApple OSS Distributions  *
81*c54f35caSApple OSS Distributions  * With the primary goal of tracing every user-land instruction and the
82*c54f35caSApple OSS Distributions  * limitation that we can't trust user space so don't want to rely on much
83*c54f35caSApple OSS Distributions  * information there, we begin by replacing the instructions we want to trace
84*c54f35caSApple OSS Distributions  * with trap instructions. Each instruction we overwrite is saved into a hash
85*c54f35caSApple OSS Distributions  * table keyed by process ID and pc address. When we enter the kernel due to
86*c54f35caSApple OSS Distributions  * this trap instruction, we need the effects of the replaced instruction to
87*c54f35caSApple OSS Distributions  * appear to have occurred before we proceed with the user thread's
88*c54f35caSApple OSS Distributions  * execution.
89*c54f35caSApple OSS Distributions  *
90*c54f35caSApple OSS Distributions  * Each user level thread is represented by a ulwp_t structure which is
91*c54f35caSApple OSS Distributions  * always easily accessible through a register. The most basic way to produce
92*c54f35caSApple OSS Distributions  * the effects of the instruction we replaced is to copy that instruction out
93*c54f35caSApple OSS Distributions  * to a bit of scratch space reserved in the user thread's ulwp_t structure
94*c54f35caSApple OSS Distributions  * (a sort of kernel-private thread local storage), set the PC to that
95*c54f35caSApple OSS Distributions  * scratch space and single step. When we reenter the kernel after single
96*c54f35caSApple OSS Distributions  * stepping the instruction we must then adjust the PC to point to what would
97*c54f35caSApple OSS Distributions  * normally be the next instruction. Of course, special care must be taken
98*c54f35caSApple OSS Distributions  * for branches and jumps, but these represent such a small fraction of any
99*c54f35caSApple OSS Distributions  * instruction set that writing the code to emulate these in the kernel is
100*c54f35caSApple OSS Distributions  * not too difficult.
101*c54f35caSApple OSS Distributions  *
102*c54f35caSApple OSS Distributions  * Return probes may require several tracepoints to trace every return site,
103*c54f35caSApple OSS Distributions  * and, conversely, each tracepoint may activate several probes (the entry
104*c54f35caSApple OSS Distributions  * and offset 0 probes, for example). To solve this muliplexing problem,
105*c54f35caSApple OSS Distributions  * tracepoints contain lists of probes to activate and probes contain lists
106*c54f35caSApple OSS Distributions  * of tracepoints to enable. If a probe is activated, it adds its ID to
107*c54f35caSApple OSS Distributions  * existing tracepoints or creates new ones as necessary.
108*c54f35caSApple OSS Distributions  *
109*c54f35caSApple OSS Distributions  * Most probes are activated _before_ the instruction is executed, but return
110*c54f35caSApple OSS Distributions  * probes are activated _after_ the effects of the last instruction of the
111*c54f35caSApple OSS Distributions  * function are visible. Return probes must be fired _after_ we have
112*c54f35caSApple OSS Distributions  * single-stepped the instruction whereas all other probes are fired
113*c54f35caSApple OSS Distributions  * beforehand.
114*c54f35caSApple OSS Distributions  *
115*c54f35caSApple OSS Distributions  *
116*c54f35caSApple OSS Distributions  * Lock Ordering
117*c54f35caSApple OSS Distributions  * -------------
118*c54f35caSApple OSS Distributions  *
119*c54f35caSApple OSS Distributions  * The lock ordering below -- both internally and with respect to the DTrace
120*c54f35caSApple OSS Distributions  * framework -- is a little tricky and bears some explanation. Each provider
121*c54f35caSApple OSS Distributions  * has a lock (ftp_mtx) that protects its members including reference counts
122*c54f35caSApple OSS Distributions  * for enabled probes (ftp_rcount), consumers actively creating probes
123*c54f35caSApple OSS Distributions  * (ftp_ccount) and USDT consumers (ftp_mcount); all three prevent a provider
124*c54f35caSApple OSS Distributions  * from being freed. A provider is looked up by taking the bucket lock for the
125*c54f35caSApple OSS Distributions  * provider hash table, and is returned with its lock held. The provider lock
126*c54f35caSApple OSS Distributions  * may be taken in functions invoked by the DTrace framework, but may not be
127*c54f35caSApple OSS Distributions  * held while calling functions in the DTrace framework.
128*c54f35caSApple OSS Distributions  *
129*c54f35caSApple OSS Distributions  * To ensure consistency over multiple calls to the DTrace framework, the
130*c54f35caSApple OSS Distributions  * creation lock (ftp_cmtx) should be held. Naturally, the creation lock may
131*c54f35caSApple OSS Distributions  * not be taken when holding the provider lock as that would create a cyclic
132*c54f35caSApple OSS Distributions  * lock ordering. In situations where one would naturally take the provider
133*c54f35caSApple OSS Distributions  * lock and then the creation lock, we instead up a reference count to prevent
134*c54f35caSApple OSS Distributions  * the provider from disappearing, drop the provider lock, and acquire the
135*c54f35caSApple OSS Distributions  * creation lock.
136*c54f35caSApple OSS Distributions  *
137*c54f35caSApple OSS Distributions  * Briefly:
138*c54f35caSApple OSS Distributions  * 	bucket lock before provider lock
139*c54f35caSApple OSS Distributions  *	DTrace before provider lock
140*c54f35caSApple OSS Distributions  *	creation lock before DTrace
141*c54f35caSApple OSS Distributions  *	never hold the provider lock and creation lock simultaneously
142*c54f35caSApple OSS Distributions  */
143*c54f35caSApple OSS Distributions 
144*c54f35caSApple OSS Distributions static dtrace_meta_provider_id_t fasttrap_meta_id;
145*c54f35caSApple OSS Distributions 
146*c54f35caSApple OSS Distributions static thread_t fasttrap_cleanup_thread;
147*c54f35caSApple OSS Distributions 
148*c54f35caSApple OSS Distributions static LCK_GRP_DECLARE(fasttrap_lck_grp, "fasttrap");
149*c54f35caSApple OSS Distributions static LCK_ATTR_DECLARE(fasttrap_lck_attr, 0, 0);
150*c54f35caSApple OSS Distributions static LCK_MTX_DECLARE_ATTR(fasttrap_cleanup_mtx,
151*c54f35caSApple OSS Distributions     &fasttrap_lck_grp, &fasttrap_lck_attr);
152*c54f35caSApple OSS Distributions 
153*c54f35caSApple OSS Distributions 
154*c54f35caSApple OSS Distributions #define FASTTRAP_CLEANUP_PROVIDER 0x1
155*c54f35caSApple OSS Distributions #define FASTTRAP_CLEANUP_TRACEPOINT 0x2
156*c54f35caSApple OSS Distributions 
157*c54f35caSApple OSS Distributions static uint32_t fasttrap_cleanup_work = 0;
158*c54f35caSApple OSS Distributions 
159*c54f35caSApple OSS Distributions /*
160*c54f35caSApple OSS Distributions  * Generation count on modifications to the global tracepoint lookup table.
161*c54f35caSApple OSS Distributions  */
162*c54f35caSApple OSS Distributions static volatile uint64_t fasttrap_mod_gen;
163*c54f35caSApple OSS Distributions 
164*c54f35caSApple OSS Distributions /*
165*c54f35caSApple OSS Distributions  * APPLE NOTE: When the fasttrap provider is loaded, fasttrap_max is computed
166*c54f35caSApple OSS Distributions  * base on system memory.  Each time a probe is created, fasttrap_total is
167*c54f35caSApple OSS Distributions  * incremented by the number of tracepoints that may be associated with that
168*c54f35caSApple OSS Distributions  * probe; fasttrap_total is capped at fasttrap_max.
169*c54f35caSApple OSS Distributions  */
170*c54f35caSApple OSS Distributions 
171*c54f35caSApple OSS Distributions static uint32_t fasttrap_max;
172*c54f35caSApple OSS Distributions static uint32_t fasttrap_retired;
173*c54f35caSApple OSS Distributions static uint32_t fasttrap_total;
174*c54f35caSApple OSS Distributions 
175*c54f35caSApple OSS Distributions 
176*c54f35caSApple OSS Distributions #define	FASTTRAP_TPOINTS_DEFAULT_SIZE	0x4000
177*c54f35caSApple OSS Distributions #define	FASTTRAP_PROVIDERS_DEFAULT_SIZE	0x100
178*c54f35caSApple OSS Distributions #define	FASTTRAP_PROCS_DEFAULT_SIZE	0x100
179*c54f35caSApple OSS Distributions 
180*c54f35caSApple OSS Distributions fasttrap_hash_t			fasttrap_tpoints;
181*c54f35caSApple OSS Distributions static fasttrap_hash_t		fasttrap_provs;
182*c54f35caSApple OSS Distributions static fasttrap_hash_t		fasttrap_procs;
183*c54f35caSApple OSS Distributions 
184*c54f35caSApple OSS Distributions static uint64_t			fasttrap_pid_count;	/* pid ref count */
185*c54f35caSApple OSS Distributions static LCK_MTX_DECLARE_ATTR(fasttrap_count_mtx,	/* lock on ref count */
186*c54f35caSApple OSS Distributions     &fasttrap_lck_grp, &fasttrap_lck_attr);
187*c54f35caSApple OSS Distributions 
188*c54f35caSApple OSS Distributions #define	FASTTRAP_ENABLE_FAIL	1
189*c54f35caSApple OSS Distributions #define	FASTTRAP_ENABLE_PARTIAL	2
190*c54f35caSApple OSS Distributions 
191*c54f35caSApple OSS Distributions static int fasttrap_tracepoint_enable(proc_t *, fasttrap_probe_t *, uint_t);
192*c54f35caSApple OSS Distributions static void fasttrap_tracepoint_disable(proc_t *, fasttrap_probe_t *, uint_t);
193*c54f35caSApple OSS Distributions 
194*c54f35caSApple OSS Distributions static fasttrap_provider_t *fasttrap_provider_lookup(proc_t*, fasttrap_provider_type_t, const char *,
195*c54f35caSApple OSS Distributions     const dtrace_pattr_t *);
196*c54f35caSApple OSS Distributions static void fasttrap_provider_retire(proc_t*, const char *, int);
197*c54f35caSApple OSS Distributions static void fasttrap_provider_free(fasttrap_provider_t *);
198*c54f35caSApple OSS Distributions 
199*c54f35caSApple OSS Distributions static fasttrap_proc_t *fasttrap_proc_lookup(pid_t);
200*c54f35caSApple OSS Distributions static void fasttrap_proc_release(fasttrap_proc_t *);
201*c54f35caSApple OSS Distributions 
202*c54f35caSApple OSS Distributions #define	FASTTRAP_PROVS_INDEX(pid, name) \
203*c54f35caSApple OSS Distributions 	((fasttrap_hash_str(name) + (pid)) & fasttrap_provs.fth_mask)
204*c54f35caSApple OSS Distributions 
205*c54f35caSApple OSS Distributions #define	FASTTRAP_PROCS_INDEX(pid) ((pid) & fasttrap_procs.fth_mask)
206*c54f35caSApple OSS Distributions 
207*c54f35caSApple OSS Distributions /*
208*c54f35caSApple OSS Distributions  * APPLE NOTE: To save memory, some common memory allocations are given
209*c54f35caSApple OSS Distributions  * a unique zone. For example, dtrace_probe_t is 72 bytes in size,
210*c54f35caSApple OSS Distributions  * which means it would fall into the kalloc.128 bucket. With
211*c54f35caSApple OSS Distributions  * 20k elements allocated, the space saved is substantial.
212*c54f35caSApple OSS Distributions  */
213*c54f35caSApple OSS Distributions 
214*c54f35caSApple OSS Distributions ZONE_DEFINE(fasttrap_tracepoint_t_zone, "dtrace.fasttrap_tracepoint_t",
215*c54f35caSApple OSS Distributions     sizeof(fasttrap_tracepoint_t), ZC_NONE);
216*c54f35caSApple OSS Distributions 
217*c54f35caSApple OSS Distributions /*
218*c54f35caSApple OSS Distributions  * APPLE NOTE: fasttrap_probe_t's are variable in size. Some quick profiling has shown
219*c54f35caSApple OSS Distributions  * that the sweet spot for reducing memory footprint is covering the first
220*c54f35caSApple OSS Distributions  * three sizes. Everything larger goes into the common pool.
221*c54f35caSApple OSS Distributions  */
222*c54f35caSApple OSS Distributions #define FASTTRAP_PROBE_T_ZONE_MAX_TRACEPOINTS 4
223*c54f35caSApple OSS Distributions 
224*c54f35caSApple OSS Distributions struct zone *fasttrap_probe_t_zones[FASTTRAP_PROBE_T_ZONE_MAX_TRACEPOINTS];
225*c54f35caSApple OSS Distributions 
226*c54f35caSApple OSS Distributions static const char *fasttrap_probe_t_zone_names[FASTTRAP_PROBE_T_ZONE_MAX_TRACEPOINTS] = {
227*c54f35caSApple OSS Distributions 	"",
228*c54f35caSApple OSS Distributions 	"dtrace.fasttrap_probe_t[1]",
229*c54f35caSApple OSS Distributions 	"dtrace.fasttrap_probe_t[2]",
230*c54f35caSApple OSS Distributions 	"dtrace.fasttrap_probe_t[3]"
231*c54f35caSApple OSS Distributions };
232*c54f35caSApple OSS Distributions 
233*c54f35caSApple OSS Distributions static int
fasttrap_highbit(ulong_t i)234*c54f35caSApple OSS Distributions fasttrap_highbit(ulong_t i)
235*c54f35caSApple OSS Distributions {
236*c54f35caSApple OSS Distributions 	int h = 1;
237*c54f35caSApple OSS Distributions 
238*c54f35caSApple OSS Distributions 	if (i == 0)
239*c54f35caSApple OSS Distributions 		return (0);
240*c54f35caSApple OSS Distributions #ifdef _LP64
241*c54f35caSApple OSS Distributions 	if (i & 0xffffffff00000000ul) {
242*c54f35caSApple OSS Distributions 		h += 32; i >>= 32;
243*c54f35caSApple OSS Distributions 	}
244*c54f35caSApple OSS Distributions #endif
245*c54f35caSApple OSS Distributions 	if (i & 0xffff0000) {
246*c54f35caSApple OSS Distributions 		h += 16; i >>= 16;
247*c54f35caSApple OSS Distributions 	}
248*c54f35caSApple OSS Distributions 	if (i & 0xff00) {
249*c54f35caSApple OSS Distributions 		h += 8; i >>= 8;
250*c54f35caSApple OSS Distributions 	}
251*c54f35caSApple OSS Distributions 	if (i & 0xf0) {
252*c54f35caSApple OSS Distributions 		h += 4; i >>= 4;
253*c54f35caSApple OSS Distributions 	}
254*c54f35caSApple OSS Distributions 	if (i & 0xc) {
255*c54f35caSApple OSS Distributions 		h += 2; i >>= 2;
256*c54f35caSApple OSS Distributions 	}
257*c54f35caSApple OSS Distributions 	if (i & 0x2) {
258*c54f35caSApple OSS Distributions 		h += 1;
259*c54f35caSApple OSS Distributions 	}
260*c54f35caSApple OSS Distributions 	return (h);
261*c54f35caSApple OSS Distributions }
262*c54f35caSApple OSS Distributions 
263*c54f35caSApple OSS Distributions static uint_t
fasttrap_hash_str(const char * p)264*c54f35caSApple OSS Distributions fasttrap_hash_str(const char *p)
265*c54f35caSApple OSS Distributions {
266*c54f35caSApple OSS Distributions 	unsigned int g;
267*c54f35caSApple OSS Distributions 	uint_t hval = 0;
268*c54f35caSApple OSS Distributions 
269*c54f35caSApple OSS Distributions 	while (*p) {
270*c54f35caSApple OSS Distributions 		hval = (hval << 4) + *p++;
271*c54f35caSApple OSS Distributions 		if ((g = (hval & 0xf0000000)) != 0)
272*c54f35caSApple OSS Distributions 			hval ^= g >> 24;
273*c54f35caSApple OSS Distributions 		hval &= ~g;
274*c54f35caSApple OSS Distributions 	}
275*c54f35caSApple OSS Distributions 	return (hval);
276*c54f35caSApple OSS Distributions }
277*c54f35caSApple OSS Distributions 
278*c54f35caSApple OSS Distributions /*
279*c54f35caSApple OSS Distributions  * APPLE NOTE: fasttrap_sigtrap not implemented
280*c54f35caSApple OSS Distributions  */
281*c54f35caSApple OSS Distributions void
fasttrap_sigtrap(proc_t * p,uthread_t t,user_addr_t pc)282*c54f35caSApple OSS Distributions fasttrap_sigtrap(proc_t *p, uthread_t t, user_addr_t pc)
283*c54f35caSApple OSS Distributions {
284*c54f35caSApple OSS Distributions #pragma unused(p, t, pc)
285*c54f35caSApple OSS Distributions 
286*c54f35caSApple OSS Distributions #if !defined(__APPLE__)
287*c54f35caSApple OSS Distributions 	sigqueue_t *sqp = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP);
288*c54f35caSApple OSS Distributions 
289*c54f35caSApple OSS Distributions 	sqp->sq_info.si_signo = SIGTRAP;
290*c54f35caSApple OSS Distributions 	sqp->sq_info.si_code = TRAP_DTRACE;
291*c54f35caSApple OSS Distributions 	sqp->sq_info.si_addr = (caddr_t)pc;
292*c54f35caSApple OSS Distributions 
293*c54f35caSApple OSS Distributions 	mutex_enter(&p->p_lock);
294*c54f35caSApple OSS Distributions 	sigaddqa(p, t, sqp);
295*c54f35caSApple OSS Distributions 	mutex_exit(&p->p_lock);
296*c54f35caSApple OSS Distributions 
297*c54f35caSApple OSS Distributions 	if (t != NULL)
298*c54f35caSApple OSS Distributions 		aston(t);
299*c54f35caSApple OSS Distributions #endif /* __APPLE__ */
300*c54f35caSApple OSS Distributions 
301*c54f35caSApple OSS Distributions 	printf("fasttrap_sigtrap called with no implementation.\n");
302*c54f35caSApple OSS Distributions }
303*c54f35caSApple OSS Distributions 
304*c54f35caSApple OSS Distributions /*
305*c54f35caSApple OSS Distributions  * This function ensures that no threads are actively using the memory
306*c54f35caSApple OSS Distributions  * associated with probes that were formerly live.
307*c54f35caSApple OSS Distributions  */
308*c54f35caSApple OSS Distributions static void
fasttrap_mod_barrier(uint64_t gen)309*c54f35caSApple OSS Distributions fasttrap_mod_barrier(uint64_t gen)
310*c54f35caSApple OSS Distributions {
311*c54f35caSApple OSS Distributions 	unsigned int i;
312*c54f35caSApple OSS Distributions 
313*c54f35caSApple OSS Distributions 	if (gen < fasttrap_mod_gen)
314*c54f35caSApple OSS Distributions 		return;
315*c54f35caSApple OSS Distributions 
316*c54f35caSApple OSS Distributions 	fasttrap_mod_gen++;
317*c54f35caSApple OSS Distributions 
318*c54f35caSApple OSS Distributions 	for (i = 0; i < NCPU; i++) {
319*c54f35caSApple OSS Distributions 		lck_mtx_lock(&cpu_core[i].cpuc_pid_lock);
320*c54f35caSApple OSS Distributions 		lck_mtx_unlock(&cpu_core[i].cpuc_pid_lock);
321*c54f35caSApple OSS Distributions 	}
322*c54f35caSApple OSS Distributions }
323*c54f35caSApple OSS Distributions 
324*c54f35caSApple OSS Distributions static void fasttrap_pid_cleanup(uint32_t);
325*c54f35caSApple OSS Distributions 
326*c54f35caSApple OSS Distributions static unsigned int
fasttrap_pid_cleanup_providers(void)327*c54f35caSApple OSS Distributions fasttrap_pid_cleanup_providers(void)
328*c54f35caSApple OSS Distributions {
329*c54f35caSApple OSS Distributions 	fasttrap_provider_t **fpp, *fp;
330*c54f35caSApple OSS Distributions 	fasttrap_bucket_t *bucket;
331*c54f35caSApple OSS Distributions 	dtrace_provider_id_t provid;
332*c54f35caSApple OSS Distributions 	unsigned int later = 0, i;
333*c54f35caSApple OSS Distributions 
334*c54f35caSApple OSS Distributions 	/*
335*c54f35caSApple OSS Distributions 	 * Iterate over all the providers trying to remove the marked
336*c54f35caSApple OSS Distributions 	 * ones. If a provider is marked but not retired, we just
337*c54f35caSApple OSS Distributions 	 * have to take a crack at removing it -- it's no big deal if
338*c54f35caSApple OSS Distributions 	 * we can't.
339*c54f35caSApple OSS Distributions 	 */
340*c54f35caSApple OSS Distributions 	for (i = 0; i < fasttrap_provs.fth_nent; i++) {
341*c54f35caSApple OSS Distributions 		bucket = &fasttrap_provs.fth_table[i];
342*c54f35caSApple OSS Distributions 		lck_mtx_lock(&bucket->ftb_mtx);
343*c54f35caSApple OSS Distributions 		fpp = (fasttrap_provider_t **)&bucket->ftb_data;
344*c54f35caSApple OSS Distributions 
345*c54f35caSApple OSS Distributions 		while ((fp = *fpp) != NULL) {
346*c54f35caSApple OSS Distributions 			if (!fp->ftp_marked) {
347*c54f35caSApple OSS Distributions 				fpp = &fp->ftp_next;
348*c54f35caSApple OSS Distributions 				continue;
349*c54f35caSApple OSS Distributions 			}
350*c54f35caSApple OSS Distributions 
351*c54f35caSApple OSS Distributions 			lck_mtx_lock(&fp->ftp_mtx);
352*c54f35caSApple OSS Distributions 
353*c54f35caSApple OSS Distributions 			/*
354*c54f35caSApple OSS Distributions 			 * If this provider has consumers actively
355*c54f35caSApple OSS Distributions 			 * creating probes (ftp_ccount) or is a USDT
356*c54f35caSApple OSS Distributions 			 * provider (ftp_mcount), we can't unregister
357*c54f35caSApple OSS Distributions 			 * or even condense.
358*c54f35caSApple OSS Distributions 			 */
359*c54f35caSApple OSS Distributions 			if (fp->ftp_ccount != 0 ||
360*c54f35caSApple OSS Distributions 			    fp->ftp_mcount != 0) {
361*c54f35caSApple OSS Distributions 				fp->ftp_marked = 0;
362*c54f35caSApple OSS Distributions 				lck_mtx_unlock(&fp->ftp_mtx);
363*c54f35caSApple OSS Distributions 				continue;
364*c54f35caSApple OSS Distributions 			}
365*c54f35caSApple OSS Distributions 
366*c54f35caSApple OSS Distributions 			if (!fp->ftp_retired || fp->ftp_rcount != 0)
367*c54f35caSApple OSS Distributions 				fp->ftp_marked = 0;
368*c54f35caSApple OSS Distributions 
369*c54f35caSApple OSS Distributions 			lck_mtx_unlock(&fp->ftp_mtx);
370*c54f35caSApple OSS Distributions 
371*c54f35caSApple OSS Distributions 			/*
372*c54f35caSApple OSS Distributions 			 * If we successfully unregister this
373*c54f35caSApple OSS Distributions 			 * provider we can remove it from the hash
374*c54f35caSApple OSS Distributions 			 * chain and free the memory. If our attempt
375*c54f35caSApple OSS Distributions 			 * to unregister fails and this is a retired
376*c54f35caSApple OSS Distributions 			 * provider, increment our flag to try again
377*c54f35caSApple OSS Distributions 			 * pretty soon. If we've consumed more than
378*c54f35caSApple OSS Distributions 			 * half of our total permitted number of
379*c54f35caSApple OSS Distributions 			 * probes call dtrace_condense() to try to
380*c54f35caSApple OSS Distributions 			 * clean out the unenabled probes.
381*c54f35caSApple OSS Distributions 			 */
382*c54f35caSApple OSS Distributions 			provid = fp->ftp_provid;
383*c54f35caSApple OSS Distributions 			if (dtrace_unregister(provid) != 0) {
384*c54f35caSApple OSS Distributions 				if (fasttrap_total > fasttrap_max / 2)
385*c54f35caSApple OSS Distributions 					(void) dtrace_condense(provid);
386*c54f35caSApple OSS Distributions 				later += fp->ftp_marked;
387*c54f35caSApple OSS Distributions 				fpp = &fp->ftp_next;
388*c54f35caSApple OSS Distributions 			} else {
389*c54f35caSApple OSS Distributions 				*fpp = fp->ftp_next;
390*c54f35caSApple OSS Distributions 				fasttrap_provider_free(fp);
391*c54f35caSApple OSS Distributions 			}
392*c54f35caSApple OSS Distributions 		}
393*c54f35caSApple OSS Distributions 		lck_mtx_unlock(&bucket->ftb_mtx);
394*c54f35caSApple OSS Distributions 	}
395*c54f35caSApple OSS Distributions 
396*c54f35caSApple OSS Distributions 	return later;
397*c54f35caSApple OSS Distributions }
398*c54f35caSApple OSS Distributions 
399*c54f35caSApple OSS Distributions typedef struct fasttrap_tracepoint_spec {
400*c54f35caSApple OSS Distributions 	pid_t fttps_pid;
401*c54f35caSApple OSS Distributions 	user_addr_t fttps_pc;
402*c54f35caSApple OSS Distributions } fasttrap_tracepoint_spec_t;
403*c54f35caSApple OSS Distributions 
404*c54f35caSApple OSS Distributions static fasttrap_tracepoint_spec_t *fasttrap_retired_spec;
405*c54f35caSApple OSS Distributions static size_t fasttrap_cur_retired = 0, fasttrap_retired_size;
406*c54f35caSApple OSS Distributions static LCK_MTX_DECLARE_ATTR(fasttrap_retired_mtx,
407*c54f35caSApple OSS Distributions     &fasttrap_lck_grp, &fasttrap_lck_attr);
408*c54f35caSApple OSS Distributions 
409*c54f35caSApple OSS Distributions #define DEFAULT_RETIRED_SIZE 256
410*c54f35caSApple OSS Distributions 
411*c54f35caSApple OSS Distributions static void
fasttrap_tracepoint_cleanup(void)412*c54f35caSApple OSS Distributions fasttrap_tracepoint_cleanup(void)
413*c54f35caSApple OSS Distributions {
414*c54f35caSApple OSS Distributions 	size_t i;
415*c54f35caSApple OSS Distributions 	pid_t pid = 0;
416*c54f35caSApple OSS Distributions 	user_addr_t pc;
417*c54f35caSApple OSS Distributions 	proc_t *p = PROC_NULL;
418*c54f35caSApple OSS Distributions 	fasttrap_tracepoint_t *tp = NULL;
419*c54f35caSApple OSS Distributions 	lck_mtx_lock(&fasttrap_retired_mtx);
420*c54f35caSApple OSS Distributions 	fasttrap_bucket_t *bucket;
421*c54f35caSApple OSS Distributions 	for (i = 0; i < fasttrap_cur_retired; i++) {
422*c54f35caSApple OSS Distributions 		pc = fasttrap_retired_spec[i].fttps_pc;
423*c54f35caSApple OSS Distributions 		if (fasttrap_retired_spec[i].fttps_pid != pid) {
424*c54f35caSApple OSS Distributions 			pid = fasttrap_retired_spec[i].fttps_pid;
425*c54f35caSApple OSS Distributions 			if (p != PROC_NULL) {
426*c54f35caSApple OSS Distributions 				sprunlock(p);
427*c54f35caSApple OSS Distributions 			}
428*c54f35caSApple OSS Distributions 			if ((p = sprlock(pid)) == PROC_NULL) {
429*c54f35caSApple OSS Distributions 				pid = 0;
430*c54f35caSApple OSS Distributions 				continue;
431*c54f35caSApple OSS Distributions 			}
432*c54f35caSApple OSS Distributions 		}
433*c54f35caSApple OSS Distributions 		bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)];
434*c54f35caSApple OSS Distributions 		lck_mtx_lock(&bucket->ftb_mtx);
435*c54f35caSApple OSS Distributions 		for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
436*c54f35caSApple OSS Distributions 			if (pid == tp->ftt_pid && pc == tp->ftt_pc &&
437*c54f35caSApple OSS Distributions 			tp->ftt_proc->ftpc_acount != 0)
438*c54f35caSApple OSS Distributions 				break;
439*c54f35caSApple OSS Distributions 		}
440*c54f35caSApple OSS Distributions 		/*
441*c54f35caSApple OSS Distributions 		 * Check that the tracepoint is not gone or has not been
442*c54f35caSApple OSS Distributions 		 * re-activated for another probe
443*c54f35caSApple OSS Distributions 		 */
444*c54f35caSApple OSS Distributions 		if (tp == NULL || tp->ftt_retired == 0) {
445*c54f35caSApple OSS Distributions 			lck_mtx_unlock(&bucket->ftb_mtx);
446*c54f35caSApple OSS Distributions 			continue;
447*c54f35caSApple OSS Distributions 		}
448*c54f35caSApple OSS Distributions 		fasttrap_tracepoint_remove(p, tp);
449*c54f35caSApple OSS Distributions 		lck_mtx_unlock(&bucket->ftb_mtx);
450*c54f35caSApple OSS Distributions 	}
451*c54f35caSApple OSS Distributions 	if (p != PROC_NULL) {
452*c54f35caSApple OSS Distributions 		sprunlock(p);
453*c54f35caSApple OSS Distributions 	}
454*c54f35caSApple OSS Distributions 
455*c54f35caSApple OSS Distributions 	fasttrap_cur_retired = 0;
456*c54f35caSApple OSS Distributions 
457*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&fasttrap_retired_mtx);
458*c54f35caSApple OSS Distributions }
459*c54f35caSApple OSS Distributions 
460*c54f35caSApple OSS Distributions void
fasttrap_tracepoint_retire(proc_t * p,fasttrap_tracepoint_t * tp)461*c54f35caSApple OSS Distributions fasttrap_tracepoint_retire(proc_t *p, fasttrap_tracepoint_t *tp)
462*c54f35caSApple OSS Distributions {
463*c54f35caSApple OSS Distributions 	if (tp->ftt_retired)
464*c54f35caSApple OSS Distributions 		return;
465*c54f35caSApple OSS Distributions 	lck_mtx_lock(&fasttrap_retired_mtx);
466*c54f35caSApple OSS Distributions 	fasttrap_tracepoint_spec_t *s = &fasttrap_retired_spec[fasttrap_cur_retired++];
467*c54f35caSApple OSS Distributions 	s->fttps_pid = proc_getpid(p);
468*c54f35caSApple OSS Distributions 	s->fttps_pc = tp->ftt_pc;
469*c54f35caSApple OSS Distributions 
470*c54f35caSApple OSS Distributions 	if (fasttrap_cur_retired == fasttrap_retired_size) {
471*c54f35caSApple OSS Distributions 		fasttrap_tracepoint_spec_t *new_retired = kmem_zalloc(
472*c54f35caSApple OSS Distributions 					fasttrap_retired_size * 2 *
473*c54f35caSApple OSS Distributions 					sizeof(*fasttrap_retired_spec),
474*c54f35caSApple OSS Distributions 					KM_SLEEP);
475*c54f35caSApple OSS Distributions 		memcpy(new_retired, fasttrap_retired_spec, sizeof(*fasttrap_retired_spec) * fasttrap_retired_size);
476*c54f35caSApple OSS Distributions 		kmem_free(fasttrap_retired_spec, sizeof(*fasttrap_retired_spec) * fasttrap_retired_size);
477*c54f35caSApple OSS Distributions 		fasttrap_retired_size *= 2;
478*c54f35caSApple OSS Distributions 		fasttrap_retired_spec = new_retired;
479*c54f35caSApple OSS Distributions 	}
480*c54f35caSApple OSS Distributions 
481*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&fasttrap_retired_mtx);
482*c54f35caSApple OSS Distributions 
483*c54f35caSApple OSS Distributions 	tp->ftt_retired = 1;
484*c54f35caSApple OSS Distributions 
485*c54f35caSApple OSS Distributions 	fasttrap_pid_cleanup(FASTTRAP_CLEANUP_TRACEPOINT);
486*c54f35caSApple OSS Distributions }
487*c54f35caSApple OSS Distributions 
488*c54f35caSApple OSS Distributions static void
fasttrap_pid_cleanup_compute_priority(void)489*c54f35caSApple OSS Distributions fasttrap_pid_cleanup_compute_priority(void)
490*c54f35caSApple OSS Distributions {
491*c54f35caSApple OSS Distributions 	if (fasttrap_total > (fasttrap_max / 100 * 90) || fasttrap_retired > fasttrap_max / 2) {
492*c54f35caSApple OSS Distributions 		thread_precedence_policy_data_t precedence = {12 /* BASEPRI_PREEMPT_HIGH */};
493*c54f35caSApple OSS Distributions 		thread_policy_set(fasttrap_cleanup_thread, THREAD_PRECEDENCE_POLICY, (thread_policy_t) &precedence, THREAD_PRECEDENCE_POLICY_COUNT);
494*c54f35caSApple OSS Distributions 	}
495*c54f35caSApple OSS Distributions 	else {
496*c54f35caSApple OSS Distributions 		thread_precedence_policy_data_t precedence = {-39 /* BASEPRI_USER_INITIATED */};
497*c54f35caSApple OSS Distributions 		thread_policy_set(fasttrap_cleanup_thread, THREAD_PRECEDENCE_POLICY, (thread_policy_t) &precedence, THREAD_PRECEDENCE_POLICY_COUNT);
498*c54f35caSApple OSS Distributions 
499*c54f35caSApple OSS Distributions 	}
500*c54f35caSApple OSS Distributions }
501*c54f35caSApple OSS Distributions 
502*c54f35caSApple OSS Distributions /*
503*c54f35caSApple OSS Distributions  * This is the timeout's callback for cleaning up the providers and their
504*c54f35caSApple OSS Distributions  * probes.
505*c54f35caSApple OSS Distributions  */
506*c54f35caSApple OSS Distributions /*ARGSUSED*/
507*c54f35caSApple OSS Distributions __attribute__((noreturn))
508*c54f35caSApple OSS Distributions static void
fasttrap_pid_cleanup_cb(void)509*c54f35caSApple OSS Distributions fasttrap_pid_cleanup_cb(void)
510*c54f35caSApple OSS Distributions {
511*c54f35caSApple OSS Distributions 	uint32_t work = 0;
512*c54f35caSApple OSS Distributions 	lck_mtx_lock(&fasttrap_cleanup_mtx);
513*c54f35caSApple OSS Distributions 	msleep(&fasttrap_pid_cleanup_cb, &fasttrap_cleanup_mtx, PRIBIO, "fasttrap_pid_cleanup_cb", NULL);
514*c54f35caSApple OSS Distributions 	while (1) {
515*c54f35caSApple OSS Distributions 		unsigned int later = 0;
516*c54f35caSApple OSS Distributions 
517*c54f35caSApple OSS Distributions 		work = os_atomic_xchg(&fasttrap_cleanup_work, 0, relaxed);
518*c54f35caSApple OSS Distributions 		lck_mtx_unlock(&fasttrap_cleanup_mtx);
519*c54f35caSApple OSS Distributions 		if (work & FASTTRAP_CLEANUP_PROVIDER) {
520*c54f35caSApple OSS Distributions 			later = fasttrap_pid_cleanup_providers();
521*c54f35caSApple OSS Distributions 		}
522*c54f35caSApple OSS Distributions 		if (work & FASTTRAP_CLEANUP_TRACEPOINT) {
523*c54f35caSApple OSS Distributions 			fasttrap_tracepoint_cleanup();
524*c54f35caSApple OSS Distributions 		}
525*c54f35caSApple OSS Distributions 		lck_mtx_lock(&fasttrap_cleanup_mtx);
526*c54f35caSApple OSS Distributions 
527*c54f35caSApple OSS Distributions 		fasttrap_pid_cleanup_compute_priority();
528*c54f35caSApple OSS Distributions 		if (!fasttrap_cleanup_work) {
529*c54f35caSApple OSS Distributions 			/*
530*c54f35caSApple OSS Distributions 			 * If we were unable to remove a retired provider, try again after
531*c54f35caSApple OSS Distributions 			 * a second. This situation can occur in certain circumstances where
532*c54f35caSApple OSS Distributions 			 * providers cannot be unregistered even though they have no probes
533*c54f35caSApple OSS Distributions 			 * enabled because of an execution of dtrace -l or something similar.
534*c54f35caSApple OSS Distributions 			 * If the timeout has been disabled (set to 1 because we're trying
535*c54f35caSApple OSS Distributions 			 * to detach), we set fasttrap_cleanup_work to ensure that we'll
536*c54f35caSApple OSS Distributions 			 * get a chance to do that work if and when the timeout is reenabled
537*c54f35caSApple OSS Distributions 			 * (if detach fails).
538*c54f35caSApple OSS Distributions 			 */
539*c54f35caSApple OSS Distributions 			if (later > 0) {
540*c54f35caSApple OSS Distributions 				struct timespec t = {.tv_sec = 1, .tv_nsec = 0};
541*c54f35caSApple OSS Distributions 				msleep(&fasttrap_pid_cleanup_cb, &fasttrap_cleanup_mtx, PRIBIO, "fasttrap_pid_cleanup_cb", &t);
542*c54f35caSApple OSS Distributions 			}
543*c54f35caSApple OSS Distributions 			else
544*c54f35caSApple OSS Distributions 				msleep(&fasttrap_pid_cleanup_cb, &fasttrap_cleanup_mtx, PRIBIO, "fasttrap_pid_cleanup_cb", NULL);
545*c54f35caSApple OSS Distributions 		}
546*c54f35caSApple OSS Distributions 	}
547*c54f35caSApple OSS Distributions 
548*c54f35caSApple OSS Distributions }
549*c54f35caSApple OSS Distributions 
550*c54f35caSApple OSS Distributions /*
551*c54f35caSApple OSS Distributions  * Activates the asynchronous cleanup mechanism.
552*c54f35caSApple OSS Distributions  */
553*c54f35caSApple OSS Distributions static void
fasttrap_pid_cleanup(uint32_t work)554*c54f35caSApple OSS Distributions fasttrap_pid_cleanup(uint32_t work)
555*c54f35caSApple OSS Distributions {
556*c54f35caSApple OSS Distributions 	lck_mtx_lock(&fasttrap_cleanup_mtx);
557*c54f35caSApple OSS Distributions 	os_atomic_or(&fasttrap_cleanup_work, work, relaxed);
558*c54f35caSApple OSS Distributions 	fasttrap_pid_cleanup_compute_priority();
559*c54f35caSApple OSS Distributions 	wakeup(&fasttrap_pid_cleanup_cb);
560*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&fasttrap_cleanup_mtx);
561*c54f35caSApple OSS Distributions }
562*c54f35caSApple OSS Distributions 
563*c54f35caSApple OSS Distributions static int
fasttrap_setdebug(proc_t * p)564*c54f35caSApple OSS Distributions fasttrap_setdebug(proc_t *p)
565*c54f35caSApple OSS Distributions {
566*c54f35caSApple OSS Distributions 	LCK_MTX_ASSERT(&p->p_mlock, LCK_MTX_ASSERT_OWNED);
567*c54f35caSApple OSS Distributions 
568*c54f35caSApple OSS Distributions 	/*
569*c54f35caSApple OSS Distributions 	 * CS_KILL and CS_HARD will cause code-signing to kill the process
570*c54f35caSApple OSS Distributions 	 * when the process text is modified, so register the intent
571*c54f35caSApple OSS Distributions 	 * to allow invalid access beforehand.
572*c54f35caSApple OSS Distributions 	 */
573*c54f35caSApple OSS Distributions 	if ((proc_getcsflags(p) & (CS_KILL|CS_HARD))) {
574*c54f35caSApple OSS Distributions 		proc_unlock(p);
575*c54f35caSApple OSS Distributions 		for (int i = 0; i < DTRACE_NCLIENTS; i++) {
576*c54f35caSApple OSS Distributions 			dtrace_state_t *state = dtrace_state_get(i);
577*c54f35caSApple OSS Distributions 			if (state == NULL)
578*c54f35caSApple OSS Distributions 				continue;
579*c54f35caSApple OSS Distributions 			if (state->dts_cred.dcr_cred == NULL)
580*c54f35caSApple OSS Distributions 				continue;
581*c54f35caSApple OSS Distributions 			/*
582*c54f35caSApple OSS Distributions 			 * The get_task call flags whether the process should
583*c54f35caSApple OSS Distributions 			 * be flagged to have the cs_allow_invalid call
584*c54f35caSApple OSS Distributions 			 * succeed. We want the best credential that any dtrace
585*c54f35caSApple OSS Distributions 			 * client has, so try all of them.
586*c54f35caSApple OSS Distributions 			 */
587*c54f35caSApple OSS Distributions 
588*c54f35caSApple OSS Distributions 			/*
589*c54f35caSApple OSS Distributions 			 * mac_proc_check_get_task() can trigger upcalls. It's
590*c54f35caSApple OSS Distributions 			 * not safe to hold proc references accross upcalls, so
591*c54f35caSApple OSS Distributions 			 * just drop the reference.  Given the context, it
592*c54f35caSApple OSS Distributions 			 * should not be possible for the process to actually
593*c54f35caSApple OSS Distributions 			 * disappear.
594*c54f35caSApple OSS Distributions 			 */
595*c54f35caSApple OSS Distributions 			struct proc_ident pident = proc_ident(p);
596*c54f35caSApple OSS Distributions 			sprunlock(p);
597*c54f35caSApple OSS Distributions 			p = PROC_NULL;
598*c54f35caSApple OSS Distributions 
599*c54f35caSApple OSS Distributions 			(void) mac_proc_check_get_task(state->dts_cred.dcr_cred, &pident, TASK_FLAVOR_CONTROL);
600*c54f35caSApple OSS Distributions 
601*c54f35caSApple OSS Distributions 			p = sprlock(pident.p_pid);
602*c54f35caSApple OSS Distributions 			if (p == PROC_NULL) {
603*c54f35caSApple OSS Distributions 				return (ESRCH);
604*c54f35caSApple OSS Distributions 			}
605*c54f35caSApple OSS Distributions 		}
606*c54f35caSApple OSS Distributions 		int rc = cs_allow_invalid(p);
607*c54f35caSApple OSS Distributions 		proc_lock(p);
608*c54f35caSApple OSS Distributions 		if (rc == 0) {
609*c54f35caSApple OSS Distributions 			return (EACCES);
610*c54f35caSApple OSS Distributions 		}
611*c54f35caSApple OSS Distributions 	}
612*c54f35caSApple OSS Distributions 	return (0);
613*c54f35caSApple OSS Distributions }
614*c54f35caSApple OSS Distributions 
615*c54f35caSApple OSS Distributions /*
616*c54f35caSApple OSS Distributions  * This is called from cfork() via dtrace_fasttrap_fork(). The child
617*c54f35caSApple OSS Distributions  * process's address space is a (roughly) a copy of the parent process's so
618*c54f35caSApple OSS Distributions  * we have to remove all the instrumentation we had previously enabled in the
619*c54f35caSApple OSS Distributions  * parent.
620*c54f35caSApple OSS Distributions  */
621*c54f35caSApple OSS Distributions static void
fasttrap_fork(proc_t * p,proc_t * cp)622*c54f35caSApple OSS Distributions fasttrap_fork(proc_t *p, proc_t *cp)
623*c54f35caSApple OSS Distributions {
624*c54f35caSApple OSS Distributions 	pid_t ppid = proc_getpid(p);
625*c54f35caSApple OSS Distributions 	unsigned int i;
626*c54f35caSApple OSS Distributions 
627*c54f35caSApple OSS Distributions 	ASSERT(current_proc() == p);
628*c54f35caSApple OSS Distributions 	LCK_MTX_ASSERT(&p->p_dtrace_sprlock, LCK_MTX_ASSERT_OWNED);
629*c54f35caSApple OSS Distributions 	ASSERT(p->p_dtrace_count > 0);
630*c54f35caSApple OSS Distributions 	ASSERT(cp->p_dtrace_count == 0);
631*c54f35caSApple OSS Distributions 
632*c54f35caSApple OSS Distributions 	/*
633*c54f35caSApple OSS Distributions 	 * This would be simpler and faster if we maintained per-process
634*c54f35caSApple OSS Distributions 	 * hash tables of enabled tracepoints. It could, however, potentially
635*c54f35caSApple OSS Distributions 	 * slow down execution of a tracepoint since we'd need to go
636*c54f35caSApple OSS Distributions 	 * through two levels of indirection. In the future, we should
637*c54f35caSApple OSS Distributions 	 * consider either maintaining per-process ancillary lists of
638*c54f35caSApple OSS Distributions 	 * enabled tracepoints or hanging a pointer to a per-process hash
639*c54f35caSApple OSS Distributions 	 * table of enabled tracepoints off the proc structure.
640*c54f35caSApple OSS Distributions 	 */
641*c54f35caSApple OSS Distributions 
642*c54f35caSApple OSS Distributions 	/*
643*c54f35caSApple OSS Distributions 	 * We don't have to worry about the child process disappearing
644*c54f35caSApple OSS Distributions 	 * because we're in fork().
645*c54f35caSApple OSS Distributions 	 */
646*c54f35caSApple OSS Distributions 	if (cp != sprlock(proc_getpid(cp))) {
647*c54f35caSApple OSS Distributions 		printf("fasttrap_fork: sprlock(%d) returned a different proc\n", proc_getpid(cp));
648*c54f35caSApple OSS Distributions 		return;
649*c54f35caSApple OSS Distributions 	}
650*c54f35caSApple OSS Distributions 
651*c54f35caSApple OSS Distributions 	proc_lock(cp);
652*c54f35caSApple OSS Distributions 	if (fasttrap_setdebug(cp) == ESRCH) {
653*c54f35caSApple OSS Distributions 		printf("fasttrap_fork: failed to re-acquire proc\n");
654*c54f35caSApple OSS Distributions 		return;
655*c54f35caSApple OSS Distributions 	}
656*c54f35caSApple OSS Distributions 	proc_unlock(cp);
657*c54f35caSApple OSS Distributions 
658*c54f35caSApple OSS Distributions 	/*
659*c54f35caSApple OSS Distributions 	 * Iterate over every tracepoint looking for ones that belong to the
660*c54f35caSApple OSS Distributions 	 * parent process, and remove each from the child process.
661*c54f35caSApple OSS Distributions 	 */
662*c54f35caSApple OSS Distributions 	for (i = 0; i < fasttrap_tpoints.fth_nent; i++) {
663*c54f35caSApple OSS Distributions 		fasttrap_tracepoint_t *tp;
664*c54f35caSApple OSS Distributions 		fasttrap_bucket_t *bucket = &fasttrap_tpoints.fth_table[i];
665*c54f35caSApple OSS Distributions 
666*c54f35caSApple OSS Distributions 		lck_mtx_lock(&bucket->ftb_mtx);
667*c54f35caSApple OSS Distributions 		for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
668*c54f35caSApple OSS Distributions 			if (tp->ftt_pid == ppid &&
669*c54f35caSApple OSS Distributions 			    tp->ftt_proc->ftpc_acount != 0) {
670*c54f35caSApple OSS Distributions 				fasttrap_tracepoint_remove(cp, tp);
671*c54f35caSApple OSS Distributions 
672*c54f35caSApple OSS Distributions 				/*
673*c54f35caSApple OSS Distributions 				 * The count of active providers can only be
674*c54f35caSApple OSS Distributions 				 * decremented (i.e. to zero) during exec,
675*c54f35caSApple OSS Distributions 				 * exit, and removal of a meta provider so it
676*c54f35caSApple OSS Distributions 				 * should be impossible to drop the count
677*c54f35caSApple OSS Distributions 				 * mid-fork.
678*c54f35caSApple OSS Distributions 				 */
679*c54f35caSApple OSS Distributions 				 ASSERT(tp->ftt_proc->ftpc_acount != 0);
680*c54f35caSApple OSS Distributions 			}
681*c54f35caSApple OSS Distributions 		}
682*c54f35caSApple OSS Distributions 		lck_mtx_unlock(&bucket->ftb_mtx);
683*c54f35caSApple OSS Distributions 	}
684*c54f35caSApple OSS Distributions 
685*c54f35caSApple OSS Distributions 	/*
686*c54f35caSApple OSS Distributions 	 * Free any ptss pages/entries in the child.
687*c54f35caSApple OSS Distributions 	 */
688*c54f35caSApple OSS Distributions 	dtrace_ptss_fork(p, cp);
689*c54f35caSApple OSS Distributions 
690*c54f35caSApple OSS Distributions 	sprunlock(cp);
691*c54f35caSApple OSS Distributions }
692*c54f35caSApple OSS Distributions 
693*c54f35caSApple OSS Distributions /*
694*c54f35caSApple OSS Distributions  * This is called from proc_exit() or from exec_common() if p_dtrace_probes
695*c54f35caSApple OSS Distributions  * is set on the proc structure to indicate that there is a pid provider
696*c54f35caSApple OSS Distributions  * associated with this process.
697*c54f35caSApple OSS Distributions  */
698*c54f35caSApple OSS Distributions static void
fasttrap_exec_exit(proc_t * p)699*c54f35caSApple OSS Distributions fasttrap_exec_exit(proc_t *p)
700*c54f35caSApple OSS Distributions {
701*c54f35caSApple OSS Distributions 	ASSERT(p == current_proc());
702*c54f35caSApple OSS Distributions 	LCK_MTX_ASSERT(&p->p_mlock, LCK_MTX_ASSERT_OWNED);
703*c54f35caSApple OSS Distributions 	LCK_MTX_ASSERT(&p->p_dtrace_sprlock, LCK_MTX_ASSERT_NOTOWNED);
704*c54f35caSApple OSS Distributions 
705*c54f35caSApple OSS Distributions 
706*c54f35caSApple OSS Distributions 	/* APPLE NOTE: Okay, the locking here is really odd and needs some
707*c54f35caSApple OSS Distributions 	 * explaining. This method is always called with the proc_lock held.
708*c54f35caSApple OSS Distributions 	 * We must drop the proc_lock before calling fasttrap_provider_retire
709*c54f35caSApple OSS Distributions 	 * to avoid a deadlock when it takes the bucket lock.
710*c54f35caSApple OSS Distributions 	 *
711*c54f35caSApple OSS Distributions 	 * Next, the dtrace_ptss_exec_exit function requires the sprlock
712*c54f35caSApple OSS Distributions 	 * be held, but not the proc_lock.
713*c54f35caSApple OSS Distributions 	 *
714*c54f35caSApple OSS Distributions 	 * Finally, we must re-acquire the proc_lock
715*c54f35caSApple OSS Distributions 	 */
716*c54f35caSApple OSS Distributions 	proc_unlock(p);
717*c54f35caSApple OSS Distributions 
718*c54f35caSApple OSS Distributions 	/*
719*c54f35caSApple OSS Distributions 	 * We clean up the pid provider for this process here; user-land
720*c54f35caSApple OSS Distributions 	 * static probes are handled by the meta-provider remove entry point.
721*c54f35caSApple OSS Distributions 	 */
722*c54f35caSApple OSS Distributions 	fasttrap_provider_retire(p, FASTTRAP_PID_NAME, 0);
723*c54f35caSApple OSS Distributions 
724*c54f35caSApple OSS Distributions 	/*
725*c54f35caSApple OSS Distributions 	 * APPLE NOTE: We also need to remove any aliased providers.
726*c54f35caSApple OSS Distributions 	 * XXX optimization: track which provider types are instantiated
727*c54f35caSApple OSS Distributions 	 * and only retire as needed.
728*c54f35caSApple OSS Distributions 	 */
729*c54f35caSApple OSS Distributions 	fasttrap_provider_retire(p, FASTTRAP_OBJC_NAME, 0);
730*c54f35caSApple OSS Distributions 	fasttrap_provider_retire(p, FASTTRAP_ONESHOT_NAME, 0);
731*c54f35caSApple OSS Distributions 
732*c54f35caSApple OSS Distributions 	/*
733*c54f35caSApple OSS Distributions 	 * This should be called after it is no longer possible for a user
734*c54f35caSApple OSS Distributions 	 * thread to execute (potentially dtrace instrumented) instructions.
735*c54f35caSApple OSS Distributions 	 */
736*c54f35caSApple OSS Distributions 	lck_mtx_lock(&p->p_dtrace_sprlock);
737*c54f35caSApple OSS Distributions 	dtrace_ptss_exec_exit(p);
738*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&p->p_dtrace_sprlock);
739*c54f35caSApple OSS Distributions 
740*c54f35caSApple OSS Distributions 	proc_lock(p);
741*c54f35caSApple OSS Distributions }
742*c54f35caSApple OSS Distributions 
743*c54f35caSApple OSS Distributions 
744*c54f35caSApple OSS Distributions /*ARGSUSED*/
745*c54f35caSApple OSS Distributions static void
fasttrap_pid_provide(void * arg,const dtrace_probedesc_t * desc)746*c54f35caSApple OSS Distributions fasttrap_pid_provide(void *arg, const dtrace_probedesc_t *desc)
747*c54f35caSApple OSS Distributions {
748*c54f35caSApple OSS Distributions #pragma unused(arg, desc)
749*c54f35caSApple OSS Distributions 	/*
750*c54f35caSApple OSS Distributions 	 * There are no "default" pid probes.
751*c54f35caSApple OSS Distributions 	 */
752*c54f35caSApple OSS Distributions }
753*c54f35caSApple OSS Distributions 
754*c54f35caSApple OSS Distributions static int
fasttrap_tracepoint_enable(proc_t * p,fasttrap_probe_t * probe,uint_t index)755*c54f35caSApple OSS Distributions fasttrap_tracepoint_enable(proc_t *p, fasttrap_probe_t *probe, uint_t index)
756*c54f35caSApple OSS Distributions {
757*c54f35caSApple OSS Distributions 	fasttrap_tracepoint_t *tp, *new_tp = NULL;
758*c54f35caSApple OSS Distributions 	fasttrap_bucket_t *bucket;
759*c54f35caSApple OSS Distributions 	fasttrap_id_t *id;
760*c54f35caSApple OSS Distributions 	pid_t pid;
761*c54f35caSApple OSS Distributions 	user_addr_t pc;
762*c54f35caSApple OSS Distributions 
763*c54f35caSApple OSS Distributions 	ASSERT(index < probe->ftp_ntps);
764*c54f35caSApple OSS Distributions 
765*c54f35caSApple OSS Distributions 	pid = probe->ftp_pid;
766*c54f35caSApple OSS Distributions 	pc = probe->ftp_tps[index].fit_tp->ftt_pc;
767*c54f35caSApple OSS Distributions 	id = &probe->ftp_tps[index].fit_id;
768*c54f35caSApple OSS Distributions 
769*c54f35caSApple OSS Distributions 	ASSERT(probe->ftp_tps[index].fit_tp->ftt_pid == pid);
770*c54f35caSApple OSS Distributions 
771*c54f35caSApple OSS Distributions 	/*
772*c54f35caSApple OSS Distributions 	 * Before we make any modifications, make sure we've imposed a barrier
773*c54f35caSApple OSS Distributions 	 * on the generation in which this probe was last modified.
774*c54f35caSApple OSS Distributions 	 */
775*c54f35caSApple OSS Distributions 	fasttrap_mod_barrier(probe->ftp_gen);
776*c54f35caSApple OSS Distributions 
777*c54f35caSApple OSS Distributions 	bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)];
778*c54f35caSApple OSS Distributions 
779*c54f35caSApple OSS Distributions 	/*
780*c54f35caSApple OSS Distributions 	 * If the tracepoint has already been enabled, just add our id to the
781*c54f35caSApple OSS Distributions 	 * list of interested probes. This may be our second time through
782*c54f35caSApple OSS Distributions 	 * this path in which case we'll have constructed the tracepoint we'd
783*c54f35caSApple OSS Distributions 	 * like to install. If we can't find a match, and have an allocated
784*c54f35caSApple OSS Distributions 	 * tracepoint ready to go, enable that one now.
785*c54f35caSApple OSS Distributions 	 *
786*c54f35caSApple OSS Distributions 	 * A tracepoint whose process is defunct is also considered defunct.
787*c54f35caSApple OSS Distributions 	 */
788*c54f35caSApple OSS Distributions again:
789*c54f35caSApple OSS Distributions 	lck_mtx_lock(&bucket->ftb_mtx);
790*c54f35caSApple OSS Distributions 	for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
791*c54f35caSApple OSS Distributions 		int rc = 0;
792*c54f35caSApple OSS Distributions 		/*
793*c54f35caSApple OSS Distributions 		 * Note that it's safe to access the active count on the
794*c54f35caSApple OSS Distributions 		 * associated proc structure because we know that at least one
795*c54f35caSApple OSS Distributions 		 * provider (this one) will still be around throughout this
796*c54f35caSApple OSS Distributions 		 * operation.
797*c54f35caSApple OSS Distributions 		 */
798*c54f35caSApple OSS Distributions 		if (tp->ftt_pid != pid || tp->ftt_pc != pc ||
799*c54f35caSApple OSS Distributions 		    tp->ftt_proc->ftpc_acount == 0)
800*c54f35caSApple OSS Distributions 			continue;
801*c54f35caSApple OSS Distributions 
802*c54f35caSApple OSS Distributions 		/*
803*c54f35caSApple OSS Distributions 		 * Now that we've found a matching tracepoint, it would be
804*c54f35caSApple OSS Distributions 		 * a decent idea to confirm that the tracepoint is still
805*c54f35caSApple OSS Distributions 		 * enabled and the trap instruction hasn't been overwritten.
806*c54f35caSApple OSS Distributions 		 * Since this is a little hairy, we'll punt for now.
807*c54f35caSApple OSS Distributions 		 */
808*c54f35caSApple OSS Distributions 		if (!tp->ftt_installed) {
809*c54f35caSApple OSS Distributions 			if (fasttrap_tracepoint_install(p, tp) != 0)
810*c54f35caSApple OSS Distributions 				rc = FASTTRAP_ENABLE_PARTIAL;
811*c54f35caSApple OSS Distributions 		}
812*c54f35caSApple OSS Distributions 		/*
813*c54f35caSApple OSS Distributions 		 * This can't be the first interested probe. We don't have
814*c54f35caSApple OSS Distributions 		 * to worry about another thread being in the midst of
815*c54f35caSApple OSS Distributions 		 * deleting this tracepoint (which would be the only valid
816*c54f35caSApple OSS Distributions 		 * reason for a tracepoint to have no interested probes)
817*c54f35caSApple OSS Distributions 		 * since we're holding P_PR_LOCK for this process.
818*c54f35caSApple OSS Distributions 		 */
819*c54f35caSApple OSS Distributions 		ASSERT(tp->ftt_ids != NULL || tp->ftt_retids != NULL);
820*c54f35caSApple OSS Distributions 
821*c54f35caSApple OSS Distributions 		switch (id->fti_ptype) {
822*c54f35caSApple OSS Distributions 		case DTFTP_ENTRY:
823*c54f35caSApple OSS Distributions 		case DTFTP_OFFSETS:
824*c54f35caSApple OSS Distributions 		case DTFTP_IS_ENABLED:
825*c54f35caSApple OSS Distributions 			id->fti_next = tp->ftt_ids;
826*c54f35caSApple OSS Distributions 			dtrace_membar_producer();
827*c54f35caSApple OSS Distributions 			tp->ftt_ids = id;
828*c54f35caSApple OSS Distributions 			dtrace_membar_producer();
829*c54f35caSApple OSS Distributions 			break;
830*c54f35caSApple OSS Distributions 
831*c54f35caSApple OSS Distributions 		case DTFTP_RETURN:
832*c54f35caSApple OSS Distributions 		case DTFTP_POST_OFFSETS:
833*c54f35caSApple OSS Distributions 			id->fti_next = tp->ftt_retids;
834*c54f35caSApple OSS Distributions 			dtrace_membar_producer();
835*c54f35caSApple OSS Distributions 			tp->ftt_retids = id;
836*c54f35caSApple OSS Distributions 			dtrace_membar_producer();
837*c54f35caSApple OSS Distributions 			break;
838*c54f35caSApple OSS Distributions 
839*c54f35caSApple OSS Distributions 		default:
840*c54f35caSApple OSS Distributions 			ASSERT(0);
841*c54f35caSApple OSS Distributions 		}
842*c54f35caSApple OSS Distributions 
843*c54f35caSApple OSS Distributions 		tp->ftt_retired = 0;
844*c54f35caSApple OSS Distributions 
845*c54f35caSApple OSS Distributions 		lck_mtx_unlock(&bucket->ftb_mtx);
846*c54f35caSApple OSS Distributions 
847*c54f35caSApple OSS Distributions 		if (new_tp != NULL) {
848*c54f35caSApple OSS Distributions 			new_tp->ftt_ids = NULL;
849*c54f35caSApple OSS Distributions 			new_tp->ftt_retids = NULL;
850*c54f35caSApple OSS Distributions 		}
851*c54f35caSApple OSS Distributions 
852*c54f35caSApple OSS Distributions 		return rc;
853*c54f35caSApple OSS Distributions 	}
854*c54f35caSApple OSS Distributions 
855*c54f35caSApple OSS Distributions 	/*
856*c54f35caSApple OSS Distributions 	 * If we have a good tracepoint ready to go, install it now while
857*c54f35caSApple OSS Distributions 	 * we have the lock held and no one can screw with us.
858*c54f35caSApple OSS Distributions 	 */
859*c54f35caSApple OSS Distributions 	if (new_tp != NULL) {
860*c54f35caSApple OSS Distributions 		int rc = 0;
861*c54f35caSApple OSS Distributions 
862*c54f35caSApple OSS Distributions 		new_tp->ftt_next = bucket->ftb_data;
863*c54f35caSApple OSS Distributions 		dtrace_membar_producer();
864*c54f35caSApple OSS Distributions 		bucket->ftb_data = new_tp;
865*c54f35caSApple OSS Distributions 		dtrace_membar_producer();
866*c54f35caSApple OSS Distributions 		lck_mtx_unlock(&bucket->ftb_mtx);
867*c54f35caSApple OSS Distributions 
868*c54f35caSApple OSS Distributions 		/*
869*c54f35caSApple OSS Distributions 		 * Activate the tracepoint in the ISA-specific manner.
870*c54f35caSApple OSS Distributions 		 * If this fails, we need to report the failure, but
871*c54f35caSApple OSS Distributions 		 * indicate that this tracepoint must still be disabled
872*c54f35caSApple OSS Distributions 		 * by calling fasttrap_tracepoint_disable().
873*c54f35caSApple OSS Distributions 		 */
874*c54f35caSApple OSS Distributions 		if (fasttrap_tracepoint_install(p, new_tp) != 0)
875*c54f35caSApple OSS Distributions 			rc = FASTTRAP_ENABLE_PARTIAL;
876*c54f35caSApple OSS Distributions 		/*
877*c54f35caSApple OSS Distributions 		 * Increment the count of the number of tracepoints active in
878*c54f35caSApple OSS Distributions 		 * the victim process.
879*c54f35caSApple OSS Distributions 		 */
880*c54f35caSApple OSS Distributions 		//ASSERT(p->p_proc_flag & P_PR_LOCK);
881*c54f35caSApple OSS Distributions 		p->p_dtrace_count++;
882*c54f35caSApple OSS Distributions 
883*c54f35caSApple OSS Distributions 
884*c54f35caSApple OSS Distributions 		return (rc);
885*c54f35caSApple OSS Distributions 	}
886*c54f35caSApple OSS Distributions 
887*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&bucket->ftb_mtx);
888*c54f35caSApple OSS Distributions 
889*c54f35caSApple OSS Distributions 	/*
890*c54f35caSApple OSS Distributions 	 * Initialize the tracepoint that's been preallocated with the probe.
891*c54f35caSApple OSS Distributions 	 */
892*c54f35caSApple OSS Distributions 	new_tp = probe->ftp_tps[index].fit_tp;
893*c54f35caSApple OSS Distributions 	new_tp->ftt_retired = 0;
894*c54f35caSApple OSS Distributions 
895*c54f35caSApple OSS Distributions 	ASSERT(new_tp->ftt_pid == pid);
896*c54f35caSApple OSS Distributions 	ASSERT(new_tp->ftt_pc == pc);
897*c54f35caSApple OSS Distributions 	ASSERT(new_tp->ftt_proc == probe->ftp_prov->ftp_proc);
898*c54f35caSApple OSS Distributions 	ASSERT(new_tp->ftt_ids == NULL);
899*c54f35caSApple OSS Distributions 	ASSERT(new_tp->ftt_retids == NULL);
900*c54f35caSApple OSS Distributions 
901*c54f35caSApple OSS Distributions 	switch (id->fti_ptype) {
902*c54f35caSApple OSS Distributions 	case DTFTP_ENTRY:
903*c54f35caSApple OSS Distributions 	case DTFTP_OFFSETS:
904*c54f35caSApple OSS Distributions 	case DTFTP_IS_ENABLED:
905*c54f35caSApple OSS Distributions 		id->fti_next = NULL;
906*c54f35caSApple OSS Distributions 		new_tp->ftt_ids = id;
907*c54f35caSApple OSS Distributions 		break;
908*c54f35caSApple OSS Distributions 
909*c54f35caSApple OSS Distributions 	case DTFTP_RETURN:
910*c54f35caSApple OSS Distributions 	case DTFTP_POST_OFFSETS:
911*c54f35caSApple OSS Distributions 		id->fti_next = NULL;
912*c54f35caSApple OSS Distributions 		new_tp->ftt_retids = id;
913*c54f35caSApple OSS Distributions 		break;
914*c54f35caSApple OSS Distributions 
915*c54f35caSApple OSS Distributions 	default:
916*c54f35caSApple OSS Distributions 		ASSERT(0);
917*c54f35caSApple OSS Distributions 	}
918*c54f35caSApple OSS Distributions 
919*c54f35caSApple OSS Distributions 	/*
920*c54f35caSApple OSS Distributions 	 * If the ISA-dependent initialization goes to plan, go back to the
921*c54f35caSApple OSS Distributions 	 * beginning and try to install this freshly made tracepoint.
922*c54f35caSApple OSS Distributions 	 */
923*c54f35caSApple OSS Distributions 	if (fasttrap_tracepoint_init(p, new_tp, pc, id->fti_ptype) == 0)
924*c54f35caSApple OSS Distributions 		goto again;
925*c54f35caSApple OSS Distributions 
926*c54f35caSApple OSS Distributions 	new_tp->ftt_ids = NULL;
927*c54f35caSApple OSS Distributions 	new_tp->ftt_retids = NULL;
928*c54f35caSApple OSS Distributions 
929*c54f35caSApple OSS Distributions 	return (FASTTRAP_ENABLE_FAIL);
930*c54f35caSApple OSS Distributions }
931*c54f35caSApple OSS Distributions 
932*c54f35caSApple OSS Distributions static void
fasttrap_tracepoint_disable(proc_t * p,fasttrap_probe_t * probe,uint_t index)933*c54f35caSApple OSS Distributions fasttrap_tracepoint_disable(proc_t *p, fasttrap_probe_t *probe, uint_t index)
934*c54f35caSApple OSS Distributions {
935*c54f35caSApple OSS Distributions 	fasttrap_bucket_t *bucket;
936*c54f35caSApple OSS Distributions 	fasttrap_provider_t *provider = probe->ftp_prov;
937*c54f35caSApple OSS Distributions 	fasttrap_tracepoint_t **pp, *tp;
938*c54f35caSApple OSS Distributions 	fasttrap_id_t *id, **idp;
939*c54f35caSApple OSS Distributions 	pid_t pid;
940*c54f35caSApple OSS Distributions 	user_addr_t pc;
941*c54f35caSApple OSS Distributions 
942*c54f35caSApple OSS Distributions 	ASSERT(index < probe->ftp_ntps);
943*c54f35caSApple OSS Distributions 
944*c54f35caSApple OSS Distributions 	pid = probe->ftp_pid;
945*c54f35caSApple OSS Distributions 	pc = probe->ftp_tps[index].fit_tp->ftt_pc;
946*c54f35caSApple OSS Distributions 	id = &probe->ftp_tps[index].fit_id;
947*c54f35caSApple OSS Distributions 
948*c54f35caSApple OSS Distributions 	ASSERT(probe->ftp_tps[index].fit_tp->ftt_pid == pid);
949*c54f35caSApple OSS Distributions 
950*c54f35caSApple OSS Distributions 	/*
951*c54f35caSApple OSS Distributions 	 * Find the tracepoint and make sure that our id is one of the
952*c54f35caSApple OSS Distributions 	 * ones registered with it.
953*c54f35caSApple OSS Distributions 	 */
954*c54f35caSApple OSS Distributions 	bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)];
955*c54f35caSApple OSS Distributions 	lck_mtx_lock(&bucket->ftb_mtx);
956*c54f35caSApple OSS Distributions 	for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
957*c54f35caSApple OSS Distributions 		if (tp->ftt_pid == pid && tp->ftt_pc == pc &&
958*c54f35caSApple OSS Distributions 		    tp->ftt_proc == provider->ftp_proc)
959*c54f35caSApple OSS Distributions 			break;
960*c54f35caSApple OSS Distributions 	}
961*c54f35caSApple OSS Distributions 
962*c54f35caSApple OSS Distributions 	/*
963*c54f35caSApple OSS Distributions 	 * If we somehow lost this tracepoint, we're in a world of hurt.
964*c54f35caSApple OSS Distributions 	 */
965*c54f35caSApple OSS Distributions 	ASSERT(tp != NULL);
966*c54f35caSApple OSS Distributions 
967*c54f35caSApple OSS Distributions 	switch (id->fti_ptype) {
968*c54f35caSApple OSS Distributions 		case DTFTP_ENTRY:
969*c54f35caSApple OSS Distributions 		case DTFTP_OFFSETS:
970*c54f35caSApple OSS Distributions 		case DTFTP_IS_ENABLED:
971*c54f35caSApple OSS Distributions 			ASSERT(tp->ftt_ids != NULL);
972*c54f35caSApple OSS Distributions 			idp = &tp->ftt_ids;
973*c54f35caSApple OSS Distributions 			break;
974*c54f35caSApple OSS Distributions 
975*c54f35caSApple OSS Distributions 		case DTFTP_RETURN:
976*c54f35caSApple OSS Distributions 		case DTFTP_POST_OFFSETS:
977*c54f35caSApple OSS Distributions 			ASSERT(tp->ftt_retids != NULL);
978*c54f35caSApple OSS Distributions 			idp = &tp->ftt_retids;
979*c54f35caSApple OSS Distributions 			break;
980*c54f35caSApple OSS Distributions 
981*c54f35caSApple OSS Distributions 		default:
982*c54f35caSApple OSS Distributions 			/* Fix compiler warning... */
983*c54f35caSApple OSS Distributions 			idp = NULL;
984*c54f35caSApple OSS Distributions 			ASSERT(0);
985*c54f35caSApple OSS Distributions 	}
986*c54f35caSApple OSS Distributions 
987*c54f35caSApple OSS Distributions 	while ((*idp)->fti_probe != probe) {
988*c54f35caSApple OSS Distributions 		idp = &(*idp)->fti_next;
989*c54f35caSApple OSS Distributions 		ASSERT(*idp != NULL);
990*c54f35caSApple OSS Distributions 	}
991*c54f35caSApple OSS Distributions 
992*c54f35caSApple OSS Distributions 	id = *idp;
993*c54f35caSApple OSS Distributions 	*idp = id->fti_next;
994*c54f35caSApple OSS Distributions 	dtrace_membar_producer();
995*c54f35caSApple OSS Distributions 
996*c54f35caSApple OSS Distributions 	ASSERT(id->fti_probe == probe);
997*c54f35caSApple OSS Distributions 
998*c54f35caSApple OSS Distributions 	/*
999*c54f35caSApple OSS Distributions 	 * If there are other registered enablings of this tracepoint, we're
1000*c54f35caSApple OSS Distributions 	 * all done, but if this was the last probe assocated with this
1001*c54f35caSApple OSS Distributions 	 * this tracepoint, we need to remove and free it.
1002*c54f35caSApple OSS Distributions 	 */
1003*c54f35caSApple OSS Distributions 	if (tp->ftt_ids != NULL || tp->ftt_retids != NULL) {
1004*c54f35caSApple OSS Distributions 
1005*c54f35caSApple OSS Distributions 		/*
1006*c54f35caSApple OSS Distributions 		 * If the current probe's tracepoint is in use, swap it
1007*c54f35caSApple OSS Distributions 		 * for an unused tracepoint.
1008*c54f35caSApple OSS Distributions 		 */
1009*c54f35caSApple OSS Distributions 		if (tp == probe->ftp_tps[index].fit_tp) {
1010*c54f35caSApple OSS Distributions 			fasttrap_probe_t *tmp_probe;
1011*c54f35caSApple OSS Distributions 			fasttrap_tracepoint_t **tmp_tp;
1012*c54f35caSApple OSS Distributions 			uint_t tmp_index;
1013*c54f35caSApple OSS Distributions 
1014*c54f35caSApple OSS Distributions 			if (tp->ftt_ids != NULL) {
1015*c54f35caSApple OSS Distributions 				tmp_probe = tp->ftt_ids->fti_probe;
1016*c54f35caSApple OSS Distributions 				/* LINTED - alignment */
1017*c54f35caSApple OSS Distributions 				tmp_index = FASTTRAP_ID_INDEX(tp->ftt_ids);
1018*c54f35caSApple OSS Distributions 				tmp_tp = &tmp_probe->ftp_tps[tmp_index].fit_tp;
1019*c54f35caSApple OSS Distributions 			} else {
1020*c54f35caSApple OSS Distributions 				tmp_probe = tp->ftt_retids->fti_probe;
1021*c54f35caSApple OSS Distributions 				/* LINTED - alignment */
1022*c54f35caSApple OSS Distributions 				tmp_index = FASTTRAP_ID_INDEX(tp->ftt_retids);
1023*c54f35caSApple OSS Distributions 				tmp_tp = &tmp_probe->ftp_tps[tmp_index].fit_tp;
1024*c54f35caSApple OSS Distributions 			}
1025*c54f35caSApple OSS Distributions 
1026*c54f35caSApple OSS Distributions 			ASSERT(*tmp_tp != NULL);
1027*c54f35caSApple OSS Distributions 			ASSERT(*tmp_tp != probe->ftp_tps[index].fit_tp);
1028*c54f35caSApple OSS Distributions 			ASSERT((*tmp_tp)->ftt_ids == NULL);
1029*c54f35caSApple OSS Distributions 			ASSERT((*tmp_tp)->ftt_retids == NULL);
1030*c54f35caSApple OSS Distributions 
1031*c54f35caSApple OSS Distributions 			probe->ftp_tps[index].fit_tp = *tmp_tp;
1032*c54f35caSApple OSS Distributions 			*tmp_tp = tp;
1033*c54f35caSApple OSS Distributions 
1034*c54f35caSApple OSS Distributions 		}
1035*c54f35caSApple OSS Distributions 
1036*c54f35caSApple OSS Distributions 		lck_mtx_unlock(&bucket->ftb_mtx);
1037*c54f35caSApple OSS Distributions 
1038*c54f35caSApple OSS Distributions 		/*
1039*c54f35caSApple OSS Distributions 		 * Tag the modified probe with the generation in which it was
1040*c54f35caSApple OSS Distributions 		 * changed.
1041*c54f35caSApple OSS Distributions 		 */
1042*c54f35caSApple OSS Distributions 		probe->ftp_gen = fasttrap_mod_gen;
1043*c54f35caSApple OSS Distributions 		return;
1044*c54f35caSApple OSS Distributions 	}
1045*c54f35caSApple OSS Distributions 
1046*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&bucket->ftb_mtx);
1047*c54f35caSApple OSS Distributions 
1048*c54f35caSApple OSS Distributions 	/*
1049*c54f35caSApple OSS Distributions 	 * We can't safely remove the tracepoint from the set of active
1050*c54f35caSApple OSS Distributions 	 * tracepoints until we've actually removed the fasttrap instruction
1051*c54f35caSApple OSS Distributions 	 * from the process's text. We can, however, operate on this
1052*c54f35caSApple OSS Distributions 	 * tracepoint secure in the knowledge that no other thread is going to
1053*c54f35caSApple OSS Distributions 	 * be looking at it since we hold P_PR_LOCK on the process if it's
1054*c54f35caSApple OSS Distributions 	 * live or we hold the provider lock on the process if it's dead and
1055*c54f35caSApple OSS Distributions 	 * gone.
1056*c54f35caSApple OSS Distributions 	 */
1057*c54f35caSApple OSS Distributions 
1058*c54f35caSApple OSS Distributions 	/*
1059*c54f35caSApple OSS Distributions 	 * We only need to remove the actual instruction if we're looking
1060*c54f35caSApple OSS Distributions 	 * at an existing process
1061*c54f35caSApple OSS Distributions 	 */
1062*c54f35caSApple OSS Distributions 	if (p != NULL) {
1063*c54f35caSApple OSS Distributions 		/*
1064*c54f35caSApple OSS Distributions 		 * If we fail to restore the instruction we need to kill
1065*c54f35caSApple OSS Distributions 		 * this process since it's in a completely unrecoverable
1066*c54f35caSApple OSS Distributions 		 * state.
1067*c54f35caSApple OSS Distributions 		 */
1068*c54f35caSApple OSS Distributions 		if (fasttrap_tracepoint_remove(p, tp) != 0)
1069*c54f35caSApple OSS Distributions 			fasttrap_sigtrap(p, NULL, pc);
1070*c54f35caSApple OSS Distributions 
1071*c54f35caSApple OSS Distributions 		/*
1072*c54f35caSApple OSS Distributions 		 * Decrement the count of the number of tracepoints active
1073*c54f35caSApple OSS Distributions 		 * in the victim process.
1074*c54f35caSApple OSS Distributions 		 */
1075*c54f35caSApple OSS Distributions 		//ASSERT(p->p_proc_flag & P_PR_LOCK);
1076*c54f35caSApple OSS Distributions 		p->p_dtrace_count--;
1077*c54f35caSApple OSS Distributions 	}
1078*c54f35caSApple OSS Distributions 
1079*c54f35caSApple OSS Distributions 	/*
1080*c54f35caSApple OSS Distributions 	 * Remove the probe from the hash table of active tracepoints.
1081*c54f35caSApple OSS Distributions 	 */
1082*c54f35caSApple OSS Distributions 	lck_mtx_lock(&bucket->ftb_mtx);
1083*c54f35caSApple OSS Distributions 	pp = (fasttrap_tracepoint_t **)&bucket->ftb_data;
1084*c54f35caSApple OSS Distributions 	ASSERT(*pp != NULL);
1085*c54f35caSApple OSS Distributions 	while (*pp != tp) {
1086*c54f35caSApple OSS Distributions 		pp = &(*pp)->ftt_next;
1087*c54f35caSApple OSS Distributions 		ASSERT(*pp != NULL);
1088*c54f35caSApple OSS Distributions 	}
1089*c54f35caSApple OSS Distributions 
1090*c54f35caSApple OSS Distributions 	*pp = tp->ftt_next;
1091*c54f35caSApple OSS Distributions 	dtrace_membar_producer();
1092*c54f35caSApple OSS Distributions 
1093*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&bucket->ftb_mtx);
1094*c54f35caSApple OSS Distributions 
1095*c54f35caSApple OSS Distributions 	/*
1096*c54f35caSApple OSS Distributions 	 * Tag the modified probe with the generation in which it was changed.
1097*c54f35caSApple OSS Distributions 	 */
1098*c54f35caSApple OSS Distributions 	probe->ftp_gen = fasttrap_mod_gen;
1099*c54f35caSApple OSS Distributions }
1100*c54f35caSApple OSS Distributions 
1101*c54f35caSApple OSS Distributions static void
fasttrap_enable_callbacks(void)1102*c54f35caSApple OSS Distributions fasttrap_enable_callbacks(void)
1103*c54f35caSApple OSS Distributions {
1104*c54f35caSApple OSS Distributions 	/*
1105*c54f35caSApple OSS Distributions 	 * We don't have to play the rw lock game here because we're
1106*c54f35caSApple OSS Distributions 	 * providing something rather than taking something away --
1107*c54f35caSApple OSS Distributions 	 * we can be sure that no threads have tried to follow this
1108*c54f35caSApple OSS Distributions 	 * function pointer yet.
1109*c54f35caSApple OSS Distributions 	 */
1110*c54f35caSApple OSS Distributions 	lck_mtx_lock(&fasttrap_count_mtx);
1111*c54f35caSApple OSS Distributions 	if (fasttrap_pid_count == 0) {
1112*c54f35caSApple OSS Distributions 		ASSERT(dtrace_pid_probe_ptr == NULL);
1113*c54f35caSApple OSS Distributions 		ASSERT(dtrace_return_probe_ptr == NULL);
1114*c54f35caSApple OSS Distributions 		dtrace_pid_probe_ptr = &fasttrap_pid_probe;
1115*c54f35caSApple OSS Distributions 		dtrace_return_probe_ptr = &fasttrap_return_probe;
1116*c54f35caSApple OSS Distributions 	}
1117*c54f35caSApple OSS Distributions 	ASSERT(dtrace_pid_probe_ptr == &fasttrap_pid_probe);
1118*c54f35caSApple OSS Distributions 	ASSERT(dtrace_return_probe_ptr == &fasttrap_return_probe);
1119*c54f35caSApple OSS Distributions 	fasttrap_pid_count++;
1120*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&fasttrap_count_mtx);
1121*c54f35caSApple OSS Distributions }
1122*c54f35caSApple OSS Distributions 
1123*c54f35caSApple OSS Distributions static void
fasttrap_disable_callbacks(void)1124*c54f35caSApple OSS Distributions fasttrap_disable_callbacks(void)
1125*c54f35caSApple OSS Distributions {
1126*c54f35caSApple OSS Distributions 	//ASSERT(MUTEX_HELD(&cpu_lock));
1127*c54f35caSApple OSS Distributions 
1128*c54f35caSApple OSS Distributions 	lck_mtx_lock(&fasttrap_count_mtx);
1129*c54f35caSApple OSS Distributions 	ASSERT(fasttrap_pid_count > 0);
1130*c54f35caSApple OSS Distributions 	fasttrap_pid_count--;
1131*c54f35caSApple OSS Distributions 	if (fasttrap_pid_count == 0) {
1132*c54f35caSApple OSS Distributions 		dtrace_cpu_t *cur, *cpu = CPU;
1133*c54f35caSApple OSS Distributions 
1134*c54f35caSApple OSS Distributions 		/*
1135*c54f35caSApple OSS Distributions 		 * APPLE NOTE: This loop seems broken, it touches every CPU
1136*c54f35caSApple OSS Distributions 		 * but the one we're actually running on. Need to ask Sun folks
1137*c54f35caSApple OSS Distributions 		 * if that is safe. Scenario is this: We're running on CPU A,
1138*c54f35caSApple OSS Distributions 		 * and lock all but A. Then we get preempted, and start running
1139*c54f35caSApple OSS Distributions 		 * on CPU B. A probe fires on A, and is allowed to enter. BOOM!
1140*c54f35caSApple OSS Distributions 		 */
1141*c54f35caSApple OSS Distributions 		for (cur = cpu->cpu_next; cur != cpu; cur = cur->cpu_next) {
1142*c54f35caSApple OSS Distributions 			lck_rw_lock_exclusive(&cur->cpu_ft_lock);
1143*c54f35caSApple OSS Distributions 			// rw_enter(&cur->cpu_ft_lock, RW_WRITER);
1144*c54f35caSApple OSS Distributions 		}
1145*c54f35caSApple OSS Distributions 
1146*c54f35caSApple OSS Distributions 		dtrace_pid_probe_ptr = NULL;
1147*c54f35caSApple OSS Distributions 		dtrace_return_probe_ptr = NULL;
1148*c54f35caSApple OSS Distributions 
1149*c54f35caSApple OSS Distributions 		for (cur = cpu->cpu_next; cur != cpu; cur = cur->cpu_next) {
1150*c54f35caSApple OSS Distributions 			lck_rw_unlock_exclusive(&cur->cpu_ft_lock);
1151*c54f35caSApple OSS Distributions 			// rw_exit(&cur->cpu_ft_lock);
1152*c54f35caSApple OSS Distributions 		}
1153*c54f35caSApple OSS Distributions 	}
1154*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&fasttrap_count_mtx);
1155*c54f35caSApple OSS Distributions }
1156*c54f35caSApple OSS Distributions 
1157*c54f35caSApple OSS Distributions /*ARGSUSED*/
1158*c54f35caSApple OSS Distributions static int
fasttrap_pid_enable(void * arg,dtrace_id_t id,void * parg)1159*c54f35caSApple OSS Distributions fasttrap_pid_enable(void *arg, dtrace_id_t id, void *parg)
1160*c54f35caSApple OSS Distributions {
1161*c54f35caSApple OSS Distributions #pragma unused(arg, id)
1162*c54f35caSApple OSS Distributions 	fasttrap_probe_t *probe = parg;
1163*c54f35caSApple OSS Distributions 	proc_t *p;
1164*c54f35caSApple OSS Distributions 	int i, rc;
1165*c54f35caSApple OSS Distributions 
1166*c54f35caSApple OSS Distributions 	ASSERT(probe != NULL);
1167*c54f35caSApple OSS Distributions 	ASSERT(!probe->ftp_enabled);
1168*c54f35caSApple OSS Distributions 	ASSERT(id == probe->ftp_id);
1169*c54f35caSApple OSS Distributions 	// ASSERT(MUTEX_HELD(&cpu_lock));
1170*c54f35caSApple OSS Distributions 
1171*c54f35caSApple OSS Distributions 	/*
1172*c54f35caSApple OSS Distributions 	 * Increment the count of enabled probes on this probe's provider;
1173*c54f35caSApple OSS Distributions 	 * the provider can't go away while the probe still exists. We
1174*c54f35caSApple OSS Distributions 	 * must increment this even if we aren't able to properly enable
1175*c54f35caSApple OSS Distributions 	 * this probe.
1176*c54f35caSApple OSS Distributions 	 */
1177*c54f35caSApple OSS Distributions 	lck_mtx_lock(&probe->ftp_prov->ftp_mtx);
1178*c54f35caSApple OSS Distributions 	probe->ftp_prov->ftp_rcount++;
1179*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&probe->ftp_prov->ftp_mtx);
1180*c54f35caSApple OSS Distributions 
1181*c54f35caSApple OSS Distributions 	/*
1182*c54f35caSApple OSS Distributions 	 * If this probe's provider is retired (meaning it was valid in a
1183*c54f35caSApple OSS Distributions 	 * previously exec'ed incarnation of this address space), bail out. The
1184*c54f35caSApple OSS Distributions 	 * provider can't go away while we're in this code path.
1185*c54f35caSApple OSS Distributions 	 */
1186*c54f35caSApple OSS Distributions 	if (probe->ftp_prov->ftp_retired)
1187*c54f35caSApple OSS Distributions 	    return(0);
1188*c54f35caSApple OSS Distributions 
1189*c54f35caSApple OSS Distributions 	/*
1190*c54f35caSApple OSS Distributions 	 * If we can't find the process, it may be that we're in the context of
1191*c54f35caSApple OSS Distributions 	 * a fork in which the traced process is being born and we're copying
1192*c54f35caSApple OSS Distributions 	 * USDT probes. Otherwise, the process is gone so bail.
1193*c54f35caSApple OSS Distributions 	 */
1194*c54f35caSApple OSS Distributions 	if ((p = sprlock(probe->ftp_pid)) == PROC_NULL) {
1195*c54f35caSApple OSS Distributions 		/*
1196*c54f35caSApple OSS Distributions 		 * APPLE NOTE: We should never end up here. The Solaris sprlock()
1197*c54f35caSApple OSS Distributions 		 * does not return process's with SIDL set, but we always return
1198*c54f35caSApple OSS Distributions 		 * the child process.
1199*c54f35caSApple OSS Distributions 		 */
1200*c54f35caSApple OSS Distributions 	    return(0);
1201*c54f35caSApple OSS Distributions 	}
1202*c54f35caSApple OSS Distributions 
1203*c54f35caSApple OSS Distributions 	proc_lock(p);
1204*c54f35caSApple OSS Distributions 	int p_pid = proc_pid(p);
1205*c54f35caSApple OSS Distributions 
1206*c54f35caSApple OSS Distributions 	rc = fasttrap_setdebug(p);
1207*c54f35caSApple OSS Distributions 	switch (rc) {
1208*c54f35caSApple OSS Distributions 	case EACCES:
1209*c54f35caSApple OSS Distributions 		proc_unlock(p);
1210*c54f35caSApple OSS Distributions 		sprunlock(p);
1211*c54f35caSApple OSS Distributions 		cmn_err(CE_WARN, "Failed to install fasttrap probe for pid %d: "
1212*c54f35caSApple OSS Distributions 		    "Process does not allow invalid code pages\n", p_pid);
1213*c54f35caSApple OSS Distributions 		return (0);
1214*c54f35caSApple OSS Distributions 	case ESRCH:
1215*c54f35caSApple OSS Distributions 		cmn_err(CE_WARN, "Failed to install fasttrap probe for pid %d: "
1216*c54f35caSApple OSS Distributions 		    "Failed to re-acquire process\n", p_pid);
1217*c54f35caSApple OSS Distributions 		return (0);
1218*c54f35caSApple OSS Distributions 	default:
1219*c54f35caSApple OSS Distributions 		assert(rc == 0);
1220*c54f35caSApple OSS Distributions 		break;
1221*c54f35caSApple OSS Distributions 	}
1222*c54f35caSApple OSS Distributions 
1223*c54f35caSApple OSS Distributions 	/*
1224*c54f35caSApple OSS Distributions 	 * APPLE NOTE: We do not have an equivalent thread structure to Solaris.
1225*c54f35caSApple OSS Distributions 	 * Solaris uses its ulwp_t struct for scratch space to support the pid provider.
1226*c54f35caSApple OSS Distributions 	 * To mimic this, we allocate on demand scratch space. If this is the first
1227*c54f35caSApple OSS Distributions 	 * time a probe has been enabled in this process, we need to allocate scratch
1228*c54f35caSApple OSS Distributions 	 * space for each already existing thread. Now is a good time to do this, as
1229*c54f35caSApple OSS Distributions 	 * the target process is suspended and the proc_lock is held.
1230*c54f35caSApple OSS Distributions 	 */
1231*c54f35caSApple OSS Distributions 	if (p->p_dtrace_ptss_pages == NULL) {
1232*c54f35caSApple OSS Distributions 		dtrace_ptss_enable(p);
1233*c54f35caSApple OSS Distributions 	}
1234*c54f35caSApple OSS Distributions 
1235*c54f35caSApple OSS Distributions 	proc_unlock(p);
1236*c54f35caSApple OSS Distributions 
1237*c54f35caSApple OSS Distributions 	/*
1238*c54f35caSApple OSS Distributions 	 * We have to enable the trap entry point before any user threads have
1239*c54f35caSApple OSS Distributions 	 * the chance to execute the trap instruction we're about to place
1240*c54f35caSApple OSS Distributions 	 * in their process's text.
1241*c54f35caSApple OSS Distributions 	 */
1242*c54f35caSApple OSS Distributions 	fasttrap_enable_callbacks();
1243*c54f35caSApple OSS Distributions 
1244*c54f35caSApple OSS Distributions 	/*
1245*c54f35caSApple OSS Distributions 	 * Enable all the tracepoints and add this probe's id to each
1246*c54f35caSApple OSS Distributions 	 * tracepoint's list of active probes.
1247*c54f35caSApple OSS Distributions 	 */
1248*c54f35caSApple OSS Distributions 	for (i = 0; i < (int)probe->ftp_ntps; i++) {
1249*c54f35caSApple OSS Distributions 		if ((rc = fasttrap_tracepoint_enable(p, probe, i)) != 0) {
1250*c54f35caSApple OSS Distributions 			/*
1251*c54f35caSApple OSS Distributions 			 * If enabling the tracepoint failed completely,
1252*c54f35caSApple OSS Distributions 			 * we don't have to disable it; if the failure
1253*c54f35caSApple OSS Distributions 			 * was only partial we must disable it.
1254*c54f35caSApple OSS Distributions 			 */
1255*c54f35caSApple OSS Distributions 			if (rc == FASTTRAP_ENABLE_FAIL)
1256*c54f35caSApple OSS Distributions 				i--;
1257*c54f35caSApple OSS Distributions 			else
1258*c54f35caSApple OSS Distributions 				ASSERT(rc == FASTTRAP_ENABLE_PARTIAL);
1259*c54f35caSApple OSS Distributions 
1260*c54f35caSApple OSS Distributions 			/*
1261*c54f35caSApple OSS Distributions 			 * Back up and pull out all the tracepoints we've
1262*c54f35caSApple OSS Distributions 			 * created so far for this probe.
1263*c54f35caSApple OSS Distributions 			 */
1264*c54f35caSApple OSS Distributions 			while (i >= 0) {
1265*c54f35caSApple OSS Distributions 				fasttrap_tracepoint_disable(p, probe, i);
1266*c54f35caSApple OSS Distributions 				i--;
1267*c54f35caSApple OSS Distributions 			}
1268*c54f35caSApple OSS Distributions 
1269*c54f35caSApple OSS Distributions 			sprunlock(p);
1270*c54f35caSApple OSS Distributions 
1271*c54f35caSApple OSS Distributions 			/*
1272*c54f35caSApple OSS Distributions 			 * Since we're not actually enabling this probe,
1273*c54f35caSApple OSS Distributions 			 * drop our reference on the trap table entry.
1274*c54f35caSApple OSS Distributions 			 */
1275*c54f35caSApple OSS Distributions 			fasttrap_disable_callbacks();
1276*c54f35caSApple OSS Distributions 			return(0);
1277*c54f35caSApple OSS Distributions 		}
1278*c54f35caSApple OSS Distributions 	}
1279*c54f35caSApple OSS Distributions 
1280*c54f35caSApple OSS Distributions 	sprunlock(p);
1281*c54f35caSApple OSS Distributions 
1282*c54f35caSApple OSS Distributions 	probe->ftp_enabled = 1;
1283*c54f35caSApple OSS Distributions 	return (0);
1284*c54f35caSApple OSS Distributions }
1285*c54f35caSApple OSS Distributions 
1286*c54f35caSApple OSS Distributions /*ARGSUSED*/
1287*c54f35caSApple OSS Distributions static void
fasttrap_pid_disable(void * arg,dtrace_id_t id,void * parg)1288*c54f35caSApple OSS Distributions fasttrap_pid_disable(void *arg, dtrace_id_t id, void *parg)
1289*c54f35caSApple OSS Distributions {
1290*c54f35caSApple OSS Distributions #pragma unused(arg, id)
1291*c54f35caSApple OSS Distributions 	fasttrap_probe_t *probe = parg;
1292*c54f35caSApple OSS Distributions 	fasttrap_provider_t *provider = probe->ftp_prov;
1293*c54f35caSApple OSS Distributions 	proc_t *p;
1294*c54f35caSApple OSS Distributions 	int i, whack = 0;
1295*c54f35caSApple OSS Distributions 
1296*c54f35caSApple OSS Distributions 	ASSERT(id == probe->ftp_id);
1297*c54f35caSApple OSS Distributions 
1298*c54f35caSApple OSS Distributions 	/*
1299*c54f35caSApple OSS Distributions 	 * We won't be able to acquire a /proc-esque lock on the process
1300*c54f35caSApple OSS Distributions 	 * iff the process is dead and gone. In this case, we rely on the
1301*c54f35caSApple OSS Distributions 	 * provider lock as a point of mutual exclusion to prevent other
1302*c54f35caSApple OSS Distributions 	 * DTrace consumers from disabling this probe.
1303*c54f35caSApple OSS Distributions 	 */
1304*c54f35caSApple OSS Distributions 	p = sprlock(probe->ftp_pid);
1305*c54f35caSApple OSS Distributions 
1306*c54f35caSApple OSS Distributions 	lck_mtx_lock(&provider->ftp_mtx);
1307*c54f35caSApple OSS Distributions 
1308*c54f35caSApple OSS Distributions 	/*
1309*c54f35caSApple OSS Distributions 	 * Disable all the associated tracepoints (for fully enabled probes).
1310*c54f35caSApple OSS Distributions 	 */
1311*c54f35caSApple OSS Distributions 	if (probe->ftp_enabled) {
1312*c54f35caSApple OSS Distributions 		for (i = 0; i < (int)probe->ftp_ntps; i++) {
1313*c54f35caSApple OSS Distributions 			fasttrap_tracepoint_disable(p, probe, i);
1314*c54f35caSApple OSS Distributions 		}
1315*c54f35caSApple OSS Distributions 	}
1316*c54f35caSApple OSS Distributions 
1317*c54f35caSApple OSS Distributions 	ASSERT(provider->ftp_rcount > 0);
1318*c54f35caSApple OSS Distributions 	provider->ftp_rcount--;
1319*c54f35caSApple OSS Distributions 
1320*c54f35caSApple OSS Distributions 	if (p != NULL) {
1321*c54f35caSApple OSS Distributions 		/*
1322*c54f35caSApple OSS Distributions 		 * Even though we may not be able to remove it entirely, we
1323*c54f35caSApple OSS Distributions 		 * mark this retired provider to get a chance to remove some
1324*c54f35caSApple OSS Distributions 		 * of the associated probes.
1325*c54f35caSApple OSS Distributions 		 */
1326*c54f35caSApple OSS Distributions 		if (provider->ftp_retired && !provider->ftp_marked)
1327*c54f35caSApple OSS Distributions 			whack = provider->ftp_marked = 1;
1328*c54f35caSApple OSS Distributions 		lck_mtx_unlock(&provider->ftp_mtx);
1329*c54f35caSApple OSS Distributions 
1330*c54f35caSApple OSS Distributions 		sprunlock(p);
1331*c54f35caSApple OSS Distributions 	} else {
1332*c54f35caSApple OSS Distributions 		/*
1333*c54f35caSApple OSS Distributions 		 * If the process is dead, we're just waiting for the
1334*c54f35caSApple OSS Distributions 		 * last probe to be disabled to be able to free it.
1335*c54f35caSApple OSS Distributions 		 */
1336*c54f35caSApple OSS Distributions 		if (provider->ftp_rcount == 0 && !provider->ftp_marked)
1337*c54f35caSApple OSS Distributions 			whack = provider->ftp_marked = 1;
1338*c54f35caSApple OSS Distributions 		lck_mtx_unlock(&provider->ftp_mtx);
1339*c54f35caSApple OSS Distributions 	}
1340*c54f35caSApple OSS Distributions 
1341*c54f35caSApple OSS Distributions 	if (whack) {
1342*c54f35caSApple OSS Distributions 		fasttrap_pid_cleanup(FASTTRAP_CLEANUP_PROVIDER);
1343*c54f35caSApple OSS Distributions 	}
1344*c54f35caSApple OSS Distributions 
1345*c54f35caSApple OSS Distributions 	if (!probe->ftp_enabled)
1346*c54f35caSApple OSS Distributions 		return;
1347*c54f35caSApple OSS Distributions 
1348*c54f35caSApple OSS Distributions 	probe->ftp_enabled = 0;
1349*c54f35caSApple OSS Distributions 
1350*c54f35caSApple OSS Distributions 	// ASSERT(MUTEX_HELD(&cpu_lock));
1351*c54f35caSApple OSS Distributions 	fasttrap_disable_callbacks();
1352*c54f35caSApple OSS Distributions }
1353*c54f35caSApple OSS Distributions 
1354*c54f35caSApple OSS Distributions /*ARGSUSED*/
1355*c54f35caSApple OSS Distributions static void
fasttrap_pid_getargdesc(void * arg,dtrace_id_t id,void * parg,dtrace_argdesc_t * desc)1356*c54f35caSApple OSS Distributions fasttrap_pid_getargdesc(void *arg, dtrace_id_t id, void *parg,
1357*c54f35caSApple OSS Distributions     dtrace_argdesc_t *desc)
1358*c54f35caSApple OSS Distributions {
1359*c54f35caSApple OSS Distributions #pragma unused(arg, id)
1360*c54f35caSApple OSS Distributions 	fasttrap_probe_t *probe = parg;
1361*c54f35caSApple OSS Distributions 	char *str;
1362*c54f35caSApple OSS Distributions 	int i, ndx;
1363*c54f35caSApple OSS Distributions 
1364*c54f35caSApple OSS Distributions 	desc->dtargd_native[0] = '\0';
1365*c54f35caSApple OSS Distributions 	desc->dtargd_xlate[0] = '\0';
1366*c54f35caSApple OSS Distributions 
1367*c54f35caSApple OSS Distributions 	if (probe->ftp_prov->ftp_retired != 0 ||
1368*c54f35caSApple OSS Distributions 		desc->dtargd_ndx < 0 ||
1369*c54f35caSApple OSS Distributions 	    desc->dtargd_ndx >= probe->ftp_nargs) {
1370*c54f35caSApple OSS Distributions 		desc->dtargd_ndx = DTRACE_ARGNONE;
1371*c54f35caSApple OSS Distributions 		return;
1372*c54f35caSApple OSS Distributions 	}
1373*c54f35caSApple OSS Distributions 
1374*c54f35caSApple OSS Distributions 	ndx = (probe->ftp_argmap != NULL) ?
1375*c54f35caSApple OSS Distributions 		probe->ftp_argmap[desc->dtargd_ndx] : desc->dtargd_ndx;
1376*c54f35caSApple OSS Distributions 
1377*c54f35caSApple OSS Distributions 	if (probe->ftp_ntypes == NULL)
1378*c54f35caSApple OSS Distributions 		return;
1379*c54f35caSApple OSS Distributions 
1380*c54f35caSApple OSS Distributions 	str = probe->ftp_ntypes;
1381*c54f35caSApple OSS Distributions 	for (i = 0; i < ndx; i++) {
1382*c54f35caSApple OSS Distributions 		str += strlen(str) + 1;
1383*c54f35caSApple OSS Distributions 	}
1384*c54f35caSApple OSS Distributions 
1385*c54f35caSApple OSS Distributions 	(void) strlcpy(desc->dtargd_native, str, sizeof(desc->dtargd_native));
1386*c54f35caSApple OSS Distributions 
1387*c54f35caSApple OSS Distributions 	if (probe->ftp_xtypes == NULL)
1388*c54f35caSApple OSS Distributions 		return;
1389*c54f35caSApple OSS Distributions 
1390*c54f35caSApple OSS Distributions 	str = probe->ftp_xtypes;
1391*c54f35caSApple OSS Distributions 	for (i = 0; i < desc->dtargd_ndx; i++) {
1392*c54f35caSApple OSS Distributions 		str += strlen(str) + 1;
1393*c54f35caSApple OSS Distributions 	}
1394*c54f35caSApple OSS Distributions 
1395*c54f35caSApple OSS Distributions 	(void) strlcpy(desc->dtargd_xlate, str, sizeof(desc->dtargd_xlate));
1396*c54f35caSApple OSS Distributions }
1397*c54f35caSApple OSS Distributions 
1398*c54f35caSApple OSS Distributions /*ARGSUSED*/
1399*c54f35caSApple OSS Distributions static void
fasttrap_pid_destroy(void * arg,dtrace_id_t id,void * parg)1400*c54f35caSApple OSS Distributions fasttrap_pid_destroy(void *arg, dtrace_id_t id, void *parg)
1401*c54f35caSApple OSS Distributions {
1402*c54f35caSApple OSS Distributions #pragma unused(arg, id)
1403*c54f35caSApple OSS Distributions 	fasttrap_probe_t *probe = parg;
1404*c54f35caSApple OSS Distributions 	unsigned int i;
1405*c54f35caSApple OSS Distributions 
1406*c54f35caSApple OSS Distributions 	ASSERT(probe != NULL);
1407*c54f35caSApple OSS Distributions 	ASSERT(!probe->ftp_enabled);
1408*c54f35caSApple OSS Distributions 	ASSERT(fasttrap_total >= probe->ftp_ntps);
1409*c54f35caSApple OSS Distributions 
1410*c54f35caSApple OSS Distributions 	os_atomic_sub(&fasttrap_total, probe->ftp_ntps, relaxed);
1411*c54f35caSApple OSS Distributions 	os_atomic_sub(&fasttrap_retired, probe->ftp_ntps, relaxed);
1412*c54f35caSApple OSS Distributions 
1413*c54f35caSApple OSS Distributions 	if (probe->ftp_gen + 1 >= fasttrap_mod_gen)
1414*c54f35caSApple OSS Distributions 		fasttrap_mod_barrier(probe->ftp_gen);
1415*c54f35caSApple OSS Distributions 
1416*c54f35caSApple OSS Distributions 	for (i = 0; i < probe->ftp_ntps; i++) {
1417*c54f35caSApple OSS Distributions 		zfree(fasttrap_tracepoint_t_zone, probe->ftp_tps[i].fit_tp);
1418*c54f35caSApple OSS Distributions 	}
1419*c54f35caSApple OSS Distributions 
1420*c54f35caSApple OSS Distributions 	if (probe->ftp_ntps < FASTTRAP_PROBE_T_ZONE_MAX_TRACEPOINTS) {
1421*c54f35caSApple OSS Distributions 		zfree(fasttrap_probe_t_zones[probe->ftp_ntps], probe);
1422*c54f35caSApple OSS Distributions 	} else {
1423*c54f35caSApple OSS Distributions 		size_t size = offsetof(fasttrap_probe_t, ftp_tps[probe->ftp_ntps]);
1424*c54f35caSApple OSS Distributions 		kmem_free(probe, size);
1425*c54f35caSApple OSS Distributions 	}
1426*c54f35caSApple OSS Distributions }
1427*c54f35caSApple OSS Distributions 
1428*c54f35caSApple OSS Distributions 
1429*c54f35caSApple OSS Distributions static const dtrace_pattr_t pid_attr = {
1430*c54f35caSApple OSS Distributions { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
1431*c54f35caSApple OSS Distributions { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
1432*c54f35caSApple OSS Distributions { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
1433*c54f35caSApple OSS Distributions { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
1434*c54f35caSApple OSS Distributions { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
1435*c54f35caSApple OSS Distributions };
1436*c54f35caSApple OSS Distributions 
1437*c54f35caSApple OSS Distributions static dtrace_pops_t pid_pops = {
1438*c54f35caSApple OSS Distributions 	.dtps_provide =		fasttrap_pid_provide,
1439*c54f35caSApple OSS Distributions 	.dtps_provide_module =	NULL,
1440*c54f35caSApple OSS Distributions 	.dtps_enable =		fasttrap_pid_enable,
1441*c54f35caSApple OSS Distributions 	.dtps_disable =		fasttrap_pid_disable,
1442*c54f35caSApple OSS Distributions 	.dtps_suspend =		NULL,
1443*c54f35caSApple OSS Distributions 	.dtps_resume =		NULL,
1444*c54f35caSApple OSS Distributions 	.dtps_getargdesc =	fasttrap_pid_getargdesc,
1445*c54f35caSApple OSS Distributions 	.dtps_getargval =	fasttrap_pid_getarg,
1446*c54f35caSApple OSS Distributions 	.dtps_usermode =	NULL,
1447*c54f35caSApple OSS Distributions 	.dtps_destroy =		fasttrap_pid_destroy
1448*c54f35caSApple OSS Distributions };
1449*c54f35caSApple OSS Distributions 
1450*c54f35caSApple OSS Distributions static dtrace_pops_t usdt_pops = {
1451*c54f35caSApple OSS Distributions 	.dtps_provide =		fasttrap_pid_provide,
1452*c54f35caSApple OSS Distributions 	.dtps_provide_module =	NULL,
1453*c54f35caSApple OSS Distributions 	.dtps_enable =		fasttrap_pid_enable,
1454*c54f35caSApple OSS Distributions 	.dtps_disable =		fasttrap_pid_disable,
1455*c54f35caSApple OSS Distributions 	.dtps_suspend =		NULL,
1456*c54f35caSApple OSS Distributions 	.dtps_resume =		NULL,
1457*c54f35caSApple OSS Distributions 	.dtps_getargdesc =	fasttrap_pid_getargdesc,
1458*c54f35caSApple OSS Distributions 	.dtps_getargval =	fasttrap_usdt_getarg,
1459*c54f35caSApple OSS Distributions 	.dtps_usermode =	NULL,
1460*c54f35caSApple OSS Distributions 	.dtps_destroy =		fasttrap_pid_destroy
1461*c54f35caSApple OSS Distributions };
1462*c54f35caSApple OSS Distributions 
1463*c54f35caSApple OSS Distributions static fasttrap_proc_t *
fasttrap_proc_lookup(pid_t pid)1464*c54f35caSApple OSS Distributions fasttrap_proc_lookup(pid_t pid)
1465*c54f35caSApple OSS Distributions {
1466*c54f35caSApple OSS Distributions 	fasttrap_bucket_t *bucket;
1467*c54f35caSApple OSS Distributions 	fasttrap_proc_t *fprc, *new_fprc;
1468*c54f35caSApple OSS Distributions 
1469*c54f35caSApple OSS Distributions 	bucket = &fasttrap_procs.fth_table[FASTTRAP_PROCS_INDEX(pid)];
1470*c54f35caSApple OSS Distributions 	lck_mtx_lock(&bucket->ftb_mtx);
1471*c54f35caSApple OSS Distributions 
1472*c54f35caSApple OSS Distributions 	for (fprc = bucket->ftb_data; fprc != NULL; fprc = fprc->ftpc_next) {
1473*c54f35caSApple OSS Distributions 		if (fprc->ftpc_pid == pid && fprc->ftpc_acount != 0) {
1474*c54f35caSApple OSS Distributions 			lck_mtx_lock(&fprc->ftpc_mtx);
1475*c54f35caSApple OSS Distributions 			lck_mtx_unlock(&bucket->ftb_mtx);
1476*c54f35caSApple OSS Distributions 			fprc->ftpc_rcount++;
1477*c54f35caSApple OSS Distributions 			os_atomic_inc(&fprc->ftpc_acount, relaxed);
1478*c54f35caSApple OSS Distributions 			ASSERT(fprc->ftpc_acount <= fprc->ftpc_rcount);
1479*c54f35caSApple OSS Distributions 			lck_mtx_unlock(&fprc->ftpc_mtx);
1480*c54f35caSApple OSS Distributions 
1481*c54f35caSApple OSS Distributions 			return (fprc);
1482*c54f35caSApple OSS Distributions 		}
1483*c54f35caSApple OSS Distributions 	}
1484*c54f35caSApple OSS Distributions 
1485*c54f35caSApple OSS Distributions 	/*
1486*c54f35caSApple OSS Distributions 	 * Drop the bucket lock so we don't try to perform a sleeping
1487*c54f35caSApple OSS Distributions 	 * allocation under it.
1488*c54f35caSApple OSS Distributions 	 */
1489*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&bucket->ftb_mtx);
1490*c54f35caSApple OSS Distributions 
1491*c54f35caSApple OSS Distributions 	new_fprc = kmem_zalloc(sizeof (fasttrap_proc_t), KM_SLEEP);
1492*c54f35caSApple OSS Distributions 	ASSERT(new_fprc != NULL);
1493*c54f35caSApple OSS Distributions 	new_fprc->ftpc_pid = pid;
1494*c54f35caSApple OSS Distributions 	new_fprc->ftpc_rcount = 1;
1495*c54f35caSApple OSS Distributions 	new_fprc->ftpc_acount = 1;
1496*c54f35caSApple OSS Distributions 
1497*c54f35caSApple OSS Distributions 	lck_mtx_lock(&bucket->ftb_mtx);
1498*c54f35caSApple OSS Distributions 
1499*c54f35caSApple OSS Distributions 	/*
1500*c54f35caSApple OSS Distributions 	 * Take another lap through the list to make sure a proc hasn't
1501*c54f35caSApple OSS Distributions 	 * been created for this pid while we weren't under the bucket lock.
1502*c54f35caSApple OSS Distributions 	 */
1503*c54f35caSApple OSS Distributions 	for (fprc = bucket->ftb_data; fprc != NULL; fprc = fprc->ftpc_next) {
1504*c54f35caSApple OSS Distributions 		if (fprc->ftpc_pid == pid && fprc->ftpc_acount != 0) {
1505*c54f35caSApple OSS Distributions 			lck_mtx_lock(&fprc->ftpc_mtx);
1506*c54f35caSApple OSS Distributions 			lck_mtx_unlock(&bucket->ftb_mtx);
1507*c54f35caSApple OSS Distributions 			fprc->ftpc_rcount++;
1508*c54f35caSApple OSS Distributions 			os_atomic_inc(&fprc->ftpc_acount, relaxed);
1509*c54f35caSApple OSS Distributions 			ASSERT(fprc->ftpc_acount <= fprc->ftpc_rcount);
1510*c54f35caSApple OSS Distributions 			lck_mtx_unlock(&fprc->ftpc_mtx);
1511*c54f35caSApple OSS Distributions 
1512*c54f35caSApple OSS Distributions 			kmem_free(new_fprc, sizeof (fasttrap_proc_t));
1513*c54f35caSApple OSS Distributions 
1514*c54f35caSApple OSS Distributions 			return (fprc);
1515*c54f35caSApple OSS Distributions 		}
1516*c54f35caSApple OSS Distributions 	}
1517*c54f35caSApple OSS Distributions 
1518*c54f35caSApple OSS Distributions 	/*
1519*c54f35caSApple OSS Distributions 	 * APPLE NOTE: We have to initialize all locks explicitly
1520*c54f35caSApple OSS Distributions 	 */
1521*c54f35caSApple OSS Distributions 	lck_mtx_init(&new_fprc->ftpc_mtx, &fasttrap_lck_grp, &fasttrap_lck_attr);
1522*c54f35caSApple OSS Distributions 
1523*c54f35caSApple OSS Distributions 	new_fprc->ftpc_next = bucket->ftb_data;
1524*c54f35caSApple OSS Distributions 	bucket->ftb_data = new_fprc;
1525*c54f35caSApple OSS Distributions 
1526*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&bucket->ftb_mtx);
1527*c54f35caSApple OSS Distributions 
1528*c54f35caSApple OSS Distributions 	return (new_fprc);
1529*c54f35caSApple OSS Distributions }
1530*c54f35caSApple OSS Distributions 
1531*c54f35caSApple OSS Distributions static void
fasttrap_proc_release(fasttrap_proc_t * proc)1532*c54f35caSApple OSS Distributions fasttrap_proc_release(fasttrap_proc_t *proc)
1533*c54f35caSApple OSS Distributions {
1534*c54f35caSApple OSS Distributions 	fasttrap_bucket_t *bucket;
1535*c54f35caSApple OSS Distributions 	fasttrap_proc_t *fprc, **fprcp;
1536*c54f35caSApple OSS Distributions 	pid_t pid = proc->ftpc_pid;
1537*c54f35caSApple OSS Distributions 
1538*c54f35caSApple OSS Distributions 	lck_mtx_lock(&proc->ftpc_mtx);
1539*c54f35caSApple OSS Distributions 
1540*c54f35caSApple OSS Distributions 	ASSERT(proc->ftpc_rcount != 0);
1541*c54f35caSApple OSS Distributions 	ASSERT(proc->ftpc_acount <= proc->ftpc_rcount);
1542*c54f35caSApple OSS Distributions 
1543*c54f35caSApple OSS Distributions 	if (--proc->ftpc_rcount != 0) {
1544*c54f35caSApple OSS Distributions 		lck_mtx_unlock(&proc->ftpc_mtx);
1545*c54f35caSApple OSS Distributions 		return;
1546*c54f35caSApple OSS Distributions 	}
1547*c54f35caSApple OSS Distributions 
1548*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&proc->ftpc_mtx);
1549*c54f35caSApple OSS Distributions 
1550*c54f35caSApple OSS Distributions 	/*
1551*c54f35caSApple OSS Distributions 	 * There should definitely be no live providers associated with this
1552*c54f35caSApple OSS Distributions 	 * process at this point.
1553*c54f35caSApple OSS Distributions 	 */
1554*c54f35caSApple OSS Distributions 	 ASSERT(proc->ftpc_acount == 0);
1555*c54f35caSApple OSS Distributions 
1556*c54f35caSApple OSS Distributions 	bucket = &fasttrap_procs.fth_table[FASTTRAP_PROCS_INDEX(pid)];
1557*c54f35caSApple OSS Distributions 	lck_mtx_lock(&bucket->ftb_mtx);
1558*c54f35caSApple OSS Distributions 
1559*c54f35caSApple OSS Distributions 	fprcp = (fasttrap_proc_t **)&bucket->ftb_data;
1560*c54f35caSApple OSS Distributions 	while ((fprc = *fprcp) != NULL) {
1561*c54f35caSApple OSS Distributions 		if (fprc == proc)
1562*c54f35caSApple OSS Distributions 			break;
1563*c54f35caSApple OSS Distributions 
1564*c54f35caSApple OSS Distributions 		fprcp = &fprc->ftpc_next;
1565*c54f35caSApple OSS Distributions 	}
1566*c54f35caSApple OSS Distributions 
1567*c54f35caSApple OSS Distributions 	/*
1568*c54f35caSApple OSS Distributions 	 * Something strange has happened if we can't find the proc.
1569*c54f35caSApple OSS Distributions 	 */
1570*c54f35caSApple OSS Distributions 	ASSERT(fprc != NULL);
1571*c54f35caSApple OSS Distributions 
1572*c54f35caSApple OSS Distributions 	*fprcp = fprc->ftpc_next;
1573*c54f35caSApple OSS Distributions 
1574*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&bucket->ftb_mtx);
1575*c54f35caSApple OSS Distributions 
1576*c54f35caSApple OSS Distributions 	/*
1577*c54f35caSApple OSS Distributions 	 * APPLE NOTE: explicit lock management. Not 100% certain we need this, the
1578*c54f35caSApple OSS Distributions 	 * memory is freed even without the destroy. Maybe accounting cleanup?
1579*c54f35caSApple OSS Distributions 	 */
1580*c54f35caSApple OSS Distributions 	lck_mtx_destroy(&fprc->ftpc_mtx, &fasttrap_lck_grp);
1581*c54f35caSApple OSS Distributions 
1582*c54f35caSApple OSS Distributions 	kmem_free(fprc, sizeof (fasttrap_proc_t));
1583*c54f35caSApple OSS Distributions }
1584*c54f35caSApple OSS Distributions 
1585*c54f35caSApple OSS Distributions /*
1586*c54f35caSApple OSS Distributions  * Lookup a fasttrap-managed provider based on its name and associated proc.
1587*c54f35caSApple OSS Distributions  * A reference to the proc must be held for the duration of the call.
1588*c54f35caSApple OSS Distributions  * If the pattr argument is non-NULL, this function instantiates the provider
1589*c54f35caSApple OSS Distributions  * if it doesn't exist otherwise it returns NULL. The provider is returned
1590*c54f35caSApple OSS Distributions  * with its lock held.
1591*c54f35caSApple OSS Distributions  */
1592*c54f35caSApple OSS Distributions static fasttrap_provider_t *
fasttrap_provider_lookup(proc_t * p,fasttrap_provider_type_t provider_type,const char * name,const dtrace_pattr_t * pattr)1593*c54f35caSApple OSS Distributions fasttrap_provider_lookup(proc_t *p, fasttrap_provider_type_t provider_type, const char *name,
1594*c54f35caSApple OSS Distributions     const dtrace_pattr_t *pattr)
1595*c54f35caSApple OSS Distributions {
1596*c54f35caSApple OSS Distributions 	pid_t pid = proc_getpid(p);
1597*c54f35caSApple OSS Distributions 	fasttrap_provider_t *fp, *new_fp = NULL;
1598*c54f35caSApple OSS Distributions 	fasttrap_bucket_t *bucket;
1599*c54f35caSApple OSS Distributions 	char provname[DTRACE_PROVNAMELEN];
1600*c54f35caSApple OSS Distributions 	cred_t *cred;
1601*c54f35caSApple OSS Distributions 
1602*c54f35caSApple OSS Distributions 	ASSERT(strlen(name) < sizeof (fp->ftp_name));
1603*c54f35caSApple OSS Distributions 	ASSERT(pattr != NULL);
1604*c54f35caSApple OSS Distributions 
1605*c54f35caSApple OSS Distributions 	bucket = &fasttrap_provs.fth_table[FASTTRAP_PROVS_INDEX(pid, name)];
1606*c54f35caSApple OSS Distributions 	lck_mtx_lock(&bucket->ftb_mtx);
1607*c54f35caSApple OSS Distributions 
1608*c54f35caSApple OSS Distributions 	/*
1609*c54f35caSApple OSS Distributions 	 * Take a lap through the list and return the match if we find it.
1610*c54f35caSApple OSS Distributions 	 */
1611*c54f35caSApple OSS Distributions 	for (fp = bucket->ftb_data; fp != NULL; fp = fp->ftp_next) {
1612*c54f35caSApple OSS Distributions 		if (fp->ftp_pid == pid &&
1613*c54f35caSApple OSS Distributions 		    fp->ftp_provider_type == provider_type &&
1614*c54f35caSApple OSS Distributions 		    strncmp(fp->ftp_name, name, sizeof(fp->ftp_name)) == 0 &&
1615*c54f35caSApple OSS Distributions 		    !fp->ftp_retired) {
1616*c54f35caSApple OSS Distributions 			lck_mtx_lock(&fp->ftp_mtx);
1617*c54f35caSApple OSS Distributions 			lck_mtx_unlock(&bucket->ftb_mtx);
1618*c54f35caSApple OSS Distributions 			return (fp);
1619*c54f35caSApple OSS Distributions 		}
1620*c54f35caSApple OSS Distributions 	}
1621*c54f35caSApple OSS Distributions 
1622*c54f35caSApple OSS Distributions 	/*
1623*c54f35caSApple OSS Distributions 	 * Drop the bucket lock so we don't try to perform a sleeping
1624*c54f35caSApple OSS Distributions 	 * allocation under it.
1625*c54f35caSApple OSS Distributions 	 */
1626*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&bucket->ftb_mtx);
1627*c54f35caSApple OSS Distributions 
1628*c54f35caSApple OSS Distributions 	/*
1629*c54f35caSApple OSS Distributions 	 * Make sure the process isn't a child
1630*c54f35caSApple OSS Distributions 	 * isn't a zombie (but may be in fork).
1631*c54f35caSApple OSS Distributions 	 */
1632*c54f35caSApple OSS Distributions 	proc_lock(p);
1633*c54f35caSApple OSS Distributions 	if (p->p_lflag & P_LEXIT) {
1634*c54f35caSApple OSS Distributions 		proc_unlock(p);
1635*c54f35caSApple OSS Distributions 		return (NULL);
1636*c54f35caSApple OSS Distributions 	}
1637*c54f35caSApple OSS Distributions 
1638*c54f35caSApple OSS Distributions 	/*
1639*c54f35caSApple OSS Distributions 	 * Increment p_dtrace_probes so that the process knows to inform us
1640*c54f35caSApple OSS Distributions 	 * when it exits or execs. fasttrap_provider_free() decrements this
1641*c54f35caSApple OSS Distributions 	 * when we're done with this provider.
1642*c54f35caSApple OSS Distributions 	 */
1643*c54f35caSApple OSS Distributions 	p->p_dtrace_probes++;
1644*c54f35caSApple OSS Distributions 
1645*c54f35caSApple OSS Distributions 	/*
1646*c54f35caSApple OSS Distributions 	 * Grab the credentials for this process so we have
1647*c54f35caSApple OSS Distributions 	 * something to pass to dtrace_register().
1648*c54f35caSApple OSS Distributions 	 * APPLE NOTE:  We have no equivalent to crhold,
1649*c54f35caSApple OSS Distributions 	 * even though there is a cr_ref filed in ucred.
1650*c54f35caSApple OSS Distributions 	 */
1651*c54f35caSApple OSS Distributions 	cred = kauth_cred_proc_ref(p);
1652*c54f35caSApple OSS Distributions 	proc_unlock(p);
1653*c54f35caSApple OSS Distributions 
1654*c54f35caSApple OSS Distributions 	new_fp = kmem_zalloc(sizeof (fasttrap_provider_t), KM_SLEEP);
1655*c54f35caSApple OSS Distributions 	ASSERT(new_fp != NULL);
1656*c54f35caSApple OSS Distributions 	new_fp->ftp_pid = proc_getpid(p);
1657*c54f35caSApple OSS Distributions 	new_fp->ftp_proc = fasttrap_proc_lookup(pid);
1658*c54f35caSApple OSS Distributions 	new_fp->ftp_provider_type = provider_type;
1659*c54f35caSApple OSS Distributions 
1660*c54f35caSApple OSS Distributions 	/*
1661*c54f35caSApple OSS Distributions 	 * APPLE NOTE:  locks require explicit init
1662*c54f35caSApple OSS Distributions 	 */
1663*c54f35caSApple OSS Distributions 	lck_mtx_init(&new_fp->ftp_mtx, &fasttrap_lck_grp, &fasttrap_lck_attr);
1664*c54f35caSApple OSS Distributions 	lck_mtx_init(&new_fp->ftp_cmtx, &fasttrap_lck_grp, &fasttrap_lck_attr);
1665*c54f35caSApple OSS Distributions 
1666*c54f35caSApple OSS Distributions 	ASSERT(new_fp->ftp_proc != NULL);
1667*c54f35caSApple OSS Distributions 
1668*c54f35caSApple OSS Distributions 	lck_mtx_lock(&bucket->ftb_mtx);
1669*c54f35caSApple OSS Distributions 
1670*c54f35caSApple OSS Distributions 	/*
1671*c54f35caSApple OSS Distributions 	 * Take another lap through the list to make sure a provider hasn't
1672*c54f35caSApple OSS Distributions 	 * been created for this pid while we weren't under the bucket lock.
1673*c54f35caSApple OSS Distributions 	 */
1674*c54f35caSApple OSS Distributions 	for (fp = bucket->ftb_data; fp != NULL; fp = fp->ftp_next) {
1675*c54f35caSApple OSS Distributions 		if (fp->ftp_pid == pid && strncmp(fp->ftp_name, name, sizeof(fp->ftp_name)) == 0 &&
1676*c54f35caSApple OSS Distributions 		    !fp->ftp_retired) {
1677*c54f35caSApple OSS Distributions 			lck_mtx_lock(&fp->ftp_mtx);
1678*c54f35caSApple OSS Distributions 			lck_mtx_unlock(&bucket->ftb_mtx);
1679*c54f35caSApple OSS Distributions 			fasttrap_provider_free(new_fp);
1680*c54f35caSApple OSS Distributions 			kauth_cred_unref(&cred);
1681*c54f35caSApple OSS Distributions 			return (fp);
1682*c54f35caSApple OSS Distributions 		}
1683*c54f35caSApple OSS Distributions 	}
1684*c54f35caSApple OSS Distributions 
1685*c54f35caSApple OSS Distributions 	(void) strlcpy(new_fp->ftp_name, name, sizeof(new_fp->ftp_name));
1686*c54f35caSApple OSS Distributions 
1687*c54f35caSApple OSS Distributions 	/*
1688*c54f35caSApple OSS Distributions 	 * Fail and return NULL if either the provider name is too long
1689*c54f35caSApple OSS Distributions 	 * or we fail to register this new provider with the DTrace
1690*c54f35caSApple OSS Distributions 	 * framework. Note that this is the only place we ever construct
1691*c54f35caSApple OSS Distributions 	 * the full provider name -- we keep it in pieces in the provider
1692*c54f35caSApple OSS Distributions 	 * structure.
1693*c54f35caSApple OSS Distributions 	 */
1694*c54f35caSApple OSS Distributions 	if (snprintf(provname, sizeof (provname), "%s%u", name, (uint_t)pid) >=
1695*c54f35caSApple OSS Distributions 	    (int)sizeof (provname) ||
1696*c54f35caSApple OSS Distributions 	    dtrace_register(provname, pattr,
1697*c54f35caSApple OSS Distributions 	    DTRACE_PRIV_PROC | DTRACE_PRIV_OWNER | DTRACE_PRIV_ZONEOWNER, cred,
1698*c54f35caSApple OSS Distributions 	    pattr == &pid_attr ? &pid_pops : &usdt_pops, new_fp,
1699*c54f35caSApple OSS Distributions 	    &new_fp->ftp_provid) != 0) {
1700*c54f35caSApple OSS Distributions 		lck_mtx_unlock(&bucket->ftb_mtx);
1701*c54f35caSApple OSS Distributions 		fasttrap_provider_free(new_fp);
1702*c54f35caSApple OSS Distributions 		kauth_cred_unref(&cred);
1703*c54f35caSApple OSS Distributions 		return (NULL);
1704*c54f35caSApple OSS Distributions 	}
1705*c54f35caSApple OSS Distributions 
1706*c54f35caSApple OSS Distributions 	new_fp->ftp_next = bucket->ftb_data;
1707*c54f35caSApple OSS Distributions 	bucket->ftb_data = new_fp;
1708*c54f35caSApple OSS Distributions 
1709*c54f35caSApple OSS Distributions 	lck_mtx_lock(&new_fp->ftp_mtx);
1710*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&bucket->ftb_mtx);
1711*c54f35caSApple OSS Distributions 
1712*c54f35caSApple OSS Distributions 	kauth_cred_unref(&cred);
1713*c54f35caSApple OSS Distributions 
1714*c54f35caSApple OSS Distributions 	return (new_fp);
1715*c54f35caSApple OSS Distributions }
1716*c54f35caSApple OSS Distributions 
1717*c54f35caSApple OSS Distributions static void
fasttrap_provider_free(fasttrap_provider_t * provider)1718*c54f35caSApple OSS Distributions fasttrap_provider_free(fasttrap_provider_t *provider)
1719*c54f35caSApple OSS Distributions {
1720*c54f35caSApple OSS Distributions 	pid_t pid = provider->ftp_pid;
1721*c54f35caSApple OSS Distributions 	proc_t *p;
1722*c54f35caSApple OSS Distributions 
1723*c54f35caSApple OSS Distributions 	/*
1724*c54f35caSApple OSS Distributions 	 * There need to be no associated enabled probes, no consumers
1725*c54f35caSApple OSS Distributions 	 * creating probes, and no meta providers referencing this provider.
1726*c54f35caSApple OSS Distributions 	 */
1727*c54f35caSApple OSS Distributions 	ASSERT(provider->ftp_rcount == 0);
1728*c54f35caSApple OSS Distributions 	ASSERT(provider->ftp_ccount == 0);
1729*c54f35caSApple OSS Distributions 	ASSERT(provider->ftp_mcount == 0);
1730*c54f35caSApple OSS Distributions 
1731*c54f35caSApple OSS Distributions 	/*
1732*c54f35caSApple OSS Distributions 	 * If this provider hasn't been retired, we need to explicitly drop the
1733*c54f35caSApple OSS Distributions 	 * count of active providers on the associated process structure.
1734*c54f35caSApple OSS Distributions 	 */
1735*c54f35caSApple OSS Distributions 	if (!provider->ftp_retired) {
1736*c54f35caSApple OSS Distributions 		os_atomic_dec(&provider->ftp_proc->ftpc_acount, relaxed);
1737*c54f35caSApple OSS Distributions 		ASSERT(provider->ftp_proc->ftpc_acount <
1738*c54f35caSApple OSS Distributions 		provider->ftp_proc->ftpc_rcount);
1739*c54f35caSApple OSS Distributions 	}
1740*c54f35caSApple OSS Distributions 
1741*c54f35caSApple OSS Distributions 	fasttrap_proc_release(provider->ftp_proc);
1742*c54f35caSApple OSS Distributions 
1743*c54f35caSApple OSS Distributions 	/*
1744*c54f35caSApple OSS Distributions 	 * APPLE NOTE:  explicit lock management. Not 100% certain we need this, the
1745*c54f35caSApple OSS Distributions 	 * memory is freed even without the destroy. Maybe accounting cleanup?
1746*c54f35caSApple OSS Distributions 	 */
1747*c54f35caSApple OSS Distributions 	lck_mtx_destroy(&provider->ftp_mtx, &fasttrap_lck_grp);
1748*c54f35caSApple OSS Distributions 	lck_mtx_destroy(&provider->ftp_cmtx, &fasttrap_lck_grp);
1749*c54f35caSApple OSS Distributions 
1750*c54f35caSApple OSS Distributions 	kmem_free(provider, sizeof (fasttrap_provider_t));
1751*c54f35caSApple OSS Distributions 
1752*c54f35caSApple OSS Distributions 	/*
1753*c54f35caSApple OSS Distributions 	 * Decrement p_dtrace_probes on the process whose provider we're
1754*c54f35caSApple OSS Distributions 	 * freeing. We don't have to worry about clobbering somone else's
1755*c54f35caSApple OSS Distributions 	 * modifications to it because we have locked the bucket that
1756*c54f35caSApple OSS Distributions 	 * corresponds to this process's hash chain in the provider hash
1757*c54f35caSApple OSS Distributions 	 * table. Don't sweat it if we can't find the process.
1758*c54f35caSApple OSS Distributions 	 */
1759*c54f35caSApple OSS Distributions 	if ((p = proc_find(pid)) == NULL) {
1760*c54f35caSApple OSS Distributions 		return;
1761*c54f35caSApple OSS Distributions 	}
1762*c54f35caSApple OSS Distributions 
1763*c54f35caSApple OSS Distributions 	proc_lock(p);
1764*c54f35caSApple OSS Distributions 	p->p_dtrace_probes--;
1765*c54f35caSApple OSS Distributions 	proc_unlock(p);
1766*c54f35caSApple OSS Distributions 
1767*c54f35caSApple OSS Distributions 	proc_rele(p);
1768*c54f35caSApple OSS Distributions }
1769*c54f35caSApple OSS Distributions 
1770*c54f35caSApple OSS Distributions static void
fasttrap_provider_retire(proc_t * p,const char * name,int mprov)1771*c54f35caSApple OSS Distributions fasttrap_provider_retire(proc_t *p, const char *name, int mprov)
1772*c54f35caSApple OSS Distributions {
1773*c54f35caSApple OSS Distributions 	fasttrap_provider_t *fp;
1774*c54f35caSApple OSS Distributions 	fasttrap_bucket_t *bucket;
1775*c54f35caSApple OSS Distributions 	dtrace_provider_id_t provid;
1776*c54f35caSApple OSS Distributions 	ASSERT(strlen(name) < sizeof (fp->ftp_name));
1777*c54f35caSApple OSS Distributions 
1778*c54f35caSApple OSS Distributions 	bucket = &fasttrap_provs.fth_table[FASTTRAP_PROVS_INDEX(proc_getpid(p), name)];
1779*c54f35caSApple OSS Distributions 	lck_mtx_lock(&bucket->ftb_mtx);
1780*c54f35caSApple OSS Distributions 
1781*c54f35caSApple OSS Distributions 	for (fp = bucket->ftb_data; fp != NULL; fp = fp->ftp_next) {
1782*c54f35caSApple OSS Distributions 		if (fp->ftp_pid == proc_getpid(p) && strncmp(fp->ftp_name, name, sizeof(fp->ftp_name)) == 0 &&
1783*c54f35caSApple OSS Distributions 		    !fp->ftp_retired)
1784*c54f35caSApple OSS Distributions 			break;
1785*c54f35caSApple OSS Distributions 	}
1786*c54f35caSApple OSS Distributions 
1787*c54f35caSApple OSS Distributions 	if (fp == NULL) {
1788*c54f35caSApple OSS Distributions 		lck_mtx_unlock(&bucket->ftb_mtx);
1789*c54f35caSApple OSS Distributions 		return;
1790*c54f35caSApple OSS Distributions 	}
1791*c54f35caSApple OSS Distributions 
1792*c54f35caSApple OSS Distributions 	lck_mtx_lock(&fp->ftp_mtx);
1793*c54f35caSApple OSS Distributions 	ASSERT(!mprov || fp->ftp_mcount > 0);
1794*c54f35caSApple OSS Distributions 	if (mprov && --fp->ftp_mcount != 0)  {
1795*c54f35caSApple OSS Distributions 		lck_mtx_unlock(&fp->ftp_mtx);
1796*c54f35caSApple OSS Distributions 		lck_mtx_unlock(&bucket->ftb_mtx);
1797*c54f35caSApple OSS Distributions 		return;
1798*c54f35caSApple OSS Distributions 	}
1799*c54f35caSApple OSS Distributions 
1800*c54f35caSApple OSS Distributions 	/*
1801*c54f35caSApple OSS Distributions 	 * Mark the provider to be removed in our post-processing step, mark it
1802*c54f35caSApple OSS Distributions 	 * retired, and drop the active count on its proc. Marking it indicates
1803*c54f35caSApple OSS Distributions 	 * that we should try to remove it; setting the retired flag indicates
1804*c54f35caSApple OSS Distributions 	 * that we're done with this provider; dropping the active the proc
1805*c54f35caSApple OSS Distributions 	 * releases our hold, and when this reaches zero (as it will during
1806*c54f35caSApple OSS Distributions 	 * exit or exec) the proc and associated providers become defunct.
1807*c54f35caSApple OSS Distributions 	 *
1808*c54f35caSApple OSS Distributions 	 * We obviously need to take the bucket lock before the provider lock
1809*c54f35caSApple OSS Distributions 	 * to perform the lookup, but we need to drop the provider lock
1810*c54f35caSApple OSS Distributions 	 * before calling into the DTrace framework since we acquire the
1811*c54f35caSApple OSS Distributions 	 * provider lock in callbacks invoked from the DTrace framework. The
1812*c54f35caSApple OSS Distributions 	 * bucket lock therefore protects the integrity of the provider hash
1813*c54f35caSApple OSS Distributions 	 * table.
1814*c54f35caSApple OSS Distributions 	 */
1815*c54f35caSApple OSS Distributions 	os_atomic_dec(&fp->ftp_proc->ftpc_acount, relaxed);
1816*c54f35caSApple OSS Distributions 	ASSERT(fp->ftp_proc->ftpc_acount < fp->ftp_proc->ftpc_rcount);
1817*c54f35caSApple OSS Distributions 
1818*c54f35caSApple OSS Distributions 	/*
1819*c54f35caSApple OSS Distributions 	 * Add this provider probes to the retired count and
1820*c54f35caSApple OSS Distributions 	 * make sure we don't add them twice
1821*c54f35caSApple OSS Distributions 	 */
1822*c54f35caSApple OSS Distributions 	os_atomic_add(&fasttrap_retired, fp->ftp_pcount, relaxed);
1823*c54f35caSApple OSS Distributions 	fp->ftp_pcount = 0;
1824*c54f35caSApple OSS Distributions 
1825*c54f35caSApple OSS Distributions 	fp->ftp_retired = 1;
1826*c54f35caSApple OSS Distributions 	fp->ftp_marked = 1;
1827*c54f35caSApple OSS Distributions 	provid = fp->ftp_provid;
1828*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&fp->ftp_mtx);
1829*c54f35caSApple OSS Distributions 
1830*c54f35caSApple OSS Distributions 	/*
1831*c54f35caSApple OSS Distributions 	 * We don't have to worry about invalidating the same provider twice
1832*c54f35caSApple OSS Distributions 	 * since fasttrap_provider_lookup() will ignore providers that have
1833*c54f35caSApple OSS Distributions 	 * been marked as retired.
1834*c54f35caSApple OSS Distributions 	 */
1835*c54f35caSApple OSS Distributions 	dtrace_invalidate(provid);
1836*c54f35caSApple OSS Distributions 
1837*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&bucket->ftb_mtx);
1838*c54f35caSApple OSS Distributions 
1839*c54f35caSApple OSS Distributions 	fasttrap_pid_cleanup(FASTTRAP_CLEANUP_PROVIDER);
1840*c54f35caSApple OSS Distributions }
1841*c54f35caSApple OSS Distributions 
1842*c54f35caSApple OSS Distributions static int
fasttrap_uint32_cmp(const void * ap,const void * bp)1843*c54f35caSApple OSS Distributions fasttrap_uint32_cmp(const void *ap, const void *bp)
1844*c54f35caSApple OSS Distributions {
1845*c54f35caSApple OSS Distributions 	return (*(const uint32_t *)ap - *(const uint32_t *)bp);
1846*c54f35caSApple OSS Distributions }
1847*c54f35caSApple OSS Distributions 
1848*c54f35caSApple OSS Distributions static int
fasttrap_uint64_cmp(const void * ap,const void * bp)1849*c54f35caSApple OSS Distributions fasttrap_uint64_cmp(const void *ap, const void *bp)
1850*c54f35caSApple OSS Distributions {
1851*c54f35caSApple OSS Distributions 	return (*(const uint64_t *)ap - *(const uint64_t *)bp);
1852*c54f35caSApple OSS Distributions }
1853*c54f35caSApple OSS Distributions 
1854*c54f35caSApple OSS Distributions static int
fasttrap_add_probe(fasttrap_probe_spec_t * pdata)1855*c54f35caSApple OSS Distributions fasttrap_add_probe(fasttrap_probe_spec_t *pdata)
1856*c54f35caSApple OSS Distributions {
1857*c54f35caSApple OSS Distributions 	proc_t *p;
1858*c54f35caSApple OSS Distributions 	fasttrap_provider_t *provider;
1859*c54f35caSApple OSS Distributions 	fasttrap_probe_t *pp;
1860*c54f35caSApple OSS Distributions 	fasttrap_tracepoint_t *tp;
1861*c54f35caSApple OSS Distributions 	const char *name;
1862*c54f35caSApple OSS Distributions 	unsigned int i, aframes, whack;
1863*c54f35caSApple OSS Distributions 
1864*c54f35caSApple OSS Distributions 	/*
1865*c54f35caSApple OSS Distributions 	 * There needs to be at least one desired trace point.
1866*c54f35caSApple OSS Distributions 	 */
1867*c54f35caSApple OSS Distributions 	 if (pdata->ftps_noffs == 0)
1868*c54f35caSApple OSS Distributions 		return (EINVAL);
1869*c54f35caSApple OSS Distributions 
1870*c54f35caSApple OSS Distributions 	switch (pdata->ftps_probe_type) {
1871*c54f35caSApple OSS Distributions 	case DTFTP_ENTRY:
1872*c54f35caSApple OSS Distributions 		name = "entry";
1873*c54f35caSApple OSS Distributions 		aframes = FASTTRAP_ENTRY_AFRAMES;
1874*c54f35caSApple OSS Distributions 		break;
1875*c54f35caSApple OSS Distributions 	case DTFTP_RETURN:
1876*c54f35caSApple OSS Distributions 		name = "return";
1877*c54f35caSApple OSS Distributions 		aframes = FASTTRAP_RETURN_AFRAMES;
1878*c54f35caSApple OSS Distributions 		break;
1879*c54f35caSApple OSS Distributions 	case DTFTP_OFFSETS:
1880*c54f35caSApple OSS Distributions 		aframes = 0;
1881*c54f35caSApple OSS Distributions 		name = NULL;
1882*c54f35caSApple OSS Distributions 		break;
1883*c54f35caSApple OSS Distributions 	default:
1884*c54f35caSApple OSS Distributions 		return (EINVAL);
1885*c54f35caSApple OSS Distributions 	}
1886*c54f35caSApple OSS Distributions 
1887*c54f35caSApple OSS Distributions 	const char* provider_name;
1888*c54f35caSApple OSS Distributions 	switch (pdata->ftps_provider_type) {
1889*c54f35caSApple OSS Distributions 		case DTFTP_PROVIDER_PID:
1890*c54f35caSApple OSS Distributions 			provider_name = FASTTRAP_PID_NAME;
1891*c54f35caSApple OSS Distributions 			break;
1892*c54f35caSApple OSS Distributions 		case DTFTP_PROVIDER_OBJC:
1893*c54f35caSApple OSS Distributions 			provider_name = FASTTRAP_OBJC_NAME;
1894*c54f35caSApple OSS Distributions 			break;
1895*c54f35caSApple OSS Distributions 		case DTFTP_PROVIDER_ONESHOT:
1896*c54f35caSApple OSS Distributions 			provider_name = FASTTRAP_ONESHOT_NAME;
1897*c54f35caSApple OSS Distributions 			break;
1898*c54f35caSApple OSS Distributions 		default:
1899*c54f35caSApple OSS Distributions 			return (EINVAL);
1900*c54f35caSApple OSS Distributions 	}
1901*c54f35caSApple OSS Distributions 
1902*c54f35caSApple OSS Distributions 	p = proc_find(pdata->ftps_pid);
1903*c54f35caSApple OSS Distributions 	if (p == PROC_NULL)
1904*c54f35caSApple OSS Distributions 		return (ESRCH);
1905*c54f35caSApple OSS Distributions 
1906*c54f35caSApple OSS Distributions 	if ((provider = fasttrap_provider_lookup(p, pdata->ftps_provider_type,
1907*c54f35caSApple OSS Distributions 						 provider_name, &pid_attr)) == NULL) {
1908*c54f35caSApple OSS Distributions 		proc_rele(p);
1909*c54f35caSApple OSS Distributions 		return (ESRCH);
1910*c54f35caSApple OSS Distributions 	}
1911*c54f35caSApple OSS Distributions 
1912*c54f35caSApple OSS Distributions 	proc_rele(p);
1913*c54f35caSApple OSS Distributions 	/*
1914*c54f35caSApple OSS Distributions 	 * Increment this reference count to indicate that a consumer is
1915*c54f35caSApple OSS Distributions 	 * actively adding a new probe associated with this provider. This
1916*c54f35caSApple OSS Distributions 	 * prevents the provider from being deleted -- we'll need to check
1917*c54f35caSApple OSS Distributions 	 * for pending deletions when we drop this reference count.
1918*c54f35caSApple OSS Distributions 	 */
1919*c54f35caSApple OSS Distributions 	provider->ftp_ccount++;
1920*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&provider->ftp_mtx);
1921*c54f35caSApple OSS Distributions 
1922*c54f35caSApple OSS Distributions 	/*
1923*c54f35caSApple OSS Distributions 	 * Grab the creation lock to ensure consistency between calls to
1924*c54f35caSApple OSS Distributions 	 * dtrace_probe_lookup() and dtrace_probe_create() in the face of
1925*c54f35caSApple OSS Distributions 	 * other threads creating probes. We must drop the provider lock
1926*c54f35caSApple OSS Distributions 	 * before taking this lock to avoid a three-way deadlock with the
1927*c54f35caSApple OSS Distributions 	 * DTrace framework.
1928*c54f35caSApple OSS Distributions 	 */
1929*c54f35caSApple OSS Distributions 	lck_mtx_lock(&provider->ftp_cmtx);
1930*c54f35caSApple OSS Distributions 
1931*c54f35caSApple OSS Distributions 	if (name == NULL) {
1932*c54f35caSApple OSS Distributions 		for (i = 0; i < pdata->ftps_noffs; i++) {
1933*c54f35caSApple OSS Distributions 			char name_str[17];
1934*c54f35caSApple OSS Distributions 
1935*c54f35caSApple OSS Distributions 			(void) snprintf(name_str, sizeof(name_str), "%llx",
1936*c54f35caSApple OSS Distributions 			    (uint64_t)pdata->ftps_offs[i]);
1937*c54f35caSApple OSS Distributions 
1938*c54f35caSApple OSS Distributions 			if (dtrace_probe_lookup(provider->ftp_provid,
1939*c54f35caSApple OSS Distributions 			    pdata->ftps_mod, pdata->ftps_func, name_str) != 0)
1940*c54f35caSApple OSS Distributions 				continue;
1941*c54f35caSApple OSS Distributions 
1942*c54f35caSApple OSS Distributions 			os_atomic_inc(&fasttrap_total, relaxed);
1943*c54f35caSApple OSS Distributions 			if (fasttrap_total > fasttrap_max) {
1944*c54f35caSApple OSS Distributions 				os_atomic_dec(&fasttrap_total, relaxed);
1945*c54f35caSApple OSS Distributions 				goto no_mem;
1946*c54f35caSApple OSS Distributions 			}
1947*c54f35caSApple OSS Distributions 			provider->ftp_pcount++;
1948*c54f35caSApple OSS Distributions 
1949*c54f35caSApple OSS Distributions 			pp = zalloc_flags(fasttrap_probe_t_zones[1], Z_WAITOK | Z_ZERO);
1950*c54f35caSApple OSS Distributions 
1951*c54f35caSApple OSS Distributions 			pp->ftp_prov = provider;
1952*c54f35caSApple OSS Distributions 			pp->ftp_faddr = pdata->ftps_pc;
1953*c54f35caSApple OSS Distributions 			pp->ftp_fsize = pdata->ftps_size;
1954*c54f35caSApple OSS Distributions 			pp->ftp_pid = pdata->ftps_pid;
1955*c54f35caSApple OSS Distributions 			pp->ftp_ntps = 1;
1956*c54f35caSApple OSS Distributions 
1957*c54f35caSApple OSS Distributions 			tp = zalloc_flags(fasttrap_tracepoint_t_zone, Z_WAITOK | Z_ZERO);
1958*c54f35caSApple OSS Distributions 
1959*c54f35caSApple OSS Distributions 			tp->ftt_proc = provider->ftp_proc;
1960*c54f35caSApple OSS Distributions 			tp->ftt_pc = pdata->ftps_offs[i] + pdata->ftps_pc;
1961*c54f35caSApple OSS Distributions 			tp->ftt_pid = pdata->ftps_pid;
1962*c54f35caSApple OSS Distributions 
1963*c54f35caSApple OSS Distributions #if defined(__arm64__)
1964*c54f35caSApple OSS Distributions 			/*
1965*c54f35caSApple OSS Distributions 			 * On arm the subinfo is used to distinguish between arm
1966*c54f35caSApple OSS Distributions 			 * and thumb modes.  On arm64 there is no thumb mode, so
1967*c54f35caSApple OSS Distributions 			 * this field is simply initialized to 0 on its way
1968*c54f35caSApple OSS Distributions 			 * into the kernel.
1969*c54f35caSApple OSS Distributions 			 */
1970*c54f35caSApple OSS Distributions 			tp->ftt_fntype = pdata->ftps_arch_subinfo;
1971*c54f35caSApple OSS Distributions #endif
1972*c54f35caSApple OSS Distributions 
1973*c54f35caSApple OSS Distributions 			pp->ftp_tps[0].fit_tp = tp;
1974*c54f35caSApple OSS Distributions 			pp->ftp_tps[0].fit_id.fti_probe = pp;
1975*c54f35caSApple OSS Distributions 			pp->ftp_tps[0].fit_id.fti_ptype = pdata->ftps_probe_type;
1976*c54f35caSApple OSS Distributions 			pp->ftp_id = dtrace_probe_create(provider->ftp_provid,
1977*c54f35caSApple OSS Distributions 			    pdata->ftps_mod, pdata->ftps_func, name_str,
1978*c54f35caSApple OSS Distributions 			    FASTTRAP_OFFSET_AFRAMES, pp);
1979*c54f35caSApple OSS Distributions 		}
1980*c54f35caSApple OSS Distributions 
1981*c54f35caSApple OSS Distributions 	} else if (dtrace_probe_lookup(provider->ftp_provid, pdata->ftps_mod,
1982*c54f35caSApple OSS Distributions 	    pdata->ftps_func, name) == 0) {
1983*c54f35caSApple OSS Distributions 		os_atomic_add(&fasttrap_total, pdata->ftps_noffs, relaxed);
1984*c54f35caSApple OSS Distributions 
1985*c54f35caSApple OSS Distributions 		if (fasttrap_total > fasttrap_max) {
1986*c54f35caSApple OSS Distributions 			os_atomic_sub(&fasttrap_total, pdata->ftps_noffs, relaxed);
1987*c54f35caSApple OSS Distributions 			goto no_mem;
1988*c54f35caSApple OSS Distributions 		}
1989*c54f35caSApple OSS Distributions 
1990*c54f35caSApple OSS Distributions 		/*
1991*c54f35caSApple OSS Distributions 		 * Make sure all tracepoint program counter values are unique.
1992*c54f35caSApple OSS Distributions 		 * We later assume that each probe has exactly one tracepoint
1993*c54f35caSApple OSS Distributions 		 * for a given pc.
1994*c54f35caSApple OSS Distributions 		 */
1995*c54f35caSApple OSS Distributions 		qsort(pdata->ftps_offs, pdata->ftps_noffs,
1996*c54f35caSApple OSS Distributions 			sizeof (uint64_t), fasttrap_uint64_cmp);
1997*c54f35caSApple OSS Distributions 		for (i = 1; i < pdata->ftps_noffs; i++) {
1998*c54f35caSApple OSS Distributions 			if (pdata->ftps_offs[i] > pdata->ftps_offs[i - 1])
1999*c54f35caSApple OSS Distributions 				continue;
2000*c54f35caSApple OSS Distributions 
2001*c54f35caSApple OSS Distributions 			os_atomic_sub(&fasttrap_total, pdata->ftps_noffs, relaxed);
2002*c54f35caSApple OSS Distributions 			goto no_mem;
2003*c54f35caSApple OSS Distributions 		}
2004*c54f35caSApple OSS Distributions 		provider->ftp_pcount += pdata->ftps_noffs;
2005*c54f35caSApple OSS Distributions 		ASSERT(pdata->ftps_noffs > 0);
2006*c54f35caSApple OSS Distributions 		if (pdata->ftps_noffs < FASTTRAP_PROBE_T_ZONE_MAX_TRACEPOINTS) {
2007*c54f35caSApple OSS Distributions 			pp = zalloc_flags(fasttrap_probe_t_zones[pdata->ftps_noffs],
2008*c54f35caSApple OSS Distributions 			    Z_WAITOK | Z_ZERO);
2009*c54f35caSApple OSS Distributions 		} else {
2010*c54f35caSApple OSS Distributions 			pp = kmem_zalloc(offsetof(fasttrap_probe_t, ftp_tps[pdata->ftps_noffs]), KM_SLEEP);
2011*c54f35caSApple OSS Distributions 		}
2012*c54f35caSApple OSS Distributions 
2013*c54f35caSApple OSS Distributions 		pp->ftp_prov = provider;
2014*c54f35caSApple OSS Distributions 		pp->ftp_faddr = pdata->ftps_pc;
2015*c54f35caSApple OSS Distributions 		pp->ftp_fsize = pdata->ftps_size;
2016*c54f35caSApple OSS Distributions 		pp->ftp_pid = pdata->ftps_pid;
2017*c54f35caSApple OSS Distributions 		pp->ftp_ntps = pdata->ftps_noffs;
2018*c54f35caSApple OSS Distributions 
2019*c54f35caSApple OSS Distributions 		for (i = 0; i < pdata->ftps_noffs; i++) {
2020*c54f35caSApple OSS Distributions 			tp = zalloc_flags(fasttrap_tracepoint_t_zone, Z_WAITOK | Z_ZERO);
2021*c54f35caSApple OSS Distributions 			tp->ftt_proc = provider->ftp_proc;
2022*c54f35caSApple OSS Distributions 			tp->ftt_pc = pdata->ftps_offs[i] + pdata->ftps_pc;
2023*c54f35caSApple OSS Distributions 			tp->ftt_pid = pdata->ftps_pid;
2024*c54f35caSApple OSS Distributions 
2025*c54f35caSApple OSS Distributions #if defined (__arm64__)
2026*c54f35caSApple OSS Distributions 			/*
2027*c54f35caSApple OSS Distributions 			 * On arm the subinfo is used to distinguish between arm
2028*c54f35caSApple OSS Distributions 			 * and thumb modes.  On arm64 there is no thumb mode, so
2029*c54f35caSApple OSS Distributions 			 * this field is simply initialized to 0 on its way
2030*c54f35caSApple OSS Distributions 			 * into the kernel.
2031*c54f35caSApple OSS Distributions 			 */
2032*c54f35caSApple OSS Distributions 
2033*c54f35caSApple OSS Distributions 			tp->ftt_fntype = pdata->ftps_arch_subinfo;
2034*c54f35caSApple OSS Distributions #endif
2035*c54f35caSApple OSS Distributions 			pp->ftp_tps[i].fit_tp = tp;
2036*c54f35caSApple OSS Distributions 			pp->ftp_tps[i].fit_id.fti_probe = pp;
2037*c54f35caSApple OSS Distributions 			pp->ftp_tps[i].fit_id.fti_ptype = pdata->ftps_probe_type;
2038*c54f35caSApple OSS Distributions 		}
2039*c54f35caSApple OSS Distributions 
2040*c54f35caSApple OSS Distributions 		pp->ftp_id = dtrace_probe_create(provider->ftp_provid,
2041*c54f35caSApple OSS Distributions 		    pdata->ftps_mod, pdata->ftps_func, name, aframes, pp);
2042*c54f35caSApple OSS Distributions 	}
2043*c54f35caSApple OSS Distributions 
2044*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&provider->ftp_cmtx);
2045*c54f35caSApple OSS Distributions 
2046*c54f35caSApple OSS Distributions 	/*
2047*c54f35caSApple OSS Distributions 	 * We know that the provider is still valid since we incremented the
2048*c54f35caSApple OSS Distributions 	 * creation reference count. If someone tried to clean up this provider
2049*c54f35caSApple OSS Distributions 	 * while we were using it (e.g. because the process called exec(2) or
2050*c54f35caSApple OSS Distributions 	 * exit(2)), take note of that and try to clean it up now.
2051*c54f35caSApple OSS Distributions 	 */
2052*c54f35caSApple OSS Distributions 	lck_mtx_lock(&provider->ftp_mtx);
2053*c54f35caSApple OSS Distributions 	provider->ftp_ccount--;
2054*c54f35caSApple OSS Distributions 	whack = provider->ftp_retired;
2055*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&provider->ftp_mtx);
2056*c54f35caSApple OSS Distributions 
2057*c54f35caSApple OSS Distributions 	if (whack)
2058*c54f35caSApple OSS Distributions 		fasttrap_pid_cleanup(FASTTRAP_CLEANUP_PROVIDER);
2059*c54f35caSApple OSS Distributions 
2060*c54f35caSApple OSS Distributions 	return (0);
2061*c54f35caSApple OSS Distributions 
2062*c54f35caSApple OSS Distributions no_mem:
2063*c54f35caSApple OSS Distributions 	/*
2064*c54f35caSApple OSS Distributions 	 * If we've exhausted the allowable resources, we'll try to remove
2065*c54f35caSApple OSS Distributions 	 * this provider to free some up. This is to cover the case where
2066*c54f35caSApple OSS Distributions 	 * the user has accidentally created many more probes than was
2067*c54f35caSApple OSS Distributions 	 * intended (e.g. pid123:::).
2068*c54f35caSApple OSS Distributions 	 */
2069*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&provider->ftp_cmtx);
2070*c54f35caSApple OSS Distributions 	lck_mtx_lock(&provider->ftp_mtx);
2071*c54f35caSApple OSS Distributions 	provider->ftp_ccount--;
2072*c54f35caSApple OSS Distributions 	provider->ftp_marked = 1;
2073*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&provider->ftp_mtx);
2074*c54f35caSApple OSS Distributions 
2075*c54f35caSApple OSS Distributions 	fasttrap_pid_cleanup(FASTTRAP_CLEANUP_PROVIDER);
2076*c54f35caSApple OSS Distributions 
2077*c54f35caSApple OSS Distributions 	return (ENOMEM);
2078*c54f35caSApple OSS Distributions }
2079*c54f35caSApple OSS Distributions 
2080*c54f35caSApple OSS Distributions /*ARGSUSED*/
2081*c54f35caSApple OSS Distributions static void *
fasttrap_meta_provide(void * arg,dtrace_helper_provdesc_t * dhpv,proc_t * p)2082*c54f35caSApple OSS Distributions fasttrap_meta_provide(void *arg, dtrace_helper_provdesc_t *dhpv, proc_t *p)
2083*c54f35caSApple OSS Distributions {
2084*c54f35caSApple OSS Distributions #pragma unused(arg)
2085*c54f35caSApple OSS Distributions 	fasttrap_provider_t *provider;
2086*c54f35caSApple OSS Distributions 
2087*c54f35caSApple OSS Distributions 	/*
2088*c54f35caSApple OSS Distributions 	 * A 32-bit unsigned integer (like a pid for example) can be
2089*c54f35caSApple OSS Distributions 	 * expressed in 10 or fewer decimal digits. Make sure that we'll
2090*c54f35caSApple OSS Distributions 	 * have enough space for the provider name.
2091*c54f35caSApple OSS Distributions 	 */
2092*c54f35caSApple OSS Distributions 	if (strlen(dhpv->dthpv_provname) + 10 >=
2093*c54f35caSApple OSS Distributions 	    sizeof (provider->ftp_name)) {
2094*c54f35caSApple OSS Distributions 		cmn_err(CE_WARN, "failed to instantiate provider %s: "
2095*c54f35caSApple OSS Distributions 		    "name too long to accomodate pid", dhpv->dthpv_provname);
2096*c54f35caSApple OSS Distributions 		return (NULL);
2097*c54f35caSApple OSS Distributions 	}
2098*c54f35caSApple OSS Distributions 
2099*c54f35caSApple OSS Distributions 	/*
2100*c54f35caSApple OSS Distributions 	 * Don't let folks spoof the true pid provider.
2101*c54f35caSApple OSS Distributions 	 */
2102*c54f35caSApple OSS Distributions 	if (strncmp(dhpv->dthpv_provname, FASTTRAP_PID_NAME, sizeof(FASTTRAP_PID_NAME)) == 0) {
2103*c54f35caSApple OSS Distributions 		cmn_err(CE_WARN, "failed to instantiate provider %s: "
2104*c54f35caSApple OSS Distributions 		    "%s is an invalid name", dhpv->dthpv_provname,
2105*c54f35caSApple OSS Distributions 		    FASTTRAP_PID_NAME);
2106*c54f35caSApple OSS Distributions 		return (NULL);
2107*c54f35caSApple OSS Distributions 	}
2108*c54f35caSApple OSS Distributions 
2109*c54f35caSApple OSS Distributions 	/*
2110*c54f35caSApple OSS Distributions 	 * APPLE NOTE: We also need to check the objc and oneshot pid provider types
2111*c54f35caSApple OSS Distributions 	 */
2112*c54f35caSApple OSS Distributions 	if (strncmp(dhpv->dthpv_provname, FASTTRAP_OBJC_NAME, sizeof(FASTTRAP_OBJC_NAME)) == 0) {
2113*c54f35caSApple OSS Distributions 		cmn_err(CE_WARN, "failed to instantiate provider %s: "
2114*c54f35caSApple OSS Distributions 		    "%s is an invalid name", dhpv->dthpv_provname,
2115*c54f35caSApple OSS Distributions 		    FASTTRAP_OBJC_NAME);
2116*c54f35caSApple OSS Distributions 		return (NULL);
2117*c54f35caSApple OSS Distributions 	}
2118*c54f35caSApple OSS Distributions 	if (strncmp(dhpv->dthpv_provname, FASTTRAP_ONESHOT_NAME, sizeof(FASTTRAP_ONESHOT_NAME)) == 0) {
2119*c54f35caSApple OSS Distributions 		cmn_err(CE_WARN, "failed to instantiate provider %s: "
2120*c54f35caSApple OSS Distributions 		    "%s is an invalid name", dhpv->dthpv_provname,
2121*c54f35caSApple OSS Distributions 		    FASTTRAP_ONESHOT_NAME);
2122*c54f35caSApple OSS Distributions 		return (NULL);
2123*c54f35caSApple OSS Distributions 	}
2124*c54f35caSApple OSS Distributions 
2125*c54f35caSApple OSS Distributions 	/*
2126*c54f35caSApple OSS Distributions 	 * The highest stability class that fasttrap supports is ISA; cap
2127*c54f35caSApple OSS Distributions 	 * the stability of the new provider accordingly.
2128*c54f35caSApple OSS Distributions 	 */
2129*c54f35caSApple OSS Distributions 	if (dhpv->dthpv_pattr.dtpa_provider.dtat_class > DTRACE_CLASS_ISA)
2130*c54f35caSApple OSS Distributions 		dhpv->dthpv_pattr.dtpa_provider.dtat_class = DTRACE_CLASS_ISA;
2131*c54f35caSApple OSS Distributions 	if (dhpv->dthpv_pattr.dtpa_mod.dtat_class > DTRACE_CLASS_ISA)
2132*c54f35caSApple OSS Distributions 		dhpv->dthpv_pattr.dtpa_mod.dtat_class = DTRACE_CLASS_ISA;
2133*c54f35caSApple OSS Distributions 	if (dhpv->dthpv_pattr.dtpa_func.dtat_class > DTRACE_CLASS_ISA)
2134*c54f35caSApple OSS Distributions 		dhpv->dthpv_pattr.dtpa_func.dtat_class = DTRACE_CLASS_ISA;
2135*c54f35caSApple OSS Distributions 	if (dhpv->dthpv_pattr.dtpa_name.dtat_class > DTRACE_CLASS_ISA)
2136*c54f35caSApple OSS Distributions 		dhpv->dthpv_pattr.dtpa_name.dtat_class = DTRACE_CLASS_ISA;
2137*c54f35caSApple OSS Distributions 	if (dhpv->dthpv_pattr.dtpa_args.dtat_class > DTRACE_CLASS_ISA)
2138*c54f35caSApple OSS Distributions 		dhpv->dthpv_pattr.dtpa_args.dtat_class = DTRACE_CLASS_ISA;
2139*c54f35caSApple OSS Distributions 
2140*c54f35caSApple OSS Distributions 	if ((provider = fasttrap_provider_lookup(p, DTFTP_PROVIDER_USDT, dhpv->dthpv_provname,
2141*c54f35caSApple OSS Distributions 	    &dhpv->dthpv_pattr)) == NULL) {
2142*c54f35caSApple OSS Distributions 		cmn_err(CE_WARN, "failed to instantiate provider %s for "
2143*c54f35caSApple OSS Distributions 		    "process %u",  dhpv->dthpv_provname, (uint_t)proc_getpid(p));
2144*c54f35caSApple OSS Distributions 		return (NULL);
2145*c54f35caSApple OSS Distributions 	}
2146*c54f35caSApple OSS Distributions 
2147*c54f35caSApple OSS Distributions 	/*
2148*c54f35caSApple OSS Distributions 	 * APPLE NOTE!
2149*c54f35caSApple OSS Distributions 	 *
2150*c54f35caSApple OSS Distributions 	 * USDT probes (fasttrap meta probes) are very expensive to create.
2151*c54f35caSApple OSS Distributions 	 * Profiling has shown that the largest single cost is verifying that
2152*c54f35caSApple OSS Distributions 	 * dtrace hasn't already created a given meta_probe. The reason for
2153*c54f35caSApple OSS Distributions 	 * this is dtrace_match() often has to strcmp ~100 hashed entries for
2154*c54f35caSApple OSS Distributions 	 * each static probe being created. We want to get rid of that check.
2155*c54f35caSApple OSS Distributions 	 * The simplest way of eliminating it is to deny the ability to add
2156*c54f35caSApple OSS Distributions 	 * probes to an existing provider. If the provider already exists, BZZT!
2157*c54f35caSApple OSS Distributions 	 * This still leaves the possibility of intentionally malformed DOF
2158*c54f35caSApple OSS Distributions 	 * having duplicate probes. However, duplicate probes are not fatal,
2159*c54f35caSApple OSS Distributions 	 * and there is no way to get that by accident, so we will not check
2160*c54f35caSApple OSS Distributions 	 * for that case.
2161*c54f35caSApple OSS Distributions 	 *
2162*c54f35caSApple OSS Distributions 	 * UPDATE: It turns out there are several use cases that require adding
2163*c54f35caSApple OSS Distributions 	 * probes to existing providers. Disabling the dtrace_probe_lookup()
2164*c54f35caSApple OSS Distributions 	 * optimization for now. See APPLE NOTE in fasttrap_meta_create_probe.
2165*c54f35caSApple OSS Distributions 	 */
2166*c54f35caSApple OSS Distributions 
2167*c54f35caSApple OSS Distributions 	/*
2168*c54f35caSApple OSS Distributions 	 * Up the meta provider count so this provider isn't removed until
2169*c54f35caSApple OSS Distributions 	 * the meta provider has been told to remove it.
2170*c54f35caSApple OSS Distributions 	 */
2171*c54f35caSApple OSS Distributions 	provider->ftp_mcount++;
2172*c54f35caSApple OSS Distributions 
2173*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&provider->ftp_mtx);
2174*c54f35caSApple OSS Distributions 
2175*c54f35caSApple OSS Distributions 	return (provider);
2176*c54f35caSApple OSS Distributions }
2177*c54f35caSApple OSS Distributions 
2178*c54f35caSApple OSS Distributions /*ARGSUSED*/
2179*c54f35caSApple OSS Distributions static void
fasttrap_meta_create_probe(void * arg,void * parg,dtrace_helper_probedesc_t * dhpb)2180*c54f35caSApple OSS Distributions fasttrap_meta_create_probe(void *arg, void *parg,
2181*c54f35caSApple OSS Distributions     dtrace_helper_probedesc_t *dhpb)
2182*c54f35caSApple OSS Distributions {
2183*c54f35caSApple OSS Distributions #pragma unused(arg)
2184*c54f35caSApple OSS Distributions 	fasttrap_provider_t *provider = parg;
2185*c54f35caSApple OSS Distributions 	fasttrap_probe_t *pp;
2186*c54f35caSApple OSS Distributions 	fasttrap_tracepoint_t *tp;
2187*c54f35caSApple OSS Distributions 	unsigned int i, j;
2188*c54f35caSApple OSS Distributions 	uint32_t ntps;
2189*c54f35caSApple OSS Distributions 
2190*c54f35caSApple OSS Distributions 	/*
2191*c54f35caSApple OSS Distributions 	 * Since the meta provider count is non-zero we don't have to worry
2192*c54f35caSApple OSS Distributions 	 * about this provider disappearing.
2193*c54f35caSApple OSS Distributions 	 */
2194*c54f35caSApple OSS Distributions 	ASSERT(provider->ftp_mcount > 0);
2195*c54f35caSApple OSS Distributions 
2196*c54f35caSApple OSS Distributions 	/*
2197*c54f35caSApple OSS Distributions 	 * The offsets must be unique.
2198*c54f35caSApple OSS Distributions 	 */
2199*c54f35caSApple OSS Distributions 	qsort(dhpb->dthpb_offs, dhpb->dthpb_noffs, sizeof (uint32_t),
2200*c54f35caSApple OSS Distributions 		fasttrap_uint32_cmp);
2201*c54f35caSApple OSS Distributions 	for (i = 1; i < dhpb->dthpb_noffs; i++) {
2202*c54f35caSApple OSS Distributions 		if (dhpb->dthpb_base + dhpb->dthpb_offs[i] <=
2203*c54f35caSApple OSS Distributions 			dhpb->dthpb_base + dhpb->dthpb_offs[i - 1])
2204*c54f35caSApple OSS Distributions 				return;
2205*c54f35caSApple OSS Distributions 	}
2206*c54f35caSApple OSS Distributions 
2207*c54f35caSApple OSS Distributions 	qsort(dhpb->dthpb_enoffs, dhpb->dthpb_nenoffs, sizeof (uint32_t),
2208*c54f35caSApple OSS Distributions 		fasttrap_uint32_cmp);
2209*c54f35caSApple OSS Distributions 	for (i = 1; i < dhpb->dthpb_nenoffs; i++) {
2210*c54f35caSApple OSS Distributions 		if (dhpb->dthpb_base + dhpb->dthpb_enoffs[i] <=
2211*c54f35caSApple OSS Distributions 			dhpb->dthpb_base + dhpb->dthpb_enoffs[i - 1])
2212*c54f35caSApple OSS Distributions 				return;
2213*c54f35caSApple OSS Distributions 	}
2214*c54f35caSApple OSS Distributions 
2215*c54f35caSApple OSS Distributions 	/*
2216*c54f35caSApple OSS Distributions 	 * Grab the creation lock to ensure consistency between calls to
2217*c54f35caSApple OSS Distributions 	 * dtrace_probe_lookup() and dtrace_probe_create() in the face of
2218*c54f35caSApple OSS Distributions 	 * other threads creating probes.
2219*c54f35caSApple OSS Distributions 	 */
2220*c54f35caSApple OSS Distributions 	lck_mtx_lock(&provider->ftp_cmtx);
2221*c54f35caSApple OSS Distributions 
2222*c54f35caSApple OSS Distributions #if 0
2223*c54f35caSApple OSS Distributions 	/*
2224*c54f35caSApple OSS Distributions 	 * APPLE NOTE: This is hideously expensive. See note in
2225*c54f35caSApple OSS Distributions 	 * fasttrap_meta_provide() for why we can get away without
2226*c54f35caSApple OSS Distributions 	 * checking here.
2227*c54f35caSApple OSS Distributions 	 */
2228*c54f35caSApple OSS Distributions 	if (dtrace_probe_lookup(provider->ftp_provid, dhpb->dthpb_mod,
2229*c54f35caSApple OSS Distributions 	    dhpb->dthpb_func, dhpb->dthpb_name) != 0) {
2230*c54f35caSApple OSS Distributions 		lck_mtx_unlock(&provider->ftp_cmtx);
2231*c54f35caSApple OSS Distributions 		return;
2232*c54f35caSApple OSS Distributions 	}
2233*c54f35caSApple OSS Distributions #endif
2234*c54f35caSApple OSS Distributions 
2235*c54f35caSApple OSS Distributions 	ntps = dhpb->dthpb_noffs + dhpb->dthpb_nenoffs;
2236*c54f35caSApple OSS Distributions 	ASSERT(ntps > 0);
2237*c54f35caSApple OSS Distributions 
2238*c54f35caSApple OSS Distributions 	os_atomic_add(&fasttrap_total, ntps, relaxed);
2239*c54f35caSApple OSS Distributions 
2240*c54f35caSApple OSS Distributions 	if (fasttrap_total > fasttrap_max) {
2241*c54f35caSApple OSS Distributions 		os_atomic_sub(&fasttrap_total, ntps, relaxed);
2242*c54f35caSApple OSS Distributions 		lck_mtx_unlock(&provider->ftp_cmtx);
2243*c54f35caSApple OSS Distributions 		return;
2244*c54f35caSApple OSS Distributions 	}
2245*c54f35caSApple OSS Distributions 
2246*c54f35caSApple OSS Distributions 	provider->ftp_pcount += ntps;
2247*c54f35caSApple OSS Distributions 
2248*c54f35caSApple OSS Distributions 	if (ntps < FASTTRAP_PROBE_T_ZONE_MAX_TRACEPOINTS) {
2249*c54f35caSApple OSS Distributions 		pp = zalloc_flags(fasttrap_probe_t_zones[ntps], Z_WAITOK | Z_ZERO);
2250*c54f35caSApple OSS Distributions 	} else {
2251*c54f35caSApple OSS Distributions 		pp = kmem_zalloc(offsetof(fasttrap_probe_t, ftp_tps[ntps]), KM_SLEEP);
2252*c54f35caSApple OSS Distributions 	}
2253*c54f35caSApple OSS Distributions 
2254*c54f35caSApple OSS Distributions 	pp->ftp_prov = provider;
2255*c54f35caSApple OSS Distributions 	pp->ftp_pid = provider->ftp_pid;
2256*c54f35caSApple OSS Distributions 	pp->ftp_ntps = ntps;
2257*c54f35caSApple OSS Distributions 	pp->ftp_nargs = dhpb->dthpb_xargc;
2258*c54f35caSApple OSS Distributions 	pp->ftp_xtypes = dhpb->dthpb_xtypes;
2259*c54f35caSApple OSS Distributions 	pp->ftp_ntypes = dhpb->dthpb_ntypes;
2260*c54f35caSApple OSS Distributions 
2261*c54f35caSApple OSS Distributions 	/*
2262*c54f35caSApple OSS Distributions 	 * First create a tracepoint for each actual point of interest.
2263*c54f35caSApple OSS Distributions 	 */
2264*c54f35caSApple OSS Distributions 	for (i = 0; i < dhpb->dthpb_noffs; i++) {
2265*c54f35caSApple OSS Distributions 		tp = zalloc_flags(fasttrap_tracepoint_t_zone, Z_WAITOK | Z_ZERO);
2266*c54f35caSApple OSS Distributions 
2267*c54f35caSApple OSS Distributions 		tp->ftt_proc = provider->ftp_proc;
2268*c54f35caSApple OSS Distributions 
2269*c54f35caSApple OSS Distributions 		/*
2270*c54f35caSApple OSS Distributions 		 * APPLE NOTE: We have linker support when creating DOF to handle all relocations for us.
2271*c54f35caSApple OSS Distributions 		 * Unfortunately, a side effect of this is that the relocations do not point at exactly
2272*c54f35caSApple OSS Distributions 		 * the location we want. We need to fix up the addresses here. The fixups vary by arch and type.
2273*c54f35caSApple OSS Distributions 		 */
2274*c54f35caSApple OSS Distributions #if defined(__x86_64__)
2275*c54f35caSApple OSS Distributions 		/*
2276*c54f35caSApple OSS Distributions 		 * Both 32 & 64 bit want to go back one byte, to point at the first NOP
2277*c54f35caSApple OSS Distributions 		 */
2278*c54f35caSApple OSS Distributions 		tp->ftt_pc = dhpb->dthpb_base + (int64_t)dhpb->dthpb_offs[i] - 1;
2279*c54f35caSApple OSS Distributions #elif defined(__arm64__)
2280*c54f35caSApple OSS Distributions 		/*
2281*c54f35caSApple OSS Distributions 		 * All ARM and ARM64 probes are zero offset. We need to zero out the
2282*c54f35caSApple OSS Distributions 		 * thumb bit because we still support 32bit user processes.
2283*c54f35caSApple OSS Distributions 		 * On 64bit user processes, bit zero won't be set anyway.
2284*c54f35caSApple OSS Distributions 		 */
2285*c54f35caSApple OSS Distributions 		tp->ftt_pc = (dhpb->dthpb_base + (int64_t)dhpb->dthpb_offs[i]) & ~0x1UL;
2286*c54f35caSApple OSS Distributions 		tp->ftt_fntype = FASTTRAP_FN_USDT;
2287*c54f35caSApple OSS Distributions #else
2288*c54f35caSApple OSS Distributions #error "Architecture not supported"
2289*c54f35caSApple OSS Distributions #endif
2290*c54f35caSApple OSS Distributions 
2291*c54f35caSApple OSS Distributions 		tp->ftt_pid = provider->ftp_pid;
2292*c54f35caSApple OSS Distributions 
2293*c54f35caSApple OSS Distributions 		pp->ftp_tps[i].fit_tp = tp;
2294*c54f35caSApple OSS Distributions 		pp->ftp_tps[i].fit_id.fti_probe = pp;
2295*c54f35caSApple OSS Distributions 		pp->ftp_tps[i].fit_id.fti_ptype = DTFTP_OFFSETS;
2296*c54f35caSApple OSS Distributions 	}
2297*c54f35caSApple OSS Distributions 
2298*c54f35caSApple OSS Distributions 	/*
2299*c54f35caSApple OSS Distributions 	 * Then create a tracepoint for each is-enabled point.
2300*c54f35caSApple OSS Distributions 	 */
2301*c54f35caSApple OSS Distributions 	for (j = 0; i < ntps; i++, j++) {
2302*c54f35caSApple OSS Distributions 		tp = zalloc_flags(fasttrap_tracepoint_t_zone, Z_WAITOK | Z_ZERO);
2303*c54f35caSApple OSS Distributions 
2304*c54f35caSApple OSS Distributions 		tp->ftt_proc = provider->ftp_proc;
2305*c54f35caSApple OSS Distributions 
2306*c54f35caSApple OSS Distributions 		/*
2307*c54f35caSApple OSS Distributions 		 * APPLE NOTE: We have linker support when creating DOF to handle all relocations for us.
2308*c54f35caSApple OSS Distributions 		 * Unfortunately, a side effect of this is that the relocations do not point at exactly
2309*c54f35caSApple OSS Distributions 		 * the location we want. We need to fix up the addresses here. The fixups vary by arch and type.
2310*c54f35caSApple OSS Distributions 		 */
2311*c54f35caSApple OSS Distributions #if defined(__x86_64__)
2312*c54f35caSApple OSS Distributions 		/*
2313*c54f35caSApple OSS Distributions 		 * Both 32 & 64 bit want to go forward two bytes, to point at a single byte nop.
2314*c54f35caSApple OSS Distributions 		 */
2315*c54f35caSApple OSS Distributions 		tp->ftt_pc = dhpb->dthpb_base + (int64_t)dhpb->dthpb_enoffs[j] + 2;
2316*c54f35caSApple OSS Distributions #elif defined(__arm64__)
2317*c54f35caSApple OSS Distributions 		/*
2318*c54f35caSApple OSS Distributions 		 * All ARM and ARM64 probes are zero offset. We need to zero out the
2319*c54f35caSApple OSS Distributions 		 * thumb bit because we still support 32bit user processes.
2320*c54f35caSApple OSS Distributions 		 * On 64bit user processes, bit zero won't be set anyway.
2321*c54f35caSApple OSS Distributions 		 */
2322*c54f35caSApple OSS Distributions 		tp->ftt_pc = (dhpb->dthpb_base + (int64_t)dhpb->dthpb_enoffs[j]) & ~0x1UL;
2323*c54f35caSApple OSS Distributions 		tp->ftt_fntype = FASTTRAP_FN_USDT;
2324*c54f35caSApple OSS Distributions #else
2325*c54f35caSApple OSS Distributions #error "Architecture not supported"
2326*c54f35caSApple OSS Distributions #endif
2327*c54f35caSApple OSS Distributions 
2328*c54f35caSApple OSS Distributions 		tp->ftt_pid = provider->ftp_pid;
2329*c54f35caSApple OSS Distributions 
2330*c54f35caSApple OSS Distributions 		pp->ftp_tps[i].fit_tp = tp;
2331*c54f35caSApple OSS Distributions 		pp->ftp_tps[i].fit_id.fti_probe = pp;
2332*c54f35caSApple OSS Distributions 		pp->ftp_tps[i].fit_id.fti_ptype = DTFTP_IS_ENABLED;
2333*c54f35caSApple OSS Distributions 	}
2334*c54f35caSApple OSS Distributions 
2335*c54f35caSApple OSS Distributions 	/*
2336*c54f35caSApple OSS Distributions 	 * If the arguments are shuffled around we set the argument remapping
2337*c54f35caSApple OSS Distributions 	 * table. Later, when the probe fires, we only remap the arguments
2338*c54f35caSApple OSS Distributions 	 * if the table is non-NULL.
2339*c54f35caSApple OSS Distributions 	 */
2340*c54f35caSApple OSS Distributions 	for (i = 0; i < dhpb->dthpb_xargc; i++) {
2341*c54f35caSApple OSS Distributions 		if (dhpb->dthpb_args[i] != i) {
2342*c54f35caSApple OSS Distributions 			pp->ftp_argmap = dhpb->dthpb_args;
2343*c54f35caSApple OSS Distributions 			break;
2344*c54f35caSApple OSS Distributions 		}
2345*c54f35caSApple OSS Distributions 	}
2346*c54f35caSApple OSS Distributions 
2347*c54f35caSApple OSS Distributions 	/*
2348*c54f35caSApple OSS Distributions 	 * The probe is fully constructed -- register it with DTrace.
2349*c54f35caSApple OSS Distributions 	 */
2350*c54f35caSApple OSS Distributions 	pp->ftp_id = dtrace_probe_create(provider->ftp_provid, dhpb->dthpb_mod,
2351*c54f35caSApple OSS Distributions 	    dhpb->dthpb_func, dhpb->dthpb_name, FASTTRAP_OFFSET_AFRAMES, pp);
2352*c54f35caSApple OSS Distributions 
2353*c54f35caSApple OSS Distributions 	lck_mtx_unlock(&provider->ftp_cmtx);
2354*c54f35caSApple OSS Distributions }
2355*c54f35caSApple OSS Distributions 
2356*c54f35caSApple OSS Distributions /*ARGSUSED*/
2357*c54f35caSApple OSS Distributions static void
fasttrap_meta_remove(void * arg,dtrace_helper_provdesc_t * dhpv,proc_t * p)2358*c54f35caSApple OSS Distributions fasttrap_meta_remove(void *arg, dtrace_helper_provdesc_t *dhpv, proc_t *p)
2359*c54f35caSApple OSS Distributions {
2360*c54f35caSApple OSS Distributions #pragma unused(arg)
2361*c54f35caSApple OSS Distributions 	/*
2362*c54f35caSApple OSS Distributions 	 * Clean up the USDT provider. There may be active consumers of the
2363*c54f35caSApple OSS Distributions 	 * provider busy adding probes, no damage will actually befall the
2364*c54f35caSApple OSS Distributions 	 * provider until that count has dropped to zero. This just puts
2365*c54f35caSApple OSS Distributions 	 * the provider on death row.
2366*c54f35caSApple OSS Distributions 	 */
2367*c54f35caSApple OSS Distributions 	fasttrap_provider_retire(p, dhpv->dthpv_provname, 1);
2368*c54f35caSApple OSS Distributions }
2369*c54f35caSApple OSS Distributions 
2370*c54f35caSApple OSS Distributions static char*
fasttrap_meta_provider_name(void * arg)2371*c54f35caSApple OSS Distributions fasttrap_meta_provider_name(void *arg)
2372*c54f35caSApple OSS Distributions {
2373*c54f35caSApple OSS Distributions 	fasttrap_provider_t *fprovider = arg;
2374*c54f35caSApple OSS Distributions 	dtrace_provider_t *provider = (dtrace_provider_t*)(fprovider->ftp_provid);
2375*c54f35caSApple OSS Distributions 	return provider->dtpv_name;
2376*c54f35caSApple OSS Distributions }
2377*c54f35caSApple OSS Distributions 
2378*c54f35caSApple OSS Distributions static dtrace_mops_t fasttrap_mops = {
2379*c54f35caSApple OSS Distributions 	.dtms_create_probe =	fasttrap_meta_create_probe,
2380*c54f35caSApple OSS Distributions 	.dtms_provide_proc =	fasttrap_meta_provide,
2381*c54f35caSApple OSS Distributions 	.dtms_remove_proc =	fasttrap_meta_remove,
2382*c54f35caSApple OSS Distributions 	.dtms_provider_name =	fasttrap_meta_provider_name
2383*c54f35caSApple OSS Distributions };
2384*c54f35caSApple OSS Distributions 
2385*c54f35caSApple OSS Distributions /*
2386*c54f35caSApple OSS Distributions  * Validate a null-terminated string. If str is not null-terminated,
2387*c54f35caSApple OSS Distributions  * or not a UTF8 valid string, the function returns -1. Otherwise, 0 is
2388*c54f35caSApple OSS Distributions  * returned.
2389*c54f35caSApple OSS Distributions  *
2390*c54f35caSApple OSS Distributions  * str: string to validate.
2391*c54f35caSApple OSS Distributions  * maxlen: maximal length of the string, null-terminated byte included.
2392*c54f35caSApple OSS Distributions  */
2393*c54f35caSApple OSS Distributions static int
fasttrap_validatestr(char const * str,size_t maxlen)2394*c54f35caSApple OSS Distributions fasttrap_validatestr(char const* str, size_t maxlen) {
2395*c54f35caSApple OSS Distributions 	size_t len;
2396*c54f35caSApple OSS Distributions 
2397*c54f35caSApple OSS Distributions 	assert(str);
2398*c54f35caSApple OSS Distributions 	assert(maxlen != 0);
2399*c54f35caSApple OSS Distributions 
2400*c54f35caSApple OSS Distributions 	/* Check if the string is null-terminated. */
2401*c54f35caSApple OSS Distributions 	len = strnlen(str, maxlen);
2402*c54f35caSApple OSS Distributions 	if (len >= maxlen)
2403*c54f35caSApple OSS Distributions 		return -1;
2404*c54f35caSApple OSS Distributions 
2405*c54f35caSApple OSS Distributions 	/* Finally, check for UTF8 validity. */
2406*c54f35caSApple OSS Distributions 	return utf8_validatestr((unsigned const char*) str, len);
2407*c54f35caSApple OSS Distributions }
2408*c54f35caSApple OSS Distributions 
2409*c54f35caSApple OSS Distributions /*
2410*c54f35caSApple OSS Distributions  * Checks that provided credentials are allowed to debug target process.
2411*c54f35caSApple OSS Distributions  */
2412*c54f35caSApple OSS Distributions static int
fasttrap_check_cred_priv(cred_t * cr,proc_t * p)2413*c54f35caSApple OSS Distributions fasttrap_check_cred_priv(cred_t *cr, proc_t *p)
2414*c54f35caSApple OSS Distributions {
2415*c54f35caSApple OSS Distributions 	int err = 0;
2416*c54f35caSApple OSS Distributions 
2417*c54f35caSApple OSS Distributions 	/* Only root can use DTrace. */
2418*c54f35caSApple OSS Distributions 	if (!kauth_cred_issuser(cr)) {
2419*c54f35caSApple OSS Distributions 		err = EPERM;
2420*c54f35caSApple OSS Distributions 		goto out;
2421*c54f35caSApple OSS Distributions 	}
2422*c54f35caSApple OSS Distributions 
2423*c54f35caSApple OSS Distributions 	/* Process is marked as no attach. */
2424*c54f35caSApple OSS Distributions 	if (ISSET(p->p_lflag, P_LNOATTACH)) {
2425*c54f35caSApple OSS Distributions 		err = EBUSY;
2426*c54f35caSApple OSS Distributions 		goto out;
2427*c54f35caSApple OSS Distributions 	}
2428*c54f35caSApple OSS Distributions 
2429*c54f35caSApple OSS Distributions #if CONFIG_MACF
2430*c54f35caSApple OSS Distributions 	/* Check with MAC framework when enabled. */
2431*c54f35caSApple OSS Distributions 	struct proc_ident cur_ident = proc_ident(current_proc());
2432*c54f35caSApple OSS Distributions 	struct proc_ident p_ident = proc_ident(p);
2433*c54f35caSApple OSS Distributions 
2434*c54f35caSApple OSS Distributions 	/* Do not hold ref to proc here to avoid deadlock. */
2435*c54f35caSApple OSS Distributions 	proc_rele(p);
2436*c54f35caSApple OSS Distributions 	err = mac_proc_check_debug(&cur_ident, cr, &p_ident);
2437*c54f35caSApple OSS Distributions 
2438*c54f35caSApple OSS Distributions 	if (proc_find_ident(&p_ident) == PROC_NULL) {
2439*c54f35caSApple OSS Distributions 		err = ESRCH;
2440*c54f35caSApple OSS Distributions 		goto out_no_proc;
2441*c54f35caSApple OSS Distributions 	}
2442*c54f35caSApple OSS Distributions #endif /* CONFIG_MACF */
2443*c54f35caSApple OSS Distributions 
2444*c54f35caSApple OSS Distributions out:
2445*c54f35caSApple OSS Distributions 	proc_rele(p);
2446*c54f35caSApple OSS Distributions 
2447*c54f35caSApple OSS Distributions out_no_proc:
2448*c54f35caSApple OSS Distributions 	return err;
2449*c54f35caSApple OSS Distributions }
2450*c54f35caSApple OSS Distributions 
2451*c54f35caSApple OSS Distributions /*ARGSUSED*/
2452*c54f35caSApple OSS Distributions static int
fasttrap_ioctl(dev_t dev,u_long cmd,user_addr_t arg,int md,cred_t * cr,int * rv)2453*c54f35caSApple OSS Distributions fasttrap_ioctl(dev_t dev, u_long cmd, user_addr_t arg, int md, cred_t *cr, int *rv)
2454*c54f35caSApple OSS Distributions {
2455*c54f35caSApple OSS Distributions #pragma unused(dev, md, rv)
2456*c54f35caSApple OSS Distributions 	if (!dtrace_attached())
2457*c54f35caSApple OSS Distributions 		return (EAGAIN);
2458*c54f35caSApple OSS Distributions 
2459*c54f35caSApple OSS Distributions 	if (cmd == FASTTRAPIOC_MAKEPROBE) {
2460*c54f35caSApple OSS Distributions 		fasttrap_probe_spec_t *probe;
2461*c54f35caSApple OSS Distributions 		uint64_t noffs;
2462*c54f35caSApple OSS Distributions 		size_t size;
2463*c54f35caSApple OSS Distributions 		int ret;
2464*c54f35caSApple OSS Distributions 
2465*c54f35caSApple OSS Distributions 		if (copyin(arg + __offsetof(fasttrap_probe_spec_t, ftps_noffs), &noffs,
2466*c54f35caSApple OSS Distributions 		    sizeof (probe->ftps_noffs)))
2467*c54f35caSApple OSS Distributions 			return (EFAULT);
2468*c54f35caSApple OSS Distributions 
2469*c54f35caSApple OSS Distributions 		/*
2470*c54f35caSApple OSS Distributions 		 * Probes must have at least one tracepoint.
2471*c54f35caSApple OSS Distributions 		 */
2472*c54f35caSApple OSS Distributions 		if (noffs == 0)
2473*c54f35caSApple OSS Distributions 			return (EINVAL);
2474*c54f35caSApple OSS Distributions 
2475*c54f35caSApple OSS Distributions 		/*
2476*c54f35caSApple OSS Distributions 		 * We want to check the number of noffs before doing
2477*c54f35caSApple OSS Distributions 		 * sizing math, to prevent potential buffer overflows.
2478*c54f35caSApple OSS Distributions 		 */
2479*c54f35caSApple OSS Distributions 		if (noffs > ((1024 * 1024) - sizeof(fasttrap_probe_spec_t)) / sizeof(probe->ftps_offs[0]))
2480*c54f35caSApple OSS Distributions 			return (ENOMEM);
2481*c54f35caSApple OSS Distributions 
2482*c54f35caSApple OSS Distributions 		size = sizeof (fasttrap_probe_spec_t) +
2483*c54f35caSApple OSS Distributions 		    sizeof (probe->ftps_offs[0]) * (noffs - 1);
2484*c54f35caSApple OSS Distributions 
2485*c54f35caSApple OSS Distributions 		probe = kmem_alloc(size, KM_SLEEP);
2486*c54f35caSApple OSS Distributions 
2487*c54f35caSApple OSS Distributions 		if (copyin(arg, probe, size) != 0 ||
2488*c54f35caSApple OSS Distributions 		    probe->ftps_noffs != noffs) {
2489*c54f35caSApple OSS Distributions 			kmem_free(probe, size);
2490*c54f35caSApple OSS Distributions 			return (EFAULT);
2491*c54f35caSApple OSS Distributions 		}
2492*c54f35caSApple OSS Distributions 
2493*c54f35caSApple OSS Distributions 		/*
2494*c54f35caSApple OSS Distributions 		 * Verify that the function and module strings contain no
2495*c54f35caSApple OSS Distributions 		 * funny characters.
2496*c54f35caSApple OSS Distributions 		 */
2497*c54f35caSApple OSS Distributions 
2498*c54f35caSApple OSS Distributions 		if (fasttrap_validatestr(probe->ftps_func, sizeof(probe->ftps_func)) != 0) {
2499*c54f35caSApple OSS Distributions 			ret = EINVAL;
2500*c54f35caSApple OSS Distributions 			goto err;
2501*c54f35caSApple OSS Distributions 		}
2502*c54f35caSApple OSS Distributions 
2503*c54f35caSApple OSS Distributions 		if (fasttrap_validatestr(probe->ftps_mod, sizeof(probe->ftps_mod)) != 0) {
2504*c54f35caSApple OSS Distributions 			ret = EINVAL;
2505*c54f35caSApple OSS Distributions 			goto err;
2506*c54f35caSApple OSS Distributions 		}
2507*c54f35caSApple OSS Distributions 
2508*c54f35caSApple OSS Distributions 		if (!PRIV_POLICY_CHOICE(cr, PRIV_ALL, B_FALSE)) {
2509*c54f35caSApple OSS Distributions 			proc_t *p;
2510*c54f35caSApple OSS Distributions 			pid_t pid = probe->ftps_pid;
2511*c54f35caSApple OSS Distributions 
2512*c54f35caSApple OSS Distributions 			/*
2513*c54f35caSApple OSS Distributions 			 * Report an error if the process doesn't exist
2514*c54f35caSApple OSS Distributions 			 * or is actively being birthed.
2515*c54f35caSApple OSS Distributions 			 */
2516*c54f35caSApple OSS Distributions 			if ((p = proc_find(pid)) == PROC_NULL || p->p_stat == SIDL) {
2517*c54f35caSApple OSS Distributions 				if (p != PROC_NULL)
2518*c54f35caSApple OSS Distributions 					proc_rele(p);
2519*c54f35caSApple OSS Distributions 				ret = ESRCH;
2520*c54f35caSApple OSS Distributions 				goto err;
2521*c54f35caSApple OSS Distributions 			}
2522*c54f35caSApple OSS Distributions 
2523*c54f35caSApple OSS Distributions 			ret = fasttrap_check_cred_priv(cr, p);
2524*c54f35caSApple OSS Distributions 			if (ret != 0) {
2525*c54f35caSApple OSS Distributions 				goto err;
2526*c54f35caSApple OSS Distributions 			}
2527*c54f35caSApple OSS Distributions 		}
2528*c54f35caSApple OSS Distributions 
2529*c54f35caSApple OSS Distributions 		ret = fasttrap_add_probe(probe);
2530*c54f35caSApple OSS Distributions 
2531*c54f35caSApple OSS Distributions err:
2532*c54f35caSApple OSS Distributions 		kmem_free(probe, size);
2533*c54f35caSApple OSS Distributions 
2534*c54f35caSApple OSS Distributions 		return (ret);
2535*c54f35caSApple OSS Distributions 
2536*c54f35caSApple OSS Distributions 	} else if (cmd == FASTTRAPIOC_GETINSTR) {
2537*c54f35caSApple OSS Distributions 		fasttrap_instr_query_t instr;
2538*c54f35caSApple OSS Distributions 		fasttrap_tracepoint_t *tp;
2539*c54f35caSApple OSS Distributions 		uint_t index;
2540*c54f35caSApple OSS Distributions 		int ret;
2541*c54f35caSApple OSS Distributions 
2542*c54f35caSApple OSS Distributions 		if (copyin(arg, &instr, sizeof (instr)) != 0)
2543*c54f35caSApple OSS Distributions 			return (EFAULT);
2544*c54f35caSApple OSS Distributions 
2545*c54f35caSApple OSS Distributions 		if (!PRIV_POLICY_CHOICE(cr, PRIV_ALL, B_FALSE)) {
2546*c54f35caSApple OSS Distributions 			proc_t *p;
2547*c54f35caSApple OSS Distributions 			pid_t pid = instr.ftiq_pid;
2548*c54f35caSApple OSS Distributions 
2549*c54f35caSApple OSS Distributions 			/*
2550*c54f35caSApple OSS Distributions 			 * Report an error if the process doesn't exist
2551*c54f35caSApple OSS Distributions 			 * or is actively being birthed.
2552*c54f35caSApple OSS Distributions 			 */
2553*c54f35caSApple OSS Distributions 			if ((p = proc_find(pid)) == NULL || p->p_stat == SIDL) {
2554*c54f35caSApple OSS Distributions 				if (p != PROC_NULL)
2555*c54f35caSApple OSS Distributions 					proc_rele(p);
2556*c54f35caSApple OSS Distributions 				return (ESRCH);
2557*c54f35caSApple OSS Distributions 			}
2558*c54f35caSApple OSS Distributions 
2559*c54f35caSApple OSS Distributions 			ret = fasttrap_check_cred_priv(cr, p);
2560*c54f35caSApple OSS Distributions 			if (ret != 0) {
2561*c54f35caSApple OSS Distributions 				return (ret);
2562*c54f35caSApple OSS Distributions 			}
2563*c54f35caSApple OSS Distributions 		}
2564*c54f35caSApple OSS Distributions 
2565*c54f35caSApple OSS Distributions 		index = FASTTRAP_TPOINTS_INDEX(instr.ftiq_pid, instr.ftiq_pc);
2566*c54f35caSApple OSS Distributions 
2567*c54f35caSApple OSS Distributions 		lck_mtx_lock(&fasttrap_tpoints.fth_table[index].ftb_mtx);
2568*c54f35caSApple OSS Distributions 		tp = fasttrap_tpoints.fth_table[index].ftb_data;
2569*c54f35caSApple OSS Distributions 		while (tp != NULL) {
2570*c54f35caSApple OSS Distributions 			if (instr.ftiq_pid == tp->ftt_pid &&
2571*c54f35caSApple OSS Distributions 			    instr.ftiq_pc == tp->ftt_pc &&
2572*c54f35caSApple OSS Distributions 			    tp->ftt_proc->ftpc_acount != 0)
2573*c54f35caSApple OSS Distributions 				break;
2574*c54f35caSApple OSS Distributions 
2575*c54f35caSApple OSS Distributions 			tp = tp->ftt_next;
2576*c54f35caSApple OSS Distributions 		}
2577*c54f35caSApple OSS Distributions 
2578*c54f35caSApple OSS Distributions 		if (tp == NULL) {
2579*c54f35caSApple OSS Distributions 			lck_mtx_unlock(&fasttrap_tpoints.fth_table[index].ftb_mtx);
2580*c54f35caSApple OSS Distributions 			return (ENOENT);
2581*c54f35caSApple OSS Distributions 		}
2582*c54f35caSApple OSS Distributions 
2583*c54f35caSApple OSS Distributions 		bcopy(&tp->ftt_instr, &instr.ftiq_instr,
2584*c54f35caSApple OSS Distributions 		    sizeof (instr.ftiq_instr));
2585*c54f35caSApple OSS Distributions 		lck_mtx_unlock(&fasttrap_tpoints.fth_table[index].ftb_mtx);
2586*c54f35caSApple OSS Distributions 
2587*c54f35caSApple OSS Distributions 		if (copyout(&instr, arg, sizeof (instr)) != 0)
2588*c54f35caSApple OSS Distributions 			return (EFAULT);
2589*c54f35caSApple OSS Distributions 
2590*c54f35caSApple OSS Distributions 		return (0);
2591*c54f35caSApple OSS Distributions 	}
2592*c54f35caSApple OSS Distributions 
2593*c54f35caSApple OSS Distributions 	return (EINVAL);
2594*c54f35caSApple OSS Distributions }
2595*c54f35caSApple OSS Distributions 
2596*c54f35caSApple OSS Distributions static void
fasttrap_attach(void)2597*c54f35caSApple OSS Distributions fasttrap_attach(void)
2598*c54f35caSApple OSS Distributions {
2599*c54f35caSApple OSS Distributions 	ulong_t nent;
2600*c54f35caSApple OSS Distributions 	unsigned int i;
2601*c54f35caSApple OSS Distributions 
2602*c54f35caSApple OSS Distributions 	/*
2603*c54f35caSApple OSS Distributions 	 * Install our hooks into fork(2), exec(2), and exit(2).
2604*c54f35caSApple OSS Distributions 	 */
2605*c54f35caSApple OSS Distributions 	dtrace_fasttrap_fork_ptr = &fasttrap_fork;
2606*c54f35caSApple OSS Distributions 	dtrace_fasttrap_exit_ptr = &fasttrap_exec_exit;
2607*c54f35caSApple OSS Distributions 	dtrace_fasttrap_exec_ptr = &fasttrap_exec_exit;
2608*c54f35caSApple OSS Distributions 
2609*c54f35caSApple OSS Distributions 	/*
2610*c54f35caSApple OSS Distributions 	 * APPLE NOTE:  We size the maximum number of fasttrap probes
2611*c54f35caSApple OSS Distributions 	 * based on system memory. 100k probes per 256M of system memory.
2612*c54f35caSApple OSS Distributions 	 * Yes, this is a WAG.
2613*c54f35caSApple OSS Distributions 	 */
2614*c54f35caSApple OSS Distributions 	fasttrap_max = (sane_size >> 28) * 100000;
2615*c54f35caSApple OSS Distributions 
2616*c54f35caSApple OSS Distributions 	if (fasttrap_max == 0)
2617*c54f35caSApple OSS Distributions 		fasttrap_max = 50000;
2618*c54f35caSApple OSS Distributions 
2619*c54f35caSApple OSS Distributions 	fasttrap_total = 0;
2620*c54f35caSApple OSS Distributions 	fasttrap_retired = 0;
2621*c54f35caSApple OSS Distributions 
2622*c54f35caSApple OSS Distributions 	/*
2623*c54f35caSApple OSS Distributions 	 * Conjure up the tracepoints hashtable...
2624*c54f35caSApple OSS Distributions 	 */
2625*c54f35caSApple OSS Distributions #ifdef illumos
2626*c54f35caSApple OSS Distributions 	nent = ddi_getprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
2627*c54f35caSApple OSS Distributions 	    "fasttrap-hash-size", FASTTRAP_TPOINTS_DEFAULT_SIZE);
2628*c54f35caSApple OSS Distributions #else
2629*c54f35caSApple OSS Distributions 	nent = FASTTRAP_TPOINTS_DEFAULT_SIZE;
2630*c54f35caSApple OSS Distributions #endif
2631*c54f35caSApple OSS Distributions 
2632*c54f35caSApple OSS Distributions 	if (nent <= 0 || nent > 0x1000000)
2633*c54f35caSApple OSS Distributions 		nent = FASTTRAP_TPOINTS_DEFAULT_SIZE;
2634*c54f35caSApple OSS Distributions 
2635*c54f35caSApple OSS Distributions 	if ((nent & (nent - 1)) == 0)
2636*c54f35caSApple OSS Distributions 		fasttrap_tpoints.fth_nent = nent;
2637*c54f35caSApple OSS Distributions 	else
2638*c54f35caSApple OSS Distributions 		fasttrap_tpoints.fth_nent = 1 << fasttrap_highbit(nent);
2639*c54f35caSApple OSS Distributions 	ASSERT(fasttrap_tpoints.fth_nent > 0);
2640*c54f35caSApple OSS Distributions 	fasttrap_tpoints.fth_mask = fasttrap_tpoints.fth_nent - 1;
2641*c54f35caSApple OSS Distributions 	fasttrap_tpoints.fth_table = kmem_zalloc(fasttrap_tpoints.fth_nent *
2642*c54f35caSApple OSS Distributions 	    sizeof (fasttrap_bucket_t), KM_SLEEP);
2643*c54f35caSApple OSS Distributions 	ASSERT(fasttrap_tpoints.fth_table != NULL);
2644*c54f35caSApple OSS Distributions 
2645*c54f35caSApple OSS Distributions 	for (i = 0; i < fasttrap_tpoints.fth_nent; i++) {
2646*c54f35caSApple OSS Distributions 		lck_mtx_init(&fasttrap_tpoints.fth_table[i].ftb_mtx, &fasttrap_lck_grp,
2647*c54f35caSApple OSS Distributions 		    &fasttrap_lck_attr);
2648*c54f35caSApple OSS Distributions 	}
2649*c54f35caSApple OSS Distributions 
2650*c54f35caSApple OSS Distributions 	/*
2651*c54f35caSApple OSS Distributions 	 * ... and the providers hash table...
2652*c54f35caSApple OSS Distributions 	 */
2653*c54f35caSApple OSS Distributions 	nent = FASTTRAP_PROVIDERS_DEFAULT_SIZE;
2654*c54f35caSApple OSS Distributions 	if ((nent & (nent - 1)) == 0)
2655*c54f35caSApple OSS Distributions 		fasttrap_provs.fth_nent = nent;
2656*c54f35caSApple OSS Distributions 	else
2657*c54f35caSApple OSS Distributions 		fasttrap_provs.fth_nent = 1 << fasttrap_highbit(nent);
2658*c54f35caSApple OSS Distributions 	ASSERT(fasttrap_provs.fth_nent > 0);
2659*c54f35caSApple OSS Distributions 	fasttrap_provs.fth_mask = fasttrap_provs.fth_nent - 1;
2660*c54f35caSApple OSS Distributions 	fasttrap_provs.fth_table = kmem_zalloc(fasttrap_provs.fth_nent *
2661*c54f35caSApple OSS Distributions 	    sizeof (fasttrap_bucket_t), KM_SLEEP);
2662*c54f35caSApple OSS Distributions 	ASSERT(fasttrap_provs.fth_table != NULL);
2663*c54f35caSApple OSS Distributions 
2664*c54f35caSApple OSS Distributions 	for (i = 0; i < fasttrap_provs.fth_nent; i++) {
2665*c54f35caSApple OSS Distributions 		lck_mtx_init(&fasttrap_provs.fth_table[i].ftb_mtx, &fasttrap_lck_grp,
2666*c54f35caSApple OSS Distributions 		    &fasttrap_lck_attr);
2667*c54f35caSApple OSS Distributions 	}
2668*c54f35caSApple OSS Distributions 
2669*c54f35caSApple OSS Distributions 	/*
2670*c54f35caSApple OSS Distributions 	 * ... and the procs hash table.
2671*c54f35caSApple OSS Distributions 	 */
2672*c54f35caSApple OSS Distributions 	nent = FASTTRAP_PROCS_DEFAULT_SIZE;
2673*c54f35caSApple OSS Distributions 	if ((nent & (nent - 1)) == 0)
2674*c54f35caSApple OSS Distributions 		fasttrap_procs.fth_nent = nent;
2675*c54f35caSApple OSS Distributions 	else
2676*c54f35caSApple OSS Distributions 		fasttrap_procs.fth_nent = 1 << fasttrap_highbit(nent);
2677*c54f35caSApple OSS Distributions 	ASSERT(fasttrap_procs.fth_nent > 0);
2678*c54f35caSApple OSS Distributions 	fasttrap_procs.fth_mask = fasttrap_procs.fth_nent - 1;
2679*c54f35caSApple OSS Distributions 	fasttrap_procs.fth_table = kmem_zalloc(fasttrap_procs.fth_nent *
2680*c54f35caSApple OSS Distributions 	    sizeof (fasttrap_bucket_t), KM_SLEEP);
2681*c54f35caSApple OSS Distributions 	ASSERT(fasttrap_procs.fth_table != NULL);
2682*c54f35caSApple OSS Distributions 
2683*c54f35caSApple OSS Distributions #ifndef illumos
2684*c54f35caSApple OSS Distributions 	for (i = 0; i < fasttrap_procs.fth_nent; i++) {
2685*c54f35caSApple OSS Distributions 		lck_mtx_init(&fasttrap_procs.fth_table[i].ftb_mtx, &fasttrap_lck_grp,
2686*c54f35caSApple OSS Distributions 		    &fasttrap_lck_attr);
2687*c54f35caSApple OSS Distributions 	}
2688*c54f35caSApple OSS Distributions #endif
2689*c54f35caSApple OSS Distributions 
2690*c54f35caSApple OSS Distributions 	(void) dtrace_meta_register("fasttrap", &fasttrap_mops, NULL,
2691*c54f35caSApple OSS Distributions 	    &fasttrap_meta_id);
2692*c54f35caSApple OSS Distributions }
2693*c54f35caSApple OSS Distributions 
2694*c54f35caSApple OSS Distributions static int
_fasttrap_open(dev_t dev,int flags,int devtype,struct proc * p)2695*c54f35caSApple OSS Distributions _fasttrap_open(dev_t dev, int flags, int devtype, struct proc *p)
2696*c54f35caSApple OSS Distributions {
2697*c54f35caSApple OSS Distributions #pragma unused(dev, flags, devtype, p)
2698*c54f35caSApple OSS Distributions 	return  0;
2699*c54f35caSApple OSS Distributions }
2700*c54f35caSApple OSS Distributions 
2701*c54f35caSApple OSS Distributions static int
_fasttrap_ioctl(dev_t dev,u_long cmd,caddr_t data,int fflag,struct proc * p)2702*c54f35caSApple OSS Distributions _fasttrap_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
2703*c54f35caSApple OSS Distributions {
2704*c54f35caSApple OSS Distributions 	int err, rv = 0;
2705*c54f35caSApple OSS Distributions 	user_addr_t uaddrp;
2706*c54f35caSApple OSS Distributions 
2707*c54f35caSApple OSS Distributions 	if (proc_is64bit(p)) {
2708*c54f35caSApple OSS Distributions 		uaddrp = *(user_addr_t *)data;
2709*c54f35caSApple OSS Distributions 	} else {
2710*c54f35caSApple OSS Distributions 		uaddrp = (user_addr_t) *(uint32_t *)data;
2711*c54f35caSApple OSS Distributions 	}
2712*c54f35caSApple OSS Distributions 
2713*c54f35caSApple OSS Distributions 	err = fasttrap_ioctl(dev, cmd, uaddrp, fflag, CRED(), &rv);
2714*c54f35caSApple OSS Distributions 
2715*c54f35caSApple OSS Distributions 	/* XXX Darwin's BSD ioctls only return -1 or zero. Overload errno to mimic Solaris. 20 bits suffice. */
2716*c54f35caSApple OSS Distributions 	if (err != 0) {
2717*c54f35caSApple OSS Distributions 		ASSERT( (err & 0xfffff000) == 0 );
2718*c54f35caSApple OSS Distributions 		return (err & 0xfff); /* ioctl returns -1 and errno set to an error code < 4096 */
2719*c54f35caSApple OSS Distributions 	} else if (rv != 0) {
2720*c54f35caSApple OSS Distributions 		ASSERT( (rv & 0xfff00000) == 0 );
2721*c54f35caSApple OSS Distributions 		return (((rv & 0xfffff) << 12)); /* ioctl returns -1 and errno set to a return value >= 4096 */
2722*c54f35caSApple OSS Distributions 	} else
2723*c54f35caSApple OSS Distributions 		return 0;
2724*c54f35caSApple OSS Distributions }
2725*c54f35caSApple OSS Distributions 
2726*c54f35caSApple OSS Distributions static int fasttrap_inited = 0;
2727*c54f35caSApple OSS Distributions 
2728*c54f35caSApple OSS Distributions #define FASTTRAP_MAJOR  -24 /* let the kernel pick the device number */
2729*c54f35caSApple OSS Distributions 
2730*c54f35caSApple OSS Distributions static const struct cdevsw fasttrap_cdevsw =
2731*c54f35caSApple OSS Distributions {
2732*c54f35caSApple OSS Distributions 	.d_open = _fasttrap_open,
2733*c54f35caSApple OSS Distributions 	.d_close = eno_opcl,
2734*c54f35caSApple OSS Distributions 	.d_read = eno_rdwrt,
2735*c54f35caSApple OSS Distributions 	.d_write = eno_rdwrt,
2736*c54f35caSApple OSS Distributions 	.d_ioctl = _fasttrap_ioctl,
2737*c54f35caSApple OSS Distributions 	.d_stop = eno_stop,
2738*c54f35caSApple OSS Distributions 	.d_reset = eno_reset,
2739*c54f35caSApple OSS Distributions 	.d_select = eno_select,
2740*c54f35caSApple OSS Distributions 	.d_mmap = eno_mmap,
2741*c54f35caSApple OSS Distributions 	.d_strategy = eno_strat,
2742*c54f35caSApple OSS Distributions 	.d_reserved_1 = eno_getc,
2743*c54f35caSApple OSS Distributions 	.d_reserved_2 = eno_putc,
2744*c54f35caSApple OSS Distributions };
2745*c54f35caSApple OSS Distributions 
2746*c54f35caSApple OSS Distributions void fasttrap_init(void);
2747*c54f35caSApple OSS Distributions 
2748*c54f35caSApple OSS Distributions void
fasttrap_init(void)2749*c54f35caSApple OSS Distributions fasttrap_init( void )
2750*c54f35caSApple OSS Distributions {
2751*c54f35caSApple OSS Distributions 	/*
2752*c54f35caSApple OSS Distributions 	 * This method is now invoked from multiple places. Any open of /dev/dtrace,
2753*c54f35caSApple OSS Distributions 	 * also dtrace_init if the dtrace_dof_mode is DTRACE_DOF_MODE_NON_LAZY.
2754*c54f35caSApple OSS Distributions 	 *
2755*c54f35caSApple OSS Distributions 	 * The reason is to delay allocating the (rather large) resources as late as possible.
2756*c54f35caSApple OSS Distributions 	 */
2757*c54f35caSApple OSS Distributions 	if (!fasttrap_inited) {
2758*c54f35caSApple OSS Distributions 		int majdevno = cdevsw_add(FASTTRAP_MAJOR, &fasttrap_cdevsw);
2759*c54f35caSApple OSS Distributions 
2760*c54f35caSApple OSS Distributions 		if (majdevno < 0) {
2761*c54f35caSApple OSS Distributions 			// FIX ME! What kind of error reporting to do here?
2762*c54f35caSApple OSS Distributions 			printf("fasttrap_init: failed to allocate a major number!\n");
2763*c54f35caSApple OSS Distributions 			return;
2764*c54f35caSApple OSS Distributions 		}
2765*c54f35caSApple OSS Distributions 
2766*c54f35caSApple OSS Distributions 		dev_t device = makedev( (uint32_t)majdevno, 0 );
2767*c54f35caSApple OSS Distributions 		if (NULL == devfs_make_node( device, DEVFS_CHAR, UID_ROOT, GID_WHEEL, 0666, "fasttrap" )) {
2768*c54f35caSApple OSS Distributions 			return;
2769*c54f35caSApple OSS Distributions 		}
2770*c54f35caSApple OSS Distributions 
2771*c54f35caSApple OSS Distributions 		/*
2772*c54f35caSApple OSS Distributions 		 * fasttrap_probe_t's are variable in size. We use an array of zones to
2773*c54f35caSApple OSS Distributions 		 * cover the most common sizes.
2774*c54f35caSApple OSS Distributions 		 */
2775*c54f35caSApple OSS Distributions 		int i;
2776*c54f35caSApple OSS Distributions 		for (i=1; i<FASTTRAP_PROBE_T_ZONE_MAX_TRACEPOINTS; i++) {
2777*c54f35caSApple OSS Distributions 			fasttrap_probe_t_zones[i] =
2778*c54f35caSApple OSS Distributions 			    zone_create(fasttrap_probe_t_zone_names[i],
2779*c54f35caSApple OSS Distributions 				    offsetof(fasttrap_probe_t, ftp_tps[i]), ZC_NONE);
2780*c54f35caSApple OSS Distributions 		}
2781*c54f35caSApple OSS Distributions 
2782*c54f35caSApple OSS Distributions 
2783*c54f35caSApple OSS Distributions 		fasttrap_attach();
2784*c54f35caSApple OSS Distributions 
2785*c54f35caSApple OSS Distributions 		/*
2786*c54f35caSApple OSS Distributions 		 * Start the fasttrap cleanup thread
2787*c54f35caSApple OSS Distributions 		 */
2788*c54f35caSApple OSS Distributions 		kern_return_t res = kernel_thread_start_priority((thread_continue_t)fasttrap_pid_cleanup_cb, NULL, 46 /* BASEPRI_BACKGROUND */, &fasttrap_cleanup_thread);
2789*c54f35caSApple OSS Distributions 		if (res != KERN_SUCCESS) {
2790*c54f35caSApple OSS Distributions 			panic("Could not create fasttrap_cleanup_thread");
2791*c54f35caSApple OSS Distributions 		}
2792*c54f35caSApple OSS Distributions 		thread_set_thread_name(fasttrap_cleanup_thread, "dtrace_fasttrap_cleanup_thread");
2793*c54f35caSApple OSS Distributions 
2794*c54f35caSApple OSS Distributions 		fasttrap_retired_size = DEFAULT_RETIRED_SIZE;
2795*c54f35caSApple OSS Distributions 		fasttrap_retired_spec = kmem_zalloc(fasttrap_retired_size * sizeof(*fasttrap_retired_spec),
2796*c54f35caSApple OSS Distributions 					KM_SLEEP);
2797*c54f35caSApple OSS Distributions 
2798*c54f35caSApple OSS Distributions 		fasttrap_inited = 1;
2799*c54f35caSApple OSS Distributions 	}
2800*c54f35caSApple OSS Distributions }
2801*c54f35caSApple OSS Distributions 
2802*c54f35caSApple OSS Distributions #undef FASTTRAP_MAJOR
2803