Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/cddl/dev/dtrace/dtrace_ioctl.c
48254 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
*/
22
23
static int dtrace_verbose_ioctl;
24
SYSCTL_INT(_debug_dtrace, OID_AUTO, verbose_ioctl, CTLFLAG_RW,
25
&dtrace_verbose_ioctl, 0, "log DTrace ioctls");
26
27
#define DTRACE_IOCTL_PRINTF(fmt, ...) if (dtrace_verbose_ioctl) printf(fmt, ## __VA_ARGS__ )
28
29
static int
30
dtrace_ioctl_helper(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
31
struct thread *td)
32
{
33
struct proc *p;
34
dof_helper_t *dhp;
35
dof_hdr_t *dof;
36
int rval;
37
38
dhp = NULL;
39
dof = NULL;
40
rval = 0;
41
switch (cmd) {
42
case DTRACEHIOC_ADDDOF:
43
dhp = (dof_helper_t *)addr;
44
addr = (caddr_t)(uintptr_t)dhp->dofhp_dof;
45
p = curproc;
46
if (p->p_pid == dhp->dofhp_pid) {
47
dof = dtrace_dof_copyin((uintptr_t)addr, &rval);
48
} else {
49
p = pfind(dhp->dofhp_pid);
50
if (p == NULL)
51
return (EINVAL);
52
if (!P_SHOULDSTOP(p) ||
53
(p->p_flag & (P_TRACED | P_WEXIT)) != P_TRACED ||
54
p->p_pptr != curproc) {
55
PROC_UNLOCK(p);
56
return (EINVAL);
57
}
58
_PHOLD(p);
59
PROC_UNLOCK(p);
60
dof = dtrace_dof_copyin_proc(p, (uintptr_t)addr, &rval);
61
}
62
63
if (dof == NULL) {
64
if (p != curproc)
65
PRELE(p);
66
break;
67
}
68
69
mutex_enter(&dtrace_lock);
70
if ((rval = dtrace_helper_slurp(dof, dhp, p)) != -1) {
71
dhp->dofhp_gen = rval;
72
rval = 0;
73
} else {
74
rval = EINVAL;
75
}
76
mutex_exit(&dtrace_lock);
77
if (p != curproc)
78
PRELE(p);
79
break;
80
case DTRACEHIOC_REMOVE:
81
mutex_enter(&dtrace_lock);
82
rval = dtrace_helper_destroygen(NULL, *(int *)(uintptr_t)addr);
83
mutex_exit(&dtrace_lock);
84
break;
85
default:
86
rval = ENOTTY;
87
break;
88
}
89
return (rval);
90
}
91
92
/* ARGSUSED */
93
static int
94
dtrace_ioctl(struct cdev *dev, u_long cmd, caddr_t addr,
95
int flags __unused, struct thread *td)
96
{
97
dtrace_state_t *state;
98
devfs_get_cdevpriv((void **) &state);
99
100
int error = 0;
101
if (state == NULL)
102
return (EINVAL);
103
104
if (state->dts_anon) {
105
ASSERT(dtrace_anon.dta_state == NULL);
106
state = state->dts_anon;
107
}
108
109
switch (cmd) {
110
case DTRACEIOC_AGGDESC: {
111
dtrace_aggdesc_t **paggdesc = (dtrace_aggdesc_t **) addr;
112
dtrace_aggdesc_t aggdesc;
113
dtrace_action_t *act;
114
dtrace_aggregation_t *agg;
115
int nrecs;
116
uint32_t offs;
117
dtrace_recdesc_t *lrec;
118
void *buf;
119
size_t size;
120
uintptr_t dest;
121
122
DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_AGGDESC\n",__func__,__LINE__);
123
124
if (copyin((void *) *paggdesc, &aggdesc, sizeof (aggdesc)) != 0)
125
return (EFAULT);
126
127
mutex_enter(&dtrace_lock);
128
129
if ((agg = dtrace_aggid2agg(state, aggdesc.dtagd_id)) == NULL) {
130
mutex_exit(&dtrace_lock);
131
return (EINVAL);
132
}
133
134
aggdesc.dtagd_epid = agg->dtag_ecb->dte_epid;
135
136
nrecs = aggdesc.dtagd_nrecs;
137
aggdesc.dtagd_nrecs = 0;
138
139
offs = agg->dtag_base;
140
lrec = &agg->dtag_action.dta_rec;
141
aggdesc.dtagd_size = lrec->dtrd_offset + lrec->dtrd_size - offs;
142
143
for (act = agg->dtag_first; ; act = act->dta_next) {
144
ASSERT(act->dta_intuple ||
145
DTRACEACT_ISAGG(act->dta_kind));
146
147
/*
148
* If this action has a record size of zero, it
149
* denotes an argument to the aggregating action.
150
* Because the presence of this record doesn't (or
151
* shouldn't) affect the way the data is interpreted,
152
* we don't copy it out to save user-level the
153
* confusion of dealing with a zero-length record.
154
*/
155
if (act->dta_rec.dtrd_size == 0) {
156
ASSERT(agg->dtag_hasarg);
157
continue;
158
}
159
160
aggdesc.dtagd_nrecs++;
161
162
if (act == &agg->dtag_action)
163
break;
164
}
165
166
/*
167
* Now that we have the size, we need to allocate a temporary
168
* buffer in which to store the complete description. We need
169
* the temporary buffer to be able to drop dtrace_lock()
170
* across the copyout(), below.
171
*/
172
size = sizeof (dtrace_aggdesc_t) +
173
(aggdesc.dtagd_nrecs * sizeof (dtrace_recdesc_t));
174
175
buf = kmem_alloc(size, KM_SLEEP);
176
dest = (uintptr_t)buf;
177
178
bcopy(&aggdesc, (void *)dest, sizeof (aggdesc));
179
dest += offsetof(dtrace_aggdesc_t, dtagd_rec[0]);
180
181
for (act = agg->dtag_first; ; act = act->dta_next) {
182
dtrace_recdesc_t rec = act->dta_rec;
183
184
/*
185
* See the comment in the above loop for why we pass
186
* over zero-length records.
187
*/
188
if (rec.dtrd_size == 0) {
189
ASSERT(agg->dtag_hasarg);
190
continue;
191
}
192
193
if (nrecs-- == 0)
194
break;
195
196
rec.dtrd_offset -= offs;
197
bcopy(&rec, (void *)dest, sizeof (rec));
198
dest += sizeof (dtrace_recdesc_t);
199
200
if (act == &agg->dtag_action)
201
break;
202
}
203
204
mutex_exit(&dtrace_lock);
205
206
if (copyout(buf, (void *) *paggdesc, dest - (uintptr_t)buf) != 0) {
207
kmem_free(buf, size);
208
return (EFAULT);
209
}
210
211
kmem_free(buf, size);
212
return (0);
213
}
214
case DTRACEIOC_AGGSNAP:
215
case DTRACEIOC_BUFSNAP: {
216
dtrace_bufdesc_t **pdesc = (dtrace_bufdesc_t **) addr;
217
dtrace_bufdesc_t desc;
218
caddr_t cached;
219
dtrace_buffer_t *buf;
220
221
dtrace_debug_output();
222
223
if (copyin((void *) *pdesc, &desc, sizeof (desc)) != 0)
224
return (EFAULT);
225
226
DTRACE_IOCTL_PRINTF("%s(%d): %s curcpu %d cpu %d\n",
227
__func__,__LINE__,
228
cmd == DTRACEIOC_AGGSNAP ?
229
"DTRACEIOC_AGGSNAP":"DTRACEIOC_BUFSNAP",
230
curcpu, desc.dtbd_cpu);
231
232
if (desc.dtbd_cpu > mp_maxid || CPU_ABSENT(desc.dtbd_cpu))
233
return (ENOENT);
234
235
mutex_enter(&dtrace_lock);
236
237
if (cmd == DTRACEIOC_BUFSNAP) {
238
buf = &state->dts_buffer[desc.dtbd_cpu];
239
} else {
240
buf = &state->dts_aggbuffer[desc.dtbd_cpu];
241
}
242
243
if (buf->dtb_flags & (DTRACEBUF_RING | DTRACEBUF_FILL)) {
244
size_t sz = buf->dtb_offset;
245
246
if (state->dts_activity != DTRACE_ACTIVITY_STOPPED) {
247
mutex_exit(&dtrace_lock);
248
return (EBUSY);
249
}
250
251
/*
252
* If this buffer has already been consumed, we're
253
* going to indicate that there's nothing left here
254
* to consume.
255
*/
256
if (buf->dtb_flags & DTRACEBUF_CONSUMED) {
257
mutex_exit(&dtrace_lock);
258
259
desc.dtbd_size = 0;
260
desc.dtbd_drops = 0;
261
desc.dtbd_errors = 0;
262
desc.dtbd_oldest = 0;
263
sz = sizeof (desc);
264
265
if (copyout(&desc, (void *) *pdesc, sz) != 0)
266
return (EFAULT);
267
268
return (0);
269
}
270
271
/*
272
* If this is a ring buffer that has wrapped, we want
273
* to copy the whole thing out.
274
*/
275
if (buf->dtb_flags & DTRACEBUF_WRAPPED) {
276
dtrace_buffer_polish(buf);
277
sz = buf->dtb_size;
278
}
279
280
if (copyout(buf->dtb_tomax, desc.dtbd_data, sz) != 0) {
281
mutex_exit(&dtrace_lock);
282
return (EFAULT);
283
}
284
285
desc.dtbd_size = sz;
286
desc.dtbd_drops = buf->dtb_drops;
287
desc.dtbd_errors = buf->dtb_errors;
288
desc.dtbd_oldest = buf->dtb_xamot_offset;
289
desc.dtbd_timestamp = dtrace_gethrtime();
290
291
mutex_exit(&dtrace_lock);
292
293
if (copyout(&desc, (void *) *pdesc, sizeof (desc)) != 0)
294
return (EFAULT);
295
296
buf->dtb_flags |= DTRACEBUF_CONSUMED;
297
298
return (0);
299
}
300
301
if (buf->dtb_tomax == NULL) {
302
ASSERT(buf->dtb_xamot == NULL);
303
mutex_exit(&dtrace_lock);
304
return (ENOENT);
305
}
306
307
cached = buf->dtb_tomax;
308
ASSERT(!(buf->dtb_flags & DTRACEBUF_NOSWITCH));
309
310
dtrace_xcall(desc.dtbd_cpu,
311
(dtrace_xcall_t)dtrace_buffer_switch, buf);
312
313
state->dts_errors += buf->dtb_xamot_errors;
314
315
/*
316
* If the buffers did not actually switch, then the cross call
317
* did not take place -- presumably because the given CPU is
318
* not in the ready set. If this is the case, we'll return
319
* ENOENT.
320
*/
321
if (buf->dtb_tomax == cached) {
322
ASSERT(buf->dtb_xamot != cached);
323
mutex_exit(&dtrace_lock);
324
return (ENOENT);
325
}
326
327
ASSERT(cached == buf->dtb_xamot);
328
329
DTRACE_IOCTL_PRINTF("%s(%d): copyout the buffer snapshot\n",__func__,__LINE__);
330
331
/*
332
* We have our snapshot; now copy it out.
333
*/
334
if (copyout(buf->dtb_xamot, desc.dtbd_data,
335
buf->dtb_xamot_offset) != 0) {
336
mutex_exit(&dtrace_lock);
337
return (EFAULT);
338
}
339
340
desc.dtbd_size = buf->dtb_xamot_offset;
341
desc.dtbd_drops = buf->dtb_xamot_drops;
342
desc.dtbd_errors = buf->dtb_xamot_errors;
343
desc.dtbd_oldest = 0;
344
desc.dtbd_timestamp = buf->dtb_switched;
345
346
mutex_exit(&dtrace_lock);
347
348
DTRACE_IOCTL_PRINTF("%s(%d): copyout buffer desc: size %zd drops %lu errors %lu\n",__func__,__LINE__,(size_t) desc.dtbd_size,(u_long) desc.dtbd_drops,(u_long) desc.dtbd_errors);
349
350
/*
351
* Finally, copy out the buffer description.
352
*/
353
if (copyout(&desc, (void *) *pdesc, sizeof (desc)) != 0)
354
return (EFAULT);
355
356
return (0);
357
}
358
case DTRACEIOC_CONF: {
359
dtrace_conf_t conf;
360
361
DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_CONF\n",__func__,__LINE__);
362
363
bzero(&conf, sizeof (conf));
364
conf.dtc_difversion = DIF_VERSION;
365
conf.dtc_difintregs = DIF_DIR_NREGS;
366
conf.dtc_diftupregs = DIF_DTR_NREGS;
367
conf.dtc_ctfmodel = CTF_MODEL_NATIVE;
368
369
*((dtrace_conf_t *) addr) = conf;
370
371
return (0);
372
}
373
case DTRACEIOC_DOFGET: {
374
dof_hdr_t **pdof = (dof_hdr_t **) addr;
375
dof_hdr_t hdr, *dof = *pdof;
376
int rval;
377
uint64_t len;
378
379
DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_DOFGET\n",__func__,__LINE__);
380
381
if (copyin((void *)dof, &hdr, sizeof (hdr)) != 0)
382
return (EFAULT);
383
384
mutex_enter(&dtrace_lock);
385
dof = dtrace_dof_create(state);
386
mutex_exit(&dtrace_lock);
387
388
len = MIN(hdr.dofh_loadsz, dof->dofh_loadsz);
389
rval = copyout(dof, (void *) *pdof, len);
390
dtrace_dof_destroy(dof);
391
392
return (rval == 0 ? 0 : EFAULT);
393
}
394
case DTRACEIOC_ENABLE: {
395
dof_hdr_t *dof = NULL;
396
dtrace_enabling_t *enab = NULL;
397
dtrace_vstate_t *vstate;
398
int err = 0;
399
int rval;
400
dtrace_enable_io_t *p = (dtrace_enable_io_t *) addr;
401
402
DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_ENABLE\n",__func__,__LINE__);
403
404
/*
405
* If a NULL argument has been passed, we take this as our
406
* cue to reevaluate our enablings.
407
*/
408
if (p->dof == NULL) {
409
dtrace_enabling_matchall();
410
411
return (0);
412
}
413
414
if ((dof = dtrace_dof_copyin((uintptr_t) p->dof, &rval)) == NULL)
415
return (EINVAL);
416
417
mutex_enter(&cpu_lock);
418
mutex_enter(&dtrace_lock);
419
vstate = &state->dts_vstate;
420
421
if (state->dts_activity != DTRACE_ACTIVITY_INACTIVE) {
422
mutex_exit(&dtrace_lock);
423
mutex_exit(&cpu_lock);
424
dtrace_dof_destroy(dof);
425
return (EBUSY);
426
}
427
428
if (dtrace_dof_slurp(dof, vstate, td->td_ucred, &enab, 0, 0,
429
B_TRUE) != 0) {
430
mutex_exit(&dtrace_lock);
431
mutex_exit(&cpu_lock);
432
dtrace_dof_destroy(dof);
433
return (EINVAL);
434
}
435
436
if ((rval = dtrace_dof_options(dof, state)) != 0) {
437
dtrace_enabling_destroy(enab);
438
mutex_exit(&dtrace_lock);
439
mutex_exit(&cpu_lock);
440
dtrace_dof_destroy(dof);
441
return (rval);
442
}
443
444
if ((err = dtrace_enabling_match(enab, &p->n_matched)) == 0) {
445
err = dtrace_enabling_retain(enab);
446
} else {
447
dtrace_enabling_destroy(enab);
448
}
449
450
mutex_exit(&cpu_lock);
451
mutex_exit(&dtrace_lock);
452
dtrace_dof_destroy(dof);
453
454
return (err);
455
}
456
case DTRACEIOC_EPROBE: {
457
dtrace_eprobedesc_t **pepdesc = (dtrace_eprobedesc_t **) addr;
458
dtrace_eprobedesc_t epdesc;
459
dtrace_ecb_t *ecb;
460
dtrace_action_t *act;
461
void *buf;
462
size_t size;
463
uintptr_t dest;
464
int nrecs;
465
466
DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_EPROBE\n",__func__,__LINE__);
467
468
if (copyin((void *)*pepdesc, &epdesc, sizeof (epdesc)) != 0)
469
return (EFAULT);
470
471
mutex_enter(&dtrace_lock);
472
473
if ((ecb = dtrace_epid2ecb(state, epdesc.dtepd_epid)) == NULL) {
474
mutex_exit(&dtrace_lock);
475
return (EINVAL);
476
}
477
478
if (ecb->dte_probe == NULL) {
479
mutex_exit(&dtrace_lock);
480
return (EINVAL);
481
}
482
483
epdesc.dtepd_probeid = ecb->dte_probe->dtpr_id;
484
epdesc.dtepd_uarg = ecb->dte_uarg;
485
epdesc.dtepd_size = ecb->dte_size;
486
487
nrecs = epdesc.dtepd_nrecs;
488
epdesc.dtepd_nrecs = 0;
489
for (act = ecb->dte_action; act != NULL; act = act->dta_next) {
490
if (DTRACEACT_ISAGG(act->dta_kind) || act->dta_intuple)
491
continue;
492
493
epdesc.dtepd_nrecs++;
494
}
495
496
/*
497
* Now that we have the size, we need to allocate a temporary
498
* buffer in which to store the complete description. We need
499
* the temporary buffer to be able to drop dtrace_lock()
500
* across the copyout(), below.
501
*/
502
size = sizeof (dtrace_eprobedesc_t) +
503
(epdesc.dtepd_nrecs * sizeof (dtrace_recdesc_t));
504
505
buf = kmem_alloc(size, KM_SLEEP);
506
dest = (uintptr_t)buf;
507
508
bcopy(&epdesc, (void *)dest, sizeof (epdesc));
509
dest += offsetof(dtrace_eprobedesc_t, dtepd_rec[0]);
510
511
for (act = ecb->dte_action; act != NULL; act = act->dta_next) {
512
if (DTRACEACT_ISAGG(act->dta_kind) || act->dta_intuple)
513
continue;
514
515
if (nrecs-- == 0)
516
break;
517
518
bcopy(&act->dta_rec, (void *)dest,
519
sizeof (dtrace_recdesc_t));
520
dest += sizeof (dtrace_recdesc_t);
521
}
522
523
mutex_exit(&dtrace_lock);
524
525
if (copyout(buf, (void *) *pepdesc, dest - (uintptr_t)buf) != 0) {
526
kmem_free(buf, size);
527
return (EFAULT);
528
}
529
530
kmem_free(buf, size);
531
return (0);
532
}
533
case DTRACEIOC_FORMAT: {
534
dtrace_fmtdesc_t *fmt = (dtrace_fmtdesc_t *) addr;
535
char *str;
536
int len;
537
538
DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_FORMAT\n",__func__,__LINE__);
539
540
mutex_enter(&dtrace_lock);
541
542
if (fmt->dtfd_format == 0 ||
543
fmt->dtfd_format > state->dts_nformats) {
544
mutex_exit(&dtrace_lock);
545
return (EINVAL);
546
}
547
548
/*
549
* Format strings are allocated contiguously and they are
550
* never freed; if a format index is less than the number
551
* of formats, we can assert that the format map is non-NULL
552
* and that the format for the specified index is non-NULL.
553
*/
554
ASSERT(state->dts_formats != NULL);
555
str = state->dts_formats[fmt->dtfd_format - 1];
556
ASSERT(str != NULL);
557
558
len = strlen(str) + 1;
559
560
if (len > fmt->dtfd_length) {
561
fmt->dtfd_length = len;
562
} else {
563
if (copyout(str, fmt->dtfd_string, len) != 0) {
564
mutex_exit(&dtrace_lock);
565
return (EINVAL);
566
}
567
}
568
569
mutex_exit(&dtrace_lock);
570
return (0);
571
}
572
case DTRACEIOC_GO: {
573
int rval;
574
processorid_t *cpuid = (processorid_t *) addr;
575
576
DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_GO\n",__func__,__LINE__);
577
578
rval = dtrace_state_go(state, cpuid);
579
580
return (rval);
581
}
582
case DTRACEIOC_PROBEARG: {
583
dtrace_argdesc_t *desc = (dtrace_argdesc_t *) addr;
584
dtrace_probe_t *probe;
585
dtrace_provider_t *prov;
586
587
DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_PROBEARG\n",__func__,__LINE__);
588
589
if (desc->dtargd_id == DTRACE_IDNONE)
590
return (EINVAL);
591
592
if (desc->dtargd_ndx == DTRACE_ARGNONE)
593
return (EINVAL);
594
595
mutex_enter(&dtrace_provider_lock);
596
#ifdef illumos
597
mutex_enter(&mod_lock);
598
#endif
599
mutex_enter(&dtrace_lock);
600
601
if (desc->dtargd_id > dtrace_nprobes) {
602
mutex_exit(&dtrace_lock);
603
#ifdef illumos
604
mutex_exit(&mod_lock);
605
#endif
606
mutex_exit(&dtrace_provider_lock);
607
return (EINVAL);
608
}
609
610
if ((probe = dtrace_probes[desc->dtargd_id - 1]) == NULL) {
611
mutex_exit(&dtrace_lock);
612
#ifdef illumos
613
mutex_exit(&mod_lock);
614
#endif
615
mutex_exit(&dtrace_provider_lock);
616
return (EINVAL);
617
}
618
619
mutex_exit(&dtrace_lock);
620
621
prov = probe->dtpr_provider;
622
623
if (prov->dtpv_pops.dtps_getargdesc == NULL) {
624
/*
625
* There isn't any typed information for this probe.
626
* Set the argument number to DTRACE_ARGNONE.
627
*/
628
desc->dtargd_ndx = DTRACE_ARGNONE;
629
} else {
630
desc->dtargd_native[0] = '\0';
631
desc->dtargd_xlate[0] = '\0';
632
desc->dtargd_mapping = desc->dtargd_ndx;
633
634
prov->dtpv_pops.dtps_getargdesc(prov->dtpv_arg,
635
probe->dtpr_id, probe->dtpr_arg, desc);
636
}
637
638
#ifdef illumos
639
mutex_exit(&mod_lock);
640
#endif
641
mutex_exit(&dtrace_provider_lock);
642
643
return (0);
644
}
645
case DTRACEIOC_PROBEMATCH:
646
case DTRACEIOC_PROBES: {
647
dtrace_probedesc_t *p_desc = (dtrace_probedesc_t *) addr;
648
dtrace_probe_t *probe = NULL;
649
dtrace_probekey_t pkey;
650
dtrace_id_t i;
651
int m = 0;
652
uint32_t priv = 0;
653
uid_t uid = 0;
654
zoneid_t zoneid = 0;
655
656
DTRACE_IOCTL_PRINTF("%s(%d): %s\n",__func__,__LINE__,
657
cmd == DTRACEIOC_PROBEMATCH ?
658
"DTRACEIOC_PROBEMATCH":"DTRACEIOC_PROBES");
659
660
p_desc->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0';
661
p_desc->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0';
662
p_desc->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0';
663
p_desc->dtpd_name[DTRACE_NAMELEN - 1] = '\0';
664
665
/*
666
* Before we attempt to match this probe, we want to give
667
* all providers the opportunity to provide it.
668
*/
669
if (p_desc->dtpd_id == DTRACE_IDNONE) {
670
mutex_enter(&dtrace_provider_lock);
671
dtrace_probe_provide(p_desc, NULL);
672
mutex_exit(&dtrace_provider_lock);
673
p_desc->dtpd_id++;
674
}
675
676
if (cmd == DTRACEIOC_PROBEMATCH) {
677
dtrace_probekey(p_desc, &pkey);
678
pkey.dtpk_id = DTRACE_IDNONE;
679
}
680
681
dtrace_cred2priv(td->td_ucred, &priv, &uid, &zoneid);
682
683
mutex_enter(&dtrace_lock);
684
685
if (cmd == DTRACEIOC_PROBEMATCH) {
686
for (i = p_desc->dtpd_id; i <= dtrace_nprobes; i++) {
687
if ((probe = dtrace_probes[i - 1]) != NULL &&
688
(m = dtrace_match_probe(probe, &pkey,
689
priv, uid, zoneid)) != 0)
690
break;
691
}
692
693
if (m < 0) {
694
mutex_exit(&dtrace_lock);
695
return (EINVAL);
696
}
697
698
} else {
699
for (i = p_desc->dtpd_id; i <= dtrace_nprobes; i++) {
700
if ((probe = dtrace_probes[i - 1]) != NULL &&
701
dtrace_match_priv(probe, priv, uid, zoneid))
702
break;
703
}
704
}
705
706
if (probe == NULL) {
707
mutex_exit(&dtrace_lock);
708
return (ESRCH);
709
}
710
711
dtrace_probe_description(probe, p_desc);
712
mutex_exit(&dtrace_lock);
713
714
return (0);
715
}
716
case DTRACEIOC_PROVIDER: {
717
dtrace_providerdesc_t *pvd = (dtrace_providerdesc_t *) addr;
718
dtrace_provider_t *pvp;
719
720
DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_PROVIDER\n",__func__,__LINE__);
721
722
pvd->dtvd_name[DTRACE_PROVNAMELEN - 1] = '\0';
723
mutex_enter(&dtrace_provider_lock);
724
725
for (pvp = dtrace_provider; pvp != NULL; pvp = pvp->dtpv_next) {
726
if (strcmp(pvp->dtpv_name, pvd->dtvd_name) == 0)
727
break;
728
}
729
730
mutex_exit(&dtrace_provider_lock);
731
732
if (pvp == NULL)
733
return (ESRCH);
734
735
bcopy(&pvp->dtpv_priv, &pvd->dtvd_priv, sizeof (dtrace_ppriv_t));
736
bcopy(&pvp->dtpv_attr, &pvd->dtvd_attr, sizeof (dtrace_pattr_t));
737
738
return (0);
739
}
740
case DTRACEIOC_REPLICATE: {
741
dtrace_repldesc_t *desc = (dtrace_repldesc_t *) addr;
742
dtrace_probedesc_t *match = &desc->dtrpd_match;
743
dtrace_probedesc_t *create = &desc->dtrpd_create;
744
int err;
745
746
DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_REPLICATE\n",__func__,__LINE__);
747
748
match->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0';
749
match->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0';
750
match->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0';
751
match->dtpd_name[DTRACE_NAMELEN - 1] = '\0';
752
753
create->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0';
754
create->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0';
755
create->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0';
756
create->dtpd_name[DTRACE_NAMELEN - 1] = '\0';
757
758
mutex_enter(&dtrace_lock);
759
err = dtrace_enabling_replicate(state, match, create);
760
mutex_exit(&dtrace_lock);
761
762
return (err);
763
}
764
case DTRACEIOC_STATUS: {
765
dtrace_status_t *stat = (dtrace_status_t *) addr;
766
dtrace_dstate_t *dstate;
767
int i, j;
768
uint64_t nerrs;
769
770
DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_STATUS\n",__func__,__LINE__);
771
772
/*
773
* See the comment in dtrace_state_deadman() for the reason
774
* for setting dts_laststatus to INT64_MAX before setting
775
* it to the correct value.
776
*/
777
state->dts_laststatus = INT64_MAX;
778
dtrace_membar_producer();
779
state->dts_laststatus = dtrace_gethrtime();
780
781
bzero(stat, sizeof (*stat));
782
783
mutex_enter(&dtrace_lock);
784
785
if (state->dts_activity == DTRACE_ACTIVITY_INACTIVE) {
786
mutex_exit(&dtrace_lock);
787
return (ENOENT);
788
}
789
790
if (state->dts_activity == DTRACE_ACTIVITY_DRAINING)
791
stat->dtst_exiting = 1;
792
793
nerrs = state->dts_errors;
794
dstate = &state->dts_vstate.dtvs_dynvars;
795
796
CPU_FOREACH(i) {
797
dtrace_dstate_percpu_t *dcpu = &dstate->dtds_percpu[i];
798
799
stat->dtst_dyndrops += dcpu->dtdsc_drops;
800
stat->dtst_dyndrops_dirty += dcpu->dtdsc_dirty_drops;
801
stat->dtst_dyndrops_rinsing += dcpu->dtdsc_rinsing_drops;
802
803
if (state->dts_buffer[i].dtb_flags & DTRACEBUF_FULL)
804
stat->dtst_filled++;
805
806
nerrs += state->dts_buffer[i].dtb_errors;
807
808
for (j = 0; j < state->dts_nspeculations; j++) {
809
dtrace_speculation_t *spec;
810
dtrace_buffer_t *buf;
811
812
spec = &state->dts_speculations[j];
813
buf = &spec->dtsp_buffer[i];
814
stat->dtst_specdrops += buf->dtb_xamot_drops;
815
}
816
}
817
818
stat->dtst_specdrops_busy = state->dts_speculations_busy;
819
stat->dtst_specdrops_unavail = state->dts_speculations_unavail;
820
stat->dtst_stkstroverflows = state->dts_stkstroverflows;
821
stat->dtst_dblerrors = state->dts_dblerrors;
822
stat->dtst_killed =
823
(state->dts_activity == DTRACE_ACTIVITY_KILLED);
824
stat->dtst_errors = nerrs;
825
826
mutex_exit(&dtrace_lock);
827
828
return (0);
829
}
830
case DTRACEIOC_STOP: {
831
int rval;
832
processorid_t *cpuid = (processorid_t *) addr;
833
834
DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_STOP\n",__func__,__LINE__);
835
836
mutex_enter(&dtrace_lock);
837
rval = dtrace_state_stop(state, cpuid);
838
mutex_exit(&dtrace_lock);
839
840
return (rval);
841
}
842
default:
843
error = ENOTTY;
844
}
845
return (error);
846
}
847
848