1 /* $NetBSD: fbt.c,v 1.29 2022/09/02 11:03:50 riastradh Exp $ */
2
3 /*
4 * CDDL HEADER START
5 *
6 * The contents of this file are subject to the terms of the
7 * Common Development and Distribution License (the "License").
8 * You may not use this file except in compliance with the License.
9 *
10 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11 * or http://www.opensolaris.org/os/licensing.
12 * See the License for the specific language governing permissions
13 * and limitations under the License.
14 *
15 * When distributing Covered Code, include this CDDL HEADER in each
16 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17 * If applicable, add the following below this CDDL HEADER, with the
18 * fields enclosed by brackets "[]" replaced with your own identifying
19 * information: Portions Copyright [yyyy] [name of copyright owner]
20 *
21 * CDDL HEADER END
22 *
23 * Portions Copyright 2006-2008 John Birrell jb@freebsd.org
24 * Portions Copyright 2010 Darran Hunt darran@NetBSD.org
25 *
26 * $FreeBSD: head/sys/cddl/dev/fbt/fbt.c 309786 2016-12-10 03:13:11Z markj $
27 *
28 */
29
30 /*
31 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
32 * Use is subject to license terms.
33 */
34
35 #include <sys/cdefs.h>
36 #include <sys/proc.h>
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/conf.h>
40 #include <sys/cpuvar.h>
41 #include <sys/fcntl.h>
42 #include <sys/filio.h>
43 #include <sys/kernel.h>
44 #include <sys/kmem.h>
45 #include <sys/ksyms.h>
46 #include <sys/cpu.h>
47 #include <sys/kthread.h>
48 #include <sys/syslimits.h>
49 #include <sys/linker.h>
50 #include <sys/lock.h>
51 #include <sys/malloc.h>
52 #include <sys/module.h>
53 #include <sys/mutex.h>
54 #include <sys/poll.h>
55 #include <sys/proc.h>
56 #include <sys/selinfo.h>
57 #include <sys/syscall.h>
58 #include <sys/uio.h>
59 #include <sys/unistd.h>
60 #include <sys/exec_elf.h>
61
62 #include <sys/dtrace.h>
63 #include <sys/dtrace_bsd.h>
64 #include <sys/kern_ctf.h>
65 #include <sys/dtrace_impl.h>
66
67 #include "fbt.h"
68
69 mod_ctf_t *modptr;
70
71 dtrace_provider_id_t fbt_id;
72 fbt_probe_t **fbt_probetab;
73 int fbt_probetab_mask;
74 static int fbt_probetab_size;
75
76 static dev_type_open(fbt_open);
77 static int fbt_unload(void);
78 static void fbt_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *);
79 static void fbt_provide_module(void *, modctl_t *);
80 static void fbt_destroy(void *, dtrace_id_t, void *);
81 static int fbt_enable(void *, dtrace_id_t, void *);
82 static void fbt_disable(void *, dtrace_id_t, void *);
83 static void fbt_load(void);
84 static void fbt_suspend(void *, dtrace_id_t, void *);
85 static void fbt_resume(void *, dtrace_id_t, void *);
86
87 static const struct cdevsw fbt_cdevsw = {
88 .d_open = fbt_open,
89 .d_close = noclose,
90 .d_read = noread,
91 .d_write = nowrite,
92 .d_ioctl = noioctl,
93 .d_stop = nostop,
94 .d_tty = notty,
95 .d_poll = nopoll,
96 .d_mmap = nommap,
97 .d_kqfilter = nokqfilter,
98 .d_discard = nodiscard,
99 .d_flag = D_OTHER
100 };
101
102 static dtrace_pattr_t fbt_attr = {
103 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
104 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
105 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
106 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
107 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
108 };
109
110 static dtrace_pops_t fbt_pops = {
111 NULL,
112 fbt_provide_module,
113 fbt_enable,
114 fbt_disable,
115 fbt_suspend,
116 fbt_resume,
117 fbt_getargdesc,
118 NULL,
119 NULL,
120 fbt_destroy
121 };
122
123 #ifdef __FreeBSD__
124 static int fbt_verbose = 0;
125
126 static struct cdev *fbt_cdev;
127 #endif /* __FreeBSD__ */
128
129 #ifdef __NetBSD__
130 specificdata_key_t fbt_module_key;
131
132 #define version xversion
133 #endif /* __NetBSD__ */
134
135 int
fbt_excluded(const char * name)136 fbt_excluded(const char *name)
137 {
138
139 if (strncmp(name, "dtrace_", 7) == 0 &&
140 strncmp(name, "dtrace_safe_", 12) != 0) {
141 /*
142 * Anything beginning with "dtrace_" may be called
143 * from probe context unless it explicitly indicates
144 * that it won't be called from probe context by
145 * using the prefix "dtrace_safe_".
146 */
147 return (1);
148 }
149
150 #ifdef __FreeBSD__
151 /*
152 * Lock owner methods may be called from probe context.
153 */
154 if (strcmp(name, "owner_mtx") == 0 ||
155 strcmp(name, "owner_rm") == 0 ||
156 strcmp(name, "owner_rw") == 0 ||
157 strcmp(name, "owner_sx") == 0)
158 return (1);
159
160 /*
161 * When DTrace is built into the kernel we need to exclude
162 * the FBT functions from instrumentation.
163 */
164 #ifndef _KLD_MODULE
165 if (strncmp(name, "fbt_", 4) == 0)
166 return (1);
167 #endif
168 #endif
169
170 #ifdef __NetBSD__
171 if (strcmp(name, "cpu_index") == 0 ||
172 strncmp(name, "db_", 3) == 0 ||
173 strncmp(name, "ddb_", 4) == 0 ||
174 strncmp(name, "kdb_", 4) == 0 ||
175 strncmp(name, "lockdebug_", 10) == 0 ||
176 strncmp(name, "kauth_", 5) == 0 ||
177 strncmp(name, "ktext_write", 11) == 0 ||
178 strncmp(name, "fbt_", 4) == 0) {
179 return (1);
180 }
181 #endif
182
183 return (0);
184 }
185
186 static void
fbt_doubletrap(void)187 fbt_doubletrap(void)
188 {
189 fbt_probe_t *fbt;
190 int i;
191
192 for (i = 0; i < fbt_probetab_size; i++) {
193 fbt = fbt_probetab[i];
194
195 for (; fbt != NULL; fbt = fbt->fbtp_next)
196 fbt_patch_tracepoint(fbt, fbt->fbtp_savedval);
197 }
198 }
199
200 #ifdef __FreeBSD__
201 static void
fbt_provide_module(void * arg,modctl_t * lf)202 fbt_provide_module(void *arg, modctl_t *lf)
203 {
204 char modname[MAXPATHLEN];
205 int i;
206 size_t len;
207
208 strlcpy(modname, lf->filename, sizeof(modname));
209 len = strlen(modname);
210 if (len > 3 && strcmp(modname + len - 3, ".ko") == 0)
211 modname[len - 3] = '\0';
212
213 /*
214 * Employees of dtrace and their families are ineligible. Void
215 * where prohibited.
216 */
217 if (strcmp(modname, "dtrace") == 0)
218 return;
219
220 /*
221 * To register with DTrace, a module must list 'dtrace' as a
222 * dependency in order for the kernel linker to resolve
223 * symbols like dtrace_register(). All modules with such a
224 * dependency are ineligible for FBT tracing.
225 */
226 for (i = 0; i < lf->ndeps; i++)
227 if (strncmp(lf->deps[i]->filename, "dtrace", 6) == 0)
228 return;
229
230 if (lf->fbt_nentries) {
231 /*
232 * This module has some FBT entries allocated; we're afraid
233 * to screw with it.
234 */
235 return;
236 }
237
238 /*
239 * List the functions in the module and the symbol values.
240 */
241 (void) linker_file_function_listall(lf, fbt_provide_module_function, modname);
242 }
243 #endif
244 #ifdef __NetBSD__
245 static void
fbt_provide_module(void * arg,modctl_t * mod)246 fbt_provide_module(void *arg, modctl_t *mod)
247 {
248 struct fbt_ksyms_arg fka;
249 struct mod_ctf *mc;
250 char modname[MAXPATHLEN];
251 int i;
252 size_t len;
253
254 if (mod_ctf_get(mod, &mc)) {
255 printf("fbt: no CTF data for module %s\n", module_name(mod));
256 return;
257 }
258
259 strlcpy(modname, module_name(mod), sizeof(modname));
260 len = strlen(modname);
261 if (len > 5 && strcmp(modname + len - 3, ".kmod") == 0)
262 modname[len - 4] = '\0';
263
264 /*
265 * Employees of dtrace and their families are ineligible. Void
266 * where prohibited.
267 */
268 if (strcmp(modname, "dtrace") == 0)
269 return;
270
271 /*
272 * The cyclic timer subsystem can be built as a module and DTrace
273 * depends on that, so it is ineligible too.
274 */
275 if (strcmp(modname, "cyclic") == 0)
276 return;
277
278 /*
279 * To register with DTrace, a module must list 'dtrace' as a
280 * dependency in order for the kernel linker to resolve
281 * symbols like dtrace_register(). All modules with such a
282 * dependency are ineligible for FBT tracing.
283 */
284 for (i = 0; i < mod->mod_nrequired; i++) {
285 if (strncmp(module_name((*mod->mod_required)[i]),
286 "dtrace", 6) == 0)
287 return;
288 }
289 if (mc->fbt_provided) {
290 return;
291 }
292
293 /*
294 * List the functions in the module and the symbol values.
295 */
296 memset(&fka, 0, sizeof(fka));
297 fka.fka_mod = mod;
298 fka.fka_mc = mc;
299 ksyms_mod_foreach(modname, fbt_provide_module_cb, &fka);
300 mc->fbt_provided = true;
301 }
302
303 static void
fbt_module_dtor(void * arg)304 fbt_module_dtor(void *arg)
305 {
306 mod_ctf_t *mc = arg;
307
308 if (mc->ctfalloc)
309 free(mc->ctftab, M_TEMP);
310 kmem_free(mc, sizeof(*mc));
311 }
312 #endif
313
314 static void
fbt_destroy(void * arg,dtrace_id_t id,void * parg)315 fbt_destroy(void *arg, dtrace_id_t id, void *parg)
316 {
317 fbt_probe_t *fbt = parg, *next, *hash, *last;
318 modctl_t *ctl;
319 int ndx;
320
321 do {
322 ctl = fbt->fbtp_ctl;
323
324 #ifdef __FreeBSD__
325 ctl->mod_fbtentries--;
326 #endif
327 #ifdef __NetBSD__
328 mod_ctf_t *mc = module_getspecific(ctl, fbt_module_key);
329 mc->fbt_provided = false;
330 #endif
331
332 /*
333 * Now we need to remove this probe from the fbt_probetab.
334 */
335 ndx = FBT_ADDR2NDX(fbt->fbtp_patchpoint);
336 last = NULL;
337 hash = fbt_probetab[ndx];
338
339 while (hash != fbt) {
340 ASSERT(hash != NULL);
341 last = hash;
342 hash = hash->fbtp_hashnext;
343 }
344
345 if (last != NULL) {
346 last->fbtp_hashnext = fbt->fbtp_hashnext;
347 } else {
348 fbt_probetab[ndx] = fbt->fbtp_hashnext;
349 }
350
351 next = fbt->fbtp_next;
352 kmem_free(fbt, sizeof(*fbt));
353
354 fbt = next;
355 } while (fbt != NULL);
356 }
357
358 static int
fbt_enable(void * arg,dtrace_id_t id,void * parg)359 fbt_enable(void *arg, dtrace_id_t id, void *parg)
360 {
361 fbt_probe_t *fbt = parg;
362 modctl_t *ctl = fbt->fbtp_ctl;
363
364 #ifdef __NetBSD__
365 module_hold(ctl);
366 #else
367 ctl->nenabled++;
368
369 /*
370 * Now check that our modctl has the expected load count. If it
371 * doesn't, this module must have been unloaded and reloaded -- and
372 * we're not going to touch it.
373 */
374 if (ctl->loadcnt != fbt->fbtp_loadcnt) {
375 if (fbt_verbose) {
376 printf("fbt is failing for probe %s "
377 "(module %s reloaded)",
378 fbt->fbtp_name, module_name(ctl));
379 }
380
381 return 0;
382 }
383 #endif
384
385 for (; fbt != NULL; fbt = fbt->fbtp_next)
386 fbt_patch_tracepoint(fbt, fbt->fbtp_patchval);
387 return 0;
388 }
389
390 static void
fbt_disable(void * arg,dtrace_id_t id,void * parg)391 fbt_disable(void *arg, dtrace_id_t id, void *parg)
392 {
393 fbt_probe_t *fbt = parg;
394 modctl_t *ctl = fbt->fbtp_ctl;
395
396 #ifndef __NetBSD__
397 ASSERT(ctl->nenabled > 0);
398 ctl->nenabled--;
399
400 if ((ctl->loadcnt != fbt->fbtp_loadcnt))
401 return;
402 #endif
403
404 for (; fbt != NULL; fbt = fbt->fbtp_next)
405 fbt_patch_tracepoint(fbt, fbt->fbtp_savedval);
406
407 #ifdef __NetBSD__
408 module_rele(ctl);
409 #endif
410 }
411
412 static void
fbt_suspend(void * arg,dtrace_id_t id,void * parg)413 fbt_suspend(void *arg, dtrace_id_t id, void *parg)
414 {
415 fbt_probe_t *fbt = parg;
416 #ifndef __NetBSD__
417 modctl_t *ctl = fbt->fbtp_ctl;
418
419 ASSERT(ctl->nenabled > 0);
420
421 if ((ctl->loadcnt != fbt->fbtp_loadcnt))
422 return;
423 #endif
424
425 for (; fbt != NULL; fbt = fbt->fbtp_next)
426 fbt_patch_tracepoint(fbt, fbt->fbtp_savedval);
427 }
428
429 static void
fbt_resume(void * arg,dtrace_id_t id,void * parg)430 fbt_resume(void *arg, dtrace_id_t id, void *parg)
431 {
432 fbt_probe_t *fbt = parg;
433 #ifndef __NetBSD__
434 modctl_t *ctl = fbt->fbtp_ctl;
435
436 ASSERT(ctl->nenabled > 0);
437
438 if ((ctl->loadcnt != fbt->fbtp_loadcnt))
439 return;
440 #endif
441
442 for (; fbt != NULL; fbt = fbt->fbtp_next)
443 fbt_patch_tracepoint(fbt, fbt->fbtp_patchval);
444 }
445
446 static int
fbt_ctfoff_init(modctl_t * mod,mod_ctf_t * mc)447 fbt_ctfoff_init(modctl_t *mod, mod_ctf_t *mc)
448 {
449 const Elf_Sym *symp = mc->symtab;
450 const ctf_header_t *hp = (const ctf_header_t *) mc->ctftab;
451 const uint8_t *ctfdata = mc->ctftab + sizeof(ctf_header_t);
452 int i;
453 uint32_t *ctfoff;
454 uint32_t objtoff = hp->cth_objtoff;
455 uint32_t funcoff = hp->cth_funcoff;
456 ushort_t info;
457 ushort_t vlen;
458 int nsyms = (mc->nmap != NULL) ? mc->nmapsize : mc->nsym;
459
460 /* Sanity check. */
461 if (hp->cth_magic != CTF_MAGIC) {
462 printf("Bad magic value in CTF data of '%s'\n",
463 module_name(mod));
464 return (EINVAL);
465 }
466
467 if (mc->symtab == NULL) {
468 printf("No symbol table in '%s'\n", module_name(mod));
469 return (EINVAL);
470 }
471
472 ctfoff = malloc(sizeof(uint32_t) * nsyms, M_FBT, M_WAITOK);
473 mc->ctfoffp = ctfoff;
474
475 for (i = 0; i < nsyms; i++, ctfoff++, symp++) {
476 if (mc->nmap != NULL) {
477 if (mc->nmap[i] == 0) {
478 printf("%s.%d: Error! Got zero nmap!\n",
479 __func__, __LINE__);
480 continue;
481 }
482
483 /*
484 * CTF expects the unsorted symbol ordering,
485 * so map it from that to the current sorted
486 * symbol table.
487 * ctfoff[new-ind] = oldind symbol info.
488 */
489
490 /* map old index to new symbol table */
491 symp = &mc->symtab[mc->nmap[i] - 1];
492
493 /* map old index to new ctfoff index */
494 ctfoff = &mc->ctfoffp[mc->nmap[i]-1];
495 }
496
497 /*
498 * Note that due to how kern_ksyms.c adjusts st_name
499 * to be the offset into a virtual combined strtab,
500 * st_name will never be 0 for loaded modules.
501 */
502
503 if (symp->st_name == 0 || symp->st_shndx == SHN_UNDEF) {
504 *ctfoff = 0xffffffff;
505 continue;
506 }
507
508 switch (ELF_ST_TYPE(symp->st_info)) {
509 case STT_OBJECT:
510 if (objtoff >= hp->cth_funcoff ||
511 (symp->st_shndx == SHN_ABS && symp->st_value == 0)) {
512 *ctfoff = 0xffffffff;
513 break;
514 }
515
516 *ctfoff = objtoff;
517 objtoff += sizeof (ushort_t);
518 break;
519
520 case STT_FUNC:
521 if (funcoff >= hp->cth_typeoff) {
522 *ctfoff = 0xffffffff;
523 break;
524 }
525
526 *ctfoff = funcoff;
527
528 info = *((const ushort_t *)(ctfdata + funcoff));
529 vlen = CTF_INFO_VLEN(info);
530
531 /*
532 * If we encounter a zero pad at the end, just skip it.
533 * Otherwise skip over the function and its return type
534 * (+2) and the argument list (vlen).
535 */
536 if (CTF_INFO_KIND(info) == CTF_K_UNKNOWN && vlen == 0)
537 funcoff += sizeof (ushort_t); /* skip pad */
538 else
539 funcoff += sizeof (ushort_t) * (vlen + 2);
540 break;
541
542 default:
543 *ctfoff = 0xffffffff;
544 break;
545 }
546 }
547
548 return (0);
549 }
550
551 static ssize_t
fbt_get_ctt_size(uint8_t version,const ctf_type_t * tp,ssize_t * sizep,ssize_t * incrementp)552 fbt_get_ctt_size(uint8_t version, const ctf_type_t *tp, ssize_t *sizep,
553 ssize_t *incrementp)
554 {
555 ssize_t size, increment;
556
557 if (version > CTF_VERSION_1 &&
558 tp->ctt_size == CTF_LSIZE_SENT) {
559 size = CTF_TYPE_LSIZE(tp);
560 increment = sizeof (ctf_type_t);
561 } else {
562 size = tp->ctt_size;
563 increment = sizeof (ctf_stype_t);
564 }
565
566 if (sizep)
567 *sizep = size;
568 if (incrementp)
569 *incrementp = increment;
570
571 return (size);
572 }
573
574 static int
fbt_typoff_init(mod_ctf_t * mc)575 fbt_typoff_init(mod_ctf_t *mc)
576 {
577 const ctf_header_t *hp = (const ctf_header_t *) mc->ctftab;
578 const ctf_type_t *tbuf;
579 const ctf_type_t *tend;
580 const ctf_type_t *tp;
581 const uint8_t *ctfdata = mc->ctftab + sizeof(ctf_header_t);
582 int ctf_typemax = 0;
583 uint32_t *xp;
584 ulong_t pop[CTF_K_MAX + 1] = { 0 };
585
586
587 /* Sanity check. */
588 if (hp->cth_magic != CTF_MAGIC)
589 return (EINVAL);
590
591 tbuf = (const ctf_type_t *) (ctfdata + hp->cth_typeoff);
592 tend = (const ctf_type_t *) (ctfdata + hp->cth_stroff);
593
594 int child = hp->cth_parname != 0;
595
596 /*
597 * We make two passes through the entire type section. In this first
598 * pass, we count the number of each type and the total number of types.
599 */
600 for (tp = tbuf; tp < tend; ctf_typemax++) {
601 ushort_t kind = CTF_INFO_KIND(tp->ctt_info);
602 ulong_t vlen = CTF_INFO_VLEN(tp->ctt_info);
603 ssize_t size, increment;
604
605 size_t vbytes;
606 uint_t n;
607
608 (void) fbt_get_ctt_size(hp->cth_version, tp, &size, &increment);
609
610 switch (kind) {
611 case CTF_K_INTEGER:
612 case CTF_K_FLOAT:
613 vbytes = sizeof (uint_t);
614 break;
615 case CTF_K_ARRAY:
616 vbytes = sizeof (ctf_array_t);
617 break;
618 case CTF_K_FUNCTION:
619 vbytes = sizeof (ushort_t) * (vlen + (vlen & 1));
620 break;
621 case CTF_K_STRUCT:
622 case CTF_K_UNION:
623 if (size < CTF_LSTRUCT_THRESH) {
624 ctf_member_t *mp = (ctf_member_t *)
625 ((uintptr_t)tp + increment);
626
627 vbytes = sizeof (ctf_member_t) * vlen;
628 for (n = vlen; n != 0; n--, mp++)
629 child |= CTF_TYPE_ISCHILD(mp->ctm_type);
630 } else {
631 ctf_lmember_t *lmp = (ctf_lmember_t *)
632 ((uintptr_t)tp + increment);
633
634 vbytes = sizeof (ctf_lmember_t) * vlen;
635 for (n = vlen; n != 0; n--, lmp++)
636 child |=
637 CTF_TYPE_ISCHILD(lmp->ctlm_type);
638 }
639 break;
640 case CTF_K_ENUM:
641 vbytes = sizeof (ctf_enum_t) * vlen;
642 break;
643 case CTF_K_FORWARD:
644 /*
645 * For forward declarations, ctt_type is the CTF_K_*
646 * kind for the tag, so bump that population count too.
647 * If ctt_type is unknown, treat the tag as a struct.
648 */
649 if (tp->ctt_type == CTF_K_UNKNOWN ||
650 tp->ctt_type >= CTF_K_MAX)
651 pop[CTF_K_STRUCT]++;
652 else
653 pop[tp->ctt_type]++;
654 /*FALLTHRU*/
655 case CTF_K_UNKNOWN:
656 vbytes = 0;
657 break;
658 case CTF_K_POINTER:
659 case CTF_K_TYPEDEF:
660 case CTF_K_VOLATILE:
661 case CTF_K_CONST:
662 case CTF_K_RESTRICT:
663 child |= CTF_TYPE_ISCHILD(tp->ctt_type);
664 vbytes = 0;
665 break;
666 default:
667 printf("%s(%d): detected invalid CTF kind -- %u\n",
668 __func__, __LINE__, kind);
669 return (EIO);
670 }
671 tp = (ctf_type_t *)((uintptr_t)tp + increment + vbytes);
672 pop[kind]++;
673 }
674
675 /* account for a sentinel value below */
676 ctf_typemax++;
677 mc->typlen = ctf_typemax;
678
679 xp = malloc(sizeof(uint32_t) * ctf_typemax, M_FBT, M_ZERO | M_WAITOK);
680
681 mc->typoffp = xp;
682
683 /* type id 0 is used as a sentinel value */
684 *xp++ = 0;
685
686 /*
687 * In the second pass, fill in the type offset.
688 */
689 for (tp = tbuf; tp < tend; xp++) {
690 ushort_t kind = CTF_INFO_KIND(tp->ctt_info);
691 ulong_t vlen = CTF_INFO_VLEN(tp->ctt_info);
692 ssize_t size, increment;
693
694 size_t vbytes;
695 uint_t n;
696
697 (void) fbt_get_ctt_size(hp->cth_version, tp, &size, &increment);
698
699 switch (kind) {
700 case CTF_K_INTEGER:
701 case CTF_K_FLOAT:
702 vbytes = sizeof (uint_t);
703 break;
704 case CTF_K_ARRAY:
705 vbytes = sizeof (ctf_array_t);
706 break;
707 case CTF_K_FUNCTION:
708 vbytes = sizeof (ushort_t) * (vlen + (vlen & 1));
709 break;
710 case CTF_K_STRUCT:
711 case CTF_K_UNION:
712 if (size < CTF_LSTRUCT_THRESH) {
713 ctf_member_t *mp = (ctf_member_t *)
714 ((uintptr_t)tp + increment);
715
716 vbytes = sizeof (ctf_member_t) * vlen;
717 for (n = vlen; n != 0; n--, mp++)
718 child |= CTF_TYPE_ISCHILD(mp->ctm_type);
719 } else {
720 ctf_lmember_t *lmp = (ctf_lmember_t *)
721 ((uintptr_t)tp + increment);
722
723 vbytes = sizeof (ctf_lmember_t) * vlen;
724 for (n = vlen; n != 0; n--, lmp++)
725 child |=
726 CTF_TYPE_ISCHILD(lmp->ctlm_type);
727 }
728 break;
729 case CTF_K_ENUM:
730 vbytes = sizeof (ctf_enum_t) * vlen;
731 break;
732 case CTF_K_FORWARD:
733 case CTF_K_UNKNOWN:
734 vbytes = 0;
735 break;
736 case CTF_K_POINTER:
737 case CTF_K_TYPEDEF:
738 case CTF_K_VOLATILE:
739 case CTF_K_CONST:
740 case CTF_K_RESTRICT:
741 vbytes = 0;
742 break;
743 default:
744 printf("%s(%d): detected invalid CTF kind -- %u\n", __func__, __LINE__, kind);
745 return (EIO);
746 }
747 *xp = (uint32_t)((uintptr_t) tp - (uintptr_t) ctfdata);
748 tp = (ctf_type_t *)((uintptr_t)tp + increment + vbytes);
749 }
750
751 return (0);
752 }
753
754 /*
755 * CTF Declaration Stack
756 *
757 * In order to implement ctf_type_name(), we must convert a type graph back
758 * into a C type declaration. Unfortunately, a type graph represents a storage
759 * class ordering of the type whereas a type declaration must obey the C rules
760 * for operator precedence, and the two orderings are frequently in conflict.
761 * For example, consider these CTF type graphs and their C declarations:
762 *
763 * CTF_K_POINTER -> CTF_K_FUNCTION -> CTF_K_INTEGER : int (*)()
764 * CTF_K_POINTER -> CTF_K_ARRAY -> CTF_K_INTEGER : int (*)[]
765 *
766 * In each case, parentheses are used to raise operator * to higher lexical
767 * precedence, so the string form of the C declaration cannot be constructed by
768 * walking the type graph links and forming the string from left to right.
769 *
770 * The functions in this file build a set of stacks from the type graph nodes
771 * corresponding to the C operator precedence levels in the appropriate order.
772 * The code in ctf_type_name() can then iterate over the levels and nodes in
773 * lexical precedence order and construct the final C declaration string.
774 */
775 typedef struct ctf_list {
776 struct ctf_list *l_prev; /* previous pointer or tail pointer */
777 struct ctf_list *l_next; /* next pointer or head pointer */
778 } ctf_list_t;
779
780 #define ctf_list_prev(elem) ((void *)(((ctf_list_t *)(elem))->l_prev))
781 #define ctf_list_next(elem) ((void *)(((ctf_list_t *)(elem))->l_next))
782
783 typedef enum {
784 CTF_PREC_BASE,
785 CTF_PREC_POINTER,
786 CTF_PREC_ARRAY,
787 CTF_PREC_FUNCTION,
788 CTF_PREC_MAX
789 } ctf_decl_prec_t;
790
791 typedef struct ctf_decl_node {
792 ctf_list_t cd_list; /* linked list pointers */
793 ctf_id_t cd_type; /* type identifier */
794 uint_t cd_kind; /* type kind */
795 uint_t cd_n; /* type dimension if array */
796 } ctf_decl_node_t;
797
798 typedef struct ctf_decl {
799 ctf_list_t cd_nodes[CTF_PREC_MAX]; /* declaration node stacks */
800 int cd_order[CTF_PREC_MAX]; /* storage order of decls */
801 ctf_decl_prec_t cd_qualp; /* qualifier precision */
802 ctf_decl_prec_t cd_ordp; /* ordered precision */
803 char *cd_buf; /* buffer for output */
804 char *cd_ptr; /* buffer location */
805 char *cd_end; /* buffer limit */
806 size_t cd_len; /* buffer space required */
807 int cd_err; /* saved error value */
808 } ctf_decl_t;
809
810 /*
811 * Simple doubly-linked list append routine. This implementation assumes that
812 * each list element contains an embedded ctf_list_t as the first member.
813 * An additional ctf_list_t is used to store the head (l_next) and tail
814 * (l_prev) pointers. The current head and tail list elements have their
815 * previous and next pointers set to NULL, respectively.
816 */
817 static void
ctf_list_append(ctf_list_t * lp,void * new)818 ctf_list_append(ctf_list_t *lp, void *new)
819 {
820 ctf_list_t *p = lp->l_prev; /* p = tail list element */
821 ctf_list_t *q = new; /* q = new list element */
822
823 lp->l_prev = q;
824 q->l_prev = p;
825 q->l_next = NULL;
826
827 if (p != NULL)
828 p->l_next = q;
829 else
830 lp->l_next = q;
831 }
832
833 /*
834 * Prepend the specified existing element to the given ctf_list_t. The
835 * existing pointer should be pointing at a struct with embedded ctf_list_t.
836 */
837 static void
ctf_list_prepend(ctf_list_t * lp,void * new)838 ctf_list_prepend(ctf_list_t *lp, void *new)
839 {
840 ctf_list_t *p = new; /* p = new list element */
841 ctf_list_t *q = lp->l_next; /* q = head list element */
842
843 lp->l_next = p;
844 p->l_prev = NULL;
845 p->l_next = q;
846
847 if (q != NULL)
848 q->l_prev = p;
849 else
850 lp->l_prev = p;
851 }
852
853 static void
ctf_decl_init(ctf_decl_t * cd,char * buf,size_t len)854 ctf_decl_init(ctf_decl_t *cd, char *buf, size_t len)
855 {
856 int i;
857
858 bzero(cd, sizeof (ctf_decl_t));
859
860 for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++)
861 cd->cd_order[i] = CTF_PREC_BASE - 1;
862
863 cd->cd_qualp = CTF_PREC_BASE;
864 cd->cd_ordp = CTF_PREC_BASE;
865
866 cd->cd_buf = buf;
867 cd->cd_ptr = buf;
868 cd->cd_end = buf + len;
869 }
870
871 static void
ctf_decl_fini(ctf_decl_t * cd)872 ctf_decl_fini(ctf_decl_t *cd)
873 {
874 ctf_decl_node_t *cdp, *ndp;
875 int i;
876
877 for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++) {
878 for (cdp = ctf_list_next(&cd->cd_nodes[i]);
879 cdp != NULL; cdp = ndp) {
880 ndp = ctf_list_next(cdp);
881 free(cdp, M_FBT);
882 }
883 }
884 }
885
886 static const ctf_type_t *
ctf_lookup_by_id(mod_ctf_t * mc,ctf_id_t type)887 ctf_lookup_by_id(mod_ctf_t *mc, ctf_id_t type)
888 {
889 const ctf_type_t *tp;
890 uint32_t offset;
891 uint32_t *typoff = mc->typoffp;
892
893 if (type >= mc->typlen) {
894 printf("%s(%d): type %d exceeds max %ld\n",__func__,__LINE__,(int) type,mc->typlen);
895 return(NULL);
896 }
897
898 /* Check if the type isn't cross-referenced. */
899 if ((offset = typoff[type]) == 0) {
900 printf("%s(%d): type %d isn't cross referenced\n",__func__,__LINE__, (int) type);
901 return(NULL);
902 }
903
904 tp = (const ctf_type_t *)(mc->ctftab + offset + sizeof(ctf_header_t));
905
906 return (tp);
907 }
908
909 static void
fbt_array_info(mod_ctf_t * mc,ctf_id_t type,ctf_arinfo_t * arp)910 fbt_array_info(mod_ctf_t *mc, ctf_id_t type, ctf_arinfo_t *arp)
911 {
912 const ctf_header_t *hp = (const ctf_header_t *) mc->ctftab;
913 const ctf_type_t *tp;
914 const ctf_array_t *ap;
915 ssize_t increment;
916
917 bzero(arp, sizeof(*arp));
918
919 if ((tp = ctf_lookup_by_id(mc, type)) == NULL)
920 return;
921
922 if (CTF_INFO_KIND(tp->ctt_info) != CTF_K_ARRAY)
923 return;
924
925 (void) fbt_get_ctt_size(hp->cth_version, tp, NULL, &increment);
926
927 ap = (const ctf_array_t *)((uintptr_t)tp + increment);
928 arp->ctr_contents = ap->cta_contents;
929 arp->ctr_index = ap->cta_index;
930 arp->ctr_nelems = ap->cta_nelems;
931 }
932
933 static const char *
ctf_strptr(mod_ctf_t * mc,int name)934 ctf_strptr(mod_ctf_t *mc, int name)
935 {
936 const ctf_header_t *hp = (const ctf_header_t *) mc->ctftab;;
937 const char *strp = "";
938
939 if (name < 0 || name >= hp->cth_strlen)
940 return(strp);
941
942 strp = (const char *)(mc->ctftab + hp->cth_stroff + name + sizeof(ctf_header_t));
943
944 return (strp);
945 }
946
947 static void
ctf_decl_push(ctf_decl_t * cd,mod_ctf_t * mc,ctf_id_t type)948 ctf_decl_push(ctf_decl_t *cd, mod_ctf_t *mc, ctf_id_t type)
949 {
950 ctf_decl_node_t *cdp;
951 ctf_decl_prec_t prec;
952 uint_t kind, n = 1;
953 int is_qual = 0;
954
955 const ctf_type_t *tp;
956 ctf_arinfo_t ar;
957
958 if ((tp = ctf_lookup_by_id(mc, type)) == NULL) {
959 cd->cd_err = ENOENT;
960 return;
961 }
962
963 switch (kind = CTF_INFO_KIND(tp->ctt_info)) {
964 case CTF_K_ARRAY:
965 fbt_array_info(mc, type, &ar);
966 ctf_decl_push(cd, mc, ar.ctr_contents);
967 n = ar.ctr_nelems;
968 prec = CTF_PREC_ARRAY;
969 break;
970
971 case CTF_K_TYPEDEF:
972 if (ctf_strptr(mc, tp->ctt_name)[0] == '\0') {
973 ctf_decl_push(cd, mc, tp->ctt_type);
974 return;
975 }
976 prec = CTF_PREC_BASE;
977 break;
978
979 case CTF_K_FUNCTION:
980 ctf_decl_push(cd, mc, tp->ctt_type);
981 prec = CTF_PREC_FUNCTION;
982 break;
983
984 case CTF_K_POINTER:
985 ctf_decl_push(cd, mc, tp->ctt_type);
986 prec = CTF_PREC_POINTER;
987 break;
988
989 case CTF_K_VOLATILE:
990 case CTF_K_CONST:
991 case CTF_K_RESTRICT:
992 ctf_decl_push(cd, mc, tp->ctt_type);
993 prec = cd->cd_qualp;
994 is_qual++;
995 break;
996
997 default:
998 prec = CTF_PREC_BASE;
999 }
1000
1001 cdp = malloc(sizeof(*cdp), M_FBT, M_WAITOK);
1002 cdp->cd_type = type;
1003 cdp->cd_kind = kind;
1004 cdp->cd_n = n;
1005
1006 if (ctf_list_next(&cd->cd_nodes[prec]) == NULL)
1007 cd->cd_order[prec] = cd->cd_ordp++;
1008
1009 /*
1010 * Reset cd_qualp to the highest precedence level that we've seen so
1011 * far that can be qualified (CTF_PREC_BASE or CTF_PREC_POINTER).
1012 */
1013 if (prec > cd->cd_qualp && prec < CTF_PREC_ARRAY)
1014 cd->cd_qualp = prec;
1015
1016 /*
1017 * C array declarators are ordered inside out so prepend them. Also by
1018 * convention qualifiers of base types precede the type specifier (e.g.
1019 * const int vs. int const) even though the two forms are equivalent.
1020 */
1021 if (kind == CTF_K_ARRAY || (is_qual && prec == CTF_PREC_BASE))
1022 ctf_list_prepend(&cd->cd_nodes[prec], cdp);
1023 else
1024 ctf_list_append(&cd->cd_nodes[prec], cdp);
1025 }
1026
1027 static void
ctf_decl_sprintf(ctf_decl_t * cd,const char * format,...)1028 ctf_decl_sprintf(ctf_decl_t *cd, const char *format, ...)
1029 {
1030 size_t len = (size_t)(cd->cd_end - cd->cd_ptr);
1031 va_list ap;
1032 size_t n;
1033
1034 va_start(ap, format);
1035 n = vsnprintf(cd->cd_ptr, len, format, ap);
1036 va_end(ap);
1037
1038 cd->cd_ptr += MIN(n, len);
1039 cd->cd_len += n;
1040 }
1041
1042 static ssize_t
fbt_type_name(mod_ctf_t * mc,ctf_id_t type,char * buf,size_t len)1043 fbt_type_name(mod_ctf_t *mc, ctf_id_t type, char *buf, size_t len)
1044 {
1045 ctf_decl_t cd;
1046 ctf_decl_node_t *cdp;
1047 ctf_decl_prec_t prec, lp, rp;
1048 int ptr, arr;
1049 uint_t k;
1050
1051 if (mc == NULL && type == CTF_ERR)
1052 return (-1); /* simplify caller code by permitting CTF_ERR */
1053
1054 ctf_decl_init(&cd, buf, len);
1055 ctf_decl_push(&cd, mc, type);
1056
1057 if (cd.cd_err != 0) {
1058 ctf_decl_fini(&cd);
1059 return (-1);
1060 }
1061
1062 /*
1063 * If the type graph's order conflicts with lexical precedence order
1064 * for pointers or arrays, then we need to surround the declarations at
1065 * the corresponding lexical precedence with parentheses. This can
1066 * result in either a parenthesized pointer (*) as in int (*)() or
1067 * int (*)[], or in a parenthesized pointer and array as in int (*[])().
1068 */
1069 ptr = cd.cd_order[CTF_PREC_POINTER] > CTF_PREC_POINTER;
1070 arr = cd.cd_order[CTF_PREC_ARRAY] > CTF_PREC_ARRAY;
1071
1072 rp = arr ? CTF_PREC_ARRAY : ptr ? CTF_PREC_POINTER : -1;
1073 lp = ptr ? CTF_PREC_POINTER : arr ? CTF_PREC_ARRAY : -1;
1074
1075 k = CTF_K_POINTER; /* avoid leading whitespace (see below) */
1076
1077 for (prec = CTF_PREC_BASE; prec < CTF_PREC_MAX; prec++) {
1078 for (cdp = ctf_list_next(&cd.cd_nodes[prec]);
1079 cdp != NULL; cdp = ctf_list_next(cdp)) {
1080
1081 const ctf_type_t *tp =
1082 ctf_lookup_by_id(mc, cdp->cd_type);
1083 const char *name = ctf_strptr(mc, tp->ctt_name);
1084
1085 if (k != CTF_K_POINTER && k != CTF_K_ARRAY)
1086 ctf_decl_sprintf(&cd, " ");
1087
1088 if (lp == prec) {
1089 ctf_decl_sprintf(&cd, "(");
1090 lp = -1;
1091 }
1092
1093 switch (cdp->cd_kind) {
1094 case CTF_K_INTEGER:
1095 case CTF_K_FLOAT:
1096 case CTF_K_TYPEDEF:
1097 ctf_decl_sprintf(&cd, "%s", name);
1098 break;
1099 case CTF_K_POINTER:
1100 ctf_decl_sprintf(&cd, "*");
1101 break;
1102 case CTF_K_ARRAY:
1103 ctf_decl_sprintf(&cd, "[%u]", cdp->cd_n);
1104 break;
1105 case CTF_K_FUNCTION:
1106 ctf_decl_sprintf(&cd, "()");
1107 break;
1108 case CTF_K_STRUCT:
1109 case CTF_K_FORWARD:
1110 ctf_decl_sprintf(&cd, "struct %s", name);
1111 break;
1112 case CTF_K_UNION:
1113 ctf_decl_sprintf(&cd, "union %s", name);
1114 break;
1115 case CTF_K_ENUM:
1116 ctf_decl_sprintf(&cd, "enum %s", name);
1117 break;
1118 case CTF_K_VOLATILE:
1119 ctf_decl_sprintf(&cd, "volatile");
1120 break;
1121 case CTF_K_CONST:
1122 ctf_decl_sprintf(&cd, "const");
1123 break;
1124 case CTF_K_RESTRICT:
1125 ctf_decl_sprintf(&cd, "restrict");
1126 break;
1127 }
1128
1129 k = cdp->cd_kind;
1130 }
1131
1132 if (rp == prec)
1133 ctf_decl_sprintf(&cd, ")");
1134 }
1135
1136 ctf_decl_fini(&cd);
1137 return (cd.cd_len);
1138 }
1139
1140 static void
fbt_getargdesc(void * arg __unused,dtrace_id_t id __unused,void * parg,dtrace_argdesc_t * desc)1141 fbt_getargdesc(void *arg __unused, dtrace_id_t id __unused, void *parg, dtrace_argdesc_t *desc)
1142 {
1143 const ushort_t *dp;
1144 fbt_probe_t *fbt = parg;
1145 mod_ctf_t *mc;
1146 modctl_t *ctl = fbt->fbtp_ctl;
1147 int ndx = desc->dtargd_ndx;
1148 int symindx = fbt->fbtp_symindx;
1149 uint32_t *ctfoff;
1150 uint32_t offset;
1151 ushort_t info, kind, n;
1152 int nsyms;
1153
1154 if (fbt->fbtp_roffset != 0 && desc->dtargd_ndx == 0) {
1155 (void) strcpy(desc->dtargd_native, "int");
1156 return;
1157 }
1158
1159 desc->dtargd_ndx = DTRACE_ARGNONE;
1160
1161 /* Get a pointer to the CTF data and its length. */
1162 if (mod_ctf_get(ctl, &mc) != 0) {
1163 static int report = 0;
1164 if (report < 1) {
1165 report++;
1166 printf("FBT: Error no CTF section found in module \"%s\"\n",
1167 module_name(ctl));
1168 }
1169 /* No CTF data? Something wrong? *shrug* */
1170 return;
1171 }
1172
1173 nsyms = (mc->nmap != NULL) ? mc->nmapsize : mc->nsym;
1174
1175 /* Check if this module hasn't been initialised yet. */
1176 if (mc->ctfoffp == NULL) {
1177 /*
1178 * Initialise the CTF object and function symindx to
1179 * byte offset array.
1180 */
1181 if (fbt_ctfoff_init(ctl, mc) != 0)
1182 return;
1183
1184 /* Initialise the CTF type to byte offset array. */
1185 if (fbt_typoff_init(mc) != 0)
1186 return;
1187 }
1188
1189 ctfoff = mc->ctfoffp;
1190
1191 if (ctfoff == NULL || mc->typoffp == NULL) {
1192 return;
1193 }
1194
1195 /* Check if the symbol index is out of range. */
1196 if (symindx >= nsyms)
1197 return;
1198
1199 /* Check if the symbol isn't cross-referenced. */
1200 if ((offset = ctfoff[symindx]) == 0xffffffff)
1201 return;
1202
1203 dp = (const ushort_t *)(mc->ctftab + offset + sizeof(ctf_header_t));
1204
1205 info = *dp++;
1206 kind = CTF_INFO_KIND(info);
1207 n = CTF_INFO_VLEN(info);
1208
1209 if (kind == CTF_K_UNKNOWN && n == 0) {
1210 printf("%s(%d): Unknown function %s!\n",__func__,__LINE__,
1211 fbt->fbtp_name);
1212 return;
1213 }
1214
1215 if (kind != CTF_K_FUNCTION) {
1216 printf("%s(%d): Expected a function %s!\n",__func__,__LINE__,
1217 fbt->fbtp_name);
1218 return;
1219 }
1220
1221 if (fbt->fbtp_roffset != 0) {
1222 /* Only return type is available for args[1] in return probe. */
1223 if (ndx > 1)
1224 return;
1225 ASSERT(ndx == 1);
1226 } else {
1227 /* Check if the requested argument doesn't exist. */
1228 if (ndx >= n)
1229 return;
1230
1231 /* Skip the return type and arguments up to the one requested. */
1232 dp += ndx + 1;
1233 }
1234
1235 if (fbt_type_name(mc, *dp, desc->dtargd_native, sizeof(desc->dtargd_native)) > 0)
1236 desc->dtargd_ndx = ndx;
1237
1238 return;
1239 }
1240
1241 #ifdef __FreeBSD__
1242 static int
fbt_linker_file_cb(linker_file_t lf,void * arg)1243 fbt_linker_file_cb(linker_file_t lf, void *arg)
1244 {
1245
1246 fbt_provide_module(arg, lf);
1247
1248 return (0);
1249 }
1250 #endif
1251
1252 static void
fbt_load(void)1253 fbt_load(void)
1254 {
1255
1256 #ifdef __FreeBSD__
1257 /* Create the /dev/dtrace/fbt entry. */
1258 fbt_cdev = make_dev(&fbt_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
1259 "dtrace/fbt");
1260 #endif
1261 #ifdef __NetBSD__
1262 (void) module_specific_key_create(&fbt_module_key, fbt_module_dtor);
1263 #endif
1264
1265 /* Default the probe table size if not specified. */
1266 if (fbt_probetab_size == 0)
1267 fbt_probetab_size = FBT_PROBETAB_SIZE;
1268
1269 /* Choose the hash mask for the probe table. */
1270 fbt_probetab_mask = fbt_probetab_size - 1;
1271
1272 /* Allocate memory for the probe table. */
1273 fbt_probetab =
1274 malloc(fbt_probetab_size * sizeof (fbt_probe_t *), M_FBT, M_WAITOK | M_ZERO);
1275
1276 dtrace_doubletrap_func = fbt_doubletrap;
1277 dtrace_invop_add(fbt_invop);
1278
1279 if (dtrace_register("fbt", &fbt_attr, DTRACE_PRIV_USER,
1280 NULL, &fbt_pops, NULL, &fbt_id) != 0)
1281 return;
1282 }
1283
1284
1285 static int
fbt_unload(void)1286 fbt_unload(void)
1287 {
1288 int error = 0;
1289
1290 /* De-register the invalid opcode handler. */
1291 dtrace_invop_remove(fbt_invop);
1292
1293 dtrace_doubletrap_func = NULL;
1294
1295 /* De-register this DTrace provider. */
1296 if ((error = dtrace_unregister(fbt_id)) != 0)
1297 return (error);
1298
1299 /* Free the probe table. */
1300 free(fbt_probetab, M_FBT);
1301 fbt_probetab = NULL;
1302 fbt_probetab_mask = 0;
1303
1304 #ifdef __FreeBSD__
1305 destroy_dev(fbt_cdev);
1306 #endif
1307 #ifdef __NetBSD__
1308 (void) module_specific_key_delete(fbt_module_key);
1309 #endif
1310 return (error);
1311 }
1312
1313
1314 static int
dtrace_fbt_modcmd(modcmd_t cmd,void * data)1315 dtrace_fbt_modcmd(modcmd_t cmd, void *data)
1316 {
1317 int bmajor = -1, cmajor = 352;
1318 int error;
1319
1320 switch (cmd) {
1321 case MODULE_CMD_INIT:
1322 fbt_load();
1323 return devsw_attach("fbt", NULL, &bmajor,
1324 &fbt_cdevsw, &cmajor);
1325 case MODULE_CMD_FINI:
1326 error = fbt_unload();
1327 if (error != 0)
1328 return error;
1329 devsw_detach(NULL, &fbt_cdevsw);
1330 return 0;
1331 case MODULE_CMD_AUTOUNLOAD:
1332 return EBUSY;
1333 default:
1334 return ENOTTY;
1335 }
1336 }
1337
1338 static int
fbt_open(dev_t dev,int flags,int mode,struct lwp * l)1339 fbt_open(dev_t dev, int flags, int mode, struct lwp *l)
1340 {
1341 return (0);
1342 }
1343
1344 #ifdef __FreeBSD__
1345 SYSINIT(fbt_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, fbt_load, NULL);
1346 SYSUNINIT(fbt_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, fbt_unload, NULL);
1347
1348 DEV_MODULE(fbt, fbt_modevent, NULL);
1349 MODULE_VERSION(fbt, 1);
1350 MODULE_DEPEND(fbt, dtrace, 1, 1, 1);
1351 MODULE_DEPEND(fbt, opensolaris, 1, 1, 1);
1352 #endif
1353 #ifdef __NetBSD__
1354 MODULE(MODULE_CLASS_MISC, dtrace_fbt, "dtrace,zlib");
1355 #endif
1356