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