1248457Sjhibbits/* 2248457Sjhibbits * CDDL HEADER START 3248457Sjhibbits * 4248457Sjhibbits * The contents of this file are subject to the terms of the 5248457Sjhibbits * Common Development and Distribution License (the "License"). 6248457Sjhibbits * You may not use this file except in compliance with the License. 7248457Sjhibbits * 8248457Sjhibbits * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9248457Sjhibbits * or http://www.opensolaris.org/os/licensing. 10248457Sjhibbits * See the License for the specific language governing permissions 11248457Sjhibbits * and limitations under the License. 12248457Sjhibbits * 13248457Sjhibbits * When distributing Covered Code, include this CDDL HEADER in each 14248457Sjhibbits * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15248457Sjhibbits * If applicable, add the following below this CDDL HEADER, with the 16248457Sjhibbits * fields enclosed by brackets "[]" replaced with your own identifying 17248457Sjhibbits * information: Portions Copyright [yyyy] [name of copyright owner] 18248457Sjhibbits * 19248457Sjhibbits * CDDL HEADER END 20248457Sjhibbits * 21248457Sjhibbits * Portions Copyright 2006-2008 John Birrell jb@freebsd.org 22248457Sjhibbits * Portions Copyright 2013 Justin Hibbits jhibbits@freebsd.org 23248457Sjhibbits * 24248457Sjhibbits * $FreeBSD$ 25248457Sjhibbits * 26248457Sjhibbits */ 27248457Sjhibbits 28248457Sjhibbits/* 29248457Sjhibbits * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 30248457Sjhibbits * Use is subject to license terms. 31248457Sjhibbits */ 32248457Sjhibbits 33248457Sjhibbits#include <sys/cdefs.h> 34248457Sjhibbits#include <sys/param.h> 35248457Sjhibbits#include <sys/systm.h> 36248457Sjhibbits#include <sys/conf.h> 37248457Sjhibbits#include <sys/cpuvar.h> 38248457Sjhibbits#include <sys/fcntl.h> 39248457Sjhibbits#include <sys/filio.h> 40248457Sjhibbits#include <sys/kdb.h> 41248457Sjhibbits#include <sys/kernel.h> 42248457Sjhibbits#include <sys/kmem.h> 43248457Sjhibbits#include <sys/kthread.h> 44248457Sjhibbits#include <sys/limits.h> 45248457Sjhibbits#include <sys/linker.h> 46248457Sjhibbits#include <sys/lock.h> 47248457Sjhibbits#include <sys/malloc.h> 48248457Sjhibbits#include <sys/module.h> 49248457Sjhibbits#include <sys/mutex.h> 50248457Sjhibbits#include <sys/pcpu.h> 51248457Sjhibbits#include <sys/poll.h> 52248457Sjhibbits#include <sys/proc.h> 53248457Sjhibbits#include <sys/selinfo.h> 54248457Sjhibbits#include <sys/smp.h> 55248457Sjhibbits#include <sys/syscall.h> 56248457Sjhibbits#include <sys/sysent.h> 57248457Sjhibbits#include <sys/sysproto.h> 58248457Sjhibbits#include <sys/uio.h> 59248457Sjhibbits#include <sys/unistd.h> 60255099Sjhibbits#include <machine/md_var.h> 61248457Sjhibbits#include <machine/stdarg.h> 62248457Sjhibbits 63248457Sjhibbits#include <sys/dtrace.h> 64248457Sjhibbits#include <sys/dtrace_bsd.h> 65248457Sjhibbits 66248457Sjhibbitsstatic MALLOC_DEFINE(M_FBT, "fbt", "Function Boundary Tracing"); 67248457Sjhibbits 68248457Sjhibbits#define FBT_PATCHVAL 0x7c810808 69248457Sjhibbits#define FBT_MFLR_R0 0x7c0802a6 70248457Sjhibbits#define FBT_MTLR_R0 0x7c0803a6 71248457Sjhibbits#define FBT_BLR 0x4e800020 72248457Sjhibbits#define FBT_BCTR 0x4e800030 73248457Sjhibbits#define FBT_BRANCH 0x48000000 74248457Sjhibbits#define FBT_BR_MASK 0x03fffffc 75248457Sjhibbits#define FBT_IS_JUMP(instr) ((instr & ~FBT_BR_MASK) == FBT_BRANCH) 76248457Sjhibbits 77248457Sjhibbitsstatic d_open_t fbt_open; 78248457Sjhibbitsstatic int fbt_unload(void); 79248457Sjhibbitsstatic void fbt_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *); 80248457Sjhibbitsstatic void fbt_provide_module(void *, modctl_t *); 81248457Sjhibbitsstatic void fbt_destroy(void *, dtrace_id_t, void *); 82248457Sjhibbitsstatic void fbt_enable(void *, dtrace_id_t, void *); 83248457Sjhibbitsstatic void fbt_disable(void *, dtrace_id_t, void *); 84248457Sjhibbitsstatic void fbt_load(void *); 85248457Sjhibbitsstatic void fbt_suspend(void *, dtrace_id_t, void *); 86248457Sjhibbitsstatic void fbt_resume(void *, dtrace_id_t, void *); 87248457Sjhibbits 88248457Sjhibbits#define FBT_ENTRY "entry" 89248457Sjhibbits#define FBT_RETURN "return" 90248457Sjhibbits#define FBT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & fbt_probetab_mask) 91248457Sjhibbits#define FBT_PROBETAB_SIZE 0x8000 /* 32k entries -- 128K total */ 92248457Sjhibbits 93248457Sjhibbitsstatic struct cdevsw fbt_cdevsw = { 94248457Sjhibbits .d_version = D_VERSION, 95248457Sjhibbits .d_open = fbt_open, 96248457Sjhibbits .d_name = "fbt", 97248457Sjhibbits}; 98248457Sjhibbits 99248457Sjhibbitsstatic dtrace_pattr_t fbt_attr = { 100248457Sjhibbits{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, 101248457Sjhibbits{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, 102248457Sjhibbits{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, 103248457Sjhibbits{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, 104248457Sjhibbits{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, 105248457Sjhibbits}; 106248457Sjhibbits 107248457Sjhibbitsstatic dtrace_pops_t fbt_pops = { 108248457Sjhibbits NULL, 109248457Sjhibbits fbt_provide_module, 110248457Sjhibbits fbt_enable, 111248457Sjhibbits fbt_disable, 112248457Sjhibbits fbt_suspend, 113248457Sjhibbits fbt_resume, 114248457Sjhibbits fbt_getargdesc, 115248457Sjhibbits NULL, 116248457Sjhibbits NULL, 117248457Sjhibbits fbt_destroy 118248457Sjhibbits}; 119248457Sjhibbits 120248457Sjhibbitstypedef struct fbt_probe { 121248457Sjhibbits struct fbt_probe *fbtp_hashnext; 122248457Sjhibbits uint32_t *fbtp_patchpoint; 123248457Sjhibbits int8_t fbtp_rval; 124248457Sjhibbits uint32_t fbtp_patchval; 125248457Sjhibbits uint32_t fbtp_savedval; 126248457Sjhibbits uintptr_t fbtp_roffset; 127248457Sjhibbits dtrace_id_t fbtp_id; 128248457Sjhibbits const char *fbtp_name; 129248457Sjhibbits modctl_t *fbtp_ctl; 130248457Sjhibbits int fbtp_loadcnt; 131248457Sjhibbits int fbtp_primary; 132248457Sjhibbits int fbtp_invop_cnt; 133248457Sjhibbits int fbtp_symindx; 134248457Sjhibbits struct fbt_probe *fbtp_next; 135248457Sjhibbits} fbt_probe_t; 136248457Sjhibbits 137248457Sjhibbitsstatic struct cdev *fbt_cdev; 138248457Sjhibbitsstatic dtrace_provider_id_t fbt_id; 139248457Sjhibbitsstatic fbt_probe_t **fbt_probetab; 140248457Sjhibbitsstatic int fbt_probetab_size; 141248457Sjhibbitsstatic int fbt_probetab_mask; 142248457Sjhibbitsstatic int fbt_verbose = 0; 143248457Sjhibbits 144248457Sjhibbitsstatic int 145248457Sjhibbitsfbt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t rval) 146248457Sjhibbits{ 147248457Sjhibbits struct trapframe *frame = (struct trapframe *)stack; 148248457Sjhibbits solaris_cpu_t *cpu = &solaris_cpu[curcpu]; 149248457Sjhibbits fbt_probe_t *fbt = fbt_probetab[FBT_ADDR2NDX(addr)]; 150248457Sjhibbits uintptr_t tmp; 151248457Sjhibbits 152248457Sjhibbits for (; fbt != NULL; fbt = fbt->fbtp_hashnext) { 153248457Sjhibbits if ((uintptr_t)fbt->fbtp_patchpoint == addr) { 154248457Sjhibbits fbt->fbtp_invop_cnt++; 155248457Sjhibbits if (fbt->fbtp_roffset == 0) { 156248457Sjhibbits cpu->cpu_dtrace_caller = addr; 157248457Sjhibbits 158248457Sjhibbits dtrace_probe(fbt->fbtp_id, frame->fixreg[3], 159248457Sjhibbits frame->fixreg[4], frame->fixreg[5], 160248457Sjhibbits frame->fixreg[6], frame->fixreg[7]); 161248457Sjhibbits 162248457Sjhibbits cpu->cpu_dtrace_caller = 0; 163248457Sjhibbits } else { 164248457Sjhibbits 165248457Sjhibbits dtrace_probe(fbt->fbtp_id, fbt->fbtp_roffset, 166248457Sjhibbits rval, 0, 0, 0); 167248457Sjhibbits /* 168248457Sjhibbits * The caller doesn't have the fbt item, so 169248457Sjhibbits * fixup tail calls here. 170248457Sjhibbits */ 171248457Sjhibbits if (fbt->fbtp_rval == DTRACE_INVOP_JUMP) { 172248457Sjhibbits frame->srr0 = (uintptr_t)fbt->fbtp_patchpoint; 173248457Sjhibbits tmp = fbt->fbtp_savedval & FBT_BR_MASK; 174248457Sjhibbits /* Sign extend. */ 175248457Sjhibbits if (tmp & 0x02000000) 176255099Sjhibbits#ifdef __powerpc64__ 177255099Sjhibbits tmp |= 0xfffffffffc000000ULL; 178255099Sjhibbits#else 179255099Sjhibbits tmp |= 0xfc000000UL; 180255099Sjhibbits#endif 181248457Sjhibbits frame->srr0 += tmp; 182248457Sjhibbits } 183248457Sjhibbits cpu->cpu_dtrace_caller = 0; 184248457Sjhibbits } 185248457Sjhibbits 186248457Sjhibbits return (fbt->fbtp_rval); 187248457Sjhibbits } 188248457Sjhibbits } 189248457Sjhibbits 190248457Sjhibbits return (0); 191248457Sjhibbits} 192248457Sjhibbits 193248457Sjhibbitsstatic int 194248457Sjhibbitsfbt_provide_module_function(linker_file_t lf, int symindx, 195248457Sjhibbits linker_symval_t *symval, void *opaque) 196248457Sjhibbits{ 197248457Sjhibbits char *modname = opaque; 198248457Sjhibbits const char *name = symval->name; 199248457Sjhibbits fbt_probe_t *fbt, *retfbt; 200248457Sjhibbits int j; 201248457Sjhibbits u_int32_t *instr, *limit; 202248457Sjhibbits 203255099Sjhibbits /* PowerPC64 uses '.' prefixes on symbol names, ignore it. */ 204255099Sjhibbits if (name[0] == '.') 205255099Sjhibbits name++; 206255099Sjhibbits 207248457Sjhibbits if (strncmp(name, "dtrace_", 7) == 0 && 208248457Sjhibbits strncmp(name, "dtrace_safe_", 12) != 0) { 209248457Sjhibbits /* 210248457Sjhibbits * Anything beginning with "dtrace_" may be called 211248457Sjhibbits * from probe context unless it explicitly indicates 212248457Sjhibbits * that it won't be called from probe context by 213248457Sjhibbits * using the prefix "dtrace_safe_". 214248457Sjhibbits */ 215248457Sjhibbits return (0); 216248457Sjhibbits } 217248457Sjhibbits 218248457Sjhibbits if (name[0] == '_' && name[1] == '_') 219248457Sjhibbits return (0); 220248457Sjhibbits 221248457Sjhibbits instr = (u_int32_t *) symval->value; 222260670Sjhibbits limit = (u_int32_t *) (symval->value + symval->size); 223248457Sjhibbits 224248457Sjhibbits for (; instr < limit; instr++) 225248457Sjhibbits if (*instr == FBT_MFLR_R0) 226248457Sjhibbits break; 227248457Sjhibbits 228255099Sjhibbits if (*instr != FBT_MFLR_R0) 229248457Sjhibbits return (0); 230248457Sjhibbits 231248457Sjhibbits fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO); 232248457Sjhibbits fbt->fbtp_name = name; 233248457Sjhibbits fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, 234248457Sjhibbits name, FBT_ENTRY, 3, fbt); 235248457Sjhibbits fbt->fbtp_patchpoint = instr; 236248457Sjhibbits fbt->fbtp_ctl = lf; 237248457Sjhibbits fbt->fbtp_loadcnt = lf->loadcnt; 238248457Sjhibbits fbt->fbtp_savedval = *instr; 239248457Sjhibbits fbt->fbtp_patchval = FBT_PATCHVAL; 240248457Sjhibbits fbt->fbtp_rval = DTRACE_INVOP_MFLR_R0; 241248457Sjhibbits fbt->fbtp_symindx = symindx; 242248457Sjhibbits 243248457Sjhibbits fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)]; 244248457Sjhibbits fbt_probetab[FBT_ADDR2NDX(instr)] = fbt; 245248457Sjhibbits 246248457Sjhibbits lf->fbt_nentries++; 247248457Sjhibbits 248248457Sjhibbits retfbt = NULL; 249248457Sjhibbitsagain: 250248457Sjhibbits if (instr >= limit) 251248457Sjhibbits return (0); 252248457Sjhibbits 253248457Sjhibbits /* 254248457Sjhibbits * We (desperately) want to avoid erroneously instrumenting a 255248457Sjhibbits * jump table To determine if we're looking at a true instruction 256248457Sjhibbits * sequence or an inline jump table that happens to contain the same 257248457Sjhibbits * byte sequences, we resort to some heuristic sleeze: we treat this 258248457Sjhibbits * instruction as being contained within a pointer, and see if that 259248457Sjhibbits * pointer points to within the body of the function. If it does, we 260248457Sjhibbits * refuse to instrument it. 261248457Sjhibbits */ 262248457Sjhibbits { 263248457Sjhibbits uint32_t *ptr; 264248457Sjhibbits 265248457Sjhibbits ptr = *(uint32_t **)instr; 266248457Sjhibbits 267248457Sjhibbits if (ptr >= (uint32_t *) symval->value && ptr < limit) { 268248457Sjhibbits instr++; 269248457Sjhibbits goto again; 270248457Sjhibbits } 271248457Sjhibbits } 272248457Sjhibbits 273248457Sjhibbits if (*instr != FBT_MTLR_R0) { 274248457Sjhibbits instr++; 275248457Sjhibbits goto again; 276248457Sjhibbits } 277248457Sjhibbits 278248457Sjhibbits instr++; 279248457Sjhibbits 280248457Sjhibbits for (j = 0; j < 12 && instr < limit; j++, instr++) { 281260670Sjhibbits if ((*instr == FBT_BCTR) || (*instr == FBT_BLR) || 282248457Sjhibbits FBT_IS_JUMP(*instr)) 283248457Sjhibbits break; 284248457Sjhibbits } 285248457Sjhibbits 286248457Sjhibbits if (!(*instr == FBT_BCTR || *instr == FBT_BLR || FBT_IS_JUMP(*instr))) 287248457Sjhibbits goto again; 288248457Sjhibbits 289248457Sjhibbits /* 290248457Sjhibbits * We have a winner! 291248457Sjhibbits */ 292248457Sjhibbits fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO); 293248457Sjhibbits fbt->fbtp_name = name; 294248457Sjhibbits 295248457Sjhibbits if (retfbt == NULL) { 296248457Sjhibbits fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, 297255099Sjhibbits name, FBT_RETURN, 5, fbt); 298248457Sjhibbits } else { 299248457Sjhibbits retfbt->fbtp_next = fbt; 300248457Sjhibbits fbt->fbtp_id = retfbt->fbtp_id; 301248457Sjhibbits } 302248457Sjhibbits 303248457Sjhibbits retfbt = fbt; 304248457Sjhibbits fbt->fbtp_patchpoint = instr; 305248457Sjhibbits fbt->fbtp_ctl = lf; 306248457Sjhibbits fbt->fbtp_loadcnt = lf->loadcnt; 307248457Sjhibbits fbt->fbtp_symindx = symindx; 308248457Sjhibbits 309248457Sjhibbits if (*instr == FBT_BCTR) 310248457Sjhibbits fbt->fbtp_rval = DTRACE_INVOP_BCTR; 311248457Sjhibbits else if (*instr == FBT_BLR) 312248457Sjhibbits fbt->fbtp_rval = DTRACE_INVOP_RET; 313248457Sjhibbits else 314248457Sjhibbits fbt->fbtp_rval = DTRACE_INVOP_JUMP; 315248457Sjhibbits 316248457Sjhibbits fbt->fbtp_savedval = *instr; 317248457Sjhibbits fbt->fbtp_patchval = FBT_PATCHVAL; 318248457Sjhibbits fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)]; 319248457Sjhibbits fbt_probetab[FBT_ADDR2NDX(instr)] = fbt; 320248457Sjhibbits 321248457Sjhibbits lf->fbt_nentries++; 322248457Sjhibbits 323255099Sjhibbits instr += 4; 324248457Sjhibbits goto again; 325248457Sjhibbits} 326248457Sjhibbits 327248457Sjhibbitsstatic void 328248457Sjhibbitsfbt_provide_module(void *arg, modctl_t *lf) 329248457Sjhibbits{ 330248457Sjhibbits char modname[MAXPATHLEN]; 331248457Sjhibbits int i; 332248457Sjhibbits size_t len; 333248457Sjhibbits 334248457Sjhibbits strlcpy(modname, lf->filename, sizeof(modname)); 335248457Sjhibbits len = strlen(modname); 336248457Sjhibbits if (len > 3 && strcmp(modname + len - 3, ".ko") == 0) 337248457Sjhibbits modname[len - 3] = '\0'; 338248457Sjhibbits 339248457Sjhibbits /* 340248457Sjhibbits * Employees of dtrace and their families are ineligible. Void 341248457Sjhibbits * where prohibited. 342248457Sjhibbits */ 343248457Sjhibbits if (strcmp(modname, "dtrace") == 0) 344248457Sjhibbits return; 345248457Sjhibbits 346248457Sjhibbits /* 347248457Sjhibbits * The cyclic timer subsystem can be built as a module and DTrace 348248457Sjhibbits * depends on that, so it is ineligible too. 349248457Sjhibbits */ 350248457Sjhibbits if (strcmp(modname, "cyclic") == 0) 351248457Sjhibbits return; 352248457Sjhibbits 353248457Sjhibbits /* 354248457Sjhibbits * To register with DTrace, a module must list 'dtrace' as a 355248457Sjhibbits * dependency in order for the kernel linker to resolve 356248457Sjhibbits * symbols like dtrace_register(). All modules with such a 357248457Sjhibbits * dependency are ineligible for FBT tracing. 358248457Sjhibbits */ 359248457Sjhibbits for (i = 0; i < lf->ndeps; i++) 360248457Sjhibbits if (strncmp(lf->deps[i]->filename, "dtrace", 6) == 0) 361248457Sjhibbits return; 362248457Sjhibbits 363248457Sjhibbits if (lf->fbt_nentries) { 364248457Sjhibbits /* 365248457Sjhibbits * This module has some FBT entries allocated; we're afraid 366248457Sjhibbits * to screw with it. 367248457Sjhibbits */ 368248457Sjhibbits return; 369248457Sjhibbits } 370248457Sjhibbits 371248457Sjhibbits /* 372248457Sjhibbits * List the functions in the module and the symbol values. 373248457Sjhibbits */ 374248457Sjhibbits (void) linker_file_function_listall(lf, fbt_provide_module_function, modname); 375248457Sjhibbits} 376248457Sjhibbits 377248457Sjhibbitsstatic void 378248457Sjhibbitsfbt_destroy(void *arg, dtrace_id_t id, void *parg) 379248457Sjhibbits{ 380248457Sjhibbits fbt_probe_t *fbt = parg, *next, *hash, *last; 381248457Sjhibbits modctl_t *ctl; 382248457Sjhibbits int ndx; 383248457Sjhibbits 384248457Sjhibbits do { 385248457Sjhibbits ctl = fbt->fbtp_ctl; 386248457Sjhibbits 387248457Sjhibbits ctl->fbt_nentries--; 388248457Sjhibbits 389248457Sjhibbits /* 390248457Sjhibbits * Now we need to remove this probe from the fbt_probetab. 391248457Sjhibbits */ 392248457Sjhibbits ndx = FBT_ADDR2NDX(fbt->fbtp_patchpoint); 393248457Sjhibbits last = NULL; 394248457Sjhibbits hash = fbt_probetab[ndx]; 395248457Sjhibbits 396248457Sjhibbits while (hash != fbt) { 397248457Sjhibbits ASSERT(hash != NULL); 398248457Sjhibbits last = hash; 399248457Sjhibbits hash = hash->fbtp_hashnext; 400248457Sjhibbits } 401248457Sjhibbits 402248457Sjhibbits if (last != NULL) { 403248457Sjhibbits last->fbtp_hashnext = fbt->fbtp_hashnext; 404248457Sjhibbits } else { 405248457Sjhibbits fbt_probetab[ndx] = fbt->fbtp_hashnext; 406248457Sjhibbits } 407248457Sjhibbits 408248457Sjhibbits next = fbt->fbtp_next; 409248457Sjhibbits free(fbt, M_FBT); 410248457Sjhibbits 411248457Sjhibbits fbt = next; 412248457Sjhibbits } while (fbt != NULL); 413248457Sjhibbits} 414248457Sjhibbits 415248457Sjhibbitsstatic void 416248457Sjhibbitsfbt_enable(void *arg, dtrace_id_t id, void *parg) 417248457Sjhibbits{ 418248457Sjhibbits fbt_probe_t *fbt = parg; 419248457Sjhibbits modctl_t *ctl = fbt->fbtp_ctl; 420248457Sjhibbits 421248457Sjhibbits ctl->nenabled++; 422248457Sjhibbits 423248457Sjhibbits /* 424248457Sjhibbits * Now check that our modctl has the expected load count. If it 425248457Sjhibbits * doesn't, this module must have been unloaded and reloaded -- and 426248457Sjhibbits * we're not going to touch it. 427248457Sjhibbits */ 428248457Sjhibbits if (ctl->loadcnt != fbt->fbtp_loadcnt) { 429248457Sjhibbits if (fbt_verbose) { 430248457Sjhibbits printf("fbt is failing for probe %s " 431248457Sjhibbits "(module %s reloaded)", 432248457Sjhibbits fbt->fbtp_name, ctl->filename); 433248457Sjhibbits } 434248457Sjhibbits 435248457Sjhibbits return; 436248457Sjhibbits } 437248457Sjhibbits 438248457Sjhibbits for (; fbt != NULL; fbt = fbt->fbtp_next) { 439248457Sjhibbits *fbt->fbtp_patchpoint = fbt->fbtp_patchval; 440255099Sjhibbits __syncicache(fbt->fbtp_patchpoint, 4); 441248457Sjhibbits } 442248457Sjhibbits} 443248457Sjhibbits 444248457Sjhibbitsstatic void 445248457Sjhibbitsfbt_disable(void *arg, dtrace_id_t id, void *parg) 446248457Sjhibbits{ 447248457Sjhibbits fbt_probe_t *fbt = parg; 448248457Sjhibbits modctl_t *ctl = fbt->fbtp_ctl; 449248457Sjhibbits 450248457Sjhibbits ASSERT(ctl->nenabled > 0); 451248457Sjhibbits ctl->nenabled--; 452248457Sjhibbits 453248457Sjhibbits if ((ctl->loadcnt != fbt->fbtp_loadcnt)) 454248457Sjhibbits return; 455248457Sjhibbits 456255099Sjhibbits for (; fbt != NULL; fbt = fbt->fbtp_next) { 457248457Sjhibbits *fbt->fbtp_patchpoint = fbt->fbtp_savedval; 458255099Sjhibbits __syncicache(fbt->fbtp_patchpoint, 4); 459255099Sjhibbits } 460248457Sjhibbits} 461248457Sjhibbits 462248457Sjhibbitsstatic void 463248457Sjhibbitsfbt_suspend(void *arg, dtrace_id_t id, void *parg) 464248457Sjhibbits{ 465248457Sjhibbits fbt_probe_t *fbt = parg; 466248457Sjhibbits modctl_t *ctl = fbt->fbtp_ctl; 467248457Sjhibbits 468248457Sjhibbits ASSERT(ctl->nenabled > 0); 469248457Sjhibbits 470248457Sjhibbits if ((ctl->loadcnt != fbt->fbtp_loadcnt)) 471248457Sjhibbits return; 472248457Sjhibbits 473255099Sjhibbits for (; fbt != NULL; fbt = fbt->fbtp_next) { 474248457Sjhibbits *fbt->fbtp_patchpoint = fbt->fbtp_savedval; 475255099Sjhibbits __syncicache(fbt->fbtp_patchpoint, 4); 476255099Sjhibbits } 477248457Sjhibbits} 478248457Sjhibbits 479248457Sjhibbitsstatic void 480248457Sjhibbitsfbt_resume(void *arg, dtrace_id_t id, void *parg) 481248457Sjhibbits{ 482248457Sjhibbits fbt_probe_t *fbt = parg; 483248457Sjhibbits modctl_t *ctl = fbt->fbtp_ctl; 484248457Sjhibbits 485248457Sjhibbits ASSERT(ctl->nenabled > 0); 486248457Sjhibbits 487248457Sjhibbits if ((ctl->loadcnt != fbt->fbtp_loadcnt)) 488248457Sjhibbits return; 489248457Sjhibbits 490255099Sjhibbits for (; fbt != NULL; fbt = fbt->fbtp_next) { 491248457Sjhibbits *fbt->fbtp_patchpoint = fbt->fbtp_patchval; 492255099Sjhibbits __syncicache(fbt->fbtp_patchpoint, 4); 493255099Sjhibbits } 494248457Sjhibbits} 495248457Sjhibbits 496248457Sjhibbitsstatic int 497248457Sjhibbitsfbt_ctfoff_init(modctl_t *lf, linker_ctf_t *lc) 498248457Sjhibbits{ 499248457Sjhibbits const Elf_Sym *symp = lc->symtab;; 500248457Sjhibbits const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab; 501248457Sjhibbits const uint8_t *ctfdata = lc->ctftab + sizeof(ctf_header_t); 502248457Sjhibbits int i; 503248457Sjhibbits uint32_t *ctfoff; 504248457Sjhibbits uint32_t objtoff = hp->cth_objtoff; 505248457Sjhibbits uint32_t funcoff = hp->cth_funcoff; 506248457Sjhibbits ushort_t info; 507248457Sjhibbits ushort_t vlen; 508248457Sjhibbits 509248457Sjhibbits /* Sanity check. */ 510248457Sjhibbits if (hp->cth_magic != CTF_MAGIC) { 511248457Sjhibbits printf("Bad magic value in CTF data of '%s'\n",lf->pathname); 512248457Sjhibbits return (EINVAL); 513248457Sjhibbits } 514248457Sjhibbits 515248457Sjhibbits if (lc->symtab == NULL) { 516248457Sjhibbits printf("No symbol table in '%s'\n",lf->pathname); 517248457Sjhibbits return (EINVAL); 518248457Sjhibbits } 519248457Sjhibbits 520248457Sjhibbits if ((ctfoff = malloc(sizeof(uint32_t) * lc->nsym, M_LINKER, M_WAITOK)) == NULL) 521248457Sjhibbits return (ENOMEM); 522248457Sjhibbits 523248457Sjhibbits *lc->ctfoffp = ctfoff; 524248457Sjhibbits 525248457Sjhibbits for (i = 0; i < lc->nsym; i++, ctfoff++, symp++) { 526248457Sjhibbits if (symp->st_name == 0 || symp->st_shndx == SHN_UNDEF) { 527248457Sjhibbits *ctfoff = 0xffffffff; 528248457Sjhibbits continue; 529248457Sjhibbits } 530248457Sjhibbits 531248457Sjhibbits switch (ELF_ST_TYPE(symp->st_info)) { 532248457Sjhibbits case STT_OBJECT: 533248457Sjhibbits if (objtoff >= hp->cth_funcoff || 534248457Sjhibbits (symp->st_shndx == SHN_ABS && symp->st_value == 0)) { 535248457Sjhibbits *ctfoff = 0xffffffff; 536248457Sjhibbits break; 537248457Sjhibbits } 538248457Sjhibbits 539248457Sjhibbits *ctfoff = objtoff; 540248457Sjhibbits objtoff += sizeof (ushort_t); 541248457Sjhibbits break; 542248457Sjhibbits 543248457Sjhibbits case STT_FUNC: 544248457Sjhibbits if (funcoff >= hp->cth_typeoff) { 545248457Sjhibbits *ctfoff = 0xffffffff; 546248457Sjhibbits break; 547248457Sjhibbits } 548248457Sjhibbits 549248457Sjhibbits *ctfoff = funcoff; 550248457Sjhibbits 551248457Sjhibbits info = *((const ushort_t *)(ctfdata + funcoff)); 552248457Sjhibbits vlen = CTF_INFO_VLEN(info); 553248457Sjhibbits 554248457Sjhibbits /* 555248457Sjhibbits * If we encounter a zero pad at the end, just skip it. 556248457Sjhibbits * Otherwise skip over the function and its return type 557248457Sjhibbits * (+2) and the argument list (vlen). 558248457Sjhibbits */ 559248457Sjhibbits if (CTF_INFO_KIND(info) == CTF_K_UNKNOWN && vlen == 0) 560248457Sjhibbits funcoff += sizeof (ushort_t); /* skip pad */ 561248457Sjhibbits else 562248457Sjhibbits funcoff += sizeof (ushort_t) * (vlen + 2); 563248457Sjhibbits break; 564248457Sjhibbits 565248457Sjhibbits default: 566248457Sjhibbits *ctfoff = 0xffffffff; 567248457Sjhibbits break; 568248457Sjhibbits } 569248457Sjhibbits } 570248457Sjhibbits 571248457Sjhibbits return (0); 572248457Sjhibbits} 573248457Sjhibbits 574248457Sjhibbitsstatic ssize_t 575248457Sjhibbitsfbt_get_ctt_size(uint8_t version, const ctf_type_t *tp, ssize_t *sizep, 576248457Sjhibbits ssize_t *incrementp) 577248457Sjhibbits{ 578248457Sjhibbits ssize_t size, increment; 579248457Sjhibbits 580248457Sjhibbits if (version > CTF_VERSION_1 && 581248457Sjhibbits tp->ctt_size == CTF_LSIZE_SENT) { 582248457Sjhibbits size = CTF_TYPE_LSIZE(tp); 583248457Sjhibbits increment = sizeof (ctf_type_t); 584248457Sjhibbits } else { 585248457Sjhibbits size = tp->ctt_size; 586248457Sjhibbits increment = sizeof (ctf_stype_t); 587248457Sjhibbits } 588248457Sjhibbits 589248457Sjhibbits if (sizep) 590248457Sjhibbits *sizep = size; 591248457Sjhibbits if (incrementp) 592248457Sjhibbits *incrementp = increment; 593248457Sjhibbits 594248457Sjhibbits return (size); 595248457Sjhibbits} 596248457Sjhibbits 597248457Sjhibbitsstatic int 598248457Sjhibbitsfbt_typoff_init(linker_ctf_t *lc) 599248457Sjhibbits{ 600248457Sjhibbits const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab; 601248457Sjhibbits const ctf_type_t *tbuf; 602248457Sjhibbits const ctf_type_t *tend; 603248457Sjhibbits const ctf_type_t *tp; 604248457Sjhibbits const uint8_t *ctfdata = lc->ctftab + sizeof(ctf_header_t); 605248457Sjhibbits int ctf_typemax = 0; 606248457Sjhibbits uint32_t *xp; 607248457Sjhibbits ulong_t pop[CTF_K_MAX + 1] = { 0 }; 608248457Sjhibbits 609248457Sjhibbits 610248457Sjhibbits /* Sanity check. */ 611248457Sjhibbits if (hp->cth_magic != CTF_MAGIC) 612248457Sjhibbits return (EINVAL); 613248457Sjhibbits 614248457Sjhibbits tbuf = (const ctf_type_t *) (ctfdata + hp->cth_typeoff); 615248457Sjhibbits tend = (const ctf_type_t *) (ctfdata + hp->cth_stroff); 616248457Sjhibbits 617248457Sjhibbits int child = hp->cth_parname != 0; 618248457Sjhibbits 619248457Sjhibbits /* 620248457Sjhibbits * We make two passes through the entire type section. In this first 621248457Sjhibbits * pass, we count the number of each type and the total number of types. 622248457Sjhibbits */ 623248457Sjhibbits for (tp = tbuf; tp < tend; ctf_typemax++) { 624248457Sjhibbits ushort_t kind = CTF_INFO_KIND(tp->ctt_info); 625248457Sjhibbits ulong_t vlen = CTF_INFO_VLEN(tp->ctt_info); 626248457Sjhibbits ssize_t size, increment; 627248457Sjhibbits 628248457Sjhibbits size_t vbytes; 629248457Sjhibbits uint_t n; 630248457Sjhibbits 631248457Sjhibbits (void) fbt_get_ctt_size(hp->cth_version, tp, &size, &increment); 632248457Sjhibbits 633248457Sjhibbits switch (kind) { 634248457Sjhibbits case CTF_K_INTEGER: 635248457Sjhibbits case CTF_K_FLOAT: 636248457Sjhibbits vbytes = sizeof (uint_t); 637248457Sjhibbits break; 638248457Sjhibbits case CTF_K_ARRAY: 639248457Sjhibbits vbytes = sizeof (ctf_array_t); 640248457Sjhibbits break; 641248457Sjhibbits case CTF_K_FUNCTION: 642248457Sjhibbits vbytes = sizeof (ushort_t) * (vlen + (vlen & 1)); 643248457Sjhibbits break; 644248457Sjhibbits case CTF_K_STRUCT: 645248457Sjhibbits case CTF_K_UNION: 646248457Sjhibbits if (size < CTF_LSTRUCT_THRESH) { 647248457Sjhibbits ctf_member_t *mp = (ctf_member_t *) 648248457Sjhibbits ((uintptr_t)tp + increment); 649248457Sjhibbits 650248457Sjhibbits vbytes = sizeof (ctf_member_t) * vlen; 651248457Sjhibbits for (n = vlen; n != 0; n--, mp++) 652248457Sjhibbits child |= CTF_TYPE_ISCHILD(mp->ctm_type); 653248457Sjhibbits } else { 654248457Sjhibbits ctf_lmember_t *lmp = (ctf_lmember_t *) 655248457Sjhibbits ((uintptr_t)tp + increment); 656248457Sjhibbits 657248457Sjhibbits vbytes = sizeof (ctf_lmember_t) * vlen; 658248457Sjhibbits for (n = vlen; n != 0; n--, lmp++) 659248457Sjhibbits child |= 660248457Sjhibbits CTF_TYPE_ISCHILD(lmp->ctlm_type); 661248457Sjhibbits } 662248457Sjhibbits break; 663248457Sjhibbits case CTF_K_ENUM: 664248457Sjhibbits vbytes = sizeof (ctf_enum_t) * vlen; 665248457Sjhibbits break; 666248457Sjhibbits case CTF_K_FORWARD: 667248457Sjhibbits /* 668248457Sjhibbits * For forward declarations, ctt_type is the CTF_K_* 669248457Sjhibbits * kind for the tag, so bump that population count too. 670248457Sjhibbits * If ctt_type is unknown, treat the tag as a struct. 671248457Sjhibbits */ 672248457Sjhibbits if (tp->ctt_type == CTF_K_UNKNOWN || 673248457Sjhibbits tp->ctt_type >= CTF_K_MAX) 674248457Sjhibbits pop[CTF_K_STRUCT]++; 675248457Sjhibbits else 676248457Sjhibbits pop[tp->ctt_type]++; 677248457Sjhibbits /*FALLTHRU*/ 678248457Sjhibbits case CTF_K_UNKNOWN: 679248457Sjhibbits vbytes = 0; 680248457Sjhibbits break; 681248457Sjhibbits case CTF_K_POINTER: 682248457Sjhibbits case CTF_K_TYPEDEF: 683248457Sjhibbits case CTF_K_VOLATILE: 684248457Sjhibbits case CTF_K_CONST: 685248457Sjhibbits case CTF_K_RESTRICT: 686248457Sjhibbits child |= CTF_TYPE_ISCHILD(tp->ctt_type); 687248457Sjhibbits vbytes = 0; 688248457Sjhibbits break; 689248457Sjhibbits default: 690248457Sjhibbits printf("%s(%d): detected invalid CTF kind -- %u\n", __func__, __LINE__, kind); 691248457Sjhibbits return (EIO); 692248457Sjhibbits } 693248457Sjhibbits tp = (ctf_type_t *)((uintptr_t)tp + increment + vbytes); 694248457Sjhibbits pop[kind]++; 695248457Sjhibbits } 696248457Sjhibbits 697255099Sjhibbits /* account for a sentinel value below */ 698255099Sjhibbits ctf_typemax++; 699248457Sjhibbits *lc->typlenp = ctf_typemax; 700248457Sjhibbits 701248457Sjhibbits if ((xp = malloc(sizeof(uint32_t) * ctf_typemax, M_LINKER, M_ZERO | M_WAITOK)) == NULL) 702248457Sjhibbits return (ENOMEM); 703248457Sjhibbits 704248457Sjhibbits *lc->typoffp = xp; 705248457Sjhibbits 706248457Sjhibbits /* type id 0 is used as a sentinel value */ 707248457Sjhibbits *xp++ = 0; 708248457Sjhibbits 709248457Sjhibbits /* 710248457Sjhibbits * In the second pass, fill in the type offset. 711248457Sjhibbits */ 712248457Sjhibbits for (tp = tbuf; tp < tend; xp++) { 713248457Sjhibbits ushort_t kind = CTF_INFO_KIND(tp->ctt_info); 714248457Sjhibbits ulong_t vlen = CTF_INFO_VLEN(tp->ctt_info); 715248457Sjhibbits ssize_t size, increment; 716248457Sjhibbits 717248457Sjhibbits size_t vbytes; 718248457Sjhibbits uint_t n; 719248457Sjhibbits 720248457Sjhibbits (void) fbt_get_ctt_size(hp->cth_version, tp, &size, &increment); 721248457Sjhibbits 722248457Sjhibbits switch (kind) { 723248457Sjhibbits case CTF_K_INTEGER: 724248457Sjhibbits case CTF_K_FLOAT: 725248457Sjhibbits vbytes = sizeof (uint_t); 726248457Sjhibbits break; 727248457Sjhibbits case CTF_K_ARRAY: 728248457Sjhibbits vbytes = sizeof (ctf_array_t); 729248457Sjhibbits break; 730248457Sjhibbits case CTF_K_FUNCTION: 731248457Sjhibbits vbytes = sizeof (ushort_t) * (vlen + (vlen & 1)); 732248457Sjhibbits break; 733248457Sjhibbits case CTF_K_STRUCT: 734248457Sjhibbits case CTF_K_UNION: 735248457Sjhibbits if (size < CTF_LSTRUCT_THRESH) { 736248457Sjhibbits ctf_member_t *mp = (ctf_member_t *) 737248457Sjhibbits ((uintptr_t)tp + increment); 738248457Sjhibbits 739248457Sjhibbits vbytes = sizeof (ctf_member_t) * vlen; 740248457Sjhibbits for (n = vlen; n != 0; n--, mp++) 741248457Sjhibbits child |= CTF_TYPE_ISCHILD(mp->ctm_type); 742248457Sjhibbits } else { 743248457Sjhibbits ctf_lmember_t *lmp = (ctf_lmember_t *) 744248457Sjhibbits ((uintptr_t)tp + increment); 745248457Sjhibbits 746248457Sjhibbits vbytes = sizeof (ctf_lmember_t) * vlen; 747248457Sjhibbits for (n = vlen; n != 0; n--, lmp++) 748248457Sjhibbits child |= 749248457Sjhibbits CTF_TYPE_ISCHILD(lmp->ctlm_type); 750248457Sjhibbits } 751248457Sjhibbits break; 752248457Sjhibbits case CTF_K_ENUM: 753248457Sjhibbits vbytes = sizeof (ctf_enum_t) * vlen; 754248457Sjhibbits break; 755248457Sjhibbits case CTF_K_FORWARD: 756248457Sjhibbits case CTF_K_UNKNOWN: 757248457Sjhibbits vbytes = 0; 758248457Sjhibbits break; 759248457Sjhibbits case CTF_K_POINTER: 760248457Sjhibbits case CTF_K_TYPEDEF: 761248457Sjhibbits case CTF_K_VOLATILE: 762248457Sjhibbits case CTF_K_CONST: 763248457Sjhibbits case CTF_K_RESTRICT: 764248457Sjhibbits vbytes = 0; 765248457Sjhibbits break; 766248457Sjhibbits default: 767248457Sjhibbits printf("%s(%d): detected invalid CTF kind -- %u\n", __func__, __LINE__, kind); 768248457Sjhibbits return (EIO); 769248457Sjhibbits } 770248457Sjhibbits *xp = (uint32_t)((uintptr_t) tp - (uintptr_t) ctfdata); 771248457Sjhibbits tp = (ctf_type_t *)((uintptr_t)tp + increment + vbytes); 772248457Sjhibbits } 773248457Sjhibbits 774248457Sjhibbits return (0); 775248457Sjhibbits} 776248457Sjhibbits 777248457Sjhibbits/* 778248457Sjhibbits * CTF Declaration Stack 779248457Sjhibbits * 780248457Sjhibbits * In order to implement ctf_type_name(), we must convert a type graph back 781248457Sjhibbits * into a C type declaration. Unfortunately, a type graph represents a storage 782248457Sjhibbits * class ordering of the type whereas a type declaration must obey the C rules 783248457Sjhibbits * for operator precedence, and the two orderings are frequently in conflict. 784248457Sjhibbits * For example, consider these CTF type graphs and their C declarations: 785248457Sjhibbits * 786248457Sjhibbits * CTF_K_POINTER -> CTF_K_FUNCTION -> CTF_K_INTEGER : int (*)() 787248457Sjhibbits * CTF_K_POINTER -> CTF_K_ARRAY -> CTF_K_INTEGER : int (*)[] 788248457Sjhibbits * 789248457Sjhibbits * In each case, parentheses are used to raise operator * to higher lexical 790248457Sjhibbits * precedence, so the string form of the C declaration cannot be constructed by 791248457Sjhibbits * walking the type graph links and forming the string from left to right. 792248457Sjhibbits * 793248457Sjhibbits * The functions in this file build a set of stacks from the type graph nodes 794248457Sjhibbits * corresponding to the C operator precedence levels in the appropriate order. 795248457Sjhibbits * The code in ctf_type_name() can then iterate over the levels and nodes in 796248457Sjhibbits * lexical precedence order and construct the final C declaration string. 797248457Sjhibbits */ 798248457Sjhibbitstypedef struct ctf_list { 799248457Sjhibbits struct ctf_list *l_prev; /* previous pointer or tail pointer */ 800248457Sjhibbits struct ctf_list *l_next; /* next pointer or head pointer */ 801248457Sjhibbits} ctf_list_t; 802248457Sjhibbits 803248457Sjhibbits#define ctf_list_prev(elem) ((void *)(((ctf_list_t *)(elem))->l_prev)) 804248457Sjhibbits#define ctf_list_next(elem) ((void *)(((ctf_list_t *)(elem))->l_next)) 805248457Sjhibbits 806248457Sjhibbitstypedef enum { 807248457Sjhibbits CTF_PREC_BASE, 808248457Sjhibbits CTF_PREC_POINTER, 809248457Sjhibbits CTF_PREC_ARRAY, 810248457Sjhibbits CTF_PREC_FUNCTION, 811248457Sjhibbits CTF_PREC_MAX 812248457Sjhibbits} ctf_decl_prec_t; 813248457Sjhibbits 814248457Sjhibbitstypedef struct ctf_decl_node { 815248457Sjhibbits ctf_list_t cd_list; /* linked list pointers */ 816248457Sjhibbits ctf_id_t cd_type; /* type identifier */ 817248457Sjhibbits uint_t cd_kind; /* type kind */ 818248457Sjhibbits uint_t cd_n; /* type dimension if array */ 819248457Sjhibbits} ctf_decl_node_t; 820248457Sjhibbits 821248457Sjhibbitstypedef struct ctf_decl { 822248457Sjhibbits ctf_list_t cd_nodes[CTF_PREC_MAX]; /* declaration node stacks */ 823248457Sjhibbits int cd_order[CTF_PREC_MAX]; /* storage order of decls */ 824248457Sjhibbits ctf_decl_prec_t cd_qualp; /* qualifier precision */ 825248457Sjhibbits ctf_decl_prec_t cd_ordp; /* ordered precision */ 826248457Sjhibbits char *cd_buf; /* buffer for output */ 827248457Sjhibbits char *cd_ptr; /* buffer location */ 828248457Sjhibbits char *cd_end; /* buffer limit */ 829248457Sjhibbits size_t cd_len; /* buffer space required */ 830248457Sjhibbits int cd_err; /* saved error value */ 831248457Sjhibbits} ctf_decl_t; 832248457Sjhibbits 833248457Sjhibbits/* 834248457Sjhibbits * Simple doubly-linked list append routine. This implementation assumes that 835248457Sjhibbits * each list element contains an embedded ctf_list_t as the first member. 836248457Sjhibbits * An additional ctf_list_t is used to store the head (l_next) and tail 837248457Sjhibbits * (l_prev) pointers. The current head and tail list elements have their 838248457Sjhibbits * previous and next pointers set to NULL, respectively. 839248457Sjhibbits */ 840248457Sjhibbitsstatic void 841248457Sjhibbitsctf_list_append(ctf_list_t *lp, void *new) 842248457Sjhibbits{ 843248457Sjhibbits ctf_list_t *p = lp->l_prev; /* p = tail list element */ 844248457Sjhibbits ctf_list_t *q = new; /* q = new list element */ 845248457Sjhibbits 846248457Sjhibbits lp->l_prev = q; 847248457Sjhibbits q->l_prev = p; 848248457Sjhibbits q->l_next = NULL; 849248457Sjhibbits 850248457Sjhibbits if (p != NULL) 851248457Sjhibbits p->l_next = q; 852248457Sjhibbits else 853248457Sjhibbits lp->l_next = q; 854248457Sjhibbits} 855248457Sjhibbits 856248457Sjhibbits/* 857248457Sjhibbits * Prepend the specified existing element to the given ctf_list_t. The 858248457Sjhibbits * existing pointer should be pointing at a struct with embedded ctf_list_t. 859248457Sjhibbits */ 860248457Sjhibbitsstatic void 861248457Sjhibbitsctf_list_prepend(ctf_list_t *lp, void *new) 862248457Sjhibbits{ 863248457Sjhibbits ctf_list_t *p = new; /* p = new list element */ 864248457Sjhibbits ctf_list_t *q = lp->l_next; /* q = head list element */ 865248457Sjhibbits 866248457Sjhibbits lp->l_next = p; 867248457Sjhibbits p->l_prev = NULL; 868248457Sjhibbits p->l_next = q; 869248457Sjhibbits 870248457Sjhibbits if (q != NULL) 871248457Sjhibbits q->l_prev = p; 872248457Sjhibbits else 873248457Sjhibbits lp->l_prev = p; 874248457Sjhibbits} 875248457Sjhibbits 876248457Sjhibbitsstatic void 877248457Sjhibbitsctf_decl_init(ctf_decl_t *cd, char *buf, size_t len) 878248457Sjhibbits{ 879248457Sjhibbits int i; 880248457Sjhibbits 881248457Sjhibbits bzero(cd, sizeof (ctf_decl_t)); 882248457Sjhibbits 883248457Sjhibbits for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++) 884248457Sjhibbits cd->cd_order[i] = CTF_PREC_BASE - 1; 885248457Sjhibbits 886248457Sjhibbits cd->cd_qualp = CTF_PREC_BASE; 887248457Sjhibbits cd->cd_ordp = CTF_PREC_BASE; 888248457Sjhibbits 889248457Sjhibbits cd->cd_buf = buf; 890248457Sjhibbits cd->cd_ptr = buf; 891248457Sjhibbits cd->cd_end = buf + len; 892248457Sjhibbits} 893248457Sjhibbits 894248457Sjhibbitsstatic void 895248457Sjhibbitsctf_decl_fini(ctf_decl_t *cd) 896248457Sjhibbits{ 897248457Sjhibbits ctf_decl_node_t *cdp, *ndp; 898248457Sjhibbits int i; 899248457Sjhibbits 900248457Sjhibbits for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++) { 901248457Sjhibbits for (cdp = ctf_list_next(&cd->cd_nodes[i]); 902248457Sjhibbits cdp != NULL; cdp = ndp) { 903248457Sjhibbits ndp = ctf_list_next(cdp); 904248457Sjhibbits free(cdp, M_FBT); 905248457Sjhibbits } 906248457Sjhibbits } 907248457Sjhibbits} 908248457Sjhibbits 909248457Sjhibbitsstatic const ctf_type_t * 910248457Sjhibbitsctf_lookup_by_id(linker_ctf_t *lc, ctf_id_t type) 911248457Sjhibbits{ 912248457Sjhibbits const ctf_type_t *tp; 913248457Sjhibbits uint32_t offset; 914248457Sjhibbits uint32_t *typoff = *lc->typoffp; 915248457Sjhibbits 916248457Sjhibbits if (type >= *lc->typlenp) { 917248457Sjhibbits printf("%s(%d): type %d exceeds max %ld\n",__func__,__LINE__,(int) type,*lc->typlenp); 918248457Sjhibbits return(NULL); 919248457Sjhibbits } 920248457Sjhibbits 921248457Sjhibbits /* Check if the type isn't cross-referenced. */ 922248457Sjhibbits if ((offset = typoff[type]) == 0) { 923248457Sjhibbits printf("%s(%d): type %d isn't cross referenced\n",__func__,__LINE__, (int) type); 924248457Sjhibbits return(NULL); 925248457Sjhibbits } 926248457Sjhibbits 927248457Sjhibbits tp = (const ctf_type_t *)(lc->ctftab + offset + sizeof(ctf_header_t)); 928248457Sjhibbits 929248457Sjhibbits return (tp); 930248457Sjhibbits} 931248457Sjhibbits 932248457Sjhibbitsstatic void 933248457Sjhibbitsfbt_array_info(linker_ctf_t *lc, ctf_id_t type, ctf_arinfo_t *arp) 934248457Sjhibbits{ 935248457Sjhibbits const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab; 936248457Sjhibbits const ctf_type_t *tp; 937248457Sjhibbits const ctf_array_t *ap; 938248457Sjhibbits ssize_t increment; 939248457Sjhibbits 940248457Sjhibbits bzero(arp, sizeof(*arp)); 941248457Sjhibbits 942248457Sjhibbits if ((tp = ctf_lookup_by_id(lc, type)) == NULL) 943248457Sjhibbits return; 944248457Sjhibbits 945248457Sjhibbits if (CTF_INFO_KIND(tp->ctt_info) != CTF_K_ARRAY) 946248457Sjhibbits return; 947248457Sjhibbits 948248457Sjhibbits (void) fbt_get_ctt_size(hp->cth_version, tp, NULL, &increment); 949248457Sjhibbits 950248457Sjhibbits ap = (const ctf_array_t *)((uintptr_t)tp + increment); 951248457Sjhibbits arp->ctr_contents = ap->cta_contents; 952248457Sjhibbits arp->ctr_index = ap->cta_index; 953248457Sjhibbits arp->ctr_nelems = ap->cta_nelems; 954248457Sjhibbits} 955248457Sjhibbits 956248457Sjhibbitsstatic const char * 957248457Sjhibbitsctf_strptr(linker_ctf_t *lc, int name) 958248457Sjhibbits{ 959248457Sjhibbits const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab;; 960248457Sjhibbits const char *strp = ""; 961248457Sjhibbits 962248457Sjhibbits if (name < 0 || name >= hp->cth_strlen) 963248457Sjhibbits return(strp); 964248457Sjhibbits 965248457Sjhibbits strp = (const char *)(lc->ctftab + hp->cth_stroff + name + sizeof(ctf_header_t)); 966248457Sjhibbits 967248457Sjhibbits return (strp); 968248457Sjhibbits} 969248457Sjhibbits 970248457Sjhibbitsstatic void 971248457Sjhibbitsctf_decl_push(ctf_decl_t *cd, linker_ctf_t *lc, ctf_id_t type) 972248457Sjhibbits{ 973248457Sjhibbits ctf_decl_node_t *cdp; 974248457Sjhibbits ctf_decl_prec_t prec; 975248457Sjhibbits uint_t kind, n = 1; 976248457Sjhibbits int is_qual = 0; 977248457Sjhibbits 978248457Sjhibbits const ctf_type_t *tp; 979248457Sjhibbits ctf_arinfo_t ar; 980248457Sjhibbits 981248457Sjhibbits if ((tp = ctf_lookup_by_id(lc, type)) == NULL) { 982248457Sjhibbits cd->cd_err = ENOENT; 983248457Sjhibbits return; 984248457Sjhibbits } 985248457Sjhibbits 986248457Sjhibbits switch (kind = CTF_INFO_KIND(tp->ctt_info)) { 987248457Sjhibbits case CTF_K_ARRAY: 988248457Sjhibbits fbt_array_info(lc, type, &ar); 989248457Sjhibbits ctf_decl_push(cd, lc, ar.ctr_contents); 990248457Sjhibbits n = ar.ctr_nelems; 991248457Sjhibbits prec = CTF_PREC_ARRAY; 992248457Sjhibbits break; 993248457Sjhibbits 994248457Sjhibbits case CTF_K_TYPEDEF: 995248457Sjhibbits if (ctf_strptr(lc, tp->ctt_name)[0] == '\0') { 996248457Sjhibbits ctf_decl_push(cd, lc, tp->ctt_type); 997248457Sjhibbits return; 998248457Sjhibbits } 999248457Sjhibbits prec = CTF_PREC_BASE; 1000248457Sjhibbits break; 1001248457Sjhibbits 1002248457Sjhibbits case CTF_K_FUNCTION: 1003248457Sjhibbits ctf_decl_push(cd, lc, tp->ctt_type); 1004248457Sjhibbits prec = CTF_PREC_FUNCTION; 1005248457Sjhibbits break; 1006248457Sjhibbits 1007248457Sjhibbits case CTF_K_POINTER: 1008248457Sjhibbits ctf_decl_push(cd, lc, tp->ctt_type); 1009248457Sjhibbits prec = CTF_PREC_POINTER; 1010248457Sjhibbits break; 1011248457Sjhibbits 1012248457Sjhibbits case CTF_K_VOLATILE: 1013248457Sjhibbits case CTF_K_CONST: 1014248457Sjhibbits case CTF_K_RESTRICT: 1015248457Sjhibbits ctf_decl_push(cd, lc, tp->ctt_type); 1016248457Sjhibbits prec = cd->cd_qualp; 1017248457Sjhibbits is_qual++; 1018248457Sjhibbits break; 1019248457Sjhibbits 1020248457Sjhibbits default: 1021248457Sjhibbits prec = CTF_PREC_BASE; 1022248457Sjhibbits } 1023248457Sjhibbits 1024248457Sjhibbits if ((cdp = malloc(sizeof (ctf_decl_node_t), M_FBT, M_WAITOK)) == NULL) { 1025248457Sjhibbits cd->cd_err = EAGAIN; 1026248457Sjhibbits return; 1027248457Sjhibbits } 1028248457Sjhibbits 1029248457Sjhibbits cdp->cd_type = type; 1030248457Sjhibbits cdp->cd_kind = kind; 1031248457Sjhibbits cdp->cd_n = n; 1032248457Sjhibbits 1033248457Sjhibbits if (ctf_list_next(&cd->cd_nodes[prec]) == NULL) 1034248457Sjhibbits cd->cd_order[prec] = cd->cd_ordp++; 1035248457Sjhibbits 1036248457Sjhibbits /* 1037248457Sjhibbits * Reset cd_qualp to the highest precedence level that we've seen so 1038248457Sjhibbits * far that can be qualified (CTF_PREC_BASE or CTF_PREC_POINTER). 1039248457Sjhibbits */ 1040248457Sjhibbits if (prec > cd->cd_qualp && prec < CTF_PREC_ARRAY) 1041248457Sjhibbits cd->cd_qualp = prec; 1042248457Sjhibbits 1043248457Sjhibbits /* 1044248457Sjhibbits * C array declarators are ordered inside out so prepend them. Also by 1045248457Sjhibbits * convention qualifiers of base types precede the type specifier (e.g. 1046248457Sjhibbits * const int vs. int const) even though the two forms are equivalent. 1047248457Sjhibbits */ 1048248457Sjhibbits if (kind == CTF_K_ARRAY || (is_qual && prec == CTF_PREC_BASE)) 1049248457Sjhibbits ctf_list_prepend(&cd->cd_nodes[prec], cdp); 1050248457Sjhibbits else 1051248457Sjhibbits ctf_list_append(&cd->cd_nodes[prec], cdp); 1052248457Sjhibbits} 1053248457Sjhibbits 1054248457Sjhibbitsstatic void 1055248457Sjhibbitsctf_decl_sprintf(ctf_decl_t *cd, const char *format, ...) 1056248457Sjhibbits{ 1057248457Sjhibbits size_t len = (size_t)(cd->cd_end - cd->cd_ptr); 1058248457Sjhibbits va_list ap; 1059248457Sjhibbits size_t n; 1060248457Sjhibbits 1061248457Sjhibbits va_start(ap, format); 1062248457Sjhibbits n = vsnprintf(cd->cd_ptr, len, format, ap); 1063248457Sjhibbits va_end(ap); 1064248457Sjhibbits 1065248457Sjhibbits cd->cd_ptr += MIN(n, len); 1066248457Sjhibbits cd->cd_len += n; 1067248457Sjhibbits} 1068248457Sjhibbits 1069248457Sjhibbitsstatic ssize_t 1070248457Sjhibbitsfbt_type_name(linker_ctf_t *lc, ctf_id_t type, char *buf, size_t len) 1071248457Sjhibbits{ 1072248457Sjhibbits ctf_decl_t cd; 1073248457Sjhibbits ctf_decl_node_t *cdp; 1074248457Sjhibbits ctf_decl_prec_t prec, lp, rp; 1075248457Sjhibbits int ptr, arr; 1076248457Sjhibbits uint_t k; 1077248457Sjhibbits 1078248457Sjhibbits if (lc == NULL && type == CTF_ERR) 1079248457Sjhibbits return (-1); /* simplify caller code by permitting CTF_ERR */ 1080248457Sjhibbits 1081248457Sjhibbits ctf_decl_init(&cd, buf, len); 1082248457Sjhibbits ctf_decl_push(&cd, lc, type); 1083248457Sjhibbits 1084248457Sjhibbits if (cd.cd_err != 0) { 1085248457Sjhibbits ctf_decl_fini(&cd); 1086248457Sjhibbits return (-1); 1087248457Sjhibbits } 1088248457Sjhibbits 1089248457Sjhibbits /* 1090248457Sjhibbits * If the type graph's order conflicts with lexical precedence order 1091248457Sjhibbits * for pointers or arrays, then we need to surround the declarations at 1092248457Sjhibbits * the corresponding lexical precedence with parentheses. This can 1093248457Sjhibbits * result in either a parenthesized pointer (*) as in int (*)() or 1094248457Sjhibbits * int (*)[], or in a parenthesized pointer and array as in int (*[])(). 1095248457Sjhibbits */ 1096248457Sjhibbits ptr = cd.cd_order[CTF_PREC_POINTER] > CTF_PREC_POINTER; 1097248457Sjhibbits arr = cd.cd_order[CTF_PREC_ARRAY] > CTF_PREC_ARRAY; 1098248457Sjhibbits 1099248457Sjhibbits rp = arr ? CTF_PREC_ARRAY : ptr ? CTF_PREC_POINTER : -1; 1100248457Sjhibbits lp = ptr ? CTF_PREC_POINTER : arr ? CTF_PREC_ARRAY : -1; 1101248457Sjhibbits 1102248457Sjhibbits k = CTF_K_POINTER; /* avoid leading whitespace (see below) */ 1103248457Sjhibbits 1104248457Sjhibbits for (prec = CTF_PREC_BASE; prec < CTF_PREC_MAX; prec++) { 1105248457Sjhibbits for (cdp = ctf_list_next(&cd.cd_nodes[prec]); 1106248457Sjhibbits cdp != NULL; cdp = ctf_list_next(cdp)) { 1107248457Sjhibbits 1108248457Sjhibbits const ctf_type_t *tp = 1109248457Sjhibbits ctf_lookup_by_id(lc, cdp->cd_type); 1110248457Sjhibbits const char *name = ctf_strptr(lc, tp->ctt_name); 1111248457Sjhibbits 1112248457Sjhibbits if (k != CTF_K_POINTER && k != CTF_K_ARRAY) 1113248457Sjhibbits ctf_decl_sprintf(&cd, " "); 1114248457Sjhibbits 1115248457Sjhibbits if (lp == prec) { 1116248457Sjhibbits ctf_decl_sprintf(&cd, "("); 1117248457Sjhibbits lp = -1; 1118248457Sjhibbits } 1119248457Sjhibbits 1120248457Sjhibbits switch (cdp->cd_kind) { 1121248457Sjhibbits case CTF_K_INTEGER: 1122248457Sjhibbits case CTF_K_FLOAT: 1123248457Sjhibbits case CTF_K_TYPEDEF: 1124248457Sjhibbits ctf_decl_sprintf(&cd, "%s", name); 1125248457Sjhibbits break; 1126248457Sjhibbits case CTF_K_POINTER: 1127248457Sjhibbits ctf_decl_sprintf(&cd, "*"); 1128248457Sjhibbits break; 1129248457Sjhibbits case CTF_K_ARRAY: 1130248457Sjhibbits ctf_decl_sprintf(&cd, "[%u]", cdp->cd_n); 1131248457Sjhibbits break; 1132248457Sjhibbits case CTF_K_FUNCTION: 1133248457Sjhibbits ctf_decl_sprintf(&cd, "()"); 1134248457Sjhibbits break; 1135248457Sjhibbits case CTF_K_STRUCT: 1136248457Sjhibbits case CTF_K_FORWARD: 1137248457Sjhibbits ctf_decl_sprintf(&cd, "struct %s", name); 1138248457Sjhibbits break; 1139248457Sjhibbits case CTF_K_UNION: 1140248457Sjhibbits ctf_decl_sprintf(&cd, "union %s", name); 1141248457Sjhibbits break; 1142248457Sjhibbits case CTF_K_ENUM: 1143248457Sjhibbits ctf_decl_sprintf(&cd, "enum %s", name); 1144248457Sjhibbits break; 1145248457Sjhibbits case CTF_K_VOLATILE: 1146248457Sjhibbits ctf_decl_sprintf(&cd, "volatile"); 1147248457Sjhibbits break; 1148248457Sjhibbits case CTF_K_CONST: 1149248457Sjhibbits ctf_decl_sprintf(&cd, "const"); 1150248457Sjhibbits break; 1151248457Sjhibbits case CTF_K_RESTRICT: 1152248457Sjhibbits ctf_decl_sprintf(&cd, "restrict"); 1153248457Sjhibbits break; 1154248457Sjhibbits } 1155248457Sjhibbits 1156248457Sjhibbits k = cdp->cd_kind; 1157248457Sjhibbits } 1158248457Sjhibbits 1159248457Sjhibbits if (rp == prec) 1160248457Sjhibbits ctf_decl_sprintf(&cd, ")"); 1161248457Sjhibbits } 1162248457Sjhibbits 1163248457Sjhibbits ctf_decl_fini(&cd); 1164248457Sjhibbits return (cd.cd_len); 1165248457Sjhibbits} 1166248457Sjhibbits 1167248457Sjhibbitsstatic void 1168248457Sjhibbitsfbt_getargdesc(void *arg __unused, dtrace_id_t id __unused, void *parg, dtrace_argdesc_t *desc) 1169248457Sjhibbits{ 1170248457Sjhibbits const ushort_t *dp; 1171248457Sjhibbits fbt_probe_t *fbt = parg; 1172248457Sjhibbits linker_ctf_t lc; 1173248457Sjhibbits modctl_t *ctl = fbt->fbtp_ctl; 1174248457Sjhibbits int ndx = desc->dtargd_ndx; 1175248457Sjhibbits int symindx = fbt->fbtp_symindx; 1176248457Sjhibbits uint32_t *ctfoff; 1177248457Sjhibbits uint32_t offset; 1178248457Sjhibbits ushort_t info, kind, n; 1179248457Sjhibbits 1180255099Sjhibbits if (fbt->fbtp_roffset != 0 && desc->dtargd_ndx == 0) { 1181255099Sjhibbits (void) strcpy(desc->dtargd_native, "int"); 1182255099Sjhibbits return; 1183255099Sjhibbits } 1184255099Sjhibbits 1185248457Sjhibbits desc->dtargd_ndx = DTRACE_ARGNONE; 1186248457Sjhibbits 1187248457Sjhibbits /* Get a pointer to the CTF data and it's length. */ 1188248457Sjhibbits if (linker_ctf_get(ctl, &lc) != 0) 1189248457Sjhibbits /* No CTF data? Something wrong? *shrug* */ 1190248457Sjhibbits return; 1191248457Sjhibbits 1192248457Sjhibbits /* Check if this module hasn't been initialised yet. */ 1193248457Sjhibbits if (*lc.ctfoffp == NULL) { 1194248457Sjhibbits /* 1195248457Sjhibbits * Initialise the CTF object and function symindx to 1196248457Sjhibbits * byte offset array. 1197248457Sjhibbits */ 1198248457Sjhibbits if (fbt_ctfoff_init(ctl, &lc) != 0) 1199248457Sjhibbits return; 1200248457Sjhibbits 1201248457Sjhibbits /* Initialise the CTF type to byte offset array. */ 1202248457Sjhibbits if (fbt_typoff_init(&lc) != 0) 1203248457Sjhibbits return; 1204248457Sjhibbits } 1205248457Sjhibbits 1206248457Sjhibbits ctfoff = *lc.ctfoffp; 1207248457Sjhibbits 1208248457Sjhibbits if (ctfoff == NULL || *lc.typoffp == NULL) 1209248457Sjhibbits return; 1210248457Sjhibbits 1211248457Sjhibbits /* Check if the symbol index is out of range. */ 1212248457Sjhibbits if (symindx >= lc.nsym) 1213248457Sjhibbits return; 1214248457Sjhibbits 1215248457Sjhibbits /* Check if the symbol isn't cross-referenced. */ 1216248457Sjhibbits if ((offset = ctfoff[symindx]) == 0xffffffff) 1217248457Sjhibbits return; 1218248457Sjhibbits 1219248457Sjhibbits dp = (const ushort_t *)(lc.ctftab + offset + sizeof(ctf_header_t)); 1220248457Sjhibbits 1221248457Sjhibbits info = *dp++; 1222248457Sjhibbits kind = CTF_INFO_KIND(info); 1223248457Sjhibbits n = CTF_INFO_VLEN(info); 1224248457Sjhibbits 1225248457Sjhibbits if (kind == CTF_K_UNKNOWN && n == 0) { 1226248457Sjhibbits printf("%s(%d): Unknown function!\n",__func__,__LINE__); 1227248457Sjhibbits return; 1228248457Sjhibbits } 1229248457Sjhibbits 1230248457Sjhibbits if (kind != CTF_K_FUNCTION) { 1231248457Sjhibbits printf("%s(%d): Expected a function!\n",__func__,__LINE__); 1232248457Sjhibbits return; 1233248457Sjhibbits } 1234248457Sjhibbits 1235255099Sjhibbits if (fbt->fbtp_roffset != 0) { 1236255099Sjhibbits /* Only return type is available for args[1] in return probe. */ 1237255099Sjhibbits if (ndx > 1) 1238255099Sjhibbits return; 1239255099Sjhibbits ASSERT(ndx == 1); 1240255099Sjhibbits } else { 1241255099Sjhibbits /* Check if the requested argument doesn't exist. */ 1242255099Sjhibbits if (ndx >= n) 1243255099Sjhibbits return; 1244248457Sjhibbits 1245255099Sjhibbits /* Skip the return type and arguments up to the one requested. */ 1246255099Sjhibbits dp += ndx + 1; 1247255099Sjhibbits } 1248248457Sjhibbits 1249248457Sjhibbits if (fbt_type_name(&lc, *dp, desc->dtargd_native, sizeof(desc->dtargd_native)) > 0) 1250248457Sjhibbits desc->dtargd_ndx = ndx; 1251248457Sjhibbits 1252248457Sjhibbits return; 1253248457Sjhibbits} 1254248457Sjhibbits 1255255099Sjhibbitsstatic int 1256255099Sjhibbitsfbt_linker_file_cb(linker_file_t lf, void *arg) 1257255099Sjhibbits{ 1258255099Sjhibbits 1259255099Sjhibbits fbt_provide_module(arg, lf); 1260255099Sjhibbits 1261255099Sjhibbits return (0); 1262255099Sjhibbits} 1263255099Sjhibbits 1264248457Sjhibbitsstatic void 1265248457Sjhibbitsfbt_load(void *dummy) 1266248457Sjhibbits{ 1267248457Sjhibbits /* Create the /dev/dtrace/fbt entry. */ 1268248457Sjhibbits fbt_cdev = make_dev(&fbt_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, 1269248457Sjhibbits "dtrace/fbt"); 1270248457Sjhibbits 1271248457Sjhibbits /* Default the probe table size if not specified. */ 1272248457Sjhibbits if (fbt_probetab_size == 0) 1273248457Sjhibbits fbt_probetab_size = FBT_PROBETAB_SIZE; 1274248457Sjhibbits 1275248457Sjhibbits /* Choose the hash mask for the probe table. */ 1276248457Sjhibbits fbt_probetab_mask = fbt_probetab_size - 1; 1277248457Sjhibbits 1278248457Sjhibbits /* Allocate memory for the probe table. */ 1279248457Sjhibbits fbt_probetab = 1280248457Sjhibbits malloc(fbt_probetab_size * sizeof (fbt_probe_t *), M_FBT, M_WAITOK | M_ZERO); 1281248457Sjhibbits 1282248457Sjhibbits dtrace_invop_add(fbt_invop); 1283248457Sjhibbits 1284248457Sjhibbits if (dtrace_register("fbt", &fbt_attr, DTRACE_PRIV_USER, 1285248457Sjhibbits NULL, &fbt_pops, NULL, &fbt_id) != 0) 1286248457Sjhibbits return; 1287255099Sjhibbits 1288255099Sjhibbits /* Create probes for the kernel and already-loaded modules. */ 1289255099Sjhibbits linker_file_foreach(fbt_linker_file_cb, NULL); 1290248457Sjhibbits} 1291248457Sjhibbits 1292248457Sjhibbits 1293248457Sjhibbitsstatic int 1294248457Sjhibbitsfbt_unload() 1295248457Sjhibbits{ 1296248457Sjhibbits int error = 0; 1297248457Sjhibbits 1298248457Sjhibbits /* De-register the invalid opcode handler. */ 1299248457Sjhibbits dtrace_invop_remove(fbt_invop); 1300248457Sjhibbits 1301248457Sjhibbits /* De-register this DTrace provider. */ 1302248457Sjhibbits if ((error = dtrace_unregister(fbt_id)) != 0) 1303248457Sjhibbits return (error); 1304248457Sjhibbits 1305248457Sjhibbits /* Free the probe table. */ 1306248457Sjhibbits free(fbt_probetab, M_FBT); 1307248457Sjhibbits fbt_probetab = NULL; 1308248457Sjhibbits fbt_probetab_mask = 0; 1309248457Sjhibbits 1310248457Sjhibbits destroy_dev(fbt_cdev); 1311248457Sjhibbits 1312248457Sjhibbits return (error); 1313248457Sjhibbits} 1314248457Sjhibbits 1315248457Sjhibbitsstatic int 1316248457Sjhibbitsfbt_modevent(module_t mod __unused, int type, void *data __unused) 1317248457Sjhibbits{ 1318248457Sjhibbits int error = 0; 1319248457Sjhibbits 1320248457Sjhibbits switch (type) { 1321248457Sjhibbits case MOD_LOAD: 1322248457Sjhibbits break; 1323248457Sjhibbits 1324248457Sjhibbits case MOD_UNLOAD: 1325248457Sjhibbits break; 1326248457Sjhibbits 1327248457Sjhibbits case MOD_SHUTDOWN: 1328248457Sjhibbits break; 1329248457Sjhibbits 1330248457Sjhibbits default: 1331248457Sjhibbits error = EOPNOTSUPP; 1332248457Sjhibbits break; 1333248457Sjhibbits 1334248457Sjhibbits } 1335248457Sjhibbits 1336248457Sjhibbits return (error); 1337248457Sjhibbits} 1338248457Sjhibbits 1339248457Sjhibbitsstatic int 1340248457Sjhibbitsfbt_open(struct cdev *dev __unused, int oflags __unused, int devtype __unused, struct thread *td __unused) 1341248457Sjhibbits{ 1342248457Sjhibbits return (0); 1343248457Sjhibbits} 1344248457Sjhibbits 1345248457SjhibbitsSYSINIT(fbt_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, fbt_load, NULL); 1346248457SjhibbitsSYSUNINIT(fbt_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, fbt_unload, NULL); 1347248457Sjhibbits 1348248457SjhibbitsDEV_MODULE(fbt, fbt_modevent, NULL); 1349248457SjhibbitsMODULE_VERSION(fbt, 1); 1350248457SjhibbitsMODULE_DEPEND(fbt, dtrace, 1, 1, 1); 1351248457SjhibbitsMODULE_DEPEND(fbt, opensolaris, 1, 1, 1); 1352