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