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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27 #include <sys/modctl.h>
28 #include <sys/dtrace.h>
29 #include <sys/kobj.h>
30 #include <sys/stat.h>
31 #include <sys/ddi.h>
32 #include <sys/sunddi.h>
33 #include <sys/conf.h>
34
35 #define FBT_PUSHL_EBP 0x55
36 #define FBT_MOVL_ESP_EBP0_V0 0x8b
37 #define FBT_MOVL_ESP_EBP1_V0 0xec
38 #define FBT_MOVL_ESP_EBP0_V1 0x89
39 #define FBT_MOVL_ESP_EBP1_V1 0xe5
40 #define FBT_REX_RSP_RBP 0x48
41
42 #define FBT_POPL_EBP 0x5d
43 #define FBT_RET 0xc3
44 #define FBT_RET_IMM16 0xc2
45 #define FBT_LEAVE 0xc9
46
47 #define FBT_PATCHVAL 0xcc
48
49 #define FBT_ENTRY "entry"
50 #define FBT_RETURN "return"
51 #define FBT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & fbt_probetab_mask)
52 #define FBT_PROBETAB_SIZE 0x8000 /* 32k entries -- 128K total */
53
54 typedef struct fbt_probe {
55 struct fbt_probe *fbtp_hashnext;
56 uint8_t *fbtp_patchpoint;
57 int8_t fbtp_rval;
58 uint8_t fbtp_patchval;
59 uint8_t fbtp_savedval;
60 uintptr_t fbtp_roffset;
61 dtrace_id_t fbtp_id;
62 char *fbtp_name;
63 struct modctl *fbtp_ctl;
64 int fbtp_loadcnt;
65 int fbtp_symndx;
66 int fbtp_primary;
67 struct fbt_probe *fbtp_next;
68 } fbt_probe_t;
69
70 static dev_info_t *fbt_devi;
71 static dtrace_provider_id_t fbt_id;
72 static fbt_probe_t **fbt_probetab;
73 static int fbt_probetab_size;
74 static int fbt_probetab_mask;
75 static int fbt_verbose = 0;
76
77 static int
fbt_invop(uintptr_t addr,uintptr_t * stack,uintptr_t rval)78 fbt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t rval)
79 {
80 uintptr_t stack0, stack1, stack2, stack3, stack4;
81 fbt_probe_t *fbt = fbt_probetab[FBT_ADDR2NDX(addr)];
82
83 for (; fbt != NULL; fbt = fbt->fbtp_hashnext) {
84 if ((uintptr_t)fbt->fbtp_patchpoint == addr) {
85 if (fbt->fbtp_roffset == 0) {
86 int i = 0;
87 /*
88 * When accessing the arguments on the stack,
89 * we must protect against accessing beyond
90 * the stack. We can safely set NOFAULT here
91 * -- we know that interrupts are already
92 * disabled.
93 */
94 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
95 CPU->cpu_dtrace_caller = stack[i++];
96 /*
97 * On amd64, stack[0] contains the dereferenced
98 * stack pointer, stack[1] contains savfp,
99 * stack[2] contains savpc. We want to step
100 * over these entries.
101 */
102 i += 2;
103 stack0 = stack[i++];
104 stack1 = stack[i++];
105 stack2 = stack[i++];
106 stack3 = stack[i++];
107 stack4 = stack[i++];
108 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT |
109 CPU_DTRACE_BADADDR);
110
111 dtrace_probe(fbt->fbtp_id, stack0, stack1,
112 stack2, stack3, stack4);
113
114 CPU->cpu_dtrace_caller = 0;
115 } else {
116 /*
117 * On amd64, we instrument the ret, not the
118 * leave. We therefore need to set the caller
119 * to assure that the top frame of a stack()
120 * action is correct.
121 */
122 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
123 CPU->cpu_dtrace_caller = stack[0];
124 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT |
125 CPU_DTRACE_BADADDR);
126
127 dtrace_probe(fbt->fbtp_id, fbt->fbtp_roffset,
128 rval, 0, 0, 0);
129 CPU->cpu_dtrace_caller = 0;
130 }
131
132 return (fbt->fbtp_rval);
133 }
134 }
135
136 return (0);
137 }
138
139 /*ARGSUSED*/
140 static void
fbt_provide_module(void * arg,struct modctl * ctl)141 fbt_provide_module(void *arg, struct modctl *ctl)
142 {
143 struct module *mp = ctl->mod_mp;
144 char *str = mp->strings;
145 int nsyms = mp->nsyms;
146 Shdr *symhdr = mp->symhdr;
147 char *modname = ctl->mod_modname;
148 char *name;
149 fbt_probe_t *fbt, *retfbt;
150 size_t symsize;
151 int i, size;
152
153 /*
154 * Employees of dtrace and their families are ineligible. Void
155 * where prohibited.
156 */
157 if (strcmp(modname, "dtrace") == 0)
158 return;
159
160 if (ctl->mod_requisites != NULL) {
161 struct modctl_list *list;
162
163 list = (struct modctl_list *)ctl->mod_requisites;
164
165 for (; list != NULL; list = list->modl_next) {
166 if (strcmp(list->modl_modp->mod_modname, "dtrace") == 0)
167 return;
168 }
169 }
170
171 /*
172 * KMDB is ineligible for instrumentation -- it may execute in
173 * any context, including probe context.
174 */
175 if (strcmp(modname, "kmdbmod") == 0)
176 return;
177
178 if (str == NULL || symhdr == NULL || symhdr->sh_addr == 0) {
179 /*
180 * If this module doesn't (yet) have its string or symbol
181 * table allocated, clear out.
182 */
183 return;
184 }
185
186 symsize = symhdr->sh_entsize;
187
188 if (mp->fbt_nentries) {
189 /*
190 * This module has some FBT entries allocated; we're afraid
191 * to screw with it.
192 */
193 return;
194 }
195
196 for (i = 1; i < nsyms; i++) {
197 uint8_t *instr, *limit;
198 Sym *sym = (Sym *)(symhdr->sh_addr + i * symsize);
199 int j;
200
201 if (ELF_ST_TYPE(sym->st_info) != STT_FUNC)
202 continue;
203
204 /*
205 * Weak symbols are not candidates. This could be made to
206 * work (where weak functions and their underlying function
207 * appear as two disjoint probes), but it's not simple.
208 */
209 if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
210 continue;
211
212 name = str + sym->st_name;
213
214 if (strstr(name, "dtrace_") == name &&
215 strstr(name, "dtrace_safe_") != name) {
216 /*
217 * Anything beginning with "dtrace_" may be called
218 * from probe context unless it explitly indicates
219 * that it won't be called from probe context by
220 * using the prefix "dtrace_safe_".
221 */
222 continue;
223 }
224
225 if (strstr(name, "kdi_") == name ||
226 strstr(name, "_kdi_") != NULL) {
227 /*
228 * Any function name beginning with "kdi_" or
229 * containing the string "_kdi_" is a part of the
230 * kernel debugger interface and may be called in
231 * arbitrary context -- including probe context.
232 */
233 continue;
234 }
235
236 /*
237 * Due to 4524008, _init and _fini may have a bloated st_size.
238 * While this bug was fixed quite some time ago, old drivers
239 * may be lurking. We need to develop a better solution to
240 * this problem, such that correct _init and _fini functions
241 * (the vast majority) may be correctly traced. One solution
242 * may be to scan through the entire symbol table to see if
243 * any symbol overlaps with _init. If none does, set a bit in
244 * the module structure that this module has correct _init and
245 * _fini sizes. This will cause some pain the first time a
246 * module is scanned, but at least it would be O(N) instead of
247 * O(N log N)...
248 */
249 if (strcmp(name, "_init") == 0)
250 continue;
251
252 if (strcmp(name, "_fini") == 0)
253 continue;
254
255 /*
256 * In order to be eligible, the function must begin with the
257 * following sequence:
258 *
259 * pushl %esp
260 * movl %esp, %ebp
261 *
262 * Note that there are two variants of encodings that generate
263 * the movl; we must check for both. For 64-bit, we would
264 * normally insist that a function begin with the following
265 * sequence:
266 *
267 * pushq %rbp
268 * movq %rsp, %rbp
269 *
270 * However, the compiler for 64-bit often splits these two
271 * instructions -- and the first instruction in the function
272 * is often not the pushq. As a result, on 64-bit we look
273 * for any "pushq %rbp" in the function and we instrument
274 * this with a breakpoint instruction.
275 */
276 instr = (uint8_t *)sym->st_value;
277 limit = (uint8_t *)(sym->st_value + sym->st_size);
278
279 while (instr < limit) {
280 if (*instr == FBT_PUSHL_EBP)
281 break;
282
283 if ((size = dtrace_instr_size(instr)) <= 0)
284 break;
285
286 instr += size;
287 }
288
289 if (instr >= limit || *instr != FBT_PUSHL_EBP) {
290 /*
291 * We either don't save the frame pointer in this
292 * function, or we ran into some disassembly
293 * screw-up. Either way, we bail.
294 */
295 continue;
296 }
297
298 fbt = kmem_zalloc(sizeof (fbt_probe_t), KM_SLEEP);
299 fbt->fbtp_name = name;
300 fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
301 name, FBT_ENTRY, 3, fbt);
302 fbt->fbtp_patchpoint = instr;
303 fbt->fbtp_ctl = ctl;
304 fbt->fbtp_loadcnt = ctl->mod_loadcnt;
305 fbt->fbtp_rval = DTRACE_INVOP_PUSHL_EBP;
306 fbt->fbtp_savedval = *instr;
307 fbt->fbtp_patchval = FBT_PATCHVAL;
308
309 fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
310 fbt->fbtp_symndx = i;
311 fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
312
313 mp->fbt_nentries++;
314
315 retfbt = NULL;
316 again:
317 if (instr >= limit)
318 continue;
319
320 /*
321 * If this disassembly fails, then we've likely walked off into
322 * a jump table or some other unsuitable area. Bail out of the
323 * disassembly now.
324 */
325 if ((size = dtrace_instr_size(instr)) <= 0)
326 continue;
327
328 /*
329 * We only instrument "ret" on amd64 -- we don't yet instrument
330 * ret imm16, largely because the compiler doesn't seem to
331 * (yet) emit them in the kernel...
332 */
333 if (*instr != FBT_RET) {
334 instr += size;
335 goto again;
336 }
337
338 /*
339 * We (desperately) want to avoid erroneously instrumenting a
340 * jump table, especially given that our markers are pretty
341 * short: two bytes on x86, and just one byte on amd64. To
342 * determine if we're looking at a true instruction sequence
343 * or an inline jump table that happens to contain the same
344 * byte sequences, we resort to some heuristic sleeze: we
345 * treat this instruction as being contained within a pointer,
346 * and see if that pointer points to within the body of the
347 * function. If it does, we refuse to instrument it.
348 */
349 for (j = 0; j < sizeof (uintptr_t); j++) {
350 uintptr_t check = (uintptr_t)instr - j;
351 uint8_t *ptr;
352
353 if (check < sym->st_value)
354 break;
355
356 if (check + sizeof (uintptr_t) > (uintptr_t)limit)
357 continue;
358
359 ptr = *(uint8_t **)check;
360
361 if (ptr >= (uint8_t *)sym->st_value && ptr < limit) {
362 instr += size;
363 goto again;
364 }
365 }
366
367 /*
368 * We have a winner!
369 */
370 fbt = kmem_zalloc(sizeof (fbt_probe_t), KM_SLEEP);
371 fbt->fbtp_name = name;
372
373 if (retfbt == NULL) {
374 fbt->fbtp_id = dtrace_probe_create(fbt_id, modname,
375 name, FBT_RETURN, 3, fbt);
376 } else {
377 retfbt->fbtp_next = fbt;
378 fbt->fbtp_id = retfbt->fbtp_id;
379 }
380
381 retfbt = fbt;
382 fbt->fbtp_patchpoint = instr;
383 fbt->fbtp_ctl = ctl;
384 fbt->fbtp_loadcnt = ctl->mod_loadcnt;
385
386 ASSERT(*instr == FBT_RET);
387 fbt->fbtp_rval = DTRACE_INVOP_RET;
388 fbt->fbtp_roffset =
389 (uintptr_t)(instr - (uint8_t *)sym->st_value);
390
391 fbt->fbtp_savedval = *instr;
392 fbt->fbtp_patchval = FBT_PATCHVAL;
393 fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)];
394 fbt->fbtp_symndx = i;
395 fbt_probetab[FBT_ADDR2NDX(instr)] = fbt;
396
397 mp->fbt_nentries++;
398
399 instr += size;
400 goto again;
401 }
402 }
403
404 /*ARGSUSED*/
405 static void
fbt_destroy(void * arg,dtrace_id_t id,void * parg)406 fbt_destroy(void *arg, dtrace_id_t id, void *parg)
407 {
408 fbt_probe_t *fbt = parg, *next, *hash, *last;
409 struct modctl *ctl = fbt->fbtp_ctl;
410 int ndx;
411
412 do {
413 if (ctl != NULL && ctl->mod_loadcnt == fbt->fbtp_loadcnt) {
414 if ((ctl->mod_loadcnt == fbt->fbtp_loadcnt &&
415 ctl->mod_loaded)) {
416 ((struct module *)
417 (ctl->mod_mp))->fbt_nentries--;
418 }
419 }
420
421 /*
422 * Now we need to remove this probe from the fbt_probetab.
423 */
424 ndx = FBT_ADDR2NDX(fbt->fbtp_patchpoint);
425 last = NULL;
426 hash = fbt_probetab[ndx];
427
428 while (hash != fbt) {
429 ASSERT(hash != NULL);
430 last = hash;
431 hash = hash->fbtp_hashnext;
432 }
433
434 if (last != NULL) {
435 last->fbtp_hashnext = fbt->fbtp_hashnext;
436 } else {
437 fbt_probetab[ndx] = fbt->fbtp_hashnext;
438 }
439
440 next = fbt->fbtp_next;
441 kmem_free(fbt, sizeof (fbt_probe_t));
442
443 fbt = next;
444 } while (fbt != NULL);
445 }
446
447 /*ARGSUSED*/
448 static int
fbt_enable(void * arg,dtrace_id_t id,void * parg)449 fbt_enable(void *arg, dtrace_id_t id, void *parg)
450 {
451 fbt_probe_t *fbt = parg;
452 struct modctl *ctl = fbt->fbtp_ctl;
453
454 ctl->mod_nenabled++;
455
456 if (!ctl->mod_loaded) {
457 if (fbt_verbose) {
458 cmn_err(CE_NOTE, "fbt is failing for probe %s "
459 "(module %s unloaded)",
460 fbt->fbtp_name, ctl->mod_modname);
461 }
462
463 return (0);
464 }
465
466 /*
467 * Now check that our modctl has the expected load count. If it
468 * doesn't, this module must have been unloaded and reloaded -- and
469 * we're not going to touch it.
470 */
471 if (ctl->mod_loadcnt != fbt->fbtp_loadcnt) {
472 if (fbt_verbose) {
473 cmn_err(CE_NOTE, "fbt is failing for probe %s "
474 "(module %s reloaded)",
475 fbt->fbtp_name, ctl->mod_modname);
476 }
477
478 return (0);
479 }
480
481 for (; fbt != NULL; fbt = fbt->fbtp_next)
482 *fbt->fbtp_patchpoint = fbt->fbtp_patchval;
483
484 return (0);
485 }
486
487 /*ARGSUSED*/
488 static void
fbt_disable(void * arg,dtrace_id_t id,void * parg)489 fbt_disable(void *arg, dtrace_id_t id, void *parg)
490 {
491 fbt_probe_t *fbt = parg;
492 struct modctl *ctl = fbt->fbtp_ctl;
493
494 ASSERT(ctl->mod_nenabled > 0);
495 ctl->mod_nenabled--;
496
497 if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt))
498 return;
499
500 for (; fbt != NULL; fbt = fbt->fbtp_next)
501 *fbt->fbtp_patchpoint = fbt->fbtp_savedval;
502 }
503
504 /*ARGSUSED*/
505 static void
fbt_suspend(void * arg,dtrace_id_t id,void * parg)506 fbt_suspend(void *arg, dtrace_id_t id, void *parg)
507 {
508 fbt_probe_t *fbt = parg;
509 struct modctl *ctl = fbt->fbtp_ctl;
510
511 ASSERT(ctl->mod_nenabled > 0);
512
513 if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt))
514 return;
515
516 for (; fbt != NULL; fbt = fbt->fbtp_next)
517 *fbt->fbtp_patchpoint = fbt->fbtp_savedval;
518 }
519
520 /*ARGSUSED*/
521 static void
fbt_resume(void * arg,dtrace_id_t id,void * parg)522 fbt_resume(void *arg, dtrace_id_t id, void *parg)
523 {
524 fbt_probe_t *fbt = parg;
525 struct modctl *ctl = fbt->fbtp_ctl;
526
527 ASSERT(ctl->mod_nenabled > 0);
528
529 if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt))
530 return;
531
532 for (; fbt != NULL; fbt = fbt->fbtp_next)
533 *fbt->fbtp_patchpoint = fbt->fbtp_patchval;
534 }
535
536 /*ARGSUSED*/
537 static void
fbt_getargdesc(void * arg,dtrace_id_t id,void * parg,dtrace_argdesc_t * desc)538 fbt_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc)
539 {
540 fbt_probe_t *fbt = parg;
541 struct modctl *ctl = fbt->fbtp_ctl;
542 struct module *mp = ctl->mod_mp;
543 ctf_file_t *fp = NULL, *pfp;
544 ctf_funcinfo_t f;
545 int error;
546 ctf_id_t argv[32], type;
547 int argc = sizeof (argv) / sizeof (ctf_id_t);
548 const char *parent;
549
550 if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt))
551 goto err;
552
553 if (fbt->fbtp_roffset != 0 && desc->dtargd_ndx == 0) {
554 (void) strcpy(desc->dtargd_native, "int");
555 return;
556 }
557
558 if ((fp = ctf_modopen(mp, &error)) == NULL) {
559 /*
560 * We have no CTF information for this module -- and therefore
561 * no args[] information.
562 */
563 goto err;
564 }
565
566 /*
567 * If we have a parent container, we must manually import it.
568 */
569 if ((parent = ctf_parent_name(fp)) != NULL) {
570 struct modctl *mp = &modules;
571 struct modctl *mod = NULL;
572
573 /*
574 * We must iterate over all modules to find the module that
575 * is our parent.
576 */
577 do {
578 if (strcmp(mp->mod_modname, parent) == 0) {
579 mod = mp;
580 break;
581 }
582 } while ((mp = mp->mod_next) != &modules);
583
584 if (mod == NULL)
585 goto err;
586
587 if ((pfp = ctf_modopen(mod->mod_mp, &error)) == NULL) {
588 goto err;
589 }
590
591 if (ctf_import(fp, pfp) != 0) {
592 ctf_close(pfp);
593 goto err;
594 }
595
596 ctf_close(pfp);
597 }
598
599 if (ctf_func_info(fp, fbt->fbtp_symndx, &f) == CTF_ERR)
600 goto err;
601
602 if (fbt->fbtp_roffset != 0) {
603 if (desc->dtargd_ndx > 1)
604 goto err;
605
606 ASSERT(desc->dtargd_ndx == 1);
607 type = f.ctc_return;
608 } else {
609 if (desc->dtargd_ndx + 1 > f.ctc_argc)
610 goto err;
611
612 if (ctf_func_args(fp, fbt->fbtp_symndx, argc, argv) == CTF_ERR)
613 goto err;
614
615 type = argv[desc->dtargd_ndx];
616 }
617
618 if (ctf_type_name(fp, type, desc->dtargd_native,
619 DTRACE_ARGTYPELEN) != NULL) {
620 ctf_close(fp);
621 return;
622 }
623 err:
624 if (fp != NULL)
625 ctf_close(fp);
626
627 desc->dtargd_ndx = DTRACE_ARGNONE;
628 }
629
630 static dtrace_pattr_t fbt_attr = {
631 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
632 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
633 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
634 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
635 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
636 };
637
638 static dtrace_pops_t fbt_pops = {
639 NULL,
640 fbt_provide_module,
641 fbt_enable,
642 fbt_disable,
643 fbt_suspend,
644 fbt_resume,
645 fbt_getargdesc,
646 NULL,
647 NULL,
648 fbt_destroy
649 };
650
651 static void
fbt_cleanup(dev_info_t * devi)652 fbt_cleanup(dev_info_t *devi)
653 {
654 dtrace_invop_remove(fbt_invop);
655 ddi_remove_minor_node(devi, NULL);
656 kmem_free(fbt_probetab, fbt_probetab_size * sizeof (fbt_probe_t *));
657 fbt_probetab = NULL;
658 fbt_probetab_mask = 0;
659 }
660
661 static int
fbt_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)662 fbt_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
663 {
664 switch (cmd) {
665 case DDI_ATTACH:
666 break;
667 case DDI_RESUME:
668 return (DDI_SUCCESS);
669 default:
670 return (DDI_FAILURE);
671 }
672
673 if (fbt_probetab_size == 0)
674 fbt_probetab_size = FBT_PROBETAB_SIZE;
675
676 fbt_probetab_mask = fbt_probetab_size - 1;
677 fbt_probetab =
678 kmem_zalloc(fbt_probetab_size * sizeof (fbt_probe_t *), KM_SLEEP);
679
680 dtrace_invop_add(fbt_invop);
681
682 if (ddi_create_minor_node(devi, "fbt", S_IFCHR, 0,
683 DDI_PSEUDO, 0) == DDI_FAILURE ||
684 dtrace_register("fbt", &fbt_attr, DTRACE_PRIV_KERNEL, NULL,
685 &fbt_pops, NULL, &fbt_id) != 0) {
686 fbt_cleanup(devi);
687 return (DDI_FAILURE);
688 }
689
690 ddi_report_dev(devi);
691 fbt_devi = devi;
692
693 return (DDI_SUCCESS);
694 }
695
696 static int
fbt_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)697 fbt_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
698 {
699 switch (cmd) {
700 case DDI_DETACH:
701 break;
702 case DDI_SUSPEND:
703 return (DDI_SUCCESS);
704 default:
705 return (DDI_FAILURE);
706 }
707
708 if (dtrace_unregister(fbt_id) != 0)
709 return (DDI_FAILURE);
710
711 fbt_cleanup(devi);
712
713 return (DDI_SUCCESS);
714 }
715
716 /*ARGSUSED*/
717 static int
fbt_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)718 fbt_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
719 {
720 int error;
721
722 switch (infocmd) {
723 case DDI_INFO_DEVT2DEVINFO:
724 *result = (void *)fbt_devi;
725 error = DDI_SUCCESS;
726 break;
727 case DDI_INFO_DEVT2INSTANCE:
728 *result = (void *)0;
729 error = DDI_SUCCESS;
730 break;
731 default:
732 error = DDI_FAILURE;
733 }
734 return (error);
735 }
736
737 /*ARGSUSED*/
738 static int
fbt_open(dev_t * devp,int flag,int otyp,cred_t * cred_p)739 fbt_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
740 {
741 return (0);
742 }
743
744 static struct cb_ops fbt_cb_ops = {
745 fbt_open, /* open */
746 nodev, /* close */
747 nulldev, /* strategy */
748 nulldev, /* print */
749 nodev, /* dump */
750 nodev, /* read */
751 nodev, /* write */
752 nodev, /* ioctl */
753 nodev, /* devmap */
754 nodev, /* mmap */
755 nodev, /* segmap */
756 nochpoll, /* poll */
757 ddi_prop_op, /* cb_prop_op */
758 0, /* streamtab */
759 D_NEW | D_MP /* Driver compatibility flag */
760 };
761
762 static struct dev_ops fbt_ops = {
763 DEVO_REV, /* devo_rev */
764 0, /* refcnt */
765 fbt_info, /* get_dev_info */
766 nulldev, /* identify */
767 nulldev, /* probe */
768 fbt_attach, /* attach */
769 fbt_detach, /* detach */
770 nodev, /* reset */
771 &fbt_cb_ops, /* driver operations */
772 NULL, /* bus operations */
773 nodev, /* dev power */
774 ddi_quiesce_not_needed, /* quiesce */
775 };
776
777 /*
778 * Module linkage information for the kernel.
779 */
780 static struct modldrv modldrv = {
781 &mod_driverops, /* module type (this is a pseudo driver) */
782 "Function Boundary Tracing", /* name of module */
783 &fbt_ops, /* driver ops */
784 };
785
786 static struct modlinkage modlinkage = {
787 MODREV_1,
788 (void *)&modldrv,
789 NULL
790 };
791
792 int
_init(void)793 _init(void)
794 {
795 return (mod_install(&modlinkage));
796 }
797
798 int
_info(struct modinfo * modinfop)799 _info(struct modinfo *modinfop)
800 {
801 return (mod_info(&modlinkage, modinfop));
802 }
803
804 int
_fini(void)805 _fini(void)
806 {
807 return (mod_remove(&modlinkage));
808 }
809