1cd844e7aSJohn Birrell /*
2cd844e7aSJohn Birrell * CDDL HEADER START
3cd844e7aSJohn Birrell *
4cd844e7aSJohn Birrell * The contents of this file are subject to the terms of the
5cd844e7aSJohn Birrell * Common Development and Distribution License (the "License").
6cd844e7aSJohn Birrell * You may not use this file except in compliance with the License.
7cd844e7aSJohn Birrell *
8cd844e7aSJohn Birrell * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9cd844e7aSJohn Birrell * or http://www.opensolaris.org/os/licensing.
10cd844e7aSJohn Birrell * See the License for the specific language governing permissions
11cd844e7aSJohn Birrell * and limitations under the License.
12cd844e7aSJohn Birrell *
13cd844e7aSJohn Birrell * When distributing Covered Code, include this CDDL HEADER in each
14cd844e7aSJohn Birrell * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15cd844e7aSJohn Birrell * If applicable, add the following below this CDDL HEADER, with the
16cd844e7aSJohn Birrell * fields enclosed by brackets "[]" replaced with your own identifying
17cd844e7aSJohn Birrell * information: Portions Copyright [yyyy] [name of copyright owner]
18cd844e7aSJohn Birrell *
19cd844e7aSJohn Birrell * CDDL HEADER END
208605d1aeSRui Paulo *
218605d1aeSRui Paulo * Portions Copyright 2010 The FreeBSD Foundation
22cd844e7aSJohn Birrell */
23cd844e7aSJohn Birrell
24cd844e7aSJohn Birrell /*
255a1b490dSJohn Birrell * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
26cd844e7aSJohn Birrell * Use is subject to license terms.
27cd844e7aSJohn Birrell */
28cd844e7aSJohn Birrell
29c6d712caSPedro F. Giffuni /*
30e8baaa99SMark Johnston * Copyright (c) 2015, Joyent, Inc. All rights reserved.
31c6d712caSPedro F. Giffuni */
32cd844e7aSJohn Birrell
33cd844e7aSJohn Birrell #include <sys/atomic.h>
34cd844e7aSJohn Birrell #include <sys/errno.h>
35cd844e7aSJohn Birrell #include <sys/stat.h>
369e5787d2SMatt Macy #include <sys/endian.h>
37cd844e7aSJohn Birrell #include <sys/modctl.h>
38cd844e7aSJohn Birrell #include <sys/conf.h>
39cd844e7aSJohn Birrell #include <sys/systm.h>
40bc96366cSSteven Hartland #ifdef illumos
41cd844e7aSJohn Birrell #include <sys/ddi.h>
428605d1aeSRui Paulo #endif
43cd844e7aSJohn Birrell #include <sys/sunddi.h>
44cd844e7aSJohn Birrell #include <sys/cpuvar.h>
45cd844e7aSJohn Birrell #include <sys/kmem.h>
46bc96366cSSteven Hartland #ifdef illumos
47cd844e7aSJohn Birrell #include <sys/strsubr.h>
488605d1aeSRui Paulo #endif
49cd844e7aSJohn Birrell #include <sys/fasttrap.h>
50cd844e7aSJohn Birrell #include <sys/fasttrap_impl.h>
51cd844e7aSJohn Birrell #include <sys/fasttrap_isa.h>
52cd844e7aSJohn Birrell #include <sys/dtrace.h>
53cd844e7aSJohn Birrell #include <sys/dtrace_impl.h>
54cd844e7aSJohn Birrell #include <sys/sysmacros.h>
55cd844e7aSJohn Birrell #include <sys/proc.h>
569e5787d2SMatt Macy #undef AT_UID
579e5787d2SMatt Macy #undef AT_GID
58cd844e7aSJohn Birrell #include <sys/policy.h>
59bc96366cSSteven Hartland #ifdef illumos
60cd844e7aSJohn Birrell #include <util/qsort.h>
618605d1aeSRui Paulo #endif
628605d1aeSRui Paulo #include <sys/mutex.h>
638605d1aeSRui Paulo #include <sys/kernel.h>
64bc96366cSSteven Hartland #ifndef illumos
658605d1aeSRui Paulo #include <sys/dtrace_bsd.h>
660626f3e4SMark Johnston #include <sys/eventhandler.h>
67380344a7SMark Johnston #include <sys/rmlock.h>
686d1ffb50SMark Johnston #include <sys/sysent.h>
69314eeef2SStanislav Sedov #include <sys/sysctl.h>
70c6d712caSPedro F. Giffuni #include <sys/u8_textprep.h>
710626f3e4SMark Johnston #include <sys/user.h>
72380344a7SMark Johnston
730626f3e4SMark Johnston #include <vm/vm.h>
740626f3e4SMark Johnston #include <vm/pmap.h>
750626f3e4SMark Johnston #include <vm/vm_map.h>
760626f3e4SMark Johnston #include <vm/vm_param.h>
77380344a7SMark Johnston
788605d1aeSRui Paulo #include <cddl/dev/dtrace/dtrace_cddl.h>
798605d1aeSRui Paulo #endif
80cd844e7aSJohn Birrell
81cd844e7aSJohn Birrell /*
82cd844e7aSJohn Birrell * User-Land Trap-Based Tracing
83cd844e7aSJohn Birrell * ----------------------------
84cd844e7aSJohn Birrell *
85cd844e7aSJohn Birrell * The fasttrap provider allows DTrace consumers to instrument any user-level
86cd844e7aSJohn Birrell * instruction to gather data; this includes probes with semantic
87cd844e7aSJohn Birrell * signifigance like entry and return as well as simple offsets into the
88cd844e7aSJohn Birrell * function. While the specific techniques used are very ISA specific, the
89cd844e7aSJohn Birrell * methodology is generalizable to any architecture.
90cd844e7aSJohn Birrell *
91cd844e7aSJohn Birrell *
92cd844e7aSJohn Birrell * The General Methodology
93cd844e7aSJohn Birrell * -----------------------
94cd844e7aSJohn Birrell *
95cd844e7aSJohn Birrell * With the primary goal of tracing every user-land instruction and the
96cd844e7aSJohn Birrell * limitation that we can't trust user space so don't want to rely on much
97cd844e7aSJohn Birrell * information there, we begin by replacing the instructions we want to trace
98cd844e7aSJohn Birrell * with trap instructions. Each instruction we overwrite is saved into a hash
99cd844e7aSJohn Birrell * table keyed by process ID and pc address. When we enter the kernel due to
100cd844e7aSJohn Birrell * this trap instruction, we need the effects of the replaced instruction to
101cd844e7aSJohn Birrell * appear to have occurred before we proceed with the user thread's
102cd844e7aSJohn Birrell * execution.
103cd844e7aSJohn Birrell *
104cd844e7aSJohn Birrell * Each user level thread is represented by a ulwp_t structure which is
105cd844e7aSJohn Birrell * always easily accessible through a register. The most basic way to produce
106cd844e7aSJohn Birrell * the effects of the instruction we replaced is to copy that instruction out
107cd844e7aSJohn Birrell * to a bit of scratch space reserved in the user thread's ulwp_t structure
108cd844e7aSJohn Birrell * (a sort of kernel-private thread local storage), set the PC to that
109cd844e7aSJohn Birrell * scratch space and single step. When we reenter the kernel after single
110cd844e7aSJohn Birrell * stepping the instruction we must then adjust the PC to point to what would
111cd844e7aSJohn Birrell * normally be the next instruction. Of course, special care must be taken
112cd844e7aSJohn Birrell * for branches and jumps, but these represent such a small fraction of any
113cd844e7aSJohn Birrell * instruction set that writing the code to emulate these in the kernel is
114cd844e7aSJohn Birrell * not too difficult.
115cd844e7aSJohn Birrell *
116cd844e7aSJohn Birrell * Return probes may require several tracepoints to trace every return site,
117cd844e7aSJohn Birrell * and, conversely, each tracepoint may activate several probes (the entry
118cd844e7aSJohn Birrell * and offset 0 probes, for example). To solve this muliplexing problem,
119cd844e7aSJohn Birrell * tracepoints contain lists of probes to activate and probes contain lists
120cd844e7aSJohn Birrell * of tracepoints to enable. If a probe is activated, it adds its ID to
121cd844e7aSJohn Birrell * existing tracepoints or creates new ones as necessary.
122cd844e7aSJohn Birrell *
123cd844e7aSJohn Birrell * Most probes are activated _before_ the instruction is executed, but return
124cd844e7aSJohn Birrell * probes are activated _after_ the effects of the last instruction of the
125cd844e7aSJohn Birrell * function are visible. Return probes must be fired _after_ we have
126cd844e7aSJohn Birrell * single-stepped the instruction whereas all other probes are fired
127cd844e7aSJohn Birrell * beforehand.
128cd844e7aSJohn Birrell *
129cd844e7aSJohn Birrell *
130cd844e7aSJohn Birrell * Lock Ordering
131cd844e7aSJohn Birrell * -------------
132cd844e7aSJohn Birrell *
133cd844e7aSJohn Birrell * The lock ordering below -- both internally and with respect to the DTrace
134cd844e7aSJohn Birrell * framework -- is a little tricky and bears some explanation. Each provider
135cd844e7aSJohn Birrell * has a lock (ftp_mtx) that protects its members including reference counts
136cd844e7aSJohn Birrell * for enabled probes (ftp_rcount), consumers actively creating probes
137cd844e7aSJohn Birrell * (ftp_ccount) and USDT consumers (ftp_mcount); all three prevent a provider
138cd844e7aSJohn Birrell * from being freed. A provider is looked up by taking the bucket lock for the
139cd844e7aSJohn Birrell * provider hash table, and is returned with its lock held. The provider lock
140cd844e7aSJohn Birrell * may be taken in functions invoked by the DTrace framework, but may not be
141cd844e7aSJohn Birrell * held while calling functions in the DTrace framework.
142cd844e7aSJohn Birrell *
143cd844e7aSJohn Birrell * To ensure consistency over multiple calls to the DTrace framework, the
144cd844e7aSJohn Birrell * creation lock (ftp_cmtx) should be held. Naturally, the creation lock may
145cd844e7aSJohn Birrell * not be taken when holding the provider lock as that would create a cyclic
146cd844e7aSJohn Birrell * lock ordering. In situations where one would naturally take the provider
147cd844e7aSJohn Birrell * lock and then the creation lock, we instead up a reference count to prevent
148cd844e7aSJohn Birrell * the provider from disappearing, drop the provider lock, and acquire the
149cd844e7aSJohn Birrell * creation lock.
150cd844e7aSJohn Birrell *
151cd844e7aSJohn Birrell * Briefly:
152cd844e7aSJohn Birrell * bucket lock before provider lock
153cd844e7aSJohn Birrell * DTrace before provider lock
154cd844e7aSJohn Birrell * creation lock before DTrace
155cd844e7aSJohn Birrell * never hold the provider lock and creation lock simultaneously
156cd844e7aSJohn Birrell */
157cd844e7aSJohn Birrell
1588605d1aeSRui Paulo static d_open_t fasttrap_open;
1598605d1aeSRui Paulo static d_ioctl_t fasttrap_ioctl;
1608605d1aeSRui Paulo
1618605d1aeSRui Paulo static struct cdevsw fasttrap_cdevsw = {
1628605d1aeSRui Paulo .d_version = D_VERSION,
1638605d1aeSRui Paulo .d_open = fasttrap_open,
1648605d1aeSRui Paulo .d_ioctl = fasttrap_ioctl,
1658605d1aeSRui Paulo .d_name = "fasttrap",
1668605d1aeSRui Paulo };
1678605d1aeSRui Paulo static struct cdev *fasttrap_cdev;
168cd844e7aSJohn Birrell static dtrace_meta_provider_id_t fasttrap_meta_id;
169cd844e7aSJohn Birrell
170427bc75eSMark Johnston static struct proc *fasttrap_cleanup_proc;
1718605d1aeSRui Paulo static struct mtx fasttrap_cleanup_mtx;
172427bc75eSMark Johnston static uint_t fasttrap_cleanup_work, fasttrap_cleanup_drain, fasttrap_cleanup_cv;
173cd844e7aSJohn Birrell
174cd844e7aSJohn Birrell /*
175cd844e7aSJohn Birrell * Generation count on modifications to the global tracepoint lookup table.
176cd844e7aSJohn Birrell */
177cd844e7aSJohn Birrell static volatile uint64_t fasttrap_mod_gen;
178cd844e7aSJohn Birrell
179cd844e7aSJohn Birrell /*
180cd844e7aSJohn Birrell * When the fasttrap provider is loaded, fasttrap_max is set to either
181314eeef2SStanislav Sedov * FASTTRAP_MAX_DEFAULT, or the value for fasttrap-max-probes in the
182314eeef2SStanislav Sedov * fasttrap.conf file (Illumos), or the value provied in the loader.conf (FreeBSD).
183314eeef2SStanislav Sedov * Each time a probe is created, fasttrap_total is incremented by the number
184314eeef2SStanislav Sedov * of tracepoints that may be associated with that probe; fasttrap_total is capped
185314eeef2SStanislav Sedov * at fasttrap_max.
186cd844e7aSJohn Birrell */
187cd844e7aSJohn Birrell #define FASTTRAP_MAX_DEFAULT 250000
188314eeef2SStanislav Sedov static uint32_t fasttrap_max = FASTTRAP_MAX_DEFAULT;
189cd844e7aSJohn Birrell static uint32_t fasttrap_total;
190cd844e7aSJohn Birrell
1919f4c7ba4SPedro F. Giffuni /*
1929f4c7ba4SPedro F. Giffuni * Copyright (c) 2011, Joyent, Inc. All rights reserved.
1939f4c7ba4SPedro F. Giffuni */
194cd844e7aSJohn Birrell
195cd844e7aSJohn Birrell #define FASTTRAP_TPOINTS_DEFAULT_SIZE 0x4000
196cd844e7aSJohn Birrell #define FASTTRAP_PROVIDERS_DEFAULT_SIZE 0x100
197cd844e7aSJohn Birrell #define FASTTRAP_PROCS_DEFAULT_SIZE 0x100
198cd844e7aSJohn Birrell
199cd844e7aSJohn Birrell #define FASTTRAP_PID_NAME "pid"
200cd844e7aSJohn Birrell
201cd844e7aSJohn Birrell fasttrap_hash_t fasttrap_tpoints;
202cd844e7aSJohn Birrell static fasttrap_hash_t fasttrap_provs;
203cd844e7aSJohn Birrell static fasttrap_hash_t fasttrap_procs;
204cd844e7aSJohn Birrell
205cd844e7aSJohn Birrell static uint64_t fasttrap_pid_count; /* pid ref count */
206cd844e7aSJohn Birrell static kmutex_t fasttrap_count_mtx; /* lock on ref count */
207cd844e7aSJohn Birrell
208cd844e7aSJohn Birrell #define FASTTRAP_ENABLE_FAIL 1
209cd844e7aSJohn Birrell #define FASTTRAP_ENABLE_PARTIAL 2
210cd844e7aSJohn Birrell
211cd844e7aSJohn Birrell static int fasttrap_tracepoint_enable(proc_t *, fasttrap_probe_t *, uint_t);
212cd844e7aSJohn Birrell static void fasttrap_tracepoint_disable(proc_t *, fasttrap_probe_t *, uint_t);
213cd844e7aSJohn Birrell
214cd844e7aSJohn Birrell static fasttrap_provider_t *fasttrap_provider_lookup(pid_t, const char *,
215cd844e7aSJohn Birrell const dtrace_pattr_t *);
216cd844e7aSJohn Birrell static void fasttrap_provider_retire(pid_t, const char *, int);
217cd844e7aSJohn Birrell static void fasttrap_provider_free(fasttrap_provider_t *);
218cd844e7aSJohn Birrell
219cd844e7aSJohn Birrell static fasttrap_proc_t *fasttrap_proc_lookup(pid_t);
220cd844e7aSJohn Birrell static void fasttrap_proc_release(fasttrap_proc_t *);
221cd844e7aSJohn Birrell
222bc96366cSSteven Hartland #ifndef illumos
2230626f3e4SMark Johnston static void fasttrap_thread_dtor(void *, struct thread *);
2240626f3e4SMark Johnston #endif
2250626f3e4SMark Johnston
226cd844e7aSJohn Birrell #define FASTTRAP_PROVS_INDEX(pid, name) \
227cd844e7aSJohn Birrell ((fasttrap_hash_str(name) + (pid)) & fasttrap_provs.fth_mask)
228cd844e7aSJohn Birrell
229cd844e7aSJohn Birrell #define FASTTRAP_PROCS_INDEX(pid) ((pid) & fasttrap_procs.fth_mask)
230cd844e7aSJohn Birrell
231bc96366cSSteven Hartland #ifndef illumos
232380344a7SMark Johnston struct rmlock fasttrap_tp_lock;
2330626f3e4SMark Johnston static eventhandler_tag fasttrap_thread_dtor_tag;
2349f4ee617SRui Paulo #endif
2359f4ee617SRui Paulo
236314eeef2SStanislav Sedov static unsigned long tpoints_hash_size = FASTTRAP_TPOINTS_DEFAULT_SIZE;
237314eeef2SStanislav Sedov
238314eeef2SStanislav Sedov #ifdef __FreeBSD__
239314eeef2SStanislav Sedov SYSCTL_DECL(_kern_dtrace);
2407029da5cSPawel Biernacki SYSCTL_NODE(_kern_dtrace, OID_AUTO, fasttrap, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
2417029da5cSPawel Biernacki "DTrace fasttrap parameters");
242314eeef2SStanislav Sedov SYSCTL_UINT(_kern_dtrace_fasttrap, OID_AUTO, max_probes, CTLFLAG_RWTUN, &fasttrap_max,
243314eeef2SStanislav Sedov FASTTRAP_MAX_DEFAULT, "Maximum number of fasttrap probes");
244314eeef2SStanislav Sedov SYSCTL_ULONG(_kern_dtrace_fasttrap, OID_AUTO, tpoints_hash_size, CTLFLAG_RDTUN, &tpoints_hash_size,
245314eeef2SStanislav Sedov FASTTRAP_TPOINTS_DEFAULT_SIZE, "Size of the tracepoint hash table");
246314eeef2SStanislav Sedov #endif
247314eeef2SStanislav Sedov
248cd844e7aSJohn Birrell static int
fasttrap_highbit(ulong_t i)249cd844e7aSJohn Birrell fasttrap_highbit(ulong_t i)
250cd844e7aSJohn Birrell {
251cd844e7aSJohn Birrell int h = 1;
252cd844e7aSJohn Birrell
253cd844e7aSJohn Birrell if (i == 0)
254cd844e7aSJohn Birrell return (0);
255cd844e7aSJohn Birrell #ifdef _LP64
256cd844e7aSJohn Birrell if (i & 0xffffffff00000000ul) {
257cd844e7aSJohn Birrell h += 32; i >>= 32;
258cd844e7aSJohn Birrell }
259cd844e7aSJohn Birrell #endif
260cd844e7aSJohn Birrell if (i & 0xffff0000) {
261cd844e7aSJohn Birrell h += 16; i >>= 16;
262cd844e7aSJohn Birrell }
263cd844e7aSJohn Birrell if (i & 0xff00) {
264cd844e7aSJohn Birrell h += 8; i >>= 8;
265cd844e7aSJohn Birrell }
266cd844e7aSJohn Birrell if (i & 0xf0) {
267cd844e7aSJohn Birrell h += 4; i >>= 4;
268cd844e7aSJohn Birrell }
269cd844e7aSJohn Birrell if (i & 0xc) {
270cd844e7aSJohn Birrell h += 2; i >>= 2;
271cd844e7aSJohn Birrell }
272cd844e7aSJohn Birrell if (i & 0x2) {
273cd844e7aSJohn Birrell h += 1;
274cd844e7aSJohn Birrell }
275cd844e7aSJohn Birrell return (h);
276cd844e7aSJohn Birrell }
277cd844e7aSJohn Birrell
278cd844e7aSJohn Birrell static uint_t
fasttrap_hash_str(const char * p)279cd844e7aSJohn Birrell fasttrap_hash_str(const char *p)
280cd844e7aSJohn Birrell {
281cd844e7aSJohn Birrell unsigned int g;
282cd844e7aSJohn Birrell uint_t hval = 0;
283cd844e7aSJohn Birrell
284cd844e7aSJohn Birrell while (*p) {
285cd844e7aSJohn Birrell hval = (hval << 4) + *p++;
286cd844e7aSJohn Birrell if ((g = (hval & 0xf0000000)) != 0)
287cd844e7aSJohn Birrell hval ^= g >> 24;
288cd844e7aSJohn Birrell hval &= ~g;
289cd844e7aSJohn Birrell }
290cd844e7aSJohn Birrell return (hval);
291cd844e7aSJohn Birrell }
292cd844e7aSJohn Birrell
293cd844e7aSJohn Birrell void
fasttrap_sigtrap(proc_t * p,kthread_t * t,uintptr_t pc)294cd844e7aSJohn Birrell fasttrap_sigtrap(proc_t *p, kthread_t *t, uintptr_t pc)
295cd844e7aSJohn Birrell {
2968e7127fdSMark Johnston ksiginfo_t ksi;
297cd844e7aSJohn Birrell
2988e7127fdSMark Johnston ksiginfo_init(&ksi);
2998e7127fdSMark Johnston ksi.ksi_signo = SIGTRAP;
3008e7127fdSMark Johnston ksi.ksi_code = TRAP_DTRACE;
3018e7127fdSMark Johnston ksi.ksi_addr = (caddr_t)pc;
3028605d1aeSRui Paulo PROC_LOCK(p);
3038e7127fdSMark Johnston (void)tdsendsignal(p, t, SIGTRAP, &ksi);
3048605d1aeSRui Paulo PROC_UNLOCK(p);
305cd844e7aSJohn Birrell }
306cd844e7aSJohn Birrell
307bc96366cSSteven Hartland #ifndef illumos
3080626f3e4SMark Johnston /*
3090626f3e4SMark Johnston * Obtain a chunk of scratch space in the address space of the target process.
3100626f3e4SMark Johnston */
3110626f3e4SMark Johnston fasttrap_scrspace_t *
fasttrap_scraddr(struct thread * td,fasttrap_proc_t * fprc)3120626f3e4SMark Johnston fasttrap_scraddr(struct thread *td, fasttrap_proc_t *fprc)
3130626f3e4SMark Johnston {
3140626f3e4SMark Johnston fasttrap_scrblock_t *scrblk;
3150626f3e4SMark Johnston fasttrap_scrspace_t *scrspc;
3160626f3e4SMark Johnston struct proc *p;
3170626f3e4SMark Johnston vm_offset_t addr;
3180626f3e4SMark Johnston int error, i;
3190626f3e4SMark Johnston
3200626f3e4SMark Johnston scrspc = NULL;
3210626f3e4SMark Johnston if (td->t_dtrace_sscr != NULL) {
3220626f3e4SMark Johnston /* If the thread already has scratch space, we're done. */
3230626f3e4SMark Johnston scrspc = (fasttrap_scrspace_t *)td->t_dtrace_sscr;
3240626f3e4SMark Johnston return (scrspc);
3250626f3e4SMark Johnston }
3260626f3e4SMark Johnston
3270626f3e4SMark Johnston p = td->td_proc;
3280626f3e4SMark Johnston
3290626f3e4SMark Johnston mutex_enter(&fprc->ftpc_mtx);
3300626f3e4SMark Johnston if (LIST_EMPTY(&fprc->ftpc_fscr)) {
3310626f3e4SMark Johnston /*
3320626f3e4SMark Johnston * No scratch space is available, so we'll map a new scratch
3330626f3e4SMark Johnston * space block into the traced process' address space.
3340626f3e4SMark Johnston */
3350626f3e4SMark Johnston addr = 0;
3360626f3e4SMark Johnston error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &addr,
337*3a56cfedSMark Johnston FASTTRAP_SCRBLOCK_SIZE, 0, VMFS_ANY_SPACE,
338*3a56cfedSMark Johnston VM_PROT_READ | VM_PROT_EXECUTE,
339*3a56cfedSMark Johnston VM_PROT_READ | VM_PROT_EXECUTE, MAP_COPY_ON_WRITE);
3400626f3e4SMark Johnston if (error != KERN_SUCCESS)
3410626f3e4SMark Johnston goto done;
3420626f3e4SMark Johnston
3430626f3e4SMark Johnston scrblk = malloc(sizeof(*scrblk), M_SOLARIS, M_WAITOK);
3440626f3e4SMark Johnston scrblk->ftsb_addr = addr;
3450626f3e4SMark Johnston LIST_INSERT_HEAD(&fprc->ftpc_scrblks, scrblk, ftsb_next);
3460626f3e4SMark Johnston
3470626f3e4SMark Johnston /*
3480626f3e4SMark Johnston * Carve the block up into chunks and put them on the free list.
3490626f3e4SMark Johnston */
3500626f3e4SMark Johnston for (i = 0;
3510626f3e4SMark Johnston i < FASTTRAP_SCRBLOCK_SIZE / FASTTRAP_SCRSPACE_SIZE; i++) {
3520626f3e4SMark Johnston scrspc = malloc(sizeof(*scrspc), M_SOLARIS, M_WAITOK);
3530626f3e4SMark Johnston scrspc->ftss_addr = addr +
3540626f3e4SMark Johnston i * FASTTRAP_SCRSPACE_SIZE;
3550626f3e4SMark Johnston LIST_INSERT_HEAD(&fprc->ftpc_fscr, scrspc,
3560626f3e4SMark Johnston ftss_next);
3570626f3e4SMark Johnston }
3580626f3e4SMark Johnston }
3590626f3e4SMark Johnston
3600626f3e4SMark Johnston /*
3610626f3e4SMark Johnston * Take the first scratch chunk off the free list, put it on the
3620626f3e4SMark Johnston * allocated list, and return its address.
3630626f3e4SMark Johnston */
3640626f3e4SMark Johnston scrspc = LIST_FIRST(&fprc->ftpc_fscr);
3650626f3e4SMark Johnston LIST_REMOVE(scrspc, ftss_next);
3660626f3e4SMark Johnston LIST_INSERT_HEAD(&fprc->ftpc_ascr, scrspc, ftss_next);
3670626f3e4SMark Johnston
3680626f3e4SMark Johnston /*
3690626f3e4SMark Johnston * This scratch space is reserved for use by td until the thread exits.
3700626f3e4SMark Johnston */
3710626f3e4SMark Johnston td->t_dtrace_sscr = scrspc;
3720626f3e4SMark Johnston
3730626f3e4SMark Johnston done:
3740626f3e4SMark Johnston mutex_exit(&fprc->ftpc_mtx);
3750626f3e4SMark Johnston
3760626f3e4SMark Johnston return (scrspc);
3770626f3e4SMark Johnston }
3780626f3e4SMark Johnston
3790626f3e4SMark Johnston /*
3800626f3e4SMark Johnston * Return any allocated per-thread scratch space chunks back to the process'
3810626f3e4SMark Johnston * free list.
3820626f3e4SMark Johnston */
3830626f3e4SMark Johnston static void
fasttrap_thread_dtor(void * arg __unused,struct thread * td)3840626f3e4SMark Johnston fasttrap_thread_dtor(void *arg __unused, struct thread *td)
3850626f3e4SMark Johnston {
3860626f3e4SMark Johnston fasttrap_bucket_t *bucket;
3870626f3e4SMark Johnston fasttrap_proc_t *fprc;
3880626f3e4SMark Johnston fasttrap_scrspace_t *scrspc;
3890626f3e4SMark Johnston pid_t pid;
3900626f3e4SMark Johnston
3910626f3e4SMark Johnston if (td->t_dtrace_sscr == NULL)
3920626f3e4SMark Johnston return;
3930626f3e4SMark Johnston
3940626f3e4SMark Johnston pid = td->td_proc->p_pid;
3950626f3e4SMark Johnston bucket = &fasttrap_procs.fth_table[FASTTRAP_PROCS_INDEX(pid)];
3960626f3e4SMark Johnston fprc = NULL;
3970626f3e4SMark Johnston
3980626f3e4SMark Johnston /* Look up the fasttrap process handle for this process. */
3990626f3e4SMark Johnston mutex_enter(&bucket->ftb_mtx);
4000626f3e4SMark Johnston for (fprc = bucket->ftb_data; fprc != NULL; fprc = fprc->ftpc_next) {
4010626f3e4SMark Johnston if (fprc->ftpc_pid == pid) {
4020626f3e4SMark Johnston mutex_enter(&fprc->ftpc_mtx);
4030626f3e4SMark Johnston mutex_exit(&bucket->ftb_mtx);
4040626f3e4SMark Johnston break;
4050626f3e4SMark Johnston }
4060626f3e4SMark Johnston }
4070626f3e4SMark Johnston if (fprc == NULL) {
4080626f3e4SMark Johnston mutex_exit(&bucket->ftb_mtx);
4090626f3e4SMark Johnston return;
4100626f3e4SMark Johnston }
4110626f3e4SMark Johnston
4120626f3e4SMark Johnston scrspc = (fasttrap_scrspace_t *)td->t_dtrace_sscr;
4130626f3e4SMark Johnston LIST_REMOVE(scrspc, ftss_next);
4140626f3e4SMark Johnston LIST_INSERT_HEAD(&fprc->ftpc_fscr, scrspc, ftss_next);
4150626f3e4SMark Johnston
4160626f3e4SMark Johnston mutex_exit(&fprc->ftpc_mtx);
4170626f3e4SMark Johnston }
4180626f3e4SMark Johnston #endif
4190626f3e4SMark Johnston
420cd844e7aSJohn Birrell /*
421cd844e7aSJohn Birrell * This function ensures that no threads are actively using the memory
422cd844e7aSJohn Birrell * associated with probes that were formerly live.
423cd844e7aSJohn Birrell */
424cd844e7aSJohn Birrell static void
fasttrap_mod_barrier(uint64_t gen)425cd844e7aSJohn Birrell fasttrap_mod_barrier(uint64_t gen)
426cd844e7aSJohn Birrell {
427cd844e7aSJohn Birrell int i;
428cd844e7aSJohn Birrell
429cd844e7aSJohn Birrell if (gen < fasttrap_mod_gen)
430cd844e7aSJohn Birrell return;
431cd844e7aSJohn Birrell
432cd844e7aSJohn Birrell fasttrap_mod_gen++;
433cd844e7aSJohn Birrell
434380344a7SMark Johnston #ifdef illumos
4359f4ee617SRui Paulo CPU_FOREACH(i) {
4369f4ee617SRui Paulo mutex_enter(&fasttrap_cpuc_pid_lock[i]);
4379f4ee617SRui Paulo mutex_exit(&fasttrap_cpuc_pid_lock[i]);
438cd844e7aSJohn Birrell }
439380344a7SMark Johnston #else
440380344a7SMark Johnston rm_wlock(&fasttrap_tp_lock);
441380344a7SMark Johnston rm_wunlock(&fasttrap_tp_lock);
442380344a7SMark Johnston #endif
443cd844e7aSJohn Birrell }
444cd844e7aSJohn Birrell
445cd844e7aSJohn Birrell /*
446427bc75eSMark Johnston * This function performs asynchronous cleanup of fasttrap providers. The
447427bc75eSMark Johnston * Solaris implementation of this mechanism use a timeout that's activated in
448427bc75eSMark Johnston * fasttrap_pid_cleanup(), but this doesn't work in FreeBSD: one may sleep while
449427bc75eSMark Johnston * holding the DTrace mutexes, but it is unsafe to sleep in a callout handler.
450427bc75eSMark Johnston * Thus we use a dedicated process to perform the cleanup when requested.
451cd844e7aSJohn Birrell */
452cd844e7aSJohn Birrell /*ARGSUSED*/
453cd844e7aSJohn Birrell static void
fasttrap_pid_cleanup_cb(void * data)454cd844e7aSJohn Birrell fasttrap_pid_cleanup_cb(void *data)
455cd844e7aSJohn Birrell {
456cd844e7aSJohn Birrell fasttrap_provider_t **fpp, *fp;
457cd844e7aSJohn Birrell fasttrap_bucket_t *bucket;
458cd844e7aSJohn Birrell dtrace_provider_id_t provid;
4599f4c7ba4SPedro F. Giffuni int i, later = 0, rval;
460cd844e7aSJohn Birrell
461427bc75eSMark Johnston mtx_lock(&fasttrap_cleanup_mtx);
462427bc75eSMark Johnston while (!fasttrap_cleanup_drain || later > 0) {
463cd844e7aSJohn Birrell fasttrap_cleanup_work = 0;
4648605d1aeSRui Paulo mtx_unlock(&fasttrap_cleanup_mtx);
465cd844e7aSJohn Birrell
466cd844e7aSJohn Birrell later = 0;
467cd844e7aSJohn Birrell
468cd844e7aSJohn Birrell /*
469cd844e7aSJohn Birrell * Iterate over all the providers trying to remove the marked
470cd844e7aSJohn Birrell * ones. If a provider is marked but not retired, we just
471cd844e7aSJohn Birrell * have to take a crack at removing it -- it's no big deal if
472cd844e7aSJohn Birrell * we can't.
473cd844e7aSJohn Birrell */
474cd844e7aSJohn Birrell for (i = 0; i < fasttrap_provs.fth_nent; i++) {
475cd844e7aSJohn Birrell bucket = &fasttrap_provs.fth_table[i];
476cd844e7aSJohn Birrell mutex_enter(&bucket->ftb_mtx);
477cd844e7aSJohn Birrell fpp = (fasttrap_provider_t **)&bucket->ftb_data;
478cd844e7aSJohn Birrell
479cd844e7aSJohn Birrell while ((fp = *fpp) != NULL) {
480cd844e7aSJohn Birrell if (!fp->ftp_marked) {
481cd844e7aSJohn Birrell fpp = &fp->ftp_next;
482cd844e7aSJohn Birrell continue;
483cd844e7aSJohn Birrell }
484cd844e7aSJohn Birrell
485cd844e7aSJohn Birrell mutex_enter(&fp->ftp_mtx);
486cd844e7aSJohn Birrell
487cd844e7aSJohn Birrell /*
488cd844e7aSJohn Birrell * If this provider has consumers actively
489cd844e7aSJohn Birrell * creating probes (ftp_ccount) or is a USDT
490cd844e7aSJohn Birrell * provider (ftp_mcount), we can't unregister
491cd844e7aSJohn Birrell * or even condense.
492cd844e7aSJohn Birrell */
493cd844e7aSJohn Birrell if (fp->ftp_ccount != 0 ||
494cd844e7aSJohn Birrell fp->ftp_mcount != 0) {
495cd844e7aSJohn Birrell mutex_exit(&fp->ftp_mtx);
496cd844e7aSJohn Birrell fp->ftp_marked = 0;
497cd844e7aSJohn Birrell continue;
498cd844e7aSJohn Birrell }
499cd844e7aSJohn Birrell
500cd844e7aSJohn Birrell if (!fp->ftp_retired || fp->ftp_rcount != 0)
501cd844e7aSJohn Birrell fp->ftp_marked = 0;
502cd844e7aSJohn Birrell
503cd844e7aSJohn Birrell mutex_exit(&fp->ftp_mtx);
504cd844e7aSJohn Birrell
505cd844e7aSJohn Birrell /*
506cd844e7aSJohn Birrell * If we successfully unregister this
507cd844e7aSJohn Birrell * provider we can remove it from the hash
508cd844e7aSJohn Birrell * chain and free the memory. If our attempt
509cd844e7aSJohn Birrell * to unregister fails and this is a retired
510cd844e7aSJohn Birrell * provider, increment our flag to try again
511cd844e7aSJohn Birrell * pretty soon. If we've consumed more than
512cd844e7aSJohn Birrell * half of our total permitted number of
513cd844e7aSJohn Birrell * probes call dtrace_condense() to try to
514cd844e7aSJohn Birrell * clean out the unenabled probes.
515cd844e7aSJohn Birrell */
516cd844e7aSJohn Birrell provid = fp->ftp_provid;
5179f4c7ba4SPedro F. Giffuni if ((rval = dtrace_unregister(provid)) != 0) {
518cd844e7aSJohn Birrell if (fasttrap_total > fasttrap_max / 2)
519cd844e7aSJohn Birrell (void) dtrace_condense(provid);
5209f4c7ba4SPedro F. Giffuni
5219f4c7ba4SPedro F. Giffuni if (rval == EAGAIN)
5229f4c7ba4SPedro F. Giffuni fp->ftp_marked = 1;
5239f4c7ba4SPedro F. Giffuni
524cd844e7aSJohn Birrell later += fp->ftp_marked;
525cd844e7aSJohn Birrell fpp = &fp->ftp_next;
526cd844e7aSJohn Birrell } else {
527cd844e7aSJohn Birrell *fpp = fp->ftp_next;
528cd844e7aSJohn Birrell fasttrap_provider_free(fp);
529cd844e7aSJohn Birrell }
530cd844e7aSJohn Birrell }
531cd844e7aSJohn Birrell mutex_exit(&bucket->ftb_mtx);
532cd844e7aSJohn Birrell }
5338605d1aeSRui Paulo mtx_lock(&fasttrap_cleanup_mtx);
534cd844e7aSJohn Birrell
535cd844e7aSJohn Birrell /*
536427bc75eSMark Johnston * If we were unable to retire a provider, try again after a
537427bc75eSMark Johnston * second. This situation can occur in certain circumstances
538427bc75eSMark Johnston * where providers cannot be unregistered even though they have
539427bc75eSMark Johnston * no probes enabled because of an execution of dtrace -l or
540427bc75eSMark Johnston * something similar.
541cd844e7aSJohn Birrell */
542427bc75eSMark Johnston if (later > 0 || fasttrap_cleanup_work ||
543427bc75eSMark Johnston fasttrap_cleanup_drain) {
544427bc75eSMark Johnston mtx_unlock(&fasttrap_cleanup_mtx);
545427bc75eSMark Johnston pause("ftclean", hz);
546427bc75eSMark Johnston mtx_lock(&fasttrap_cleanup_mtx);
547427bc75eSMark Johnston } else
548427bc75eSMark Johnston mtx_sleep(&fasttrap_cleanup_cv, &fasttrap_cleanup_mtx,
549427bc75eSMark Johnston 0, "ftcl", 0);
5509f4c7ba4SPedro F. Giffuni }
5519f4c7ba4SPedro F. Giffuni
552427bc75eSMark Johnston /*
553427bc75eSMark Johnston * Wake up the thread in fasttrap_unload() now that we're done.
554427bc75eSMark Johnston */
555427bc75eSMark Johnston wakeup(&fasttrap_cleanup_drain);
556427bc75eSMark Johnston mtx_unlock(&fasttrap_cleanup_mtx);
557cd844e7aSJohn Birrell
558427bc75eSMark Johnston kthread_exit();
559cd844e7aSJohn Birrell }
560cd844e7aSJohn Birrell
561cd844e7aSJohn Birrell /*
562cd844e7aSJohn Birrell * Activates the asynchronous cleanup mechanism.
563cd844e7aSJohn Birrell */
564cd844e7aSJohn Birrell static void
fasttrap_pid_cleanup(void)565cd844e7aSJohn Birrell fasttrap_pid_cleanup(void)
566cd844e7aSJohn Birrell {
5678605d1aeSRui Paulo
5688605d1aeSRui Paulo mtx_lock(&fasttrap_cleanup_mtx);
569427bc75eSMark Johnston if (!fasttrap_cleanup_work) {
570cd844e7aSJohn Birrell fasttrap_cleanup_work = 1;
571427bc75eSMark Johnston wakeup(&fasttrap_cleanup_cv);
572427bc75eSMark Johnston }
5738605d1aeSRui Paulo mtx_unlock(&fasttrap_cleanup_mtx);
574cd844e7aSJohn Birrell }
575cd844e7aSJohn Birrell
576cd844e7aSJohn Birrell /*
577cd844e7aSJohn Birrell * This is called from cfork() via dtrace_fasttrap_fork(). The child
5785a1b490dSJohn Birrell * process's address space is (roughly) a copy of the parent process's so
579cd844e7aSJohn Birrell * we have to remove all the instrumentation we had previously enabled in the
580cd844e7aSJohn Birrell * parent.
581cd844e7aSJohn Birrell */
582cd844e7aSJohn Birrell static void
fasttrap_fork(proc_t * p,proc_t * cp)583cd844e7aSJohn Birrell fasttrap_fork(proc_t *p, proc_t *cp)
584cd844e7aSJohn Birrell {
585bc96366cSSteven Hartland #ifndef illumos
5860626f3e4SMark Johnston fasttrap_scrblock_t *scrblk;
5870626f3e4SMark Johnston fasttrap_proc_t *fprc = NULL;
5880626f3e4SMark Johnston #endif
589cd844e7aSJohn Birrell pid_t ppid = p->p_pid;
59083958173SMark Johnston int error, i;
591cd844e7aSJohn Birrell
592cd844e7aSJohn Birrell ASSERT(curproc == p);
593e9f63df7SMark Johnston #ifdef illumos
594cd844e7aSJohn Birrell ASSERT(p->p_proc_flag & P_PR_LOCK);
5958605d1aeSRui Paulo #else
5968605d1aeSRui Paulo PROC_LOCK_ASSERT(p, MA_OWNED);
5978605d1aeSRui Paulo #endif
598bc96366cSSteven Hartland #ifdef illumos
599cd844e7aSJohn Birrell ASSERT(p->p_dtrace_count > 0);
6008605d1aeSRui Paulo #else
6018605d1aeSRui Paulo /*
6028605d1aeSRui Paulo * This check is purposely here instead of in kern_fork.c because,
6038605d1aeSRui Paulo * for legal resons, we cannot include the dtrace_cddl.h header
6048605d1aeSRui Paulo * inside kern_fork.c and insert if-clause there.
6058605d1aeSRui Paulo */
606e9f63df7SMark Johnston if (p->p_dtrace_count == 0 && p->p_dtrace_helpers == NULL)
6078605d1aeSRui Paulo return;
6088605d1aeSRui Paulo #endif
609e9f63df7SMark Johnston
610cd844e7aSJohn Birrell ASSERT(cp->p_dtrace_count == 0);
611cd844e7aSJohn Birrell
612cd844e7aSJohn Birrell /*
613cd844e7aSJohn Birrell * This would be simpler and faster if we maintained per-process
614cd844e7aSJohn Birrell * hash tables of enabled tracepoints. It could, however, potentially
615cd844e7aSJohn Birrell * slow down execution of a tracepoint since we'd need to go
616cd844e7aSJohn Birrell * through two levels of indirection. In the future, we should
617cd844e7aSJohn Birrell * consider either maintaining per-process ancillary lists of
618cd844e7aSJohn Birrell * enabled tracepoints or hanging a pointer to a per-process hash
619cd844e7aSJohn Birrell * table of enabled tracepoints off the proc structure.
620cd844e7aSJohn Birrell */
621cd844e7aSJohn Birrell
622cd844e7aSJohn Birrell /*
623cd844e7aSJohn Birrell * We don't have to worry about the child process disappearing
624cd844e7aSJohn Birrell * because we're in fork().
625cd844e7aSJohn Birrell */
626bc96366cSSteven Hartland #ifdef illumos
6278605d1aeSRui Paulo mtx_lock_spin(&cp->p_slock);
628cd844e7aSJohn Birrell sprlock_proc(cp);
6298605d1aeSRui Paulo mtx_unlock_spin(&cp->p_slock);
63047047e34SRui Paulo #else
631e009490aSRui Paulo /*
632e009490aSRui Paulo * fasttrap_tracepoint_remove() expects the child process to be
633e009490aSRui Paulo * unlocked and the VM then expects curproc to be unlocked.
634e009490aSRui Paulo */
63547047e34SRui Paulo _PHOLD(cp);
636e009490aSRui Paulo PROC_UNLOCK(cp);
637e009490aSRui Paulo PROC_UNLOCK(p);
638e9f63df7SMark Johnston if (p->p_dtrace_count == 0)
639e9f63df7SMark Johnston goto dup_helpers;
6408605d1aeSRui Paulo #endif
641cd844e7aSJohn Birrell
642cd844e7aSJohn Birrell /*
643cd844e7aSJohn Birrell * Iterate over every tracepoint looking for ones that belong to the
644cd844e7aSJohn Birrell * parent process, and remove each from the child process.
645cd844e7aSJohn Birrell */
646cd844e7aSJohn Birrell for (i = 0; i < fasttrap_tpoints.fth_nent; i++) {
647cd844e7aSJohn Birrell fasttrap_tracepoint_t *tp;
648cd844e7aSJohn Birrell fasttrap_bucket_t *bucket = &fasttrap_tpoints.fth_table[i];
649cd844e7aSJohn Birrell
650cd844e7aSJohn Birrell mutex_enter(&bucket->ftb_mtx);
651cd844e7aSJohn Birrell for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
652cd844e7aSJohn Birrell if (tp->ftt_pid == ppid &&
653cd844e7aSJohn Birrell tp->ftt_proc->ftpc_acount != 0) {
654cd844e7aSJohn Birrell int ret = fasttrap_tracepoint_remove(cp, tp);
655cd844e7aSJohn Birrell ASSERT(ret == 0);
6565a1b490dSJohn Birrell
6575a1b490dSJohn Birrell /*
6585a1b490dSJohn Birrell * The count of active providers can only be
6595a1b490dSJohn Birrell * decremented (i.e. to zero) during exec,
6605a1b490dSJohn Birrell * exit, and removal of a meta provider so it
6615a1b490dSJohn Birrell * should be impossible to drop the count
6625a1b490dSJohn Birrell * mid-fork.
6635a1b490dSJohn Birrell */
6645a1b490dSJohn Birrell ASSERT(tp->ftt_proc->ftpc_acount != 0);
665bc96366cSSteven Hartland #ifndef illumos
6660626f3e4SMark Johnston fprc = tp->ftt_proc;
6670626f3e4SMark Johnston #endif
668cd844e7aSJohn Birrell }
669cd844e7aSJohn Birrell }
670cd844e7aSJohn Birrell mutex_exit(&bucket->ftb_mtx);
6710626f3e4SMark Johnston
672bc96366cSSteven Hartland #ifndef illumos
6730626f3e4SMark Johnston /*
6740626f3e4SMark Johnston * Unmap any scratch space inherited from the parent's address
6750626f3e4SMark Johnston * space.
6760626f3e4SMark Johnston */
6770626f3e4SMark Johnston if (fprc != NULL) {
6780626f3e4SMark Johnston mutex_enter(&fprc->ftpc_mtx);
6790626f3e4SMark Johnston LIST_FOREACH(scrblk, &fprc->ftpc_scrblks, ftsb_next) {
68083958173SMark Johnston error = vm_map_remove(&cp->p_vmspace->vm_map,
6810626f3e4SMark Johnston scrblk->ftsb_addr,
6820626f3e4SMark Johnston scrblk->ftsb_addr + FASTTRAP_SCRBLOCK_SIZE);
68383958173SMark Johnston ASSERT(error == KERN_SUCCESS);
6840626f3e4SMark Johnston }
6850626f3e4SMark Johnston mutex_exit(&fprc->ftpc_mtx);
6860626f3e4SMark Johnston }
6870626f3e4SMark Johnston #endif
688cd844e7aSJohn Birrell }
689cd844e7aSJohn Birrell
690bc96366cSSteven Hartland #ifdef illumos
691cd844e7aSJohn Birrell mutex_enter(&cp->p_lock);
692cd844e7aSJohn Birrell sprunlock(cp);
69347047e34SRui Paulo #else
694e9f63df7SMark Johnston dup_helpers:
695e9f63df7SMark Johnston if (p->p_dtrace_helpers != NULL)
696e9f63df7SMark Johnston dtrace_helpers_duplicate(p, cp);
697e009490aSRui Paulo PROC_LOCK(p);
698e009490aSRui Paulo PROC_LOCK(cp);
69947047e34SRui Paulo _PRELE(cp);
7008605d1aeSRui Paulo #endif
701cd844e7aSJohn Birrell }
702cd844e7aSJohn Birrell
703cd844e7aSJohn Birrell /*
704cd844e7aSJohn Birrell * This is called from proc_exit() or from exec_common() if p_dtrace_probes
705cd844e7aSJohn Birrell * is set on the proc structure to indicate that there is a pid provider
706cd844e7aSJohn Birrell * associated with this process.
707cd844e7aSJohn Birrell */
708cd844e7aSJohn Birrell static void
fasttrap_exec_exit(proc_t * p)709cd844e7aSJohn Birrell fasttrap_exec_exit(proc_t *p)
710cd844e7aSJohn Birrell {
711bc96366cSSteven Hartland #ifndef illumos
7120626f3e4SMark Johnston struct thread *td;
7130626f3e4SMark Johnston #endif
7140626f3e4SMark Johnston
715bc96366cSSteven Hartland #ifdef illumos
716cd844e7aSJohn Birrell ASSERT(p == curproc);
7170626f3e4SMark Johnston #else
7188605d1aeSRui Paulo PROC_LOCK_ASSERT(p, MA_OWNED);
71947047e34SRui Paulo _PHOLD(p);
7200626f3e4SMark Johnston /*
7210626f3e4SMark Johnston * Since struct threads may be recycled, we cannot rely on t_dtrace_sscr
7220626f3e4SMark Johnston * fields to be zeroed by kdtrace_thread_ctor. Thus we must zero it
7230626f3e4SMark Johnston * ourselves when a process exits.
7240626f3e4SMark Johnston */
7250626f3e4SMark Johnston FOREACH_THREAD_IN_PROC(p, td)
7260626f3e4SMark Johnston td->t_dtrace_sscr = NULL;
7278605d1aeSRui Paulo PROC_UNLOCK(p);
7280626f3e4SMark Johnston #endif
729cd844e7aSJohn Birrell
730cd844e7aSJohn Birrell /*
731cd844e7aSJohn Birrell * We clean up the pid provider for this process here; user-land
732cd844e7aSJohn Birrell * static probes are handled by the meta-provider remove entry point.
733cd844e7aSJohn Birrell */
734cd844e7aSJohn Birrell fasttrap_provider_retire(p->p_pid, FASTTRAP_PID_NAME, 0);
735bc96366cSSteven Hartland #ifndef illumos
736d3555b6fSRui Paulo if (p->p_dtrace_helpers)
737d3555b6fSRui Paulo dtrace_helpers_destroy(p);
7388605d1aeSRui Paulo PROC_LOCK(p);
73947047e34SRui Paulo _PRELE(p);
7400626f3e4SMark Johnston #endif
741cd844e7aSJohn Birrell }
742cd844e7aSJohn Birrell
743cd844e7aSJohn Birrell
744cd844e7aSJohn Birrell /*ARGSUSED*/
745cd844e7aSJohn Birrell static void
fasttrap_pid_provide(void * arg,dtrace_probedesc_t * desc)7468605d1aeSRui Paulo fasttrap_pid_provide(void *arg, dtrace_probedesc_t *desc)
747cd844e7aSJohn Birrell {
748cd844e7aSJohn Birrell /*
749cd844e7aSJohn Birrell * There are no "default" pid probes.
750cd844e7aSJohn Birrell */
751cd844e7aSJohn Birrell }
752cd844e7aSJohn Birrell
753cd844e7aSJohn Birrell static int
fasttrap_tracepoint_enable(proc_t * p,fasttrap_probe_t * probe,uint_t index)754cd844e7aSJohn Birrell fasttrap_tracepoint_enable(proc_t *p, fasttrap_probe_t *probe, uint_t index)
755cd844e7aSJohn Birrell {
756cd844e7aSJohn Birrell fasttrap_tracepoint_t *tp, *new_tp = NULL;
757cd844e7aSJohn Birrell fasttrap_bucket_t *bucket;
758cd844e7aSJohn Birrell fasttrap_id_t *id;
759cd844e7aSJohn Birrell pid_t pid;
760cd844e7aSJohn Birrell uintptr_t pc;
761cd844e7aSJohn Birrell
762cd844e7aSJohn Birrell ASSERT(index < probe->ftp_ntps);
763cd844e7aSJohn Birrell
764cd844e7aSJohn Birrell pid = probe->ftp_pid;
765cd844e7aSJohn Birrell pc = probe->ftp_tps[index].fit_tp->ftt_pc;
766cd844e7aSJohn Birrell id = &probe->ftp_tps[index].fit_id;
767cd844e7aSJohn Birrell
768cd844e7aSJohn Birrell ASSERT(probe->ftp_tps[index].fit_tp->ftt_pid == pid);
769cd844e7aSJohn Birrell
770bc96366cSSteven Hartland #ifdef illumos
771cd844e7aSJohn Birrell ASSERT(!(p->p_flag & SVFORK));
7728605d1aeSRui Paulo #endif
773cd844e7aSJohn Birrell
774cd844e7aSJohn Birrell /*
775cd844e7aSJohn Birrell * Before we make any modifications, make sure we've imposed a barrier
776cd844e7aSJohn Birrell * on the generation in which this probe was last modified.
777cd844e7aSJohn Birrell */
778cd844e7aSJohn Birrell fasttrap_mod_barrier(probe->ftp_gen);
779cd844e7aSJohn Birrell
780cd844e7aSJohn Birrell bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)];
781cd844e7aSJohn Birrell
782cd844e7aSJohn Birrell /*
783cd844e7aSJohn Birrell * If the tracepoint has already been enabled, just add our id to the
784cd844e7aSJohn Birrell * list of interested probes. This may be our second time through
785cd844e7aSJohn Birrell * this path in which case we'll have constructed the tracepoint we'd
786cd844e7aSJohn Birrell * like to install. If we can't find a match, and have an allocated
787cd844e7aSJohn Birrell * tracepoint ready to go, enable that one now.
788cd844e7aSJohn Birrell *
789cd844e7aSJohn Birrell * A tracepoint whose process is defunct is also considered defunct.
790cd844e7aSJohn Birrell */
791cd844e7aSJohn Birrell again:
792cd844e7aSJohn Birrell mutex_enter(&bucket->ftb_mtx);
793cd844e7aSJohn Birrell for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
7945a1b490dSJohn Birrell /*
7955a1b490dSJohn Birrell * Note that it's safe to access the active count on the
7965a1b490dSJohn Birrell * associated proc structure because we know that at least one
7975a1b490dSJohn Birrell * provider (this one) will still be around throughout this
7985a1b490dSJohn Birrell * operation.
7995a1b490dSJohn Birrell */
800cd844e7aSJohn Birrell if (tp->ftt_pid != pid || tp->ftt_pc != pc ||
801cd844e7aSJohn Birrell tp->ftt_proc->ftpc_acount == 0)
802cd844e7aSJohn Birrell continue;
803cd844e7aSJohn Birrell
804cd844e7aSJohn Birrell /*
805cd844e7aSJohn Birrell * Now that we've found a matching tracepoint, it would be
806cd844e7aSJohn Birrell * a decent idea to confirm that the tracepoint is still
807cd844e7aSJohn Birrell * enabled and the trap instruction hasn't been overwritten.
808cd844e7aSJohn Birrell * Since this is a little hairy, we'll punt for now.
809cd844e7aSJohn Birrell */
810cd844e7aSJohn Birrell
811cd844e7aSJohn Birrell /*
812cd844e7aSJohn Birrell * This can't be the first interested probe. We don't have
813cd844e7aSJohn Birrell * to worry about another thread being in the midst of
814cd844e7aSJohn Birrell * deleting this tracepoint (which would be the only valid
815cd844e7aSJohn Birrell * reason for a tracepoint to have no interested probes)
816cd844e7aSJohn Birrell * since we're holding P_PR_LOCK for this process.
817cd844e7aSJohn Birrell */
818cd844e7aSJohn Birrell ASSERT(tp->ftt_ids != NULL || tp->ftt_retids != NULL);
819cd844e7aSJohn Birrell
820cd844e7aSJohn Birrell switch (id->fti_ptype) {
821cd844e7aSJohn Birrell case DTFTP_ENTRY:
822cd844e7aSJohn Birrell case DTFTP_OFFSETS:
823cd844e7aSJohn Birrell case DTFTP_IS_ENABLED:
824cd844e7aSJohn Birrell id->fti_next = tp->ftt_ids;
825cd844e7aSJohn Birrell membar_producer();
826cd844e7aSJohn Birrell tp->ftt_ids = id;
827cd844e7aSJohn Birrell membar_producer();
828cd844e7aSJohn Birrell break;
829cd844e7aSJohn Birrell
830cd844e7aSJohn Birrell case DTFTP_RETURN:
831cd844e7aSJohn Birrell case DTFTP_POST_OFFSETS:
832cd844e7aSJohn Birrell id->fti_next = tp->ftt_retids;
833cd844e7aSJohn Birrell membar_producer();
834cd844e7aSJohn Birrell tp->ftt_retids = id;
835cd844e7aSJohn Birrell membar_producer();
836cd844e7aSJohn Birrell break;
837cd844e7aSJohn Birrell
838cd844e7aSJohn Birrell default:
839cd844e7aSJohn Birrell ASSERT(0);
840cd844e7aSJohn Birrell }
841cd844e7aSJohn Birrell
842cd844e7aSJohn Birrell mutex_exit(&bucket->ftb_mtx);
843cd844e7aSJohn Birrell
844cd844e7aSJohn Birrell if (new_tp != NULL) {
845cd844e7aSJohn Birrell new_tp->ftt_ids = NULL;
846cd844e7aSJohn Birrell new_tp->ftt_retids = NULL;
847cd844e7aSJohn Birrell }
848cd844e7aSJohn Birrell
849cd844e7aSJohn Birrell return (0);
850cd844e7aSJohn Birrell }
851cd844e7aSJohn Birrell
852cd844e7aSJohn Birrell /*
853cd844e7aSJohn Birrell * If we have a good tracepoint ready to go, install it now while
854cd844e7aSJohn Birrell * we have the lock held and no one can screw with us.
855cd844e7aSJohn Birrell */
856cd844e7aSJohn Birrell if (new_tp != NULL) {
857cd844e7aSJohn Birrell int rc = 0;
858cd844e7aSJohn Birrell
859cd844e7aSJohn Birrell new_tp->ftt_next = bucket->ftb_data;
860cd844e7aSJohn Birrell membar_producer();
861cd844e7aSJohn Birrell bucket->ftb_data = new_tp;
862cd844e7aSJohn Birrell membar_producer();
863cd844e7aSJohn Birrell mutex_exit(&bucket->ftb_mtx);
864cd844e7aSJohn Birrell
865cd844e7aSJohn Birrell /*
866cd844e7aSJohn Birrell * Activate the tracepoint in the ISA-specific manner.
867cd844e7aSJohn Birrell * If this fails, we need to report the failure, but
868cd844e7aSJohn Birrell * indicate that this tracepoint must still be disabled
869cd844e7aSJohn Birrell * by calling fasttrap_tracepoint_disable().
870cd844e7aSJohn Birrell */
871cd844e7aSJohn Birrell if (fasttrap_tracepoint_install(p, new_tp) != 0)
872cd844e7aSJohn Birrell rc = FASTTRAP_ENABLE_PARTIAL;
873cd844e7aSJohn Birrell
874cd844e7aSJohn Birrell /*
875cd844e7aSJohn Birrell * Increment the count of the number of tracepoints active in
876cd844e7aSJohn Birrell * the victim process.
877cd844e7aSJohn Birrell */
878bc96366cSSteven Hartland #ifdef illumos
879cd844e7aSJohn Birrell ASSERT(p->p_proc_flag & P_PR_LOCK);
8808605d1aeSRui Paulo #endif
881cd844e7aSJohn Birrell p->p_dtrace_count++;
882cd844e7aSJohn Birrell
883cd844e7aSJohn Birrell return (rc);
884cd844e7aSJohn Birrell }
885cd844e7aSJohn Birrell
886cd844e7aSJohn Birrell mutex_exit(&bucket->ftb_mtx);
887cd844e7aSJohn Birrell
888cd844e7aSJohn Birrell /*
889cd844e7aSJohn Birrell * Initialize the tracepoint that's been preallocated with the probe.
890cd844e7aSJohn Birrell */
891cd844e7aSJohn Birrell new_tp = probe->ftp_tps[index].fit_tp;
892cd844e7aSJohn Birrell
893cd844e7aSJohn Birrell ASSERT(new_tp->ftt_pid == pid);
894cd844e7aSJohn Birrell ASSERT(new_tp->ftt_pc == pc);
895cd844e7aSJohn Birrell ASSERT(new_tp->ftt_proc == probe->ftp_prov->ftp_proc);
896cd844e7aSJohn Birrell ASSERT(new_tp->ftt_ids == NULL);
897cd844e7aSJohn Birrell ASSERT(new_tp->ftt_retids == NULL);
898cd844e7aSJohn Birrell
899cd844e7aSJohn Birrell switch (id->fti_ptype) {
900cd844e7aSJohn Birrell case DTFTP_ENTRY:
901cd844e7aSJohn Birrell case DTFTP_OFFSETS:
902cd844e7aSJohn Birrell case DTFTP_IS_ENABLED:
903cd844e7aSJohn Birrell id->fti_next = NULL;
904cd844e7aSJohn Birrell new_tp->ftt_ids = id;
905cd844e7aSJohn Birrell break;
906cd844e7aSJohn Birrell
907cd844e7aSJohn Birrell case DTFTP_RETURN:
908cd844e7aSJohn Birrell case DTFTP_POST_OFFSETS:
909cd844e7aSJohn Birrell id->fti_next = NULL;
910cd844e7aSJohn Birrell new_tp->ftt_retids = id;
911cd844e7aSJohn Birrell break;
912cd844e7aSJohn Birrell
913cd844e7aSJohn Birrell default:
914cd844e7aSJohn Birrell ASSERT(0);
915cd844e7aSJohn Birrell }
916cd844e7aSJohn Birrell
9176d1ffb50SMark Johnston #ifdef __FreeBSD__
9186d1ffb50SMark Johnston if (SV_PROC_FLAG(p, SV_LP64))
9196d1ffb50SMark Johnston p->p_model = DATAMODEL_LP64;
9206d1ffb50SMark Johnston else
9216d1ffb50SMark Johnston p->p_model = DATAMODEL_ILP32;
9226d1ffb50SMark Johnston #endif
9236d1ffb50SMark Johnston
924cd844e7aSJohn Birrell /*
925cd844e7aSJohn Birrell * If the ISA-dependent initialization goes to plan, go back to the
926cd844e7aSJohn Birrell * beginning and try to install this freshly made tracepoint.
927cd844e7aSJohn Birrell */
928cd844e7aSJohn Birrell if (fasttrap_tracepoint_init(p, new_tp, pc, id->fti_ptype) == 0)
929cd844e7aSJohn Birrell goto again;
930cd844e7aSJohn Birrell
931cd844e7aSJohn Birrell new_tp->ftt_ids = NULL;
932cd844e7aSJohn Birrell new_tp->ftt_retids = NULL;
933cd844e7aSJohn Birrell
934cd844e7aSJohn Birrell return (FASTTRAP_ENABLE_FAIL);
935cd844e7aSJohn Birrell }
936cd844e7aSJohn Birrell
937cd844e7aSJohn Birrell static void
fasttrap_tracepoint_disable(proc_t * p,fasttrap_probe_t * probe,uint_t index)938cd844e7aSJohn Birrell fasttrap_tracepoint_disable(proc_t *p, fasttrap_probe_t *probe, uint_t index)
939cd844e7aSJohn Birrell {
940cd844e7aSJohn Birrell fasttrap_bucket_t *bucket;
941cd844e7aSJohn Birrell fasttrap_provider_t *provider = probe->ftp_prov;
942cd844e7aSJohn Birrell fasttrap_tracepoint_t **pp, *tp;
9438605d1aeSRui Paulo fasttrap_id_t *id, **idp = NULL;
944cd844e7aSJohn Birrell pid_t pid;
945cd844e7aSJohn Birrell uintptr_t pc;
946cd844e7aSJohn Birrell
947cd844e7aSJohn Birrell ASSERT(index < probe->ftp_ntps);
948cd844e7aSJohn Birrell
949cd844e7aSJohn Birrell pid = probe->ftp_pid;
950cd844e7aSJohn Birrell pc = probe->ftp_tps[index].fit_tp->ftt_pc;
951cd844e7aSJohn Birrell id = &probe->ftp_tps[index].fit_id;
952cd844e7aSJohn Birrell
953cd844e7aSJohn Birrell ASSERT(probe->ftp_tps[index].fit_tp->ftt_pid == pid);
954cd844e7aSJohn Birrell
955cd844e7aSJohn Birrell /*
956cd844e7aSJohn Birrell * Find the tracepoint and make sure that our id is one of the
957cd844e7aSJohn Birrell * ones registered with it.
958cd844e7aSJohn Birrell */
959cd844e7aSJohn Birrell bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)];
960cd844e7aSJohn Birrell mutex_enter(&bucket->ftb_mtx);
961cd844e7aSJohn Birrell for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
962cd844e7aSJohn Birrell if (tp->ftt_pid == pid && tp->ftt_pc == pc &&
963cd844e7aSJohn Birrell tp->ftt_proc == provider->ftp_proc)
964cd844e7aSJohn Birrell break;
965cd844e7aSJohn Birrell }
966cd844e7aSJohn Birrell
967cd844e7aSJohn Birrell /*
968cd844e7aSJohn Birrell * If we somehow lost this tracepoint, we're in a world of hurt.
969cd844e7aSJohn Birrell */
970cd844e7aSJohn Birrell ASSERT(tp != NULL);
971cd844e7aSJohn Birrell
972cd844e7aSJohn Birrell switch (id->fti_ptype) {
973cd844e7aSJohn Birrell case DTFTP_ENTRY:
974cd844e7aSJohn Birrell case DTFTP_OFFSETS:
975cd844e7aSJohn Birrell case DTFTP_IS_ENABLED:
976cd844e7aSJohn Birrell ASSERT(tp->ftt_ids != NULL);
977cd844e7aSJohn Birrell idp = &tp->ftt_ids;
978cd844e7aSJohn Birrell break;
979cd844e7aSJohn Birrell
980cd844e7aSJohn Birrell case DTFTP_RETURN:
981cd844e7aSJohn Birrell case DTFTP_POST_OFFSETS:
982cd844e7aSJohn Birrell ASSERT(tp->ftt_retids != NULL);
983cd844e7aSJohn Birrell idp = &tp->ftt_retids;
984cd844e7aSJohn Birrell break;
985cd844e7aSJohn Birrell
986cd844e7aSJohn Birrell default:
987cd844e7aSJohn Birrell ASSERT(0);
988cd844e7aSJohn Birrell }
989cd844e7aSJohn Birrell
990cd844e7aSJohn Birrell while ((*idp)->fti_probe != probe) {
991cd844e7aSJohn Birrell idp = &(*idp)->fti_next;
992cd844e7aSJohn Birrell ASSERT(*idp != NULL);
993cd844e7aSJohn Birrell }
994cd844e7aSJohn Birrell
995cd844e7aSJohn Birrell id = *idp;
996cd844e7aSJohn Birrell *idp = id->fti_next;
997cd844e7aSJohn Birrell membar_producer();
998cd844e7aSJohn Birrell
999cd844e7aSJohn Birrell ASSERT(id->fti_probe == probe);
1000cd844e7aSJohn Birrell
1001cd844e7aSJohn Birrell /*
1002cd844e7aSJohn Birrell * If there are other registered enablings of this tracepoint, we're
1003cd844e7aSJohn Birrell * all done, but if this was the last probe assocated with this
1004cd844e7aSJohn Birrell * this tracepoint, we need to remove and free it.
1005cd844e7aSJohn Birrell */
1006cd844e7aSJohn Birrell if (tp->ftt_ids != NULL || tp->ftt_retids != NULL) {
1007cd844e7aSJohn Birrell
1008cd844e7aSJohn Birrell /*
1009cd844e7aSJohn Birrell * If the current probe's tracepoint is in use, swap it
1010cd844e7aSJohn Birrell * for an unused tracepoint.
1011cd844e7aSJohn Birrell */
1012cd844e7aSJohn Birrell if (tp == probe->ftp_tps[index].fit_tp) {
1013cd844e7aSJohn Birrell fasttrap_probe_t *tmp_probe;
1014cd844e7aSJohn Birrell fasttrap_tracepoint_t **tmp_tp;
1015cd844e7aSJohn Birrell uint_t tmp_index;
1016cd844e7aSJohn Birrell
1017cd844e7aSJohn Birrell if (tp->ftt_ids != NULL) {
1018cd844e7aSJohn Birrell tmp_probe = tp->ftt_ids->fti_probe;
1019cd844e7aSJohn Birrell /* LINTED - alignment */
1020cd844e7aSJohn Birrell tmp_index = FASTTRAP_ID_INDEX(tp->ftt_ids);
1021cd844e7aSJohn Birrell tmp_tp = &tmp_probe->ftp_tps[tmp_index].fit_tp;
1022cd844e7aSJohn Birrell } else {
1023cd844e7aSJohn Birrell tmp_probe = tp->ftt_retids->fti_probe;
1024cd844e7aSJohn Birrell /* LINTED - alignment */
1025cd844e7aSJohn Birrell tmp_index = FASTTRAP_ID_INDEX(tp->ftt_retids);
1026cd844e7aSJohn Birrell tmp_tp = &tmp_probe->ftp_tps[tmp_index].fit_tp;
1027cd844e7aSJohn Birrell }
1028cd844e7aSJohn Birrell
1029cd844e7aSJohn Birrell ASSERT(*tmp_tp != NULL);
1030cd844e7aSJohn Birrell ASSERT(*tmp_tp != probe->ftp_tps[index].fit_tp);
1031cd844e7aSJohn Birrell ASSERT((*tmp_tp)->ftt_ids == NULL);
1032cd844e7aSJohn Birrell ASSERT((*tmp_tp)->ftt_retids == NULL);
1033cd844e7aSJohn Birrell
1034cd844e7aSJohn Birrell probe->ftp_tps[index].fit_tp = *tmp_tp;
1035cd844e7aSJohn Birrell *tmp_tp = tp;
1036cd844e7aSJohn Birrell }
1037cd844e7aSJohn Birrell
1038cd844e7aSJohn Birrell mutex_exit(&bucket->ftb_mtx);
1039cd844e7aSJohn Birrell
1040cd844e7aSJohn Birrell /*
1041cd844e7aSJohn Birrell * Tag the modified probe with the generation in which it was
1042cd844e7aSJohn Birrell * changed.
1043cd844e7aSJohn Birrell */
1044cd844e7aSJohn Birrell probe->ftp_gen = fasttrap_mod_gen;
1045cd844e7aSJohn Birrell return;
1046cd844e7aSJohn Birrell }
1047cd844e7aSJohn Birrell
1048cd844e7aSJohn Birrell mutex_exit(&bucket->ftb_mtx);
1049cd844e7aSJohn Birrell
1050cd844e7aSJohn Birrell /*
1051cd844e7aSJohn Birrell * We can't safely remove the tracepoint from the set of active
1052cd844e7aSJohn Birrell * tracepoints until we've actually removed the fasttrap instruction
1053cd844e7aSJohn Birrell * from the process's text. We can, however, operate on this
1054cd844e7aSJohn Birrell * tracepoint secure in the knowledge that no other thread is going to
1055cd844e7aSJohn Birrell * be looking at it since we hold P_PR_LOCK on the process if it's
1056cd844e7aSJohn Birrell * live or we hold the provider lock on the process if it's dead and
1057cd844e7aSJohn Birrell * gone.
1058cd844e7aSJohn Birrell */
1059cd844e7aSJohn Birrell
1060cd844e7aSJohn Birrell /*
1061cd844e7aSJohn Birrell * We only need to remove the actual instruction if we're looking
1062cd844e7aSJohn Birrell * at an existing process
1063cd844e7aSJohn Birrell */
1064cd844e7aSJohn Birrell if (p != NULL) {
1065cd844e7aSJohn Birrell /*
1066cd844e7aSJohn Birrell * If we fail to restore the instruction we need to kill
1067cd844e7aSJohn Birrell * this process since it's in a completely unrecoverable
1068cd844e7aSJohn Birrell * state.
1069cd844e7aSJohn Birrell */
1070cd844e7aSJohn Birrell if (fasttrap_tracepoint_remove(p, tp) != 0)
1071cd844e7aSJohn Birrell fasttrap_sigtrap(p, NULL, pc);
1072cd844e7aSJohn Birrell
1073cd844e7aSJohn Birrell /*
1074cd844e7aSJohn Birrell * Decrement the count of the number of tracepoints active
1075cd844e7aSJohn Birrell * in the victim process.
1076cd844e7aSJohn Birrell */
1077bc96366cSSteven Hartland #ifdef illumos
1078cd844e7aSJohn Birrell ASSERT(p->p_proc_flag & P_PR_LOCK);
10798605d1aeSRui Paulo #endif
1080cd844e7aSJohn Birrell p->p_dtrace_count--;
10814f1b715cSMark Johnston
10824f1b715cSMark Johnston atomic_add_rel_64(&p->p_fasttrap_tp_gen, 1);
1083cd844e7aSJohn Birrell }
1084cd844e7aSJohn Birrell
1085cd844e7aSJohn Birrell /*
1086cd844e7aSJohn Birrell * Remove the probe from the hash table of active tracepoints.
1087cd844e7aSJohn Birrell */
1088cd844e7aSJohn Birrell mutex_enter(&bucket->ftb_mtx);
1089cd844e7aSJohn Birrell pp = (fasttrap_tracepoint_t **)&bucket->ftb_data;
1090cd844e7aSJohn Birrell ASSERT(*pp != NULL);
1091cd844e7aSJohn Birrell while (*pp != tp) {
1092cd844e7aSJohn Birrell pp = &(*pp)->ftt_next;
1093cd844e7aSJohn Birrell ASSERT(*pp != NULL);
1094cd844e7aSJohn Birrell }
1095cd844e7aSJohn Birrell
1096cd844e7aSJohn Birrell *pp = tp->ftt_next;
1097cd844e7aSJohn Birrell membar_producer();
1098cd844e7aSJohn Birrell
1099cd844e7aSJohn Birrell mutex_exit(&bucket->ftb_mtx);
1100cd844e7aSJohn Birrell
1101cd844e7aSJohn Birrell /*
1102cd844e7aSJohn Birrell * Tag the modified probe with the generation in which it was changed.
1103cd844e7aSJohn Birrell */
1104cd844e7aSJohn Birrell probe->ftp_gen = fasttrap_mod_gen;
1105cd844e7aSJohn Birrell }
1106cd844e7aSJohn Birrell
1107cd844e7aSJohn Birrell static void
fasttrap_enable_callbacks(void)1108cd844e7aSJohn Birrell fasttrap_enable_callbacks(void)
1109cd844e7aSJohn Birrell {
1110cd844e7aSJohn Birrell /*
1111cd844e7aSJohn Birrell * We don't have to play the rw lock game here because we're
1112cd844e7aSJohn Birrell * providing something rather than taking something away --
1113cd844e7aSJohn Birrell * we can be sure that no threads have tried to follow this
1114cd844e7aSJohn Birrell * function pointer yet.
1115cd844e7aSJohn Birrell */
1116cd844e7aSJohn Birrell mutex_enter(&fasttrap_count_mtx);
1117cd844e7aSJohn Birrell if (fasttrap_pid_count == 0) {
1118cd844e7aSJohn Birrell ASSERT(dtrace_pid_probe_ptr == NULL);
1119cd844e7aSJohn Birrell ASSERT(dtrace_return_probe_ptr == NULL);
1120cd844e7aSJohn Birrell dtrace_pid_probe_ptr = &fasttrap_pid_probe;
1121cd844e7aSJohn Birrell dtrace_return_probe_ptr = &fasttrap_return_probe;
1122cd844e7aSJohn Birrell }
1123cd844e7aSJohn Birrell ASSERT(dtrace_pid_probe_ptr == &fasttrap_pid_probe);
1124cd844e7aSJohn Birrell ASSERT(dtrace_return_probe_ptr == &fasttrap_return_probe);
1125cd844e7aSJohn Birrell fasttrap_pid_count++;
1126cd844e7aSJohn Birrell mutex_exit(&fasttrap_count_mtx);
1127cd844e7aSJohn Birrell }
1128cd844e7aSJohn Birrell
1129cd844e7aSJohn Birrell static void
fasttrap_disable_callbacks(void)1130cd844e7aSJohn Birrell fasttrap_disable_callbacks(void)
1131cd844e7aSJohn Birrell {
1132cd844e7aSJohn Birrell mutex_enter(&fasttrap_count_mtx);
1133cd844e7aSJohn Birrell ASSERT(fasttrap_pid_count > 0);
1134cd844e7aSJohn Birrell fasttrap_pid_count--;
1135cd844e7aSJohn Birrell if (fasttrap_pid_count == 0) {
1136c0806554SMark Johnston /*
1137c0806554SMark Johnston * Synchronize with the breakpoint handler, which is careful to
1138c0806554SMark Johnston * enable interrupts only after loading the hook pointer.
1139c0806554SMark Johnston */
1140c0806554SMark Johnston dtrace_sync();
1141cd844e7aSJohn Birrell dtrace_pid_probe_ptr = NULL;
1142cd844e7aSJohn Birrell dtrace_return_probe_ptr = NULL;
1143cd844e7aSJohn Birrell }
1144cd844e7aSJohn Birrell mutex_exit(&fasttrap_count_mtx);
1145cd844e7aSJohn Birrell }
1146cd844e7aSJohn Birrell
1147cd844e7aSJohn Birrell /*ARGSUSED*/
1148cd844e7aSJohn Birrell static void
fasttrap_pid_enable(void * arg,dtrace_id_t id,void * parg)1149cd844e7aSJohn Birrell fasttrap_pid_enable(void *arg, dtrace_id_t id, void *parg)
1150cd844e7aSJohn Birrell {
1151cd844e7aSJohn Birrell fasttrap_probe_t *probe = parg;
11528605d1aeSRui Paulo proc_t *p = NULL;
1153cd844e7aSJohn Birrell int i, rc;
1154cd844e7aSJohn Birrell
1155cd844e7aSJohn Birrell ASSERT(probe != NULL);
1156cd844e7aSJohn Birrell ASSERT(!probe->ftp_enabled);
1157cd844e7aSJohn Birrell ASSERT(id == probe->ftp_id);
1158bc96366cSSteven Hartland #ifdef illumos
1159cd844e7aSJohn Birrell ASSERT(MUTEX_HELD(&cpu_lock));
11608605d1aeSRui Paulo #endif
1161cd844e7aSJohn Birrell
1162cd844e7aSJohn Birrell /*
1163cd844e7aSJohn Birrell * Increment the count of enabled probes on this probe's provider;
1164cd844e7aSJohn Birrell * the provider can't go away while the probe still exists. We
1165cd844e7aSJohn Birrell * must increment this even if we aren't able to properly enable
1166cd844e7aSJohn Birrell * this probe.
1167cd844e7aSJohn Birrell */
1168cd844e7aSJohn Birrell mutex_enter(&probe->ftp_prov->ftp_mtx);
1169cd844e7aSJohn Birrell probe->ftp_prov->ftp_rcount++;
1170cd844e7aSJohn Birrell mutex_exit(&probe->ftp_prov->ftp_mtx);
1171cd844e7aSJohn Birrell
1172cd844e7aSJohn Birrell /*
1173cd844e7aSJohn Birrell * If this probe's provider is retired (meaning it was valid in a
1174cd844e7aSJohn Birrell * previously exec'ed incarnation of this address space), bail out. The
1175cd844e7aSJohn Birrell * provider can't go away while we're in this code path.
1176cd844e7aSJohn Birrell */
1177cd844e7aSJohn Birrell if (probe->ftp_prov->ftp_retired)
1178cd844e7aSJohn Birrell return;
1179cd844e7aSJohn Birrell
1180cd844e7aSJohn Birrell /*
1181cd844e7aSJohn Birrell * If we can't find the process, it may be that we're in the context of
1182cd844e7aSJohn Birrell * a fork in which the traced process is being born and we're copying
1183cd844e7aSJohn Birrell * USDT probes. Otherwise, the process is gone so bail.
1184cd844e7aSJohn Birrell */
1185bc96366cSSteven Hartland #ifdef illumos
1186cd844e7aSJohn Birrell if ((p = sprlock(probe->ftp_pid)) == NULL) {
1187cd844e7aSJohn Birrell if ((curproc->p_flag & SFORKING) == 0)
1188cd844e7aSJohn Birrell return;
1189cd844e7aSJohn Birrell
1190cd844e7aSJohn Birrell mutex_enter(&pidlock);
1191cd844e7aSJohn Birrell p = prfind(probe->ftp_pid);
1192cd844e7aSJohn Birrell
1193e8baaa99SMark Johnston if (p == NULL) {
1194e8baaa99SMark Johnston /*
1195e8baaa99SMark Johnston * So it's not that the target process is being born,
1196e8baaa99SMark Johnston * it's that it isn't there at all (and we simply
1197e8baaa99SMark Johnston * happen to be forking). Anyway, we know that the
1198e8baaa99SMark Johnston * target is definitely gone, so bail out.
1199e8baaa99SMark Johnston */
1200e8baaa99SMark Johnston mutex_exit(&pidlock);
1201e8baaa99SMark Johnston return (0);
1202e8baaa99SMark Johnston }
1203e8baaa99SMark Johnston
1204cd844e7aSJohn Birrell /*
1205cd844e7aSJohn Birrell * Confirm that curproc is indeed forking the process in which
1206cd844e7aSJohn Birrell * we're trying to enable probes.
1207cd844e7aSJohn Birrell */
1208cd844e7aSJohn Birrell ASSERT(p->p_parent == curproc);
1209cd844e7aSJohn Birrell ASSERT(p->p_stat == SIDL);
1210cd844e7aSJohn Birrell
1211cd844e7aSJohn Birrell mutex_enter(&p->p_lock);
1212cd844e7aSJohn Birrell mutex_exit(&pidlock);
1213cd844e7aSJohn Birrell
1214cd844e7aSJohn Birrell sprlock_proc(p);
1215cd844e7aSJohn Birrell }
1216cd844e7aSJohn Birrell
1217cd844e7aSJohn Birrell ASSERT(!(p->p_flag & SVFORK));
1218cd844e7aSJohn Birrell mutex_exit(&p->p_lock);
12198605d1aeSRui Paulo #else
122028180effSMark Johnston if (pget(probe->ftp_pid, PGET_HOLD | PGET_NOTWEXIT, &p) != 0)
12218605d1aeSRui Paulo return;
12228605d1aeSRui Paulo #endif
1223cd844e7aSJohn Birrell
1224cd844e7aSJohn Birrell /*
1225cd844e7aSJohn Birrell * We have to enable the trap entry point before any user threads have
1226cd844e7aSJohn Birrell * the chance to execute the trap instruction we're about to place
1227cd844e7aSJohn Birrell * in their process's text.
1228cd844e7aSJohn Birrell */
1229cd844e7aSJohn Birrell fasttrap_enable_callbacks();
1230cd844e7aSJohn Birrell
1231cd844e7aSJohn Birrell /*
1232cd844e7aSJohn Birrell * Enable all the tracepoints and add this probe's id to each
1233cd844e7aSJohn Birrell * tracepoint's list of active probes.
1234cd844e7aSJohn Birrell */
1235cd844e7aSJohn Birrell for (i = 0; i < probe->ftp_ntps; i++) {
1236cd844e7aSJohn Birrell if ((rc = fasttrap_tracepoint_enable(p, probe, i)) != 0) {
1237cd844e7aSJohn Birrell /*
1238cd844e7aSJohn Birrell * If enabling the tracepoint failed completely,
1239cd844e7aSJohn Birrell * we don't have to disable it; if the failure
1240cd844e7aSJohn Birrell * was only partial we must disable it.
1241cd844e7aSJohn Birrell */
1242cd844e7aSJohn Birrell if (rc == FASTTRAP_ENABLE_FAIL)
1243cd844e7aSJohn Birrell i--;
1244cd844e7aSJohn Birrell else
1245cd844e7aSJohn Birrell ASSERT(rc == FASTTRAP_ENABLE_PARTIAL);
1246cd844e7aSJohn Birrell
1247cd844e7aSJohn Birrell /*
1248cd844e7aSJohn Birrell * Back up and pull out all the tracepoints we've
1249cd844e7aSJohn Birrell * created so far for this probe.
1250cd844e7aSJohn Birrell */
1251cd844e7aSJohn Birrell while (i >= 0) {
1252cd844e7aSJohn Birrell fasttrap_tracepoint_disable(p, probe, i);
1253cd844e7aSJohn Birrell i--;
1254cd844e7aSJohn Birrell }
1255cd844e7aSJohn Birrell
1256bc96366cSSteven Hartland #ifdef illumos
1257cd844e7aSJohn Birrell mutex_enter(&p->p_lock);
1258cd844e7aSJohn Birrell sprunlock(p);
12598605d1aeSRui Paulo #else
126047047e34SRui Paulo PRELE(p);
12618605d1aeSRui Paulo #endif
1262cd844e7aSJohn Birrell
1263cd844e7aSJohn Birrell /*
1264cd844e7aSJohn Birrell * Since we're not actually enabling this probe,
1265cd844e7aSJohn Birrell * drop our reference on the trap table entry.
1266cd844e7aSJohn Birrell */
1267cd844e7aSJohn Birrell fasttrap_disable_callbacks();
1268cd844e7aSJohn Birrell return;
1269cd844e7aSJohn Birrell }
1270cd844e7aSJohn Birrell }
1271bc96366cSSteven Hartland #ifdef illumos
1272cd844e7aSJohn Birrell mutex_enter(&p->p_lock);
1273cd844e7aSJohn Birrell sprunlock(p);
12748605d1aeSRui Paulo #else
127547047e34SRui Paulo PRELE(p);
12768605d1aeSRui Paulo #endif
1277cd844e7aSJohn Birrell
1278cd844e7aSJohn Birrell probe->ftp_enabled = 1;
1279cd844e7aSJohn Birrell }
1280cd844e7aSJohn Birrell
1281cd844e7aSJohn Birrell /*ARGSUSED*/
1282cd844e7aSJohn Birrell static void
fasttrap_pid_disable(void * arg,dtrace_id_t id,void * parg)1283cd844e7aSJohn Birrell fasttrap_pid_disable(void *arg, dtrace_id_t id, void *parg)
1284cd844e7aSJohn Birrell {
1285cd844e7aSJohn Birrell fasttrap_probe_t *probe = parg;
1286cd844e7aSJohn Birrell fasttrap_provider_t *provider = probe->ftp_prov;
1287cd844e7aSJohn Birrell proc_t *p;
1288cd844e7aSJohn Birrell int i, whack = 0;
1289cd844e7aSJohn Birrell
1290cd844e7aSJohn Birrell ASSERT(id == probe->ftp_id);
1291cd844e7aSJohn Birrell
12928605d1aeSRui Paulo mutex_enter(&provider->ftp_mtx);
12938605d1aeSRui Paulo
1294cd844e7aSJohn Birrell /*
1295cd844e7aSJohn Birrell * We won't be able to acquire a /proc-esque lock on the process
1296cd844e7aSJohn Birrell * iff the process is dead and gone. In this case, we rely on the
1297cd844e7aSJohn Birrell * provider lock as a point of mutual exclusion to prevent other
1298cd844e7aSJohn Birrell * DTrace consumers from disabling this probe.
1299cd844e7aSJohn Birrell */
130028180effSMark Johnston if (pget(probe->ftp_pid, PGET_HOLD | PGET_NOTWEXIT, &p) != 0)
1301a70a59eaSMark Johnston p = NULL;
1302cd844e7aSJohn Birrell
1303cd844e7aSJohn Birrell /*
1304cd844e7aSJohn Birrell * Disable all the associated tracepoints (for fully enabled probes).
1305cd844e7aSJohn Birrell */
1306cd844e7aSJohn Birrell if (probe->ftp_enabled) {
1307cd844e7aSJohn Birrell for (i = 0; i < probe->ftp_ntps; i++) {
1308cd844e7aSJohn Birrell fasttrap_tracepoint_disable(p, probe, i);
1309cd844e7aSJohn Birrell }
1310cd844e7aSJohn Birrell }
1311cd844e7aSJohn Birrell
1312cd844e7aSJohn Birrell ASSERT(provider->ftp_rcount > 0);
1313cd844e7aSJohn Birrell provider->ftp_rcount--;
1314cd844e7aSJohn Birrell
1315cd844e7aSJohn Birrell if (p != NULL) {
1316cd844e7aSJohn Birrell /*
1317cd844e7aSJohn Birrell * Even though we may not be able to remove it entirely, we
1318cd844e7aSJohn Birrell * mark this retired provider to get a chance to remove some
1319cd844e7aSJohn Birrell * of the associated probes.
1320cd844e7aSJohn Birrell */
1321cd844e7aSJohn Birrell if (provider->ftp_retired && !provider->ftp_marked)
1322cd844e7aSJohn Birrell whack = provider->ftp_marked = 1;
1323cd844e7aSJohn Birrell mutex_exit(&provider->ftp_mtx);
1324cd844e7aSJohn Birrell } else {
1325cd844e7aSJohn Birrell /*
1326cd844e7aSJohn Birrell * If the process is dead, we're just waiting for the
1327cd844e7aSJohn Birrell * last probe to be disabled to be able to free it.
1328cd844e7aSJohn Birrell */
1329cd844e7aSJohn Birrell if (provider->ftp_rcount == 0 && !provider->ftp_marked)
1330cd844e7aSJohn Birrell whack = provider->ftp_marked = 1;
1331cd844e7aSJohn Birrell mutex_exit(&provider->ftp_mtx);
1332cd844e7aSJohn Birrell }
1333cd844e7aSJohn Birrell
1334cd844e7aSJohn Birrell if (whack)
1335cd844e7aSJohn Birrell fasttrap_pid_cleanup();
1336cd844e7aSJohn Birrell
133747047e34SRui Paulo #ifdef __FreeBSD__
13386a8f90edSJustin T. Gibbs if (p != NULL)
133947047e34SRui Paulo PRELE(p);
134047047e34SRui Paulo #endif
1341cd844e7aSJohn Birrell if (!probe->ftp_enabled)
1342cd844e7aSJohn Birrell return;
1343cd844e7aSJohn Birrell
1344cd844e7aSJohn Birrell probe->ftp_enabled = 0;
1345cd844e7aSJohn Birrell
1346bc96366cSSteven Hartland #ifdef illumos
1347cd844e7aSJohn Birrell ASSERT(MUTEX_HELD(&cpu_lock));
13488605d1aeSRui Paulo #endif
1349cd844e7aSJohn Birrell fasttrap_disable_callbacks();
1350cd844e7aSJohn Birrell }
1351cd844e7aSJohn Birrell
1352cd844e7aSJohn Birrell /*ARGSUSED*/
1353cd844e7aSJohn Birrell static void
fasttrap_pid_getargdesc(void * arg,dtrace_id_t id,void * parg,dtrace_argdesc_t * desc)1354cd844e7aSJohn Birrell fasttrap_pid_getargdesc(void *arg, dtrace_id_t id, void *parg,
1355cd844e7aSJohn Birrell dtrace_argdesc_t *desc)
1356cd844e7aSJohn Birrell {
1357cd844e7aSJohn Birrell fasttrap_probe_t *probe = parg;
1358cd844e7aSJohn Birrell char *str;
1359cd844e7aSJohn Birrell int i, ndx;
1360cd844e7aSJohn Birrell
1361cd844e7aSJohn Birrell desc->dtargd_native[0] = '\0';
1362cd844e7aSJohn Birrell desc->dtargd_xlate[0] = '\0';
1363cd844e7aSJohn Birrell
1364cd844e7aSJohn Birrell if (probe->ftp_prov->ftp_retired != 0 ||
1365cd844e7aSJohn Birrell desc->dtargd_ndx >= probe->ftp_nargs) {
1366cd844e7aSJohn Birrell desc->dtargd_ndx = DTRACE_ARGNONE;
1367cd844e7aSJohn Birrell return;
1368cd844e7aSJohn Birrell }
1369cd844e7aSJohn Birrell
1370cd844e7aSJohn Birrell ndx = (probe->ftp_argmap != NULL) ?
1371cd844e7aSJohn Birrell probe->ftp_argmap[desc->dtargd_ndx] : desc->dtargd_ndx;
1372cd844e7aSJohn Birrell
1373cd844e7aSJohn Birrell str = probe->ftp_ntypes;
1374cd844e7aSJohn Birrell for (i = 0; i < ndx; i++) {
1375cd844e7aSJohn Birrell str += strlen(str) + 1;
1376cd844e7aSJohn Birrell }
1377cd844e7aSJohn Birrell
1378cd844e7aSJohn Birrell ASSERT(strlen(str + 1) < sizeof (desc->dtargd_native));
1379cd844e7aSJohn Birrell (void) strcpy(desc->dtargd_native, str);
1380cd844e7aSJohn Birrell
1381cd844e7aSJohn Birrell if (probe->ftp_xtypes == NULL)
1382cd844e7aSJohn Birrell return;
1383cd844e7aSJohn Birrell
1384cd844e7aSJohn Birrell str = probe->ftp_xtypes;
1385cd844e7aSJohn Birrell for (i = 0; i < desc->dtargd_ndx; i++) {
1386cd844e7aSJohn Birrell str += strlen(str) + 1;
1387cd844e7aSJohn Birrell }
1388cd844e7aSJohn Birrell
1389cd844e7aSJohn Birrell ASSERT(strlen(str + 1) < sizeof (desc->dtargd_xlate));
1390cd844e7aSJohn Birrell (void) strcpy(desc->dtargd_xlate, str);
1391cd844e7aSJohn Birrell }
1392cd844e7aSJohn Birrell
1393cd844e7aSJohn Birrell /*ARGSUSED*/
1394cd844e7aSJohn Birrell static void
fasttrap_pid_destroy(void * arg,dtrace_id_t id,void * parg)1395cd844e7aSJohn Birrell fasttrap_pid_destroy(void *arg, dtrace_id_t id, void *parg)
1396cd844e7aSJohn Birrell {
1397cd844e7aSJohn Birrell fasttrap_probe_t *probe = parg;
1398cd844e7aSJohn Birrell int i;
1399cd844e7aSJohn Birrell size_t size;
1400cd844e7aSJohn Birrell
1401cd844e7aSJohn Birrell ASSERT(probe != NULL);
1402cd844e7aSJohn Birrell ASSERT(!probe->ftp_enabled);
1403cd844e7aSJohn Birrell ASSERT(fasttrap_total >= probe->ftp_ntps);
1404cd844e7aSJohn Birrell
1405cd844e7aSJohn Birrell atomic_add_32(&fasttrap_total, -probe->ftp_ntps);
1406cd844e7aSJohn Birrell size = offsetof(fasttrap_probe_t, ftp_tps[probe->ftp_ntps]);
1407cd844e7aSJohn Birrell
1408cd844e7aSJohn Birrell if (probe->ftp_gen + 1 >= fasttrap_mod_gen)
1409cd844e7aSJohn Birrell fasttrap_mod_barrier(probe->ftp_gen);
1410cd844e7aSJohn Birrell
1411cd844e7aSJohn Birrell for (i = 0; i < probe->ftp_ntps; i++) {
1412cd844e7aSJohn Birrell kmem_free(probe->ftp_tps[i].fit_tp,
1413cd844e7aSJohn Birrell sizeof (fasttrap_tracepoint_t));
1414cd844e7aSJohn Birrell }
1415cd844e7aSJohn Birrell
1416cd844e7aSJohn Birrell kmem_free(probe, size);
1417cd844e7aSJohn Birrell }
1418cd844e7aSJohn Birrell
1419cd844e7aSJohn Birrell
1420cd844e7aSJohn Birrell static const dtrace_pattr_t pid_attr = {
1421cd844e7aSJohn Birrell { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
1422cd844e7aSJohn Birrell { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
1423cd844e7aSJohn Birrell { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
1424cd844e7aSJohn Birrell { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
1425cd844e7aSJohn Birrell { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
1426cd844e7aSJohn Birrell };
1427cd844e7aSJohn Birrell
1428cd844e7aSJohn Birrell static dtrace_pops_t pid_pops = {
142947f11baaSMark Johnston .dtps_provide = fasttrap_pid_provide,
143047f11baaSMark Johnston .dtps_provide_module = NULL,
143147f11baaSMark Johnston .dtps_enable = fasttrap_pid_enable,
143247f11baaSMark Johnston .dtps_disable = fasttrap_pid_disable,
143347f11baaSMark Johnston .dtps_suspend = NULL,
143447f11baaSMark Johnston .dtps_resume = NULL,
143547f11baaSMark Johnston .dtps_getargdesc = fasttrap_pid_getargdesc,
143647f11baaSMark Johnston .dtps_getargval = fasttrap_pid_getarg,
143747f11baaSMark Johnston .dtps_usermode = NULL,
143847f11baaSMark Johnston .dtps_destroy = fasttrap_pid_destroy
1439cd844e7aSJohn Birrell };
1440cd844e7aSJohn Birrell
1441cd844e7aSJohn Birrell static dtrace_pops_t usdt_pops = {
144247f11baaSMark Johnston .dtps_provide = fasttrap_pid_provide,
144347f11baaSMark Johnston .dtps_provide_module = NULL,
144447f11baaSMark Johnston .dtps_enable = fasttrap_pid_enable,
144547f11baaSMark Johnston .dtps_disable = fasttrap_pid_disable,
144647f11baaSMark Johnston .dtps_suspend = NULL,
144747f11baaSMark Johnston .dtps_resume = NULL,
144847f11baaSMark Johnston .dtps_getargdesc = fasttrap_pid_getargdesc,
144947f11baaSMark Johnston .dtps_getargval = fasttrap_usdt_getarg,
145047f11baaSMark Johnston .dtps_usermode = NULL,
145147f11baaSMark Johnston .dtps_destroy = fasttrap_pid_destroy
1452cd844e7aSJohn Birrell };
1453cd844e7aSJohn Birrell
1454cd844e7aSJohn Birrell static fasttrap_proc_t *
fasttrap_proc_lookup(pid_t pid)1455cd844e7aSJohn Birrell fasttrap_proc_lookup(pid_t pid)
1456cd844e7aSJohn Birrell {
1457cd844e7aSJohn Birrell fasttrap_bucket_t *bucket;
1458cd844e7aSJohn Birrell fasttrap_proc_t *fprc, *new_fprc;
1459cd844e7aSJohn Birrell
14608605d1aeSRui Paulo
1461cd844e7aSJohn Birrell bucket = &fasttrap_procs.fth_table[FASTTRAP_PROCS_INDEX(pid)];
1462cd844e7aSJohn Birrell mutex_enter(&bucket->ftb_mtx);
1463cd844e7aSJohn Birrell
1464cd844e7aSJohn Birrell for (fprc = bucket->ftb_data; fprc != NULL; fprc = fprc->ftpc_next) {
1465cd844e7aSJohn Birrell if (fprc->ftpc_pid == pid && fprc->ftpc_acount != 0) {
1466cd844e7aSJohn Birrell mutex_enter(&fprc->ftpc_mtx);
1467cd844e7aSJohn Birrell mutex_exit(&bucket->ftb_mtx);
1468cd844e7aSJohn Birrell fprc->ftpc_rcount++;
1469249ddb42SXin LI atomic_inc_64(&fprc->ftpc_acount);
14705a1b490dSJohn Birrell ASSERT(fprc->ftpc_acount <= fprc->ftpc_rcount);
1471cd844e7aSJohn Birrell mutex_exit(&fprc->ftpc_mtx);
1472cd844e7aSJohn Birrell
1473cd844e7aSJohn Birrell return (fprc);
1474cd844e7aSJohn Birrell }
1475cd844e7aSJohn Birrell }
1476cd844e7aSJohn Birrell
1477cd844e7aSJohn Birrell /*
1478cd844e7aSJohn Birrell * Drop the bucket lock so we don't try to perform a sleeping
1479cd844e7aSJohn Birrell * allocation under it.
1480cd844e7aSJohn Birrell */
1481cd844e7aSJohn Birrell mutex_exit(&bucket->ftb_mtx);
1482cd844e7aSJohn Birrell
1483cd844e7aSJohn Birrell new_fprc = kmem_zalloc(sizeof (fasttrap_proc_t), KM_SLEEP);
1484cd844e7aSJohn Birrell new_fprc->ftpc_pid = pid;
1485cd844e7aSJohn Birrell new_fprc->ftpc_rcount = 1;
1486cd844e7aSJohn Birrell new_fprc->ftpc_acount = 1;
1487bc96366cSSteven Hartland #ifndef illumos
14888605d1aeSRui Paulo mutex_init(&new_fprc->ftpc_mtx, "fasttrap proc mtx", MUTEX_DEFAULT,
14898605d1aeSRui Paulo NULL);
14908605d1aeSRui Paulo #endif
1491cd844e7aSJohn Birrell
1492cd844e7aSJohn Birrell mutex_enter(&bucket->ftb_mtx);
1493cd844e7aSJohn Birrell
1494cd844e7aSJohn Birrell /*
1495cd844e7aSJohn Birrell * Take another lap through the list to make sure a proc hasn't
1496cd844e7aSJohn Birrell * been created for this pid while we weren't under the bucket lock.
1497cd844e7aSJohn Birrell */
1498cd844e7aSJohn Birrell for (fprc = bucket->ftb_data; fprc != NULL; fprc = fprc->ftpc_next) {
1499cd844e7aSJohn Birrell if (fprc->ftpc_pid == pid && fprc->ftpc_acount != 0) {
1500cd844e7aSJohn Birrell mutex_enter(&fprc->ftpc_mtx);
1501cd844e7aSJohn Birrell mutex_exit(&bucket->ftb_mtx);
1502cd844e7aSJohn Birrell fprc->ftpc_rcount++;
1503249ddb42SXin LI atomic_inc_64(&fprc->ftpc_acount);
15045a1b490dSJohn Birrell ASSERT(fprc->ftpc_acount <= fprc->ftpc_rcount);
1505cd844e7aSJohn Birrell mutex_exit(&fprc->ftpc_mtx);
1506cd844e7aSJohn Birrell
1507cd844e7aSJohn Birrell kmem_free(new_fprc, sizeof (fasttrap_proc_t));
1508cd844e7aSJohn Birrell
1509cd844e7aSJohn Birrell return (fprc);
1510cd844e7aSJohn Birrell }
1511cd844e7aSJohn Birrell }
1512cd844e7aSJohn Birrell
1513cd844e7aSJohn Birrell new_fprc->ftpc_next = bucket->ftb_data;
1514cd844e7aSJohn Birrell bucket->ftb_data = new_fprc;
1515cd844e7aSJohn Birrell
1516cd844e7aSJohn Birrell mutex_exit(&bucket->ftb_mtx);
1517cd844e7aSJohn Birrell
1518cd844e7aSJohn Birrell return (new_fprc);
1519cd844e7aSJohn Birrell }
1520cd844e7aSJohn Birrell
1521cd844e7aSJohn Birrell static void
fasttrap_proc_release(fasttrap_proc_t * proc)1522cd844e7aSJohn Birrell fasttrap_proc_release(fasttrap_proc_t *proc)
1523cd844e7aSJohn Birrell {
1524cd844e7aSJohn Birrell fasttrap_bucket_t *bucket;
1525cd844e7aSJohn Birrell fasttrap_proc_t *fprc, **fprcp;
1526cd844e7aSJohn Birrell pid_t pid = proc->ftpc_pid;
1527bc96366cSSteven Hartland #ifndef illumos
15280626f3e4SMark Johnston fasttrap_scrblock_t *scrblk, *scrblktmp;
15290626f3e4SMark Johnston fasttrap_scrspace_t *scrspc, *scrspctmp;
15300626f3e4SMark Johnston struct proc *p;
15310626f3e4SMark Johnston struct thread *td;
15320626f3e4SMark Johnston #endif
1533cd844e7aSJohn Birrell
1534cd844e7aSJohn Birrell mutex_enter(&proc->ftpc_mtx);
1535cd844e7aSJohn Birrell
1536cd844e7aSJohn Birrell ASSERT(proc->ftpc_rcount != 0);
15375a1b490dSJohn Birrell ASSERT(proc->ftpc_acount <= proc->ftpc_rcount);
1538cd844e7aSJohn Birrell
1539cd844e7aSJohn Birrell if (--proc->ftpc_rcount != 0) {
1540cd844e7aSJohn Birrell mutex_exit(&proc->ftpc_mtx);
1541cd844e7aSJohn Birrell return;
1542cd844e7aSJohn Birrell }
1543cd844e7aSJohn Birrell
1544bc96366cSSteven Hartland #ifndef illumos
15450626f3e4SMark Johnston /*
15460626f3e4SMark Johnston * Free all structures used to manage per-thread scratch space.
15470626f3e4SMark Johnston */
15480626f3e4SMark Johnston LIST_FOREACH_SAFE(scrblk, &proc->ftpc_scrblks, ftsb_next,
15490626f3e4SMark Johnston scrblktmp) {
15500626f3e4SMark Johnston LIST_REMOVE(scrblk, ftsb_next);
15510626f3e4SMark Johnston free(scrblk, M_SOLARIS);
15520626f3e4SMark Johnston }
15530626f3e4SMark Johnston LIST_FOREACH_SAFE(scrspc, &proc->ftpc_fscr, ftss_next, scrspctmp) {
15540626f3e4SMark Johnston LIST_REMOVE(scrspc, ftss_next);
15550626f3e4SMark Johnston free(scrspc, M_SOLARIS);
15560626f3e4SMark Johnston }
15570626f3e4SMark Johnston LIST_FOREACH_SAFE(scrspc, &proc->ftpc_ascr, ftss_next, scrspctmp) {
15580626f3e4SMark Johnston LIST_REMOVE(scrspc, ftss_next);
15590626f3e4SMark Johnston free(scrspc, M_SOLARIS);
15600626f3e4SMark Johnston }
15610626f3e4SMark Johnston
15620626f3e4SMark Johnston if ((p = pfind(pid)) != NULL) {
15630626f3e4SMark Johnston FOREACH_THREAD_IN_PROC(p, td)
15640626f3e4SMark Johnston td->t_dtrace_sscr = NULL;
15650626f3e4SMark Johnston PROC_UNLOCK(p);
15660626f3e4SMark Johnston }
15670626f3e4SMark Johnston #endif
15680626f3e4SMark Johnston
1569cd844e7aSJohn Birrell mutex_exit(&proc->ftpc_mtx);
1570cd844e7aSJohn Birrell
1571cd844e7aSJohn Birrell /*
1572cd844e7aSJohn Birrell * There should definitely be no live providers associated with this
1573cd844e7aSJohn Birrell * process at this point.
1574cd844e7aSJohn Birrell */
1575cd844e7aSJohn Birrell ASSERT(proc->ftpc_acount == 0);
1576cd844e7aSJohn Birrell
1577cd844e7aSJohn Birrell bucket = &fasttrap_procs.fth_table[FASTTRAP_PROCS_INDEX(pid)];
1578cd844e7aSJohn Birrell mutex_enter(&bucket->ftb_mtx);
1579cd844e7aSJohn Birrell
1580cd844e7aSJohn Birrell fprcp = (fasttrap_proc_t **)&bucket->ftb_data;
1581cd844e7aSJohn Birrell while ((fprc = *fprcp) != NULL) {
1582cd844e7aSJohn Birrell if (fprc == proc)
1583cd844e7aSJohn Birrell break;
1584cd844e7aSJohn Birrell
1585cd844e7aSJohn Birrell fprcp = &fprc->ftpc_next;
1586cd844e7aSJohn Birrell }
1587cd844e7aSJohn Birrell
1588cd844e7aSJohn Birrell /*
1589cd844e7aSJohn Birrell * Something strange has happened if we can't find the proc.
1590cd844e7aSJohn Birrell */
1591cd844e7aSJohn Birrell ASSERT(fprc != NULL);
1592cd844e7aSJohn Birrell
1593cd844e7aSJohn Birrell *fprcp = fprc->ftpc_next;
1594cd844e7aSJohn Birrell
1595cd844e7aSJohn Birrell mutex_exit(&bucket->ftb_mtx);
1596cd844e7aSJohn Birrell
1597cd844e7aSJohn Birrell kmem_free(fprc, sizeof (fasttrap_proc_t));
1598cd844e7aSJohn Birrell }
1599cd844e7aSJohn Birrell
1600cd844e7aSJohn Birrell /*
1601cd844e7aSJohn Birrell * Lookup a fasttrap-managed provider based on its name and associated pid.
1602cd844e7aSJohn Birrell * If the pattr argument is non-NULL, this function instantiates the provider
1603cd844e7aSJohn Birrell * if it doesn't exist otherwise it returns NULL. The provider is returned
1604cd844e7aSJohn Birrell * with its lock held.
1605cd844e7aSJohn Birrell */
1606cd844e7aSJohn Birrell static fasttrap_provider_t *
fasttrap_provider_lookup(pid_t pid,const char * name,const dtrace_pattr_t * pattr)1607cd844e7aSJohn Birrell fasttrap_provider_lookup(pid_t pid, const char *name,
1608cd844e7aSJohn Birrell const dtrace_pattr_t *pattr)
1609cd844e7aSJohn Birrell {
1610cd844e7aSJohn Birrell fasttrap_provider_t *fp, *new_fp = NULL;
1611cd844e7aSJohn Birrell fasttrap_bucket_t *bucket;
1612cd844e7aSJohn Birrell char provname[DTRACE_PROVNAMELEN];
1613cd844e7aSJohn Birrell proc_t *p;
1614cd844e7aSJohn Birrell cred_t *cred;
1615cd844e7aSJohn Birrell
1616cd844e7aSJohn Birrell ASSERT(strlen(name) < sizeof (fp->ftp_name));
1617cd844e7aSJohn Birrell ASSERT(pattr != NULL);
1618cd844e7aSJohn Birrell
1619cd844e7aSJohn Birrell bucket = &fasttrap_provs.fth_table[FASTTRAP_PROVS_INDEX(pid, name)];
1620cd844e7aSJohn Birrell mutex_enter(&bucket->ftb_mtx);
1621cd844e7aSJohn Birrell
1622cd844e7aSJohn Birrell /*
1623cd844e7aSJohn Birrell * Take a lap through the list and return the match if we find it.
1624cd844e7aSJohn Birrell */
1625cd844e7aSJohn Birrell for (fp = bucket->ftb_data; fp != NULL; fp = fp->ftp_next) {
1626cd844e7aSJohn Birrell if (fp->ftp_pid == pid && strcmp(fp->ftp_name, name) == 0 &&
1627cd844e7aSJohn Birrell !fp->ftp_retired) {
1628cd844e7aSJohn Birrell mutex_enter(&fp->ftp_mtx);
1629cd844e7aSJohn Birrell mutex_exit(&bucket->ftb_mtx);
1630cd844e7aSJohn Birrell return (fp);
1631cd844e7aSJohn Birrell }
1632cd844e7aSJohn Birrell }
1633cd844e7aSJohn Birrell
1634cd844e7aSJohn Birrell /*
1635cd844e7aSJohn Birrell * Drop the bucket lock so we don't try to perform a sleeping
1636cd844e7aSJohn Birrell * allocation under it.
1637cd844e7aSJohn Birrell */
1638cd844e7aSJohn Birrell mutex_exit(&bucket->ftb_mtx);
1639cd844e7aSJohn Birrell
1640cd844e7aSJohn Birrell /*
1641cd844e7aSJohn Birrell * Make sure the process exists, isn't a child created as the result
1642cd844e7aSJohn Birrell * of a vfork(2), and isn't a zombie (but may be in fork).
1643cd844e7aSJohn Birrell */
16448605d1aeSRui Paulo if ((p = pfind(pid)) == NULL)
1645cd844e7aSJohn Birrell return (NULL);
1646cd844e7aSJohn Birrell
1647cd844e7aSJohn Birrell /*
1648cd844e7aSJohn Birrell * Increment p_dtrace_probes so that the process knows to inform us
1649cd844e7aSJohn Birrell * when it exits or execs. fasttrap_provider_free() decrements this
1650cd844e7aSJohn Birrell * when we're done with this provider.
1651cd844e7aSJohn Birrell */
1652cd844e7aSJohn Birrell p->p_dtrace_probes++;
1653cd844e7aSJohn Birrell
1654cd844e7aSJohn Birrell /*
1655cd844e7aSJohn Birrell * Grab the credentials for this process so we have
1656cd844e7aSJohn Birrell * something to pass to dtrace_register().
1657cd844e7aSJohn Birrell */
16588605d1aeSRui Paulo PROC_LOCK_ASSERT(p, MA_OWNED);
16598605d1aeSRui Paulo crhold(p->p_ucred);
16608605d1aeSRui Paulo cred = p->p_ucred;
16618605d1aeSRui Paulo PROC_UNLOCK(p);
1662cd844e7aSJohn Birrell
1663cd844e7aSJohn Birrell new_fp = kmem_zalloc(sizeof (fasttrap_provider_t), KM_SLEEP);
1664cd844e7aSJohn Birrell new_fp->ftp_pid = pid;
1665cd844e7aSJohn Birrell new_fp->ftp_proc = fasttrap_proc_lookup(pid);
1666bc96366cSSteven Hartland #ifndef illumos
16678605d1aeSRui Paulo mutex_init(&new_fp->ftp_mtx, "provider mtx", MUTEX_DEFAULT, NULL);
16688605d1aeSRui Paulo mutex_init(&new_fp->ftp_cmtx, "lock on creating", MUTEX_DEFAULT, NULL);
16698605d1aeSRui Paulo #endif
1670cd844e7aSJohn Birrell
1671cd844e7aSJohn Birrell ASSERT(new_fp->ftp_proc != NULL);
1672cd844e7aSJohn Birrell
1673cd844e7aSJohn Birrell mutex_enter(&bucket->ftb_mtx);
1674cd844e7aSJohn Birrell
1675cd844e7aSJohn Birrell /*
1676cd844e7aSJohn Birrell * Take another lap through the list to make sure a provider hasn't
1677cd844e7aSJohn Birrell * been created for this pid while we weren't under the bucket lock.
1678cd844e7aSJohn Birrell */
1679cd844e7aSJohn Birrell for (fp = bucket->ftb_data; fp != NULL; fp = fp->ftp_next) {
1680cd844e7aSJohn Birrell if (fp->ftp_pid == pid && strcmp(fp->ftp_name, name) == 0 &&
1681cd844e7aSJohn Birrell !fp->ftp_retired) {
1682cd844e7aSJohn Birrell mutex_enter(&fp->ftp_mtx);
1683cd844e7aSJohn Birrell mutex_exit(&bucket->ftb_mtx);
1684cd844e7aSJohn Birrell fasttrap_provider_free(new_fp);
1685cd844e7aSJohn Birrell crfree(cred);
1686cd844e7aSJohn Birrell return (fp);
1687cd844e7aSJohn Birrell }
1688cd844e7aSJohn Birrell }
1689cd844e7aSJohn Birrell
1690cd844e7aSJohn Birrell (void) strcpy(new_fp->ftp_name, name);
1691cd844e7aSJohn Birrell
1692cd844e7aSJohn Birrell /*
1693cd844e7aSJohn Birrell * Fail and return NULL if either the provider name is too long
1694cd844e7aSJohn Birrell * or we fail to register this new provider with the DTrace
1695cd844e7aSJohn Birrell * framework. Note that this is the only place we ever construct
1696cd844e7aSJohn Birrell * the full provider name -- we keep it in pieces in the provider
1697cd844e7aSJohn Birrell * structure.
1698cd844e7aSJohn Birrell */
1699cd844e7aSJohn Birrell if (snprintf(provname, sizeof (provname), "%s%u", name, (uint_t)pid) >=
1700cd844e7aSJohn Birrell sizeof (provname) ||
1701cd844e7aSJohn Birrell dtrace_register(provname, pattr,
1702cd844e7aSJohn Birrell DTRACE_PRIV_PROC | DTRACE_PRIV_OWNER | DTRACE_PRIV_ZONEOWNER, cred,
1703cd844e7aSJohn Birrell pattr == &pid_attr ? &pid_pops : &usdt_pops, new_fp,
1704cd844e7aSJohn Birrell &new_fp->ftp_provid) != 0) {
1705cd844e7aSJohn Birrell mutex_exit(&bucket->ftb_mtx);
1706cd844e7aSJohn Birrell fasttrap_provider_free(new_fp);
1707cd844e7aSJohn Birrell crfree(cred);
1708cd844e7aSJohn Birrell return (NULL);
1709cd844e7aSJohn Birrell }
1710cd844e7aSJohn Birrell
1711cd844e7aSJohn Birrell new_fp->ftp_next = bucket->ftb_data;
1712cd844e7aSJohn Birrell bucket->ftb_data = new_fp;
1713cd844e7aSJohn Birrell
1714cd844e7aSJohn Birrell mutex_enter(&new_fp->ftp_mtx);
1715cd844e7aSJohn Birrell mutex_exit(&bucket->ftb_mtx);
1716cd844e7aSJohn Birrell
1717cd844e7aSJohn Birrell crfree(cred);
1718cd844e7aSJohn Birrell return (new_fp);
1719cd844e7aSJohn Birrell }
1720cd844e7aSJohn Birrell
1721cd844e7aSJohn Birrell static void
fasttrap_provider_free(fasttrap_provider_t * provider)1722cd844e7aSJohn Birrell fasttrap_provider_free(fasttrap_provider_t *provider)
1723cd844e7aSJohn Birrell {
1724cd844e7aSJohn Birrell pid_t pid = provider->ftp_pid;
1725cd844e7aSJohn Birrell proc_t *p;
1726cd844e7aSJohn Birrell
1727cd844e7aSJohn Birrell /*
1728cd844e7aSJohn Birrell * There need to be no associated enabled probes, no consumers
1729cd844e7aSJohn Birrell * creating probes, and no meta providers referencing this provider.
1730cd844e7aSJohn Birrell */
1731cd844e7aSJohn Birrell ASSERT(provider->ftp_rcount == 0);
1732cd844e7aSJohn Birrell ASSERT(provider->ftp_ccount == 0);
1733cd844e7aSJohn Birrell ASSERT(provider->ftp_mcount == 0);
1734cd844e7aSJohn Birrell
17355a1b490dSJohn Birrell /*
17365a1b490dSJohn Birrell * If this provider hasn't been retired, we need to explicitly drop the
17375a1b490dSJohn Birrell * count of active providers on the associated process structure.
17385a1b490dSJohn Birrell */
17395a1b490dSJohn Birrell if (!provider->ftp_retired) {
1740249ddb42SXin LI atomic_dec_64(&provider->ftp_proc->ftpc_acount);
17415a1b490dSJohn Birrell ASSERT(provider->ftp_proc->ftpc_acount <
17425a1b490dSJohn Birrell provider->ftp_proc->ftpc_rcount);
17435a1b490dSJohn Birrell }
17445a1b490dSJohn Birrell
1745cd844e7aSJohn Birrell fasttrap_proc_release(provider->ftp_proc);
1746cd844e7aSJohn Birrell
1747bc96366cSSteven Hartland #ifndef illumos
17488605d1aeSRui Paulo mutex_destroy(&provider->ftp_mtx);
17498605d1aeSRui Paulo mutex_destroy(&provider->ftp_cmtx);
17508605d1aeSRui Paulo #endif
1751cd844e7aSJohn Birrell kmem_free(provider, sizeof (fasttrap_provider_t));
1752cd844e7aSJohn Birrell
1753cd844e7aSJohn Birrell /*
1754cd844e7aSJohn Birrell * Decrement p_dtrace_probes on the process whose provider we're
1755cd844e7aSJohn Birrell * freeing. We don't have to worry about clobbering somone else's
1756cd844e7aSJohn Birrell * modifications to it because we have locked the bucket that
1757cd844e7aSJohn Birrell * corresponds to this process's hash chain in the provider hash
1758cd844e7aSJohn Birrell * table. Don't sweat it if we can't find the process.
1759cd844e7aSJohn Birrell */
17608605d1aeSRui Paulo if ((p = pfind(pid)) == NULL) {
1761cd844e7aSJohn Birrell return;
1762cd844e7aSJohn Birrell }
1763cd844e7aSJohn Birrell
1764cd844e7aSJohn Birrell p->p_dtrace_probes--;
1765bc96366cSSteven Hartland #ifndef illumos
17668605d1aeSRui Paulo PROC_UNLOCK(p);
17678605d1aeSRui Paulo #endif
1768cd844e7aSJohn Birrell }
1769cd844e7aSJohn Birrell
1770cd844e7aSJohn Birrell static void
fasttrap_provider_retire(pid_t pid,const char * name,int mprov)1771cd844e7aSJohn Birrell fasttrap_provider_retire(pid_t pid, const char *name, int mprov)
1772cd844e7aSJohn Birrell {
1773cd844e7aSJohn Birrell fasttrap_provider_t *fp;
1774cd844e7aSJohn Birrell fasttrap_bucket_t *bucket;
1775cd844e7aSJohn Birrell dtrace_provider_id_t provid;
1776cd844e7aSJohn Birrell
1777cd844e7aSJohn Birrell ASSERT(strlen(name) < sizeof (fp->ftp_name));
1778cd844e7aSJohn Birrell
1779cd844e7aSJohn Birrell bucket = &fasttrap_provs.fth_table[FASTTRAP_PROVS_INDEX(pid, name)];
1780cd844e7aSJohn Birrell mutex_enter(&bucket->ftb_mtx);
1781cd844e7aSJohn Birrell
1782cd844e7aSJohn Birrell for (fp = bucket->ftb_data; fp != NULL; fp = fp->ftp_next) {
1783cd844e7aSJohn Birrell if (fp->ftp_pid == pid && strcmp(fp->ftp_name, name) == 0 &&
1784cd844e7aSJohn Birrell !fp->ftp_retired)
1785cd844e7aSJohn Birrell break;
1786cd844e7aSJohn Birrell }
1787cd844e7aSJohn Birrell
1788cd844e7aSJohn Birrell if (fp == NULL) {
1789cd844e7aSJohn Birrell mutex_exit(&bucket->ftb_mtx);
1790cd844e7aSJohn Birrell return;
1791cd844e7aSJohn Birrell }
1792cd844e7aSJohn Birrell
1793cd844e7aSJohn Birrell mutex_enter(&fp->ftp_mtx);
1794cd844e7aSJohn Birrell ASSERT(!mprov || fp->ftp_mcount > 0);
1795cd844e7aSJohn Birrell if (mprov && --fp->ftp_mcount != 0) {
1796cd844e7aSJohn Birrell mutex_exit(&fp->ftp_mtx);
1797cd844e7aSJohn Birrell mutex_exit(&bucket->ftb_mtx);
1798cd844e7aSJohn Birrell return;
1799cd844e7aSJohn Birrell }
1800cd844e7aSJohn Birrell
1801cd844e7aSJohn Birrell /*
1802cd844e7aSJohn Birrell * Mark the provider to be removed in our post-processing step, mark it
1803cd844e7aSJohn Birrell * retired, and drop the active count on its proc. Marking it indicates
1804cd844e7aSJohn Birrell * that we should try to remove it; setting the retired flag indicates
1805cd844e7aSJohn Birrell * that we're done with this provider; dropping the active the proc
1806cd844e7aSJohn Birrell * releases our hold, and when this reaches zero (as it will during
1807cd844e7aSJohn Birrell * exit or exec) the proc and associated providers become defunct.
1808cd844e7aSJohn Birrell *
1809cd844e7aSJohn Birrell * We obviously need to take the bucket lock before the provider lock
1810cd844e7aSJohn Birrell * to perform the lookup, but we need to drop the provider lock
1811cd844e7aSJohn Birrell * before calling into the DTrace framework since we acquire the
1812cd844e7aSJohn Birrell * provider lock in callbacks invoked from the DTrace framework. The
1813cd844e7aSJohn Birrell * bucket lock therefore protects the integrity of the provider hash
1814cd844e7aSJohn Birrell * table.
1815cd844e7aSJohn Birrell */
1816249ddb42SXin LI atomic_dec_64(&fp->ftp_proc->ftpc_acount);
18175a1b490dSJohn Birrell ASSERT(fp->ftp_proc->ftpc_acount < fp->ftp_proc->ftpc_rcount);
18185a1b490dSJohn Birrell
1819cd844e7aSJohn Birrell fp->ftp_retired = 1;
1820cd844e7aSJohn Birrell fp->ftp_marked = 1;
1821cd844e7aSJohn Birrell provid = fp->ftp_provid;
1822cd844e7aSJohn Birrell mutex_exit(&fp->ftp_mtx);
1823cd844e7aSJohn Birrell
1824cd844e7aSJohn Birrell /*
1825cd844e7aSJohn Birrell * We don't have to worry about invalidating the same provider twice
1826cd844e7aSJohn Birrell * since fasttrap_provider_lookup() will ignore provider that have
1827cd844e7aSJohn Birrell * been marked as retired.
1828cd844e7aSJohn Birrell */
1829cd844e7aSJohn Birrell dtrace_invalidate(provid);
1830cd844e7aSJohn Birrell
1831cd844e7aSJohn Birrell mutex_exit(&bucket->ftb_mtx);
1832cd844e7aSJohn Birrell
1833cd844e7aSJohn Birrell fasttrap_pid_cleanup();
1834cd844e7aSJohn Birrell }
1835cd844e7aSJohn Birrell
1836cd844e7aSJohn Birrell static int
fasttrap_uint32_cmp(const void * ap,const void * bp)1837cd844e7aSJohn Birrell fasttrap_uint32_cmp(const void *ap, const void *bp)
1838cd844e7aSJohn Birrell {
1839cd844e7aSJohn Birrell return (*(const uint32_t *)ap - *(const uint32_t *)bp);
1840cd844e7aSJohn Birrell }
1841cd844e7aSJohn Birrell
1842cd844e7aSJohn Birrell static int
fasttrap_uint64_cmp(const void * ap,const void * bp)1843cd844e7aSJohn Birrell fasttrap_uint64_cmp(const void *ap, const void *bp)
1844cd844e7aSJohn Birrell {
1845cd844e7aSJohn Birrell return (*(const uint64_t *)ap - *(const uint64_t *)bp);
1846cd844e7aSJohn Birrell }
1847cd844e7aSJohn Birrell
1848cd844e7aSJohn Birrell static int
fasttrap_add_probe(fasttrap_probe_spec_t * pdata)1849cd844e7aSJohn Birrell fasttrap_add_probe(fasttrap_probe_spec_t *pdata)
1850cd844e7aSJohn Birrell {
1851cd844e7aSJohn Birrell fasttrap_provider_t *provider;
1852cd844e7aSJohn Birrell fasttrap_probe_t *pp;
1853cd844e7aSJohn Birrell fasttrap_tracepoint_t *tp;
1854cd844e7aSJohn Birrell char *name;
18558605d1aeSRui Paulo int i, aframes = 0, whack;
1856cd844e7aSJohn Birrell
1857cd844e7aSJohn Birrell /*
1858cd844e7aSJohn Birrell * There needs to be at least one desired trace point.
1859cd844e7aSJohn Birrell */
1860cd844e7aSJohn Birrell if (pdata->ftps_noffs == 0)
1861cd844e7aSJohn Birrell return (EINVAL);
1862cd844e7aSJohn Birrell
1863cd844e7aSJohn Birrell switch (pdata->ftps_type) {
1864cd844e7aSJohn Birrell case DTFTP_ENTRY:
1865cd844e7aSJohn Birrell name = "entry";
1866cd844e7aSJohn Birrell aframes = FASTTRAP_ENTRY_AFRAMES;
1867cd844e7aSJohn Birrell break;
1868cd844e7aSJohn Birrell case DTFTP_RETURN:
1869cd844e7aSJohn Birrell name = "return";
1870cd844e7aSJohn Birrell aframes = FASTTRAP_RETURN_AFRAMES;
1871cd844e7aSJohn Birrell break;
1872cd844e7aSJohn Birrell case DTFTP_OFFSETS:
1873cd844e7aSJohn Birrell name = NULL;
1874cd844e7aSJohn Birrell break;
1875cd844e7aSJohn Birrell default:
1876cd844e7aSJohn Birrell return (EINVAL);
1877cd844e7aSJohn Birrell }
1878cd844e7aSJohn Birrell
1879cd844e7aSJohn Birrell if ((provider = fasttrap_provider_lookup(pdata->ftps_pid,
1880cd844e7aSJohn Birrell FASTTRAP_PID_NAME, &pid_attr)) == NULL)
1881cd844e7aSJohn Birrell return (ESRCH);
1882cd844e7aSJohn Birrell
1883cd844e7aSJohn Birrell /*
1884cd844e7aSJohn Birrell * Increment this reference count to indicate that a consumer is
1885cd844e7aSJohn Birrell * actively adding a new probe associated with this provider. This
1886cd844e7aSJohn Birrell * prevents the provider from being deleted -- we'll need to check
1887cd844e7aSJohn Birrell * for pending deletions when we drop this reference count.
1888cd844e7aSJohn Birrell */
1889cd844e7aSJohn Birrell provider->ftp_ccount++;
1890cd844e7aSJohn Birrell mutex_exit(&provider->ftp_mtx);
1891cd844e7aSJohn Birrell
1892cd844e7aSJohn Birrell /*
1893cd844e7aSJohn Birrell * Grab the creation lock to ensure consistency between calls to
1894cd844e7aSJohn Birrell * dtrace_probe_lookup() and dtrace_probe_create() in the face of
1895cd844e7aSJohn Birrell * other threads creating probes. We must drop the provider lock
1896cd844e7aSJohn Birrell * before taking this lock to avoid a three-way deadlock with the
1897cd844e7aSJohn Birrell * DTrace framework.
1898cd844e7aSJohn Birrell */
1899cd844e7aSJohn Birrell mutex_enter(&provider->ftp_cmtx);
1900cd844e7aSJohn Birrell
1901cd844e7aSJohn Birrell if (name == NULL) {
1902cd844e7aSJohn Birrell for (i = 0; i < pdata->ftps_noffs; i++) {
1903cd844e7aSJohn Birrell char name_str[17];
1904cd844e7aSJohn Birrell
1905cd844e7aSJohn Birrell (void) sprintf(name_str, "%llx",
1906cd844e7aSJohn Birrell (unsigned long long)pdata->ftps_offs[i]);
1907cd844e7aSJohn Birrell
1908cd844e7aSJohn Birrell if (dtrace_probe_lookup(provider->ftp_provid,
1909cd844e7aSJohn Birrell pdata->ftps_mod, pdata->ftps_func, name_str) != 0)
1910cd844e7aSJohn Birrell continue;
1911cd844e7aSJohn Birrell
1912249ddb42SXin LI atomic_inc_32(&fasttrap_total);
1913cd844e7aSJohn Birrell
1914cd844e7aSJohn Birrell if (fasttrap_total > fasttrap_max) {
1915249ddb42SXin LI atomic_dec_32(&fasttrap_total);
1916cd844e7aSJohn Birrell goto no_mem;
1917cd844e7aSJohn Birrell }
1918cd844e7aSJohn Birrell
1919cd844e7aSJohn Birrell pp = kmem_zalloc(sizeof (fasttrap_probe_t), KM_SLEEP);
1920cd844e7aSJohn Birrell
1921cd844e7aSJohn Birrell pp->ftp_prov = provider;
1922cd844e7aSJohn Birrell pp->ftp_faddr = pdata->ftps_pc;
1923cd844e7aSJohn Birrell pp->ftp_fsize = pdata->ftps_size;
1924cd844e7aSJohn Birrell pp->ftp_pid = pdata->ftps_pid;
1925cd844e7aSJohn Birrell pp->ftp_ntps = 1;
1926cd844e7aSJohn Birrell
1927cd844e7aSJohn Birrell tp = kmem_zalloc(sizeof (fasttrap_tracepoint_t),
1928cd844e7aSJohn Birrell KM_SLEEP);
1929cd844e7aSJohn Birrell
1930cd844e7aSJohn Birrell tp->ftt_proc = provider->ftp_proc;
1931cd844e7aSJohn Birrell tp->ftt_pc = pdata->ftps_offs[i] + pdata->ftps_pc;
1932cd844e7aSJohn Birrell tp->ftt_pid = pdata->ftps_pid;
1933cd844e7aSJohn Birrell
1934cd844e7aSJohn Birrell pp->ftp_tps[0].fit_tp = tp;
1935cd844e7aSJohn Birrell pp->ftp_tps[0].fit_id.fti_probe = pp;
1936cd844e7aSJohn Birrell pp->ftp_tps[0].fit_id.fti_ptype = pdata->ftps_type;
1937cd844e7aSJohn Birrell
1938cd844e7aSJohn Birrell pp->ftp_id = dtrace_probe_create(provider->ftp_provid,
1939cd844e7aSJohn Birrell pdata->ftps_mod, pdata->ftps_func, name_str,
1940cd844e7aSJohn Birrell FASTTRAP_OFFSET_AFRAMES, pp);
1941cd844e7aSJohn Birrell }
1942cd844e7aSJohn Birrell
1943cd844e7aSJohn Birrell } else if (dtrace_probe_lookup(provider->ftp_provid, pdata->ftps_mod,
1944cd844e7aSJohn Birrell pdata->ftps_func, name) == 0) {
1945cd844e7aSJohn Birrell atomic_add_32(&fasttrap_total, pdata->ftps_noffs);
1946cd844e7aSJohn Birrell
1947cd844e7aSJohn Birrell if (fasttrap_total > fasttrap_max) {
1948cd844e7aSJohn Birrell atomic_add_32(&fasttrap_total, -pdata->ftps_noffs);
1949cd844e7aSJohn Birrell goto no_mem;
1950cd844e7aSJohn Birrell }
1951cd844e7aSJohn Birrell
1952cd844e7aSJohn Birrell /*
1953cd844e7aSJohn Birrell * Make sure all tracepoint program counter values are unique.
1954cd844e7aSJohn Birrell * We later assume that each probe has exactly one tracepoint
1955cd844e7aSJohn Birrell * for a given pc.
1956cd844e7aSJohn Birrell */
1957cd844e7aSJohn Birrell qsort(pdata->ftps_offs, pdata->ftps_noffs,
1958cd844e7aSJohn Birrell sizeof (uint64_t), fasttrap_uint64_cmp);
1959cd844e7aSJohn Birrell for (i = 1; i < pdata->ftps_noffs; i++) {
1960cd844e7aSJohn Birrell if (pdata->ftps_offs[i] > pdata->ftps_offs[i - 1])
1961cd844e7aSJohn Birrell continue;
1962cd844e7aSJohn Birrell
1963cd844e7aSJohn Birrell atomic_add_32(&fasttrap_total, -pdata->ftps_noffs);
1964cd844e7aSJohn Birrell goto no_mem;
1965cd844e7aSJohn Birrell }
1966cd844e7aSJohn Birrell
1967cd844e7aSJohn Birrell ASSERT(pdata->ftps_noffs > 0);
1968cd844e7aSJohn Birrell pp = kmem_zalloc(offsetof(fasttrap_probe_t,
1969cd844e7aSJohn Birrell ftp_tps[pdata->ftps_noffs]), KM_SLEEP);
1970cd844e7aSJohn Birrell
1971cd844e7aSJohn Birrell pp->ftp_prov = provider;
1972cd844e7aSJohn Birrell pp->ftp_faddr = pdata->ftps_pc;
1973cd844e7aSJohn Birrell pp->ftp_fsize = pdata->ftps_size;
1974cd844e7aSJohn Birrell pp->ftp_pid = pdata->ftps_pid;
1975cd844e7aSJohn Birrell pp->ftp_ntps = pdata->ftps_noffs;
1976cd844e7aSJohn Birrell
1977cd844e7aSJohn Birrell for (i = 0; i < pdata->ftps_noffs; i++) {
1978cd844e7aSJohn Birrell tp = kmem_zalloc(sizeof (fasttrap_tracepoint_t),
1979cd844e7aSJohn Birrell KM_SLEEP);
1980cd844e7aSJohn Birrell
1981cd844e7aSJohn Birrell tp->ftt_proc = provider->ftp_proc;
1982cd844e7aSJohn Birrell tp->ftt_pc = pdata->ftps_offs[i] + pdata->ftps_pc;
1983cd844e7aSJohn Birrell tp->ftt_pid = pdata->ftps_pid;
1984cd844e7aSJohn Birrell
1985cd844e7aSJohn Birrell pp->ftp_tps[i].fit_tp = tp;
1986cd844e7aSJohn Birrell pp->ftp_tps[i].fit_id.fti_probe = pp;
1987cd844e7aSJohn Birrell pp->ftp_tps[i].fit_id.fti_ptype = pdata->ftps_type;
1988cd844e7aSJohn Birrell }
1989cd844e7aSJohn Birrell
1990cd844e7aSJohn Birrell pp->ftp_id = dtrace_probe_create(provider->ftp_provid,
1991cd844e7aSJohn Birrell pdata->ftps_mod, pdata->ftps_func, name, aframes, pp);
1992cd844e7aSJohn Birrell }
1993cd844e7aSJohn Birrell
1994cd844e7aSJohn Birrell mutex_exit(&provider->ftp_cmtx);
1995cd844e7aSJohn Birrell
1996cd844e7aSJohn Birrell /*
1997cd844e7aSJohn Birrell * We know that the provider is still valid since we incremented the
1998cd844e7aSJohn Birrell * creation reference count. If someone tried to clean up this provider
1999cd844e7aSJohn Birrell * while we were using it (e.g. because the process called exec(2) or
2000cd844e7aSJohn Birrell * exit(2)), take note of that and try to clean it up now.
2001cd844e7aSJohn Birrell */
2002cd844e7aSJohn Birrell mutex_enter(&provider->ftp_mtx);
2003cd844e7aSJohn Birrell provider->ftp_ccount--;
2004cd844e7aSJohn Birrell whack = provider->ftp_retired;
2005cd844e7aSJohn Birrell mutex_exit(&provider->ftp_mtx);
2006cd844e7aSJohn Birrell
2007cd844e7aSJohn Birrell if (whack)
2008cd844e7aSJohn Birrell fasttrap_pid_cleanup();
2009cd844e7aSJohn Birrell
2010cd844e7aSJohn Birrell return (0);
2011cd844e7aSJohn Birrell
2012cd844e7aSJohn Birrell no_mem:
2013cd844e7aSJohn Birrell /*
2014cd844e7aSJohn Birrell * If we've exhausted the allowable resources, we'll try to remove
2015cd844e7aSJohn Birrell * this provider to free some up. This is to cover the case where
2016cd844e7aSJohn Birrell * the user has accidentally created many more probes than was
2017cd844e7aSJohn Birrell * intended (e.g. pid123:::).
2018cd844e7aSJohn Birrell */
2019cd844e7aSJohn Birrell mutex_exit(&provider->ftp_cmtx);
2020cd844e7aSJohn Birrell mutex_enter(&provider->ftp_mtx);
2021cd844e7aSJohn Birrell provider->ftp_ccount--;
2022cd844e7aSJohn Birrell provider->ftp_marked = 1;
2023cd844e7aSJohn Birrell mutex_exit(&provider->ftp_mtx);
2024cd844e7aSJohn Birrell
2025cd844e7aSJohn Birrell fasttrap_pid_cleanup();
2026cd844e7aSJohn Birrell
2027cd844e7aSJohn Birrell return (ENOMEM);
2028cd844e7aSJohn Birrell }
2029cd844e7aSJohn Birrell
2030cd844e7aSJohn Birrell /*ARGSUSED*/
2031cd844e7aSJohn Birrell static void *
fasttrap_meta_provide(void * arg,dtrace_helper_provdesc_t * dhpv,pid_t pid)2032cd844e7aSJohn Birrell fasttrap_meta_provide(void *arg, dtrace_helper_provdesc_t *dhpv, pid_t pid)
2033cd844e7aSJohn Birrell {
2034cd844e7aSJohn Birrell fasttrap_provider_t *provider;
2035cd844e7aSJohn Birrell
2036cd844e7aSJohn Birrell /*
2037cd844e7aSJohn Birrell * A 32-bit unsigned integer (like a pid for example) can be
2038cd844e7aSJohn Birrell * expressed in 10 or fewer decimal digits. Make sure that we'll
2039cd844e7aSJohn Birrell * have enough space for the provider name.
2040cd844e7aSJohn Birrell */
2041cd844e7aSJohn Birrell if (strlen(dhpv->dthpv_provname) + 10 >=
2042cd844e7aSJohn Birrell sizeof (provider->ftp_name)) {
20438605d1aeSRui Paulo printf("failed to instantiate provider %s: "
2044cd844e7aSJohn Birrell "name too long to accomodate pid", dhpv->dthpv_provname);
2045cd844e7aSJohn Birrell return (NULL);
2046cd844e7aSJohn Birrell }
2047cd844e7aSJohn Birrell
2048cd844e7aSJohn Birrell /*
2049cd844e7aSJohn Birrell * Don't let folks spoof the true pid provider.
2050cd844e7aSJohn Birrell */
2051cd844e7aSJohn Birrell if (strcmp(dhpv->dthpv_provname, FASTTRAP_PID_NAME) == 0) {
20528605d1aeSRui Paulo printf("failed to instantiate provider %s: "
2053cd844e7aSJohn Birrell "%s is an invalid name", dhpv->dthpv_provname,
2054cd844e7aSJohn Birrell FASTTRAP_PID_NAME);
2055cd844e7aSJohn Birrell return (NULL);
2056cd844e7aSJohn Birrell }
2057cd844e7aSJohn Birrell
2058cd844e7aSJohn Birrell /*
2059cd844e7aSJohn Birrell * The highest stability class that fasttrap supports is ISA; cap
2060cd844e7aSJohn Birrell * the stability of the new provider accordingly.
2061cd844e7aSJohn Birrell */
2062cd844e7aSJohn Birrell if (dhpv->dthpv_pattr.dtpa_provider.dtat_class > DTRACE_CLASS_ISA)
2063cd844e7aSJohn Birrell dhpv->dthpv_pattr.dtpa_provider.dtat_class = DTRACE_CLASS_ISA;
2064cd844e7aSJohn Birrell if (dhpv->dthpv_pattr.dtpa_mod.dtat_class > DTRACE_CLASS_ISA)
2065cd844e7aSJohn Birrell dhpv->dthpv_pattr.dtpa_mod.dtat_class = DTRACE_CLASS_ISA;
2066cd844e7aSJohn Birrell if (dhpv->dthpv_pattr.dtpa_func.dtat_class > DTRACE_CLASS_ISA)
2067cd844e7aSJohn Birrell dhpv->dthpv_pattr.dtpa_func.dtat_class = DTRACE_CLASS_ISA;
2068cd844e7aSJohn Birrell if (dhpv->dthpv_pattr.dtpa_name.dtat_class > DTRACE_CLASS_ISA)
2069cd844e7aSJohn Birrell dhpv->dthpv_pattr.dtpa_name.dtat_class = DTRACE_CLASS_ISA;
2070cd844e7aSJohn Birrell if (dhpv->dthpv_pattr.dtpa_args.dtat_class > DTRACE_CLASS_ISA)
2071cd844e7aSJohn Birrell dhpv->dthpv_pattr.dtpa_args.dtat_class = DTRACE_CLASS_ISA;
2072cd844e7aSJohn Birrell
2073cd844e7aSJohn Birrell if ((provider = fasttrap_provider_lookup(pid, dhpv->dthpv_provname,
2074cd844e7aSJohn Birrell &dhpv->dthpv_pattr)) == NULL) {
20758605d1aeSRui Paulo printf("failed to instantiate provider %s for "
2076cd844e7aSJohn Birrell "process %u", dhpv->dthpv_provname, (uint_t)pid);
2077cd844e7aSJohn Birrell return (NULL);
2078cd844e7aSJohn Birrell }
2079cd844e7aSJohn Birrell
2080cd844e7aSJohn Birrell /*
2081cd844e7aSJohn Birrell * Up the meta provider count so this provider isn't removed until
2082cd844e7aSJohn Birrell * the meta provider has been told to remove it.
2083cd844e7aSJohn Birrell */
2084cd844e7aSJohn Birrell provider->ftp_mcount++;
2085cd844e7aSJohn Birrell
2086cd844e7aSJohn Birrell mutex_exit(&provider->ftp_mtx);
2087cd844e7aSJohn Birrell
2088cd844e7aSJohn Birrell return (provider);
2089cd844e7aSJohn Birrell }
2090cd844e7aSJohn Birrell
209116392907SMark Johnston /*
209216392907SMark Johnston * We know a few things about our context here: we know that the probe being
209316392907SMark Johnston * created doesn't already exist (DTrace won't load DOF at the same address
209416392907SMark Johnston * twice, even if explicitly told to do so) and we know that we are
209516392907SMark Johnston * single-threaded with respect to the meta provider machinery. Knowing that
209616392907SMark Johnston * this is a new probe and that there is no way for us to race with another
209716392907SMark Johnston * operation on this provider allows us an important optimization: we need not
209816392907SMark Johnston * lookup a probe before adding it. Saving this lookup is important because
209916392907SMark Johnston * this code is in the fork path for processes with USDT probes, and lookups
210016392907SMark Johnston * here are potentially very expensive because of long hash conflicts on
210116392907SMark Johnston * module, function and name (DTrace doesn't hash on provider name).
210216392907SMark Johnston */
2103cd844e7aSJohn Birrell /*ARGSUSED*/
2104cd844e7aSJohn Birrell static void
fasttrap_meta_create_probe(void * arg,void * parg,dtrace_helper_probedesc_t * dhpb)2105cd844e7aSJohn Birrell fasttrap_meta_create_probe(void *arg, void *parg,
2106cd844e7aSJohn Birrell dtrace_helper_probedesc_t *dhpb)
2107cd844e7aSJohn Birrell {
2108cd844e7aSJohn Birrell fasttrap_provider_t *provider = parg;
2109cd844e7aSJohn Birrell fasttrap_probe_t *pp;
2110cd844e7aSJohn Birrell fasttrap_tracepoint_t *tp;
2111cd844e7aSJohn Birrell int i, j;
2112cd844e7aSJohn Birrell uint32_t ntps;
2113cd844e7aSJohn Birrell
2114cd844e7aSJohn Birrell /*
2115cd844e7aSJohn Birrell * Since the meta provider count is non-zero we don't have to worry
2116cd844e7aSJohn Birrell * about this provider disappearing.
2117cd844e7aSJohn Birrell */
2118cd844e7aSJohn Birrell ASSERT(provider->ftp_mcount > 0);
2119cd844e7aSJohn Birrell
2120cd844e7aSJohn Birrell /*
2121cd844e7aSJohn Birrell * The offsets must be unique.
2122cd844e7aSJohn Birrell */
2123cd844e7aSJohn Birrell qsort(dhpb->dthpb_offs, dhpb->dthpb_noffs, sizeof (uint32_t),
2124cd844e7aSJohn Birrell fasttrap_uint32_cmp);
2125cd844e7aSJohn Birrell for (i = 1; i < dhpb->dthpb_noffs; i++) {
2126cd844e7aSJohn Birrell if (dhpb->dthpb_base + dhpb->dthpb_offs[i] <=
2127cd844e7aSJohn Birrell dhpb->dthpb_base + dhpb->dthpb_offs[i - 1])
2128cd844e7aSJohn Birrell return;
2129cd844e7aSJohn Birrell }
2130cd844e7aSJohn Birrell
2131cd844e7aSJohn Birrell qsort(dhpb->dthpb_enoffs, dhpb->dthpb_nenoffs, sizeof (uint32_t),
2132cd844e7aSJohn Birrell fasttrap_uint32_cmp);
2133cd844e7aSJohn Birrell for (i = 1; i < dhpb->dthpb_nenoffs; i++) {
2134cd844e7aSJohn Birrell if (dhpb->dthpb_base + dhpb->dthpb_enoffs[i] <=
2135cd844e7aSJohn Birrell dhpb->dthpb_base + dhpb->dthpb_enoffs[i - 1])
2136cd844e7aSJohn Birrell return;
2137cd844e7aSJohn Birrell }
2138cd844e7aSJohn Birrell
2139cd844e7aSJohn Birrell ntps = dhpb->dthpb_noffs + dhpb->dthpb_nenoffs;
2140cd844e7aSJohn Birrell ASSERT(ntps > 0);
2141cd844e7aSJohn Birrell
2142cd844e7aSJohn Birrell atomic_add_32(&fasttrap_total, ntps);
2143cd844e7aSJohn Birrell
2144cd844e7aSJohn Birrell if (fasttrap_total > fasttrap_max) {
2145cd844e7aSJohn Birrell atomic_add_32(&fasttrap_total, -ntps);
2146cd844e7aSJohn Birrell return;
2147cd844e7aSJohn Birrell }
2148cd844e7aSJohn Birrell
2149cd844e7aSJohn Birrell pp = kmem_zalloc(offsetof(fasttrap_probe_t, ftp_tps[ntps]), KM_SLEEP);
2150cd844e7aSJohn Birrell
2151cd844e7aSJohn Birrell pp->ftp_prov = provider;
2152cd844e7aSJohn Birrell pp->ftp_pid = provider->ftp_pid;
2153cd844e7aSJohn Birrell pp->ftp_ntps = ntps;
2154cd844e7aSJohn Birrell pp->ftp_nargs = dhpb->dthpb_xargc;
2155cd844e7aSJohn Birrell pp->ftp_xtypes = dhpb->dthpb_xtypes;
2156cd844e7aSJohn Birrell pp->ftp_ntypes = dhpb->dthpb_ntypes;
2157cd844e7aSJohn Birrell
2158cd844e7aSJohn Birrell /*
2159cd844e7aSJohn Birrell * First create a tracepoint for each actual point of interest.
2160cd844e7aSJohn Birrell */
2161cd844e7aSJohn Birrell for (i = 0; i < dhpb->dthpb_noffs; i++) {
2162cd844e7aSJohn Birrell tp = kmem_zalloc(sizeof (fasttrap_tracepoint_t), KM_SLEEP);
2163cd844e7aSJohn Birrell
2164cd844e7aSJohn Birrell tp->ftt_proc = provider->ftp_proc;
2165cd844e7aSJohn Birrell tp->ftt_pc = dhpb->dthpb_base + dhpb->dthpb_offs[i];
2166cd844e7aSJohn Birrell tp->ftt_pid = provider->ftp_pid;
2167cd844e7aSJohn Birrell
2168cd844e7aSJohn Birrell pp->ftp_tps[i].fit_tp = tp;
2169cd844e7aSJohn Birrell pp->ftp_tps[i].fit_id.fti_probe = pp;
2170cd844e7aSJohn Birrell #ifdef __sparc
2171cd844e7aSJohn Birrell pp->ftp_tps[i].fit_id.fti_ptype = DTFTP_POST_OFFSETS;
2172cd844e7aSJohn Birrell #else
2173cd844e7aSJohn Birrell pp->ftp_tps[i].fit_id.fti_ptype = DTFTP_OFFSETS;
2174cd844e7aSJohn Birrell #endif
2175cd844e7aSJohn Birrell }
2176cd844e7aSJohn Birrell
2177cd844e7aSJohn Birrell /*
2178cd844e7aSJohn Birrell * Then create a tracepoint for each is-enabled point.
2179cd844e7aSJohn Birrell */
2180cd844e7aSJohn Birrell for (j = 0; i < ntps; i++, j++) {
2181cd844e7aSJohn Birrell tp = kmem_zalloc(sizeof (fasttrap_tracepoint_t), KM_SLEEP);
2182cd844e7aSJohn Birrell
2183cd844e7aSJohn Birrell tp->ftt_proc = provider->ftp_proc;
2184cd844e7aSJohn Birrell tp->ftt_pc = dhpb->dthpb_base + dhpb->dthpb_enoffs[j];
2185cd844e7aSJohn Birrell tp->ftt_pid = provider->ftp_pid;
2186cd844e7aSJohn Birrell
2187cd844e7aSJohn Birrell pp->ftp_tps[i].fit_tp = tp;
2188cd844e7aSJohn Birrell pp->ftp_tps[i].fit_id.fti_probe = pp;
2189cd844e7aSJohn Birrell pp->ftp_tps[i].fit_id.fti_ptype = DTFTP_IS_ENABLED;
2190cd844e7aSJohn Birrell }
2191cd844e7aSJohn Birrell
2192cd844e7aSJohn Birrell /*
2193cd844e7aSJohn Birrell * If the arguments are shuffled around we set the argument remapping
2194cd844e7aSJohn Birrell * table. Later, when the probe fires, we only remap the arguments
2195cd844e7aSJohn Birrell * if the table is non-NULL.
2196cd844e7aSJohn Birrell */
2197cd844e7aSJohn Birrell for (i = 0; i < dhpb->dthpb_xargc; i++) {
2198cd844e7aSJohn Birrell if (dhpb->dthpb_args[i] != i) {
2199cd844e7aSJohn Birrell pp->ftp_argmap = dhpb->dthpb_args;
2200cd844e7aSJohn Birrell break;
2201cd844e7aSJohn Birrell }
2202cd844e7aSJohn Birrell }
2203cd844e7aSJohn Birrell
2204cd844e7aSJohn Birrell /*
2205cd844e7aSJohn Birrell * The probe is fully constructed -- register it with DTrace.
2206cd844e7aSJohn Birrell */
2207cd844e7aSJohn Birrell pp->ftp_id = dtrace_probe_create(provider->ftp_provid, dhpb->dthpb_mod,
2208cd844e7aSJohn Birrell dhpb->dthpb_func, dhpb->dthpb_name, FASTTRAP_OFFSET_AFRAMES, pp);
2209cd844e7aSJohn Birrell }
2210cd844e7aSJohn Birrell
2211cd844e7aSJohn Birrell /*ARGSUSED*/
2212cd844e7aSJohn Birrell static void
fasttrap_meta_remove(void * arg,dtrace_helper_provdesc_t * dhpv,pid_t pid)2213cd844e7aSJohn Birrell fasttrap_meta_remove(void *arg, dtrace_helper_provdesc_t *dhpv, pid_t pid)
2214cd844e7aSJohn Birrell {
2215cd844e7aSJohn Birrell /*
2216cd844e7aSJohn Birrell * Clean up the USDT provider. There may be active consumers of the
2217cd844e7aSJohn Birrell * provider busy adding probes, no damage will actually befall the
2218cd844e7aSJohn Birrell * provider until that count has dropped to zero. This just puts
2219cd844e7aSJohn Birrell * the provider on death row.
2220cd844e7aSJohn Birrell */
2221cd844e7aSJohn Birrell fasttrap_provider_retire(pid, dhpv->dthpv_provname, 1);
2222cd844e7aSJohn Birrell }
2223cd844e7aSJohn Birrell
2224cd844e7aSJohn Birrell static dtrace_mops_t fasttrap_mops = {
222547f11baaSMark Johnston .dtms_create_probe = fasttrap_meta_create_probe,
222647f11baaSMark Johnston .dtms_provide_pid = fasttrap_meta_provide,
222747f11baaSMark Johnston .dtms_remove_pid = fasttrap_meta_remove
2228cd844e7aSJohn Birrell };
2229cd844e7aSJohn Birrell
2230cd844e7aSJohn Birrell /*ARGSUSED*/
2231cd844e7aSJohn Birrell static int
fasttrap_open(struct cdev * dev __unused,int oflags __unused,int devtype __unused,struct thread * td __unused)22328605d1aeSRui Paulo fasttrap_open(struct cdev *dev __unused, int oflags __unused,
22338605d1aeSRui Paulo int devtype __unused, struct thread *td __unused)
2234cd844e7aSJohn Birrell {
2235cd844e7aSJohn Birrell return (0);
2236cd844e7aSJohn Birrell }
2237cd844e7aSJohn Birrell
2238cd844e7aSJohn Birrell /*ARGSUSED*/
2239cd844e7aSJohn Birrell static int
fasttrap_ioctl(struct cdev * dev,u_long cmd,caddr_t arg,int fflag,struct thread * td)22408605d1aeSRui Paulo fasttrap_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int fflag,
22418605d1aeSRui Paulo struct thread *td)
2242cd844e7aSJohn Birrell {
2243cd844e7aSJohn Birrell if (!dtrace_attached())
2244cd844e7aSJohn Birrell return (EAGAIN);
2245cd844e7aSJohn Birrell
2246cd844e7aSJohn Birrell if (cmd == FASTTRAPIOC_MAKEPROBE) {
2247dd580326SMark Johnston fasttrap_probe_spec_t *uprobe = *(fasttrap_probe_spec_t **)arg;
2248cd844e7aSJohn Birrell fasttrap_probe_spec_t *probe;
2249cd844e7aSJohn Birrell uint64_t noffs;
2250cd844e7aSJohn Birrell size_t size;
2251c6d712caSPedro F. Giffuni int ret, err;
2252cd844e7aSJohn Birrell
2253cd844e7aSJohn Birrell if (copyin(&uprobe->ftps_noffs, &noffs,
2254cd844e7aSJohn Birrell sizeof (uprobe->ftps_noffs)))
2255cd844e7aSJohn Birrell return (EFAULT);
2256cd844e7aSJohn Birrell
2257cd844e7aSJohn Birrell /*
2258cd844e7aSJohn Birrell * Probes must have at least one tracepoint.
2259cd844e7aSJohn Birrell */
2260cd844e7aSJohn Birrell if (noffs == 0)
2261cd844e7aSJohn Birrell return (EINVAL);
2262cd844e7aSJohn Birrell
2263cd844e7aSJohn Birrell size = sizeof (fasttrap_probe_spec_t) +
2264cd844e7aSJohn Birrell sizeof (probe->ftps_offs[0]) * (noffs - 1);
2265cd844e7aSJohn Birrell
2266cd844e7aSJohn Birrell if (size > 1024 * 1024)
2267cd844e7aSJohn Birrell return (ENOMEM);
2268cd844e7aSJohn Birrell
2269cd844e7aSJohn Birrell probe = kmem_alloc(size, KM_SLEEP);
2270cd844e7aSJohn Birrell
227187e109c3SPedro F. Giffuni if (copyin(uprobe, probe, size) != 0 ||
227287e109c3SPedro F. Giffuni probe->ftps_noffs != noffs) {
2273cd844e7aSJohn Birrell kmem_free(probe, size);
2274cd844e7aSJohn Birrell return (EFAULT);
2275cd844e7aSJohn Birrell }
2276cd844e7aSJohn Birrell
2277cd844e7aSJohn Birrell /*
2278cd844e7aSJohn Birrell * Verify that the function and module strings contain no
2279cd844e7aSJohn Birrell * funny characters.
2280cd844e7aSJohn Birrell */
2281c6d712caSPedro F. Giffuni if (u8_validate(probe->ftps_func, strlen(probe->ftps_func),
2282c6d712caSPedro F. Giffuni NULL, U8_VALIDATE_ENTIRE, &err) < 0) {
2283cd844e7aSJohn Birrell ret = EINVAL;
2284cd844e7aSJohn Birrell goto err;
2285cd844e7aSJohn Birrell }
2286cd844e7aSJohn Birrell
2287c6d712caSPedro F. Giffuni if (u8_validate(probe->ftps_mod, strlen(probe->ftps_mod),
2288c6d712caSPedro F. Giffuni NULL, U8_VALIDATE_ENTIRE, &err) < 0) {
2289cd844e7aSJohn Birrell ret = EINVAL;
2290cd844e7aSJohn Birrell goto err;
2291cd844e7aSJohn Birrell }
2292cd844e7aSJohn Birrell
22938605d1aeSRui Paulo #ifdef notyet
2294cd844e7aSJohn Birrell if (!PRIV_POLICY_CHOICE(cr, PRIV_ALL, B_FALSE)) {
2295cd844e7aSJohn Birrell proc_t *p;
2296cd844e7aSJohn Birrell pid_t pid = probe->ftps_pid;
2297cd844e7aSJohn Birrell
2298cd844e7aSJohn Birrell mutex_enter(&pidlock);
2299cd844e7aSJohn Birrell /*
2300cd844e7aSJohn Birrell * Report an error if the process doesn't exist
2301cd844e7aSJohn Birrell * or is actively being birthed.
2302cd844e7aSJohn Birrell */
2303babf030fSMark Johnston if ((p = pfind(pid)) == NULL || p->p_stat == SIDL) {
2304cd844e7aSJohn Birrell mutex_exit(&pidlock);
2305cd844e7aSJohn Birrell return (ESRCH);
2306cd844e7aSJohn Birrell }
2307cd844e7aSJohn Birrell mutex_enter(&p->p_lock);
2308cd844e7aSJohn Birrell mutex_exit(&pidlock);
2309cd844e7aSJohn Birrell
2310cd844e7aSJohn Birrell if ((ret = priv_proc_cred_perm(cr, p, NULL,
2311cd844e7aSJohn Birrell VREAD | VWRITE)) != 0) {
2312cd844e7aSJohn Birrell mutex_exit(&p->p_lock);
2313cd844e7aSJohn Birrell return (ret);
2314cd844e7aSJohn Birrell }
2315cd844e7aSJohn Birrell mutex_exit(&p->p_lock);
2316cd844e7aSJohn Birrell }
23178605d1aeSRui Paulo #endif /* notyet */
2318cd844e7aSJohn Birrell
2319cd844e7aSJohn Birrell ret = fasttrap_add_probe(probe);
2320cd844e7aSJohn Birrell err:
2321cd844e7aSJohn Birrell kmem_free(probe, size);
2322cd844e7aSJohn Birrell
2323cd844e7aSJohn Birrell return (ret);
2324cd844e7aSJohn Birrell
2325cd844e7aSJohn Birrell } else if (cmd == FASTTRAPIOC_GETINSTR) {
2326cd844e7aSJohn Birrell fasttrap_instr_query_t instr;
2327cd844e7aSJohn Birrell fasttrap_tracepoint_t *tp;
2328cd844e7aSJohn Birrell uint_t index;
2329babf030fSMark Johnston #ifdef notyet
2330cd844e7aSJohn Birrell int ret;
23318605d1aeSRui Paulo #endif
2332cd844e7aSJohn Birrell
2333cd844e7aSJohn Birrell if (copyin((void *)arg, &instr, sizeof (instr)) != 0)
2334cd844e7aSJohn Birrell return (EFAULT);
2335cd844e7aSJohn Birrell
23368605d1aeSRui Paulo #ifdef notyet
2337cd844e7aSJohn Birrell if (!PRIV_POLICY_CHOICE(cr, PRIV_ALL, B_FALSE)) {
2338cd844e7aSJohn Birrell proc_t *p;
2339cd844e7aSJohn Birrell pid_t pid = instr.ftiq_pid;
2340cd844e7aSJohn Birrell
2341cd844e7aSJohn Birrell mutex_enter(&pidlock);
2342cd844e7aSJohn Birrell /*
2343cd844e7aSJohn Birrell * Report an error if the process doesn't exist
2344cd844e7aSJohn Birrell * or is actively being birthed.
2345cd844e7aSJohn Birrell */
2346babf030fSMark Johnston if ((p == pfind(pid)) == NULL || p->p_stat == SIDL) {
2347cd844e7aSJohn Birrell mutex_exit(&pidlock);
2348cd844e7aSJohn Birrell return (ESRCH);
2349cd844e7aSJohn Birrell }
2350cd844e7aSJohn Birrell mutex_enter(&p->p_lock);
2351cd844e7aSJohn Birrell mutex_exit(&pidlock);
2352cd844e7aSJohn Birrell
2353cd844e7aSJohn Birrell if ((ret = priv_proc_cred_perm(cr, p, NULL,
2354cd844e7aSJohn Birrell VREAD)) != 0) {
2355cd844e7aSJohn Birrell mutex_exit(&p->p_lock);
2356cd844e7aSJohn Birrell return (ret);
2357cd844e7aSJohn Birrell }
2358cd844e7aSJohn Birrell
2359cd844e7aSJohn Birrell mutex_exit(&p->p_lock);
2360cd844e7aSJohn Birrell }
23618605d1aeSRui Paulo #endif /* notyet */
2362cd844e7aSJohn Birrell
2363cd844e7aSJohn Birrell index = FASTTRAP_TPOINTS_INDEX(instr.ftiq_pid, instr.ftiq_pc);
2364cd844e7aSJohn Birrell
2365cd844e7aSJohn Birrell mutex_enter(&fasttrap_tpoints.fth_table[index].ftb_mtx);
2366cd844e7aSJohn Birrell tp = fasttrap_tpoints.fth_table[index].ftb_data;
2367cd844e7aSJohn Birrell while (tp != NULL) {
2368cd844e7aSJohn Birrell if (instr.ftiq_pid == tp->ftt_pid &&
2369cd844e7aSJohn Birrell instr.ftiq_pc == tp->ftt_pc &&
2370cd844e7aSJohn Birrell tp->ftt_proc->ftpc_acount != 0)
2371cd844e7aSJohn Birrell break;
2372cd844e7aSJohn Birrell
2373cd844e7aSJohn Birrell tp = tp->ftt_next;
2374cd844e7aSJohn Birrell }
2375cd844e7aSJohn Birrell
2376cd844e7aSJohn Birrell if (tp == NULL) {
2377cd844e7aSJohn Birrell mutex_exit(&fasttrap_tpoints.fth_table[index].ftb_mtx);
2378cd844e7aSJohn Birrell return (ENOENT);
2379cd844e7aSJohn Birrell }
2380cd844e7aSJohn Birrell
2381cd844e7aSJohn Birrell bcopy(&tp->ftt_instr, &instr.ftiq_instr,
2382cd844e7aSJohn Birrell sizeof (instr.ftiq_instr));
2383cd844e7aSJohn Birrell mutex_exit(&fasttrap_tpoints.fth_table[index].ftb_mtx);
2384cd844e7aSJohn Birrell
2385cd844e7aSJohn Birrell if (copyout(&instr, (void *)arg, sizeof (instr)) != 0)
2386cd844e7aSJohn Birrell return (EFAULT);
2387cd844e7aSJohn Birrell
2388cd844e7aSJohn Birrell return (0);
2389cd844e7aSJohn Birrell }
2390cd844e7aSJohn Birrell
2391cd844e7aSJohn Birrell return (EINVAL);
2392cd844e7aSJohn Birrell }
2393cd844e7aSJohn Birrell
2394cd844e7aSJohn Birrell static int
fasttrap_load(void)23958605d1aeSRui Paulo fasttrap_load(void)
2396cd844e7aSJohn Birrell {
2397cd844e7aSJohn Birrell ulong_t nent;
2398427bc75eSMark Johnston int i, ret;
2399cd844e7aSJohn Birrell
24008605d1aeSRui Paulo /* Create the /dev/dtrace/fasttrap entry. */
24018605d1aeSRui Paulo fasttrap_cdev = make_dev(&fasttrap_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
24028605d1aeSRui Paulo "dtrace/fasttrap");
2403cd844e7aSJohn Birrell
24048605d1aeSRui Paulo mtx_init(&fasttrap_cleanup_mtx, "fasttrap clean", "dtrace", MTX_DEF);
24058605d1aeSRui Paulo mutex_init(&fasttrap_count_mtx, "fasttrap count mtx", MUTEX_DEFAULT,
24068605d1aeSRui Paulo NULL);
2407cd844e7aSJohn Birrell
2408bc96366cSSteven Hartland #ifdef illumos
2409cd844e7aSJohn Birrell fasttrap_max = ddi_getprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
2410cd844e7aSJohn Birrell "fasttrap-max-probes", FASTTRAP_MAX_DEFAULT);
24118605d1aeSRui Paulo #endif
2412cd844e7aSJohn Birrell fasttrap_total = 0;
2413cd844e7aSJohn Birrell
2414cd844e7aSJohn Birrell /*
2415cd844e7aSJohn Birrell * Conjure up the tracepoints hashtable...
2416cd844e7aSJohn Birrell */
2417bc96366cSSteven Hartland #ifdef illumos
2418cd844e7aSJohn Birrell nent = ddi_getprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
2419cd844e7aSJohn Birrell "fasttrap-hash-size", FASTTRAP_TPOINTS_DEFAULT_SIZE);
24208605d1aeSRui Paulo #else
2421314eeef2SStanislav Sedov nent = tpoints_hash_size;
24228605d1aeSRui Paulo #endif
2423cd844e7aSJohn Birrell
2424cd844e7aSJohn Birrell if (nent == 0 || nent > 0x1000000)
2425cd844e7aSJohn Birrell nent = FASTTRAP_TPOINTS_DEFAULT_SIZE;
2426cd844e7aSJohn Birrell
2427314eeef2SStanislav Sedov tpoints_hash_size = nent;
2428314eeef2SStanislav Sedov
242954f76dcbSXin LI if (ISP2(nent))
2430cd844e7aSJohn Birrell fasttrap_tpoints.fth_nent = nent;
2431cd844e7aSJohn Birrell else
2432cd844e7aSJohn Birrell fasttrap_tpoints.fth_nent = 1 << fasttrap_highbit(nent);
2433cd844e7aSJohn Birrell ASSERT(fasttrap_tpoints.fth_nent > 0);
2434cd844e7aSJohn Birrell fasttrap_tpoints.fth_mask = fasttrap_tpoints.fth_nent - 1;
2435cd844e7aSJohn Birrell fasttrap_tpoints.fth_table = kmem_zalloc(fasttrap_tpoints.fth_nent *
2436cd844e7aSJohn Birrell sizeof (fasttrap_bucket_t), KM_SLEEP);
2437bc96366cSSteven Hartland #ifndef illumos
24388605d1aeSRui Paulo for (i = 0; i < fasttrap_tpoints.fth_nent; i++)
24398605d1aeSRui Paulo mutex_init(&fasttrap_tpoints.fth_table[i].ftb_mtx,
24408605d1aeSRui Paulo "tracepoints bucket mtx", MUTEX_DEFAULT, NULL);
24418605d1aeSRui Paulo #endif
2442cd844e7aSJohn Birrell
2443cd844e7aSJohn Birrell /*
2444cd844e7aSJohn Birrell * ... and the providers hash table...
2445cd844e7aSJohn Birrell */
2446cd844e7aSJohn Birrell nent = FASTTRAP_PROVIDERS_DEFAULT_SIZE;
244754f76dcbSXin LI if (ISP2(nent))
2448cd844e7aSJohn Birrell fasttrap_provs.fth_nent = nent;
2449cd844e7aSJohn Birrell else
2450cd844e7aSJohn Birrell fasttrap_provs.fth_nent = 1 << fasttrap_highbit(nent);
2451cd844e7aSJohn Birrell ASSERT(fasttrap_provs.fth_nent > 0);
2452cd844e7aSJohn Birrell fasttrap_provs.fth_mask = fasttrap_provs.fth_nent - 1;
2453cd844e7aSJohn Birrell fasttrap_provs.fth_table = kmem_zalloc(fasttrap_provs.fth_nent *
2454cd844e7aSJohn Birrell sizeof (fasttrap_bucket_t), KM_SLEEP);
2455bc96366cSSteven Hartland #ifndef illumos
24568605d1aeSRui Paulo for (i = 0; i < fasttrap_provs.fth_nent; i++)
24578605d1aeSRui Paulo mutex_init(&fasttrap_provs.fth_table[i].ftb_mtx,
24588605d1aeSRui Paulo "providers bucket mtx", MUTEX_DEFAULT, NULL);
24598605d1aeSRui Paulo #endif
2460cd844e7aSJohn Birrell
24611f9e80bcSAlan Somers ret = kproc_create(fasttrap_pid_cleanup_cb, NULL,
24621f9e80bcSAlan Somers &fasttrap_cleanup_proc, 0, 0, "ftcleanup");
24631f9e80bcSAlan Somers if (ret != 0) {
24641f9e80bcSAlan Somers destroy_dev(fasttrap_cdev);
2465bc96366cSSteven Hartland #ifndef illumos
24661f9e80bcSAlan Somers for (i = 0; i < fasttrap_provs.fth_nent; i++)
24671f9e80bcSAlan Somers mutex_destroy(&fasttrap_provs.fth_table[i].ftb_mtx);
24681f9e80bcSAlan Somers for (i = 0; i < fasttrap_tpoints.fth_nent; i++)
24691f9e80bcSAlan Somers mutex_destroy(&fasttrap_tpoints.fth_table[i].ftb_mtx);
24701f9e80bcSAlan Somers #endif
24711f9e80bcSAlan Somers kmem_free(fasttrap_provs.fth_table, fasttrap_provs.fth_nent *
24721f9e80bcSAlan Somers sizeof (fasttrap_bucket_t));
24731f9e80bcSAlan Somers mtx_destroy(&fasttrap_cleanup_mtx);
24741f9e80bcSAlan Somers mutex_destroy(&fasttrap_count_mtx);
24751f9e80bcSAlan Somers return (ret);
24761f9e80bcSAlan Somers }
24771f9e80bcSAlan Somers
24781f9e80bcSAlan Somers
2479cd844e7aSJohn Birrell /*
2480cd844e7aSJohn Birrell * ... and the procs hash table.
2481cd844e7aSJohn Birrell */
2482cd844e7aSJohn Birrell nent = FASTTRAP_PROCS_DEFAULT_SIZE;
248354f76dcbSXin LI if (ISP2(nent))
2484cd844e7aSJohn Birrell fasttrap_procs.fth_nent = nent;
2485cd844e7aSJohn Birrell else
2486cd844e7aSJohn Birrell fasttrap_procs.fth_nent = 1 << fasttrap_highbit(nent);
2487cd844e7aSJohn Birrell ASSERT(fasttrap_procs.fth_nent > 0);
2488cd844e7aSJohn Birrell fasttrap_procs.fth_mask = fasttrap_procs.fth_nent - 1;
2489cd844e7aSJohn Birrell fasttrap_procs.fth_table = kmem_zalloc(fasttrap_procs.fth_nent *
2490cd844e7aSJohn Birrell sizeof (fasttrap_bucket_t), KM_SLEEP);
2491bc96366cSSteven Hartland #ifndef illumos
24928605d1aeSRui Paulo for (i = 0; i < fasttrap_procs.fth_nent; i++)
24938605d1aeSRui Paulo mutex_init(&fasttrap_procs.fth_table[i].ftb_mtx,
24948605d1aeSRui Paulo "processes bucket mtx", MUTEX_DEFAULT, NULL);
24959f4ee617SRui Paulo
2496380344a7SMark Johnston rm_init(&fasttrap_tp_lock, "fasttrap tracepoint");
24970626f3e4SMark Johnston
24980626f3e4SMark Johnston /*
24990626f3e4SMark Johnston * This event handler must run before kdtrace_thread_dtor() since it
25000626f3e4SMark Johnston * accesses the thread's struct kdtrace_thread.
25010626f3e4SMark Johnston */
25020626f3e4SMark Johnston fasttrap_thread_dtor_tag = EVENTHANDLER_REGISTER(thread_dtor,
25030626f3e4SMark Johnston fasttrap_thread_dtor, NULL, EVENTHANDLER_PRI_FIRST);
25048605d1aeSRui Paulo #endif
2505cd844e7aSJohn Birrell
250637b8b2d4SAndriy Gapon /*
250737b8b2d4SAndriy Gapon * Install our hooks into fork(2), exec(2), and exit(2).
250837b8b2d4SAndriy Gapon */
250937b8b2d4SAndriy Gapon dtrace_fasttrap_fork = &fasttrap_fork;
251037b8b2d4SAndriy Gapon dtrace_fasttrap_exit = &fasttrap_exec_exit;
251137b8b2d4SAndriy Gapon dtrace_fasttrap_exec = &fasttrap_exec_exit;
251237b8b2d4SAndriy Gapon
2513cd844e7aSJohn Birrell (void) dtrace_meta_register("fasttrap", &fasttrap_mops, NULL,
2514cd844e7aSJohn Birrell &fasttrap_meta_id);
2515cd844e7aSJohn Birrell
25168605d1aeSRui Paulo return (0);
2517cd844e7aSJohn Birrell }
2518cd844e7aSJohn Birrell
2519cd844e7aSJohn Birrell static int
fasttrap_unload(void)25208605d1aeSRui Paulo fasttrap_unload(void)
2521cd844e7aSJohn Birrell {
2522cd844e7aSJohn Birrell int i, fail = 0;
2523cd844e7aSJohn Birrell
2524cd844e7aSJohn Birrell /*
2525cd844e7aSJohn Birrell * Unregister the meta-provider to make sure no new fasttrap-
2526cd844e7aSJohn Birrell * managed providers come along while we're trying to close up
2527cd844e7aSJohn Birrell * shop. If we fail to detach, we'll need to re-register as a
2528cd844e7aSJohn Birrell * meta-provider. We can fail to unregister as a meta-provider
2529cd844e7aSJohn Birrell * if providers we manage still exist.
2530cd844e7aSJohn Birrell */
2531cd844e7aSJohn Birrell if (fasttrap_meta_id != DTRACE_METAPROVNONE &&
2532cd844e7aSJohn Birrell dtrace_meta_unregister(fasttrap_meta_id) != 0)
25338605d1aeSRui Paulo return (-1);
2534cd844e7aSJohn Birrell
2535cd844e7aSJohn Birrell /*
2536cd844e7aSJohn Birrell * Iterate over all of our providers. If there's still a process
2537cd844e7aSJohn Birrell * that corresponds to that pid, fail to detach.
2538cd844e7aSJohn Birrell */
2539cd844e7aSJohn Birrell for (i = 0; i < fasttrap_provs.fth_nent; i++) {
2540cd844e7aSJohn Birrell fasttrap_provider_t **fpp, *fp;
2541cd844e7aSJohn Birrell fasttrap_bucket_t *bucket = &fasttrap_provs.fth_table[i];
2542cd844e7aSJohn Birrell
2543cd844e7aSJohn Birrell mutex_enter(&bucket->ftb_mtx);
2544cd844e7aSJohn Birrell fpp = (fasttrap_provider_t **)&bucket->ftb_data;
2545cd844e7aSJohn Birrell while ((fp = *fpp) != NULL) {
2546cd844e7aSJohn Birrell /*
2547cd844e7aSJohn Birrell * Acquire and release the lock as a simple way of
2548cd844e7aSJohn Birrell * waiting for any other consumer to finish with
2549cd844e7aSJohn Birrell * this provider. A thread must first acquire the
2550cd844e7aSJohn Birrell * bucket lock so there's no chance of another thread
2551cd844e7aSJohn Birrell * blocking on the provider's lock.
2552cd844e7aSJohn Birrell */
2553cd844e7aSJohn Birrell mutex_enter(&fp->ftp_mtx);
2554cd844e7aSJohn Birrell mutex_exit(&fp->ftp_mtx);
2555cd844e7aSJohn Birrell
2556cd844e7aSJohn Birrell if (dtrace_unregister(fp->ftp_provid) != 0) {
2557cd844e7aSJohn Birrell fail = 1;
2558cd844e7aSJohn Birrell fpp = &fp->ftp_next;
2559cd844e7aSJohn Birrell } else {
2560cd844e7aSJohn Birrell *fpp = fp->ftp_next;
2561cd844e7aSJohn Birrell fasttrap_provider_free(fp);
2562cd844e7aSJohn Birrell }
2563cd844e7aSJohn Birrell }
2564cd844e7aSJohn Birrell
2565cd844e7aSJohn Birrell mutex_exit(&bucket->ftb_mtx);
2566cd844e7aSJohn Birrell }
2567cd844e7aSJohn Birrell
2568cd844e7aSJohn Birrell if (fail) {
2569cd844e7aSJohn Birrell (void) dtrace_meta_register("fasttrap", &fasttrap_mops, NULL,
2570cd844e7aSJohn Birrell &fasttrap_meta_id);
2571cd844e7aSJohn Birrell
25728605d1aeSRui Paulo return (-1);
2573cd844e7aSJohn Birrell }
2574cd844e7aSJohn Birrell
25751f9e80bcSAlan Somers /*
25761f9e80bcSAlan Somers * Stop new processes from entering these hooks now, before the
25771f9e80bcSAlan Somers * fasttrap_cleanup thread runs. That way all processes will hopefully
25781f9e80bcSAlan Somers * be out of these hooks before we free fasttrap_provs.fth_table
25791f9e80bcSAlan Somers */
25801f9e80bcSAlan Somers ASSERT(dtrace_fasttrap_fork == &fasttrap_fork);
25811f9e80bcSAlan Somers dtrace_fasttrap_fork = NULL;
25821f9e80bcSAlan Somers
25831f9e80bcSAlan Somers ASSERT(dtrace_fasttrap_exec == &fasttrap_exec_exit);
25841f9e80bcSAlan Somers dtrace_fasttrap_exec = NULL;
25851f9e80bcSAlan Somers
25861f9e80bcSAlan Somers ASSERT(dtrace_fasttrap_exit == &fasttrap_exec_exit);
25871f9e80bcSAlan Somers dtrace_fasttrap_exit = NULL;
25881f9e80bcSAlan Somers
2589427bc75eSMark Johnston mtx_lock(&fasttrap_cleanup_mtx);
2590427bc75eSMark Johnston fasttrap_cleanup_drain = 1;
2591427bc75eSMark Johnston /* Wait for the cleanup thread to finish up and signal us. */
2592427bc75eSMark Johnston wakeup(&fasttrap_cleanup_cv);
2593427bc75eSMark Johnston mtx_sleep(&fasttrap_cleanup_drain, &fasttrap_cleanup_mtx, 0, "ftcld",
2594427bc75eSMark Johnston 0);
2595427bc75eSMark Johnston fasttrap_cleanup_proc = NULL;
25960022f867SMark Johnston mtx_destroy(&fasttrap_cleanup_mtx);
2597427bc75eSMark Johnston
2598cd844e7aSJohn Birrell #ifdef DEBUG
2599cd844e7aSJohn Birrell mutex_enter(&fasttrap_count_mtx);
2600cd844e7aSJohn Birrell ASSERT(fasttrap_pid_count == 0);
2601cd844e7aSJohn Birrell mutex_exit(&fasttrap_count_mtx);
2602cd844e7aSJohn Birrell #endif
2603cd844e7aSJohn Birrell
2604bc96366cSSteven Hartland #ifndef illumos
26050626f3e4SMark Johnston EVENTHANDLER_DEREGISTER(thread_dtor, fasttrap_thread_dtor_tag);
26060626f3e4SMark Johnston
26071f9e80bcSAlan Somers for (i = 0; i < fasttrap_tpoints.fth_nent; i++)
26081f9e80bcSAlan Somers mutex_destroy(&fasttrap_tpoints.fth_table[i].ftb_mtx);
26091f9e80bcSAlan Somers for (i = 0; i < fasttrap_provs.fth_nent; i++)
26101f9e80bcSAlan Somers mutex_destroy(&fasttrap_provs.fth_table[i].ftb_mtx);
26111f9e80bcSAlan Somers for (i = 0; i < fasttrap_procs.fth_nent; i++)
26121f9e80bcSAlan Somers mutex_destroy(&fasttrap_procs.fth_table[i].ftb_mtx);
26131f9e80bcSAlan Somers #endif
2614cd844e7aSJohn Birrell kmem_free(fasttrap_tpoints.fth_table,
2615cd844e7aSJohn Birrell fasttrap_tpoints.fth_nent * sizeof (fasttrap_bucket_t));
2616cd844e7aSJohn Birrell fasttrap_tpoints.fth_nent = 0;
2617cd844e7aSJohn Birrell
2618cd844e7aSJohn Birrell kmem_free(fasttrap_provs.fth_table,
2619cd844e7aSJohn Birrell fasttrap_provs.fth_nent * sizeof (fasttrap_bucket_t));
2620cd844e7aSJohn Birrell fasttrap_provs.fth_nent = 0;
2621cd844e7aSJohn Birrell
2622cd844e7aSJohn Birrell kmem_free(fasttrap_procs.fth_table,
2623cd844e7aSJohn Birrell fasttrap_procs.fth_nent * sizeof (fasttrap_bucket_t));
2624cd844e7aSJohn Birrell fasttrap_procs.fth_nent = 0;
2625cd844e7aSJohn Birrell
2626bc96366cSSteven Hartland #ifndef illumos
26278605d1aeSRui Paulo destroy_dev(fasttrap_cdev);
26288605d1aeSRui Paulo mutex_destroy(&fasttrap_count_mtx);
2629380344a7SMark Johnston rm_destroy(&fasttrap_tp_lock);
26308605d1aeSRui Paulo #endif
2631cd844e7aSJohn Birrell
26328605d1aeSRui Paulo return (0);
2633cd844e7aSJohn Birrell }
2634cd844e7aSJohn Birrell
26358605d1aeSRui Paulo /* ARGSUSED */
26368605d1aeSRui Paulo static int
fasttrap_modevent(module_t mod __unused,int type,void * data __unused)26378605d1aeSRui Paulo fasttrap_modevent(module_t mod __unused, int type, void *data __unused)
2638cd844e7aSJohn Birrell {
26398605d1aeSRui Paulo int error = 0;
26408605d1aeSRui Paulo
26418605d1aeSRui Paulo switch (type) {
26428605d1aeSRui Paulo case MOD_LOAD:
26438605d1aeSRui Paulo break;
26448605d1aeSRui Paulo
26458605d1aeSRui Paulo case MOD_UNLOAD:
26468605d1aeSRui Paulo break;
26478605d1aeSRui Paulo
26488605d1aeSRui Paulo case MOD_SHUTDOWN:
26498605d1aeSRui Paulo break;
26508605d1aeSRui Paulo
26518605d1aeSRui Paulo default:
26528605d1aeSRui Paulo error = EOPNOTSUPP;
26538605d1aeSRui Paulo break;
26548605d1aeSRui Paulo }
26558605d1aeSRui Paulo return (error);
2656cd844e7aSJohn Birrell }
2657cd844e7aSJohn Birrell
26588605d1aeSRui Paulo SYSINIT(fasttrap_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, fasttrap_load,
26598605d1aeSRui Paulo NULL);
26608605d1aeSRui Paulo SYSUNINIT(fasttrap_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY,
26618605d1aeSRui Paulo fasttrap_unload, NULL);
2662cd844e7aSJohn Birrell
26638605d1aeSRui Paulo DEV_MODULE(fasttrap, fasttrap_modevent, NULL);
26648605d1aeSRui Paulo MODULE_VERSION(fasttrap, 1);
26658605d1aeSRui Paulo MODULE_DEPEND(fasttrap, dtrace, 1, 1, 1);
26668605d1aeSRui Paulo MODULE_DEPEND(fasttrap, opensolaris, 1, 1, 1);
2667