fbt.c revision 275576
1139826Simp/* 253541Sshin * CDDL HEADER START 353541Sshin * 453541Sshin * The contents of this file are subject to the terms of the 553541Sshin * Common Development and Distribution License (the "License"). 653541Sshin * You may not use this file except in compliance with the License. 753541Sshin * 853541Sshin * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 953541Sshin * or http://www.opensolaris.org/os/licensing. 1053541Sshin * See the License for the specific language governing permissions 1153541Sshin * and limitations under the License. 1253541Sshin * 1353541Sshin * When distributing Covered Code, include this CDDL HEADER in each 1453541Sshin * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1553541Sshin * If applicable, add the following below this CDDL HEADER, with the 1653541Sshin * fields enclosed by brackets "[]" replaced with your own identifying 1753541Sshin * information: Portions Copyright [yyyy] [name of copyright owner] 1853541Sshin * 1953541Sshin * CDDL HEADER END 2053541Sshin * 2153541Sshin * Portions Copyright 2006-2008 John Birrell jb@freebsd.org 2253541Sshin * 2353541Sshin * $FreeBSD: head/sys/cddl/dev/fbt/fbt.c 275576 2014-12-07 11:21:41Z avg $ 2453541Sshin * 2553541Sshin */ 2653541Sshin 2753541Sshin/* 2853541Sshin * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 2953541Sshin * Use is subject to license terms. 30139826Simp */ 3153541Sshin 32180305Srwatson#include <sys/cdefs.h> 33180305Srwatson#include <sys/param.h> 3453541Sshin#include <sys/systm.h> 3553541Sshin#include <sys/conf.h> 3653541Sshin#include <sys/cpuvar.h> 3753541Sshin#include <sys/fcntl.h> 3853541Sshin#include <sys/filio.h> 3953541Sshin#include <sys/kdb.h> 4053541Sshin#include <sys/kernel.h> 4153541Sshin#include <sys/kmem.h> 4253541Sshin#include <sys/kthread.h> 4353541Sshin#include <sys/limits.h> 4453541Sshin#include <sys/linker.h> 4553541Sshin#include <sys/lock.h> 4653541Sshin#include <sys/malloc.h> 4753541Sshin#include <sys/module.h> 4853541Sshin#include <sys/mutex.h> 4953541Sshin#include <sys/pcpu.h> 5053541Sshin#include <sys/poll.h> 5153541Sshin#include <sys/proc.h> 5253541Sshin#include <sys/selinfo.h> 5353541Sshin#include <sys/smp.h> 5453541Sshin#include <sys/syscall.h> 5553541Sshin#include <sys/sysent.h> 5653541Sshin#include <sys/sysproto.h> 5753541Sshin#include <sys/uio.h> 5853541Sshin#include <sys/unistd.h> 5953541Sshin#include <machine/stdarg.h> 6053541Sshin 6153541Sshin#include <sys/dtrace.h> 62174510Sobrien#include <sys/dtrace_bsd.h> 63174510Sobrien 64174510Sobrien#include "fbt.h" 6555009Sshin 6678064SumeMALLOC_DEFINE(M_FBT, "fbt", "Function Boundary Tracing"); 6755009Sshin 6853541Sshindtrace_provider_id_t fbt_id; 6995759Stanimurafbt_probe_t **fbt_probetab; 70185435Sbzint fbt_probetab_mask; 71253085Sae 7295759Stanimurastatic d_open_t fbt_open; 7353541Sshinstatic int fbt_unload(void); 7495759Stanimurastatic void fbt_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *); 75170689Srwatsonstatic void fbt_provide_module(void *, modctl_t *); 7653541Sshinstatic void fbt_destroy(void *, dtrace_id_t, void *); 7795759Stanimurastatic void fbt_enable(void *, dtrace_id_t, void *); 7895759Stanimurastatic void fbt_disable(void *, dtrace_id_t, void *); 7953541Sshinstatic void fbt_load(void *); 8053541Sshinstatic void fbt_suspend(void *, dtrace_id_t, void *); 8195759Stanimurastatic void fbt_resume(void *, dtrace_id_t, void *); 82148385Sume 8353541Sshinstatic struct cdevsw fbt_cdevsw = { 8453541Sshin .d_version = D_VERSION, 8595759Stanimura .d_open = fbt_open, 8653541Sshin .d_name = "fbt", 87185571Sbz}; 8853541Sshin 8953541Sshinstatic dtrace_pattr_t fbt_attr = { 9053541Sshin{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, 9153541Sshin{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, 92185571Sbz{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, 93185571Sbz{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, 9495759Stanimura{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, 9562587Sitojun}; 96211501Sanchie 9795759Stanimurastatic dtrace_pops_t fbt_pops = { 9856723Sshin NULL, 9953541Sshin fbt_provide_module, 10095759Stanimura fbt_enable, 10153541Sshin fbt_disable, 10295759Stanimura fbt_suspend, 10362587Sitojun fbt_resume, 104211501Sanchie fbt_getargdesc, 10553541Sshin NULL, 106171167Sgnn NULL, 107105199Ssam fbt_destroy 108105199Ssam}; 109171167Sgnn 110105199Ssamstatic struct cdev *fbt_cdev; 11153541Sshinstatic int fbt_probetab_size; 11253541Sshinstatic int fbt_verbose = 0; 11353541Sshin 11453541Sshinstatic void 11553541Sshinfbt_doubletrap(void) 11653541Sshin{ 11753541Sshin fbt_probe_t *fbt; 11853541Sshin int i; 11953541Sshin 120195699Srwatson for (i = 0; i < fbt_probetab_size; i++) { 121195699Srwatson fbt = fbt_probetab[i]; 122195727Srwatson 123195727Srwatson for (; fbt != NULL; fbt = fbt->fbtp_next) 124185348Szec fbt_patch_tracepoint(fbt, fbt->fbtp_savedval); 12553541Sshin } 12653541Sshin} 12753541Sshin 128253085Saestatic void 129253085Saefbt_provide_module(void *arg, modctl_t *lf) 130207369Sbz{ 131253085Sae char modname[MAXPATHLEN]; 132253085Sae int i; 133253085Sae size_t len; 134253085Sae 13553541Sshin strlcpy(modname, lf->filename, sizeof(modname)); 136191672Sbms len = strlen(modname); 137191672Sbms if (len > 3 && strcmp(modname + len - 3, ".ko") == 0) 138166938Sbms modname[len - 3] = '\0'; 139191672Sbms 140191672Sbms /* 141191672Sbms * Employees of dtrace and their families are ineligible. Void 142191672Sbms * where prohibited. 143195699Srwatson */ 144191672Sbms if (strcmp(modname, "dtrace") == 0) 145191672Sbms return; 146191672Sbms 147191672Sbms /* 148166938Sbms * To register with DTrace, a module must list 'dtrace' as a 149166938Sbms * dependency in order for the kernel linker to resolve 150166938Sbms * symbols like dtrace_register(). All modules with such a 151166938Sbms * dependency are ineligible for FBT tracing. 152194581Srdivacky */ 153166938Sbms for (i = 0; i < lf->ndeps; i++) 154166938Sbms if (strncmp(lf->deps[i]->filename, "dtrace", 6) == 0) 155180305Srwatson return; 156180305Srwatson 15753541Sshin if (lf->fbt_nentries) { 15853541Sshin /* 159171259Sdelphij * This module has some FBT entries allocated; we're afraid 16053541Sshin * to screw with it. 161191672Sbms */ 16253541Sshin return; 16353541Sshin } 16453541Sshin 16553541Sshin /* 16678064Sume * List the functions in the module and the symbol values. 167121901Sume */ 16853541Sshin (void) linker_file_function_listall(lf, fbt_provide_module_function, modname); 169252007Sae} 17078064Sume 17183934Sbrooksstatic void 172180305Srwatsonfbt_destroy(void *arg, dtrace_id_t id, void *parg) 17378064Sume{ 174180305Srwatson fbt_probe_t *fbt = parg, *next, *hash, *last; 17553541Sshin modctl_t *ctl; 17678064Sume int ndx; 177121901Sume 17853541Sshin do { 179191672Sbms ctl = fbt->fbtp_ctl; 180191672Sbms 181181803Sbz ctl->fbt_nentries--; 182181803Sbz 183185435Sbz /* 184186141Sbz * Now we need to remove this probe from the fbt_probetab. 18553541Sshin */ 186186141Sbz ndx = FBT_ADDR2NDX(fbt->fbtp_patchpoint); 187186141Sbz last = NULL; 188180850Smav hash = fbt_probetab[ndx]; 18953541Sshin 19053541Sshin while (hash != fbt) { 191180850Smav ASSERT(hash != NULL); 19253541Sshin last = hash; 19353541Sshin hash = hash->fbtp_hashnext; 194180850Smav } 195200473Sbz 196191672Sbms if (last != NULL) { 197191672Sbms last->fbtp_hashnext = fbt->fbtp_hashnext; 198191672Sbms } else { 199191672Sbms fbt_probetab[ndx] = fbt->fbtp_hashnext; 200191672Sbms } 201191672Sbms 202191672Sbms next = fbt->fbtp_next; 203191672Sbms free(fbt, M_FBT); 204191672Sbms 205191672Sbms fbt = next; 206248180Sae } while (fbt != NULL); 20778064Sume} 208252007Sae 209151459Ssuzstatic void 21078064Sumefbt_enable(void *arg, dtrace_id_t id, void *parg) 211180932Smav{ 212252007Sae fbt_probe_t *fbt = parg; 213180850Smav modctl_t *ctl = fbt->fbtp_ctl; 21478064Sume 21553541Sshin ctl->nenabled++; 216191672Sbms 217191672Sbms /* 218191672Sbms * Now check that our modctl has the expected load count. If it 219191672Sbms * doesn't, this module must have been unloaded and reloaded -- and 220191672Sbms * we're not going to touch it. 221191672Sbms */ 222191672Sbms if (ctl->loadcnt != fbt->fbtp_loadcnt) { 223191672Sbms if (fbt_verbose) { 224199518Sbms printf("fbt is failing for probe %s " 225199518Sbms "(module %s reloaded)", 226199518Sbms fbt->fbtp_name, ctl->filename); 227199518Sbms } 228199518Sbms 229199518Sbms return; 230199518Sbms } 231199518Sbms 232199518Sbms for (; fbt != NULL; fbt = fbt->fbtp_next) 233199518Sbms fbt_patch_tracepoint(fbt, fbt->fbtp_patchval); 234199518Sbms} 235199518Sbms 236199518Sbmsstatic void 237199518Sbmsfbt_disable(void *arg, dtrace_id_t id, void *parg) 238199518Sbms{ 239199518Sbms fbt_probe_t *fbt = parg; 240199518Sbms modctl_t *ctl = fbt->fbtp_ctl; 241191672Sbms 242191672Sbms ASSERT(ctl->nenabled > 0); 243199518Sbms ctl->nenabled--; 244199518Sbms 245199518Sbms if ((ctl->loadcnt != fbt->fbtp_loadcnt)) 246191672Sbms return; 247199518Sbms 248199518Sbms for (; fbt != NULL; fbt = fbt->fbtp_next) 249199518Sbms fbt_patch_tracepoint(fbt, fbt->fbtp_savedval); 250199518Sbms} 251199518Sbms 252199518Sbmsstatic void 253199518Sbmsfbt_suspend(void *arg, dtrace_id_t id, void *parg) 254199518Sbms{ 255199518Sbms fbt_probe_t *fbt = parg; 256199518Sbms modctl_t *ctl = fbt->fbtp_ctl; 257191672Sbms 258191672Sbms ASSERT(ctl->nenabled > 0); 259211301Sbz 260191672Sbms if ((ctl->loadcnt != fbt->fbtp_loadcnt)) 261191672Sbms return; 262191672Sbms 263186163Skmacy for (; fbt != NULL; fbt = fbt->fbtp_next) 26453541Sshin fbt_patch_tracepoint(fbt, fbt->fbtp_savedval); 26578064Sume} 266171167Sgnn 26778064Sumestatic void 26878064Sumefbt_resume(void *arg, dtrace_id_t id, void *parg) 26978064Sume{ 270125396Sume fbt_probe_t *fbt = parg; 27178064Sume modctl_t *ctl = fbt->fbtp_ctl; 272253571Sae 273180305Srwatson ASSERT(ctl->nenabled > 0); 274105199Ssam 275171167Sgnn if ((ctl->loadcnt != fbt->fbtp_loadcnt)) 27653541Sshin return; 277186223Sbz 278186141Sbz for (; fbt != NULL; fbt = fbt->fbtp_next) 279121674Sume fbt_patch_tracepoint(fbt, fbt->fbtp_patchval); 28053541Sshin} 28153541Sshin 282186141Sbzstatic int 283121901Sumefbt_ctfoff_init(modctl_t *lf, linker_ctf_t *lc) 28453541Sshin{ 28553541Sshin const Elf_Sym *symp = lc->symtab;; 28653541Sshin const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab; 28753541Sshin const uint8_t *ctfdata = lc->ctftab + sizeof(ctf_header_t); 288252007Sae int i; 28997658Stanimura uint32_t *ctfoff; 290186141Sbz uint32_t objtoff = hp->cth_objtoff; 29153541Sshin uint32_t funcoff = hp->cth_funcoff; 29253541Sshin ushort_t info; 293178377Srwatson ushort_t vlen; 29453541Sshin 29553541Sshin /* Sanity check. */ 29653541Sshin if (hp->cth_magic != CTF_MAGIC) { 297181803Sbz printf("Bad magic value in CTF data of '%s'\n",lf->pathname); 298171167Sgnn return (EINVAL); 29978064Sume } 30078064Sume 30178064Sume if (lc->symtab == NULL) { 302186170Skmacy printf("No symbol table in '%s'\n",lf->pathname); 30378064Sume return (EINVAL); 304253571Sae } 305249294Sae 306180305Srwatson if ((ctfoff = malloc(sizeof(uint32_t) * lc->nsym, M_LINKER, M_WAITOK)) == NULL) 307178377Srwatson return (ENOMEM); 308105199Ssam 309171167Sgnn *lc->ctfoffp = ctfoff; 310186163Skmacy 311186223Sbz for (i = 0; i < lc->nsym; i++, ctfoff++, symp++) { 312186141Sbz if (symp->st_name == 0 || symp->st_shndx == SHN_UNDEF) { 313121674Sume *ctfoff = 0xffffffff; 314180305Srwatson continue; 31553541Sshin } 316186141Sbz 317180305Srwatson switch (ELF_ST_TYPE(symp->st_info)) { 31853541Sshin case STT_OBJECT: 31953541Sshin if (objtoff >= hp->cth_funcoff || 32053541Sshin (symp->st_shndx == SHN_ABS && symp->st_value == 0)) { 321252007Sae *ctfoff = 0xffffffff; 32297658Stanimura break; 323186141Sbz } 324178377Srwatson 32553541Sshin *ctfoff = objtoff; 326252007Sae objtoff += sizeof (ushort_t); 32778064Sume break; 328252007Sae 32953541Sshin case STT_FUNC: 33053541Sshin if (funcoff >= hp->cth_typeoff) { 331329158Sae *ctfoff = 0xffffffff; 33253541Sshin break; 333180305Srwatson } 334329158Sae 335249294Sae *ctfoff = funcoff; 33653541Sshin 337180305Srwatson info = *((const ushort_t *)(ctfdata + funcoff)); 33853541Sshin vlen = CTF_INFO_VLEN(info); 33953541Sshin 34062587Sitojun /* 341171259Sdelphij * If we encounter a zero pad at the end, just skip it. 34262587Sitojun * Otherwise skip over the function and its return type 34362587Sitojun * (+2) and the argument list (vlen). 34462587Sitojun */ 34562587Sitojun if (CTF_INFO_KIND(info) == CTF_K_UNKNOWN && vlen == 0) 34678064Sume funcoff += sizeof (ushort_t); /* skip pad */ 34778064Sume else 348125776Sume funcoff += sizeof (ushort_t) * (vlen + 2); 349175162Sobrien break; 35062587Sitojun 35162587Sitojun default: 35262587Sitojun *ctfoff = 0xffffffff; 35362587Sitojun break; 35462587Sitojun } 35562587Sitojun } 35662587Sitojun 35762587Sitojun return (0); 35862587Sitojun} 35962587Sitojun 36062587Sitojunstatic ssize_t 36162587Sitojunfbt_get_ctt_size(uint8_t version, const ctf_type_t *tp, ssize_t *sizep, 36262587Sitojun ssize_t *incrementp) 36362587Sitojun{ 364180305Srwatson ssize_t size, increment; 365180305Srwatson 366180305Srwatson if (version > CTF_VERSION_1 && 36762587Sitojun tp->ctt_size == CTF_LSIZE_SENT) { 36878064Sume size = CTF_TYPE_LSIZE(tp); 36962587Sitojun increment = sizeof (ctf_type_t); 37062587Sitojun } else { 37162587Sitojun size = tp->ctt_size; 372125776Sume increment = sizeof (ctf_stype_t); 37378064Sume } 37462587Sitojun 37562587Sitojun if (sizep) 37662587Sitojun *sizep = size; 377125776Sume if (incrementp) 37878064Sume *incrementp = increment; 37962587Sitojun 38062587Sitojun return (size); 381181803Sbz} 382180305Srwatson 38362587Sitojunstatic int 38462587Sitojunfbt_typoff_init(linker_ctf_t *lc) 38553541Sshin{ 386180305Srwatson const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab; 387180305Srwatson const ctf_type_t *tbuf; 38853541Sshin const ctf_type_t *tend; 38953541Sshin const ctf_type_t *tp; 39053541Sshin const uint8_t *ctfdata = lc->ctftab + sizeof(ctf_header_t); 39153541Sshin int ctf_typemax = 0; 39253541Sshin uint32_t *xp; 39353541Sshin ulong_t pop[CTF_K_MAX + 1] = { 0 }; 39453541Sshin 39553541Sshin 39653541Sshin /* Sanity check. */ 39753541Sshin if (hp->cth_magic != CTF_MAGIC) 398120941Sume return (EINVAL); 399211501Sanchie 40053541Sshin tbuf = (const ctf_type_t *) (ctfdata + hp->cth_typeoff); 40153541Sshin tend = (const ctf_type_t *) (ctfdata + hp->cth_stroff); 40253541Sshin 40353541Sshin int child = hp->cth_parname != 0; 40453541Sshin 40553541Sshin /* 40653541Sshin * We make two passes through the entire type section. In this first 407148247Sume * pass, we count the number of each type and the total number of types. 40853541Sshin */ 40953541Sshin for (tp = tbuf; tp < tend; ctf_typemax++) { 410148385Sume ushort_t kind = CTF_INFO_KIND(tp->ctt_info); 411211435Sume ulong_t vlen = CTF_INFO_VLEN(tp->ctt_info); 412194777Sbz ssize_t size, increment; 41353541Sshin 41453541Sshin size_t vbytes; 41553541Sshin uint_t n; 41653541Sshin 41753541Sshin (void) fbt_get_ctt_size(hp->cth_version, tp, &size, &increment); 41853541Sshin 41953541Sshin switch (kind) { 42053541Sshin case CTF_K_INTEGER: 421186141Sbz case CTF_K_FLOAT: 422178285Srwatson vbytes = sizeof (uint_t); 42353541Sshin break; 42453541Sshin case CTF_K_ARRAY: 425186170Skmacy vbytes = sizeof (ctf_array_t); 426148242Sume break; 427175630Sbz case CTF_K_FUNCTION: 428175630Sbz vbytes = sizeof (ushort_t) * (vlen + (vlen & 1)); 42953541Sshin break; 430121472Sume case CTF_K_STRUCT: 431148247Sume case CTF_K_UNION: 432148247Sume if (size < CTF_LSTRUCT_THRESH) { 433148247Sume ctf_member_t *mp = (ctf_member_t *) 43453541Sshin ((uintptr_t)tp + increment); 43553541Sshin 436148385Sume vbytes = sizeof (ctf_member_t) * vlen; 437180305Srwatson for (n = vlen; n != 0; n--, mp++) 438148385Sume child |= CTF_TYPE_ISCHILD(mp->ctm_type); 439148385Sume } else { 440148385Sume ctf_lmember_t *lmp = (ctf_lmember_t *) 441211530Sume ((uintptr_t)tp + increment); 442211530Sume 443211435Sume vbytes = sizeof (ctf_lmember_t) * vlen; 444211435Sume for (n = vlen; n != 0; n--, lmp++) 445148385Sume child |= 446211435Sume CTF_TYPE_ISCHILD(lmp->ctlm_type); 447148385Sume } 448148385Sume break; 449148385Sume case CTF_K_ENUM: 450148385Sume vbytes = sizeof (ctf_enum_t) * vlen; 451180305Srwatson break; 452180305Srwatson case CTF_K_FORWARD: 45353541Sshin /* 45453541Sshin * For forward declarations, ctt_type is the CTF_K_* 45553541Sshin * kind for the tag, so bump that population count too. 45653541Sshin * If ctt_type is unknown, treat the tag as a struct. 45753541Sshin */ 45853541Sshin if (tp->ctt_type == CTF_K_UNKNOWN || 45953541Sshin tp->ctt_type >= CTF_K_MAX) 46053541Sshin pop[CTF_K_STRUCT]++; 46153541Sshin else 46253541Sshin pop[tp->ctt_type]++; 46353541Sshin /*FALLTHRU*/ 46453541Sshin case CTF_K_UNKNOWN: 46553541Sshin vbytes = 0; 466243882Sglebius break; 467133592Srwatson case CTF_K_POINTER: 468133592Srwatson case CTF_K_TYPEDEF: 469133592Srwatson case CTF_K_VOLATILE: 470133592Srwatson case CTF_K_CONST: 47153541Sshin case CTF_K_RESTRICT: 47253541Sshin child |= CTF_TYPE_ISCHILD(tp->ctt_type); 47353541Sshin vbytes = 0; 47453541Sshin break; 47553541Sshin default: 476194777Sbz printf("%s(%d): detected invalid CTF kind -- %u\n", __func__, __LINE__, kind); 477194777Sbz return (EIO); 478194777Sbz } 479121472Sume tp = (ctf_type_t *)((uintptr_t)tp + increment + vbytes); 480207277Sbz pop[kind]++; 481188144Sjamie } 482188144Sjamie 483194777Sbz /* account for a sentinel value below */ 484148385Sume ctf_typemax++; 485148385Sume *lc->typlenp = ctf_typemax; 486148385Sume 487148385Sume if ((xp = malloc(sizeof(uint32_t) * ctf_typemax, M_LINKER, M_ZERO | M_WAITOK)) == NULL) 488148385Sume return (ENOMEM); 489148385Sume 490148385Sume *lc->typoffp = xp; 491148385Sume 492148385Sume /* type id 0 is used as a sentinel value */ 493148385Sume *xp++ = 0; 494148385Sume 495148385Sume /* 496148385Sume * In the second pass, fill in the type offset. 497148385Sume */ 498148385Sume for (tp = tbuf; tp < tend; xp++) { 499148385Sume ushort_t kind = CTF_INFO_KIND(tp->ctt_info); 500180305Srwatson ulong_t vlen = CTF_INFO_VLEN(tp->ctt_info); 501180305Srwatson ssize_t size, increment; 502180305Srwatson 50355009Sshin size_t vbytes; 504186141Sbz uint_t n; 50555009Sshin 506180305Srwatson (void) fbt_get_ctt_size(hp->cth_version, tp, &size, &increment); 507180305Srwatson 508180305Srwatson switch (kind) { 509180305Srwatson case CTF_K_INTEGER: 510180305Srwatson case CTF_K_FLOAT: 511186141Sbz vbytes = sizeof (uint_t); 51253541Sshin break; 51353541Sshin case CTF_K_ARRAY: 51453541Sshin vbytes = sizeof (ctf_array_t); 51553541Sshin break; 51653541Sshin case CTF_K_FUNCTION: 51753541Sshin vbytes = sizeof (ushort_t) * (vlen + (vlen & 1)); 51853541Sshin break; 51953541Sshin case CTF_K_STRUCT: 520180305Srwatson case CTF_K_UNION: 52153541Sshin if (size < CTF_LSTRUCT_THRESH) { 52253541Sshin ctf_member_t *mp = (ctf_member_t *) 52353541Sshin ((uintptr_t)tp + increment); 52453541Sshin 52553541Sshin vbytes = sizeof (ctf_member_t) * vlen; 52653541Sshin for (n = vlen; n != 0; n--, mp++) 52753541Sshin child |= CTF_TYPE_ISCHILD(mp->ctm_type); 52853541Sshin } else { 52953541Sshin ctf_lmember_t *lmp = (ctf_lmember_t *) 53053541Sshin ((uintptr_t)tp + increment); 53153541Sshin 53253541Sshin vbytes = sizeof (ctf_lmember_t) * vlen; 53353541Sshin for (n = vlen; n != 0; n--, lmp++) 53453541Sshin child |= 53553541Sshin CTF_TYPE_ISCHILD(lmp->ctlm_type); 53653541Sshin } 53753541Sshin break; 53853541Sshin case CTF_K_ENUM: 53953541Sshin vbytes = sizeof (ctf_enum_t) * vlen; 54053541Sshin break; 54153541Sshin case CTF_K_FORWARD: 54253541Sshin case CTF_K_UNKNOWN: 543211501Sanchie vbytes = 0; 544211501Sanchie break; 545211501Sanchie case CTF_K_POINTER: 546211501Sanchie case CTF_K_TYPEDEF: 547211501Sanchie case CTF_K_VOLATILE: 548211501Sanchie case CTF_K_CONST: 549211501Sanchie case CTF_K_RESTRICT: 550211501Sanchie vbytes = 0; 551211501Sanchie break; 552211501Sanchie default: 553211501Sanchie printf("%s(%d): detected invalid CTF kind -- %u\n", __func__, __LINE__, kind); 554211501Sanchie return (EIO); 555211501Sanchie } 556211501Sanchie *xp = (uint32_t)((uintptr_t) tp - (uintptr_t) ctfdata); 557211501Sanchie tp = (ctf_type_t *)((uintptr_t)tp + increment + vbytes); 558211501Sanchie } 559211501Sanchie 560148247Sume return (0); 56153541Sshin} 56253541Sshin 56353541Sshin/* 564190964Srwatson * CTF Declaration Stack 56578064Sume * 566252007Sae * In order to implement ctf_type_name(), we must convert a type graph back 56753541Sshin * into a C type declaration. Unfortunately, a type graph represents a storage 56853541Sshin * class ordering of the type whereas a type declaration must obey the C rules 56953541Sshin * for operator precedence, and the two orderings are frequently in conflict. 57053541Sshin * For example, consider these CTF type graphs and their C declarations: 57153541Sshin * 57253541Sshin * CTF_K_POINTER -> CTF_K_FUNCTION -> CTF_K_INTEGER : int (*)() 57353541Sshin * CTF_K_POINTER -> CTF_K_ARRAY -> CTF_K_INTEGER : int (*)[] 57453541Sshin * 575186170Skmacy * In each case, parentheses are used to raise operator * to higher lexical 576148247Sume * precedence, so the string form of the C declaration cannot be constructed by 57753541Sshin * walking the type graph links and forming the string from left to right. 57878064Sume * 579178285Srwatson * The functions in this file build a set of stacks from the type graph nodes 580120856Sume * corresponding to the C operator precedence levels in the appropriate order. 58153541Sshin * The code in ctf_type_name() can then iterate over the levels and nodes in 58253541Sshin * lexical precedence order and construct the final C declaration string. 58353541Sshin */ 58453541Sshintypedef struct ctf_list { 58553541Sshin struct ctf_list *l_prev; /* previous pointer or tail pointer */ 58653541Sshin struct ctf_list *l_next; /* next pointer or head pointer */ 587171259Sdelphij} ctf_list_t; 58853541Sshin 589231852Sbz#define ctf_list_prev(elem) ((void *)(((ctf_list_t *)(elem))->l_prev)) 59053541Sshin#define ctf_list_next(elem) ((void *)(((ctf_list_t *)(elem))->l_next)) 59153541Sshin 59253541Sshintypedef enum { 59353541Sshin CTF_PREC_BASE, 59453541Sshin CTF_PREC_POINTER, 59553541Sshin CTF_PREC_ARRAY, 59653541Sshin CTF_PREC_FUNCTION, 597120856Sume CTF_PREC_MAX 598231852Sbz} ctf_decl_prec_t; 599231852Sbz 600231852Sbztypedef struct ctf_decl_node { 601231852Sbz ctf_list_t cd_list; /* linked list pointers */ 602231852Sbz ctf_id_t cd_type; /* type identifier */ 603231852Sbz uint_t cd_kind; /* type kind */ 604231852Sbz uint_t cd_n; /* type dimension if array */ 605231852Sbz} ctf_decl_node_t; 606231852Sbz 60753541Sshintypedef struct ctf_decl { 608231852Sbz ctf_list_t cd_nodes[CTF_PREC_MAX]; /* declaration node stacks */ 60953541Sshin int cd_order[CTF_PREC_MAX]; /* storage order of decls */ 61053541Sshin ctf_decl_prec_t cd_qualp; /* qualifier precision */ 61153541Sshin ctf_decl_prec_t cd_ordp; /* ordered precision */ 61253541Sshin char *cd_buf; /* buffer for output */ 61353541Sshin char *cd_ptr; /* buffer location */ 61453541Sshin char *cd_end; /* buffer limit */ 61556723Sshin size_t cd_len; /* buffer space required */ 61656723Sshin int cd_err; /* saved error value */ 61756723Sshin} ctf_decl_t; 61856723Sshin 61956723Sshin/* 62056723Sshin * Simple doubly-linked list append routine. This implementation assumes that 62156723Sshin * each list element contains an embedded ctf_list_t as the first member. 622166938Sbms * An additional ctf_list_t is used to store the head (l_next) and tail 623166938Sbms * (l_prev) pointers. The current head and tail list elements have their 62456723Sshin * previous and next pointers set to NULL, respectively. 625121578Sume */ 626121578Sumestatic void 627121578Sumectf_list_append(ctf_list_t *lp, void *new) 62853541Sshin{ 62953541Sshin ctf_list_t *p = lp->l_prev; /* p = tail list element */ 63053541Sshin ctf_list_t *q = new; /* q = new list element */ 63153541Sshin 63253541Sshin lp->l_prev = q; 63353541Sshin q->l_prev = p; 63453541Sshin q->l_next = NULL; 63553541Sshin 63656723Sshin if (p != NULL) 63756723Sshin p->l_next = q; 63856723Sshin else 63956723Sshin lp->l_next = q; 64056723Sshin} 64156723Sshin 64256723Sshin/* 643166938Sbms * Prepend the specified existing element to the given ctf_list_t. The 644166938Sbms * existing pointer should be pointing at a struct with embedded ctf_list_t. 64556723Sshin */ 646121578Sumestatic void 647121578Sumectf_list_prepend(ctf_list_t *lp, void *new) 648121578Sume{ 64953541Sshin ctf_list_t *p = new; /* p = new list element */ 65053541Sshin ctf_list_t *q = lp->l_next; /* q = head list element */ 65153541Sshin 65253541Sshin lp->l_next = p; 65353541Sshin p->l_prev = NULL; 65453541Sshin p->l_next = q; 65553541Sshin 65653541Sshin if (q != NULL) 65753541Sshin q->l_prev = p; 65853541Sshin else 65953541Sshin lp->l_prev = p; 66083366Sjulian} 66153541Sshin 66253541Sshinstatic void 663144261Ssamctf_decl_init(ctf_decl_t *cd, char *buf, size_t len) 664157676Srwatson{ 66553541Sshin int i; 66653541Sshin 667157374Srwatson bzero(cd, sizeof (ctf_decl_t)); 668180305Srwatson 669175630Sbz for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++) 670175630Sbz cd->cd_order[i] = CTF_PREC_BASE - 1; 671180305Srwatson 67255009Sshin cd->cd_qualp = CTF_PREC_BASE; 673157374Srwatson cd->cd_ordp = CTF_PREC_BASE; 674180305Srwatson 675184214Sdes cd->cd_buf = buf; 676157374Srwatson cd->cd_ptr = buf; 677180305Srwatson cd->cd_end = buf + len; 678181803Sbz} 679181803Sbz 680132714Srwatsonstatic void 681181803Sbzctf_decl_fini(ctf_decl_t *cd) 682184205Sdes{ 683180305Srwatson ctf_decl_node_t *cdp, *ndp; 684132714Srwatson int i; 68553541Sshin 686181803Sbz for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++) { 68753541Sshin for (cdp = ctf_list_next(&cd->cd_nodes[i]); 688186141Sbz cdp != NULL; cdp = ndp) { 68953541Sshin ndp = ctf_list_next(cdp); 69053541Sshin free(cdp, M_FBT); 691144261Ssam } 69253541Sshin } 693178285Srwatson} 694180305Srwatson 69553541Sshinstatic const ctf_type_t * 69653541Sshinctf_lookup_by_id(linker_ctf_t *lc, ctf_id_t type) 697157370Srwatson{ 69853541Sshin const ctf_type_t *tp; 69953541Sshin uint32_t offset; 70053541Sshin uint32_t *typoff = *lc->typoffp; 70153541Sshin 70253541Sshin if (type >= *lc->typlenp) { 703157374Srwatson printf("%s(%d): type %d exceeds max %ld\n",__func__,__LINE__,(int) type,*lc->typlenp); 704160549Srwatson return(NULL); 705191672Sbms } 706166938Sbms 70753541Sshin /* Check if the type isn't cross-referenced. */ 708181803Sbz if ((offset = typoff[type]) == 0) { 709178285Srwatson printf("%s(%d): type %d isn't cross referenced\n",__func__,__LINE__, (int) type); 710184205Sdes return(NULL); 711185344Sbz } 712185370Sbz 713181803Sbz tp = (const ctf_type_t *)(lc->ctftab + offset + sizeof(ctf_header_t)); 71453541Sshin 71553541Sshin return (tp); 716160549Srwatson} 717157366Srwatson 71853541Sshinstatic void 71953541Sshinfbt_array_info(linker_ctf_t *lc, ctf_id_t type, ctf_arinfo_t *arp) 720160549Srwatson{ 721160549Srwatson const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab; 722160549Srwatson const ctf_type_t *tp; 723160549Srwatson const ctf_array_t *ap; 724160549Srwatson ssize_t increment; 72553541Sshin 72653541Sshin bzero(arp, sizeof(*arp)); 72753541Sshin 728160549Srwatson if ((tp = ctf_lookup_by_id(lc, type)) == NULL) 729160549Srwatson return; 730160549Srwatson 731160549Srwatson if (CTF_INFO_KIND(tp->ctt_info) != CTF_K_ARRAY) 732160549Srwatson return; 733160549Srwatson 734160549Srwatson (void) fbt_get_ctt_size(hp->cth_version, tp, NULL, &increment); 735160549Srwatson 736160549Srwatson ap = (const ctf_array_t *)((uintptr_t)tp + increment); 737160549Srwatson arp->ctr_contents = ap->cta_contents; 738160549Srwatson arp->ctr_index = ap->cta_index; 73953541Sshin arp->ctr_nelems = ap->cta_nelems; 74053541Sshin} 74153541Sshin 742180305Srwatsonstatic const char * 74353541Sshinctf_strptr(linker_ctf_t *lc, int name) 744180305Srwatson{ 745180305Srwatson const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab;; 746180305Srwatson const char *strp = ""; 74797658Stanimura 748180305Srwatson if (name < 0 || name >= hp->cth_strlen) 74953541Sshin return(strp); 750157366Srwatson 751157374Srwatson strp = (const char *)(lc->ctftab + hp->cth_stroff + name + sizeof(ctf_header_t)); 75253541Sshin 75353541Sshin return (strp); 75453541Sshin} 75583366Sjulian 75653541Sshinstatic void 757180305Srwatsonctf_decl_push(ctf_decl_t *cd, linker_ctf_t *lc, ctf_id_t type) 75853541Sshin{ 759194760Srwatson ctf_decl_node_t *cdp; 760148385Sume ctf_decl_prec_t prec; 76153541Sshin uint_t kind, n = 1; 762180305Srwatson int is_qual = 0; 763157374Srwatson 764180305Srwatson const ctf_type_t *tp; 76553541Sshin ctf_arinfo_t ar; 766180305Srwatson 767188144Sjamie if ((tp = ctf_lookup_by_id(lc, type)) == NULL) { 768188144Sjamie cd->cd_err = ENOENT; 769181803Sbz return; 770180305Srwatson } 771181803Sbz 772180305Srwatson switch (kind = CTF_INFO_KIND(tp->ctt_info)) { 773148385Sume case CTF_K_ARRAY: 77453541Sshin fbt_array_info(lc, type, &ar); 775194760Srwatson ctf_decl_push(cd, lc, ar.ctr_contents); 776180305Srwatson n = ar.ctr_nelems; 777194760Srwatson prec = CTF_PREC_ARRAY; 778194760Srwatson break; 77953541Sshin 78053541Sshin case CTF_K_TYPEDEF: 781194760Srwatson if (ctf_strptr(lc, tp->ctt_name)[0] == '\0') { 782120856Sume ctf_decl_push(cd, lc, tp->ctt_type); 78353541Sshin return; 784194760Srwatson } 785194760Srwatson prec = CTF_PREC_BASE; 786181803Sbz break; 787178285Srwatson 78853541Sshin case CTF_K_FUNCTION: 789178285Srwatson ctf_decl_push(cd, lc, tp->ctt_type); 790181803Sbz prec = CTF_PREC_FUNCTION; 791180305Srwatson break; 79253541Sshin 79353541Sshin case CTF_K_POINTER: 79453541Sshin ctf_decl_push(cd, lc, tp->ctt_type); 79583366Sjulian prec = CTF_PREC_POINTER; 79653541Sshin break; 797180305Srwatson 79853541Sshin case CTF_K_VOLATILE: 799194777Sbz case CTF_K_CONST: 800148385Sume case CTF_K_RESTRICT: 801148385Sume ctf_decl_push(cd, lc, tp->ctt_type); 80253541Sshin prec = cd->cd_qualp; 803180305Srwatson is_qual++; 804157374Srwatson break; 805180305Srwatson 80653541Sshin default: 807180305Srwatson prec = CTF_PREC_BASE; 808181803Sbz } 809180305Srwatson 81053541Sshin if ((cdp = malloc(sizeof (ctf_decl_node_t), M_FBT, M_WAITOK)) == NULL) { 811180305Srwatson cd->cd_err = EAGAIN; 812148385Sume return; 813148385Sume } 814180305Srwatson 815180305Srwatson cdp->cd_type = type; 816180305Srwatson cdp->cd_kind = kind; 817180305Srwatson cdp->cd_n = n; 818180305Srwatson 819180305Srwatson if (ctf_list_next(&cd->cd_nodes[prec]) == NULL) 820148385Sume cd->cd_order[prec] = cd->cd_ordp++; 821181803Sbz 822148385Sume /* 823181803Sbz * Reset cd_qualp to the highest precedence level that we've seen so 824180305Srwatson * far that can be qualified (CTF_PREC_BASE or CTF_PREC_POINTER). 825148385Sume */ 826181803Sbz if (prec > cd->cd_qualp && prec < CTF_PREC_ARRAY) 827178285Srwatson cd->cd_qualp = prec; 82853541Sshin 829194777Sbz /* 830194777Sbz * C array declarators are ordered inside out so prepend them. Also by 831194777Sbz * convention qualifiers of base types precede the type specifier (e.g. 832178285Srwatson * const int vs. int const) even though the two forms are equivalent. 833181803Sbz */ 834194777Sbz if (kind == CTF_K_ARRAY || (is_qual && prec == CTF_PREC_BASE)) 835132714Srwatson ctf_list_prepend(&cd->cd_nodes[prec], cdp); 836148385Sume else 837148385Sume ctf_list_append(&cd->cd_nodes[prec], cdp); 838148385Sume} 839148385Sume 840178285Srwatsonstatic void 841181803Sbzctf_decl_sprintf(ctf_decl_t *cd, const char *format, ...) 842180305Srwatson{ 843148385Sume size_t len = (size_t)(cd->cd_end - cd->cd_ptr); 844148385Sume va_list ap; 845194777Sbz size_t n; 84653541Sshin 847178285Srwatson va_start(ap, format); 848181803Sbz n = vsnprintf(cd->cd_ptr, len, format, ap); 849180305Srwatson va_end(ap); 85053541Sshin 85153541Sshin cd->cd_ptr += MIN(n, len); 85253541Sshin cd->cd_len += n; 85353541Sshin} 85453541Sshin 855132714Srwatsonstatic ssize_t 856132714Srwatsonfbt_type_name(linker_ctf_t *lc, ctf_id_t type, char *buf, size_t len) 857132714Srwatson{ 858157374Srwatson ctf_decl_t cd; 859180305Srwatson ctf_decl_node_t *cdp; 860178285Srwatson ctf_decl_prec_t prec, lp, rp; 86153541Sshin int ptr, arr; 862178285Srwatson uint_t k; 863180305Srwatson 86453541Sshin if (lc == NULL && type == CTF_ERR) 86553541Sshin return (-1); /* simplify caller code by permitting CTF_ERR */ 86653541Sshin 86753541Sshin ctf_decl_init(&cd, buf, len); 868171260Sdelphij ctf_decl_push(&cd, lc, type); 86953541Sshin 870180305Srwatson if (cd.cd_err != 0) { 87153541Sshin ctf_decl_fini(&cd); 87253541Sshin return (-1); 873132714Srwatson } 87453541Sshin 875180305Srwatson /* 876157374Srwatson * If the type graph's order conflicts with lexical precedence order 877180305Srwatson * for pointers or arrays, then we need to surround the declarations at 878180305Srwatson * the corresponding lexical precedence with parentheses. This can 879132714Srwatson * result in either a parenthesized pointer (*) as in int (*)() or 88053541Sshin * int (*)[], or in a parenthesized pointer and array as in int (*[])(). 88153541Sshin */ 88253541Sshin ptr = cd.cd_order[CTF_PREC_POINTER] > CTF_PREC_POINTER; 883180305Srwatson arr = cd.cd_order[CTF_PREC_ARRAY] > CTF_PREC_ARRAY; 88453541Sshin 88553541Sshin rp = arr ? CTF_PREC_ARRAY : ptr ? CTF_PREC_POINTER : -1; 88653541Sshin lp = ptr ? CTF_PREC_POINTER : arr ? CTF_PREC_ARRAY : -1; 88753541Sshin 88853541Sshin k = CTF_K_POINTER; /* avoid leading whitespace (see below) */ 889180990Srwatson 89053541Sshin for (prec = CTF_PREC_BASE; prec < CTF_PREC_MAX; prec++) { 891180990Srwatson for (cdp = ctf_list_next(&cd.cd_nodes[prec]); 892180990Srwatson cdp != NULL; cdp = ctf_list_next(cdp)) { 89353541Sshin 89453541Sshin const ctf_type_t *tp = 89553541Sshin ctf_lookup_by_id(lc, cdp->cd_type); 89653541Sshin const char *name = ctf_strptr(lc, tp->ctt_name); 897180305Srwatson 89853541Sshin if (k != CTF_K_POINTER && k != CTF_K_ARRAY) 899148385Sume ctf_decl_sprintf(&cd, " "); 900148385Sume 901180305Srwatson if (lp == prec) { 902148385Sume ctf_decl_sprintf(&cd, "("); 90362587Sitojun lp = -1; 90462587Sitojun } 905148385Sume 906148385Sume switch (cdp->cd_kind) { 907148385Sume case CTF_K_INTEGER: 908148385Sume case CTF_K_FLOAT: 909148385Sume case CTF_K_TYPEDEF: 910148385Sume ctf_decl_sprintf(&cd, "%s", name); 911148385Sume break; 912148385Sume case CTF_K_POINTER: 913148385Sume ctf_decl_sprintf(&cd, "*"); 914148385Sume break; 915148385Sume case CTF_K_ARRAY: 916148385Sume ctf_decl_sprintf(&cd, "[%u]", cdp->cd_n); 917148385Sume break; 918148385Sume case CTF_K_FUNCTION: 91953541Sshin ctf_decl_sprintf(&cd, "()"); 920132714Srwatson break; 921132714Srwatson case CTF_K_STRUCT: 92253541Sshin case CTF_K_FORWARD: 92353541Sshin ctf_decl_sprintf(&cd, "struct %s", name); 92453541Sshin break; 925137386Sphk case CTF_K_UNION: 926137386Sphk ctf_decl_sprintf(&cd, "union %s", name); 927137386Sphk break; 928137386Sphk case CTF_K_ENUM: 929137386Sphk ctf_decl_sprintf(&cd, "enum %s", name); 930137386Sphk break; 931137386Sphk case CTF_K_VOLATILE: 932169462Srwatson ctf_decl_sprintf(&cd, "volatile"); 933137386Sphk break; 934137386Sphk case CTF_K_CONST: 935169462Srwatson ctf_decl_sprintf(&cd, "const"); 936160549Srwatson break; 93753541Sshin case CTF_K_RESTRICT: 938 ctf_decl_sprintf(&cd, "restrict"); 939 break; 940 } 941 942 k = cdp->cd_kind; 943 } 944 945 if (rp == prec) 946 ctf_decl_sprintf(&cd, ")"); 947 } 948 949 ctf_decl_fini(&cd); 950 return (cd.cd_len); 951} 952 953static void 954fbt_getargdesc(void *arg __unused, dtrace_id_t id __unused, void *parg, dtrace_argdesc_t *desc) 955{ 956 const ushort_t *dp; 957 fbt_probe_t *fbt = parg; 958 linker_ctf_t lc; 959 modctl_t *ctl = fbt->fbtp_ctl; 960 int ndx = desc->dtargd_ndx; 961 int symindx = fbt->fbtp_symindx; 962 uint32_t *ctfoff; 963 uint32_t offset; 964 ushort_t info, kind, n; 965 966 if (fbt->fbtp_roffset != 0 && desc->dtargd_ndx == 0) { 967 (void) strcpy(desc->dtargd_native, "int"); 968 return; 969 } 970 971 desc->dtargd_ndx = DTRACE_ARGNONE; 972 973 /* Get a pointer to the CTF data and it's length. */ 974 if (linker_ctf_get(ctl, &lc) != 0) 975 /* No CTF data? Something wrong? *shrug* */ 976 return; 977 978 /* Check if this module hasn't been initialised yet. */ 979 if (*lc.ctfoffp == NULL) { 980 /* 981 * Initialise the CTF object and function symindx to 982 * byte offset array. 983 */ 984 if (fbt_ctfoff_init(ctl, &lc) != 0) 985 return; 986 987 /* Initialise the CTF type to byte offset array. */ 988 if (fbt_typoff_init(&lc) != 0) 989 return; 990 } 991 992 ctfoff = *lc.ctfoffp; 993 994 if (ctfoff == NULL || *lc.typoffp == NULL) 995 return; 996 997 /* Check if the symbol index is out of range. */ 998 if (symindx >= lc.nsym) 999 return; 1000 1001 /* Check if the symbol isn't cross-referenced. */ 1002 if ((offset = ctfoff[symindx]) == 0xffffffff) 1003 return; 1004 1005 dp = (const ushort_t *)(lc.ctftab + offset + sizeof(ctf_header_t)); 1006 1007 info = *dp++; 1008 kind = CTF_INFO_KIND(info); 1009 n = CTF_INFO_VLEN(info); 1010 1011 if (kind == CTF_K_UNKNOWN && n == 0) { 1012 printf("%s(%d): Unknown function!\n",__func__,__LINE__); 1013 return; 1014 } 1015 1016 if (kind != CTF_K_FUNCTION) { 1017 printf("%s(%d): Expected a function!\n",__func__,__LINE__); 1018 return; 1019 } 1020 1021 if (fbt->fbtp_roffset != 0) { 1022 /* Only return type is available for args[1] in return probe. */ 1023 if (ndx > 1) 1024 return; 1025 ASSERT(ndx == 1); 1026 } else { 1027 /* Check if the requested argument doesn't exist. */ 1028 if (ndx >= n) 1029 return; 1030 1031 /* Skip the return type and arguments up to the one requested. */ 1032 dp += ndx + 1; 1033 } 1034 1035 if (fbt_type_name(&lc, *dp, desc->dtargd_native, sizeof(desc->dtargd_native)) > 0) 1036 desc->dtargd_ndx = ndx; 1037 1038 return; 1039} 1040 1041static int 1042fbt_linker_file_cb(linker_file_t lf, void *arg) 1043{ 1044 1045 fbt_provide_module(arg, lf); 1046 1047 return (0); 1048} 1049 1050static void 1051fbt_load(void *dummy) 1052{ 1053 /* Create the /dev/dtrace/fbt entry. */ 1054 fbt_cdev = make_dev(&fbt_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, 1055 "dtrace/fbt"); 1056 1057 /* Default the probe table size if not specified. */ 1058 if (fbt_probetab_size == 0) 1059 fbt_probetab_size = FBT_PROBETAB_SIZE; 1060 1061 /* Choose the hash mask for the probe table. */ 1062 fbt_probetab_mask = fbt_probetab_size - 1; 1063 1064 /* Allocate memory for the probe table. */ 1065 fbt_probetab = 1066 malloc(fbt_probetab_size * sizeof (fbt_probe_t *), M_FBT, M_WAITOK | M_ZERO); 1067 1068 dtrace_doubletrap_func = fbt_doubletrap; 1069 dtrace_invop_add(fbt_invop); 1070 1071 if (dtrace_register("fbt", &fbt_attr, DTRACE_PRIV_USER, 1072 NULL, &fbt_pops, NULL, &fbt_id) != 0) 1073 return; 1074 1075 /* Create probes for the kernel and already-loaded modules. */ 1076 linker_file_foreach(fbt_linker_file_cb, NULL); 1077} 1078 1079static int 1080fbt_unload() 1081{ 1082 int error = 0; 1083 1084 /* De-register the invalid opcode handler. */ 1085 dtrace_invop_remove(fbt_invop); 1086 1087 dtrace_doubletrap_func = NULL; 1088 1089 /* De-register this DTrace provider. */ 1090 if ((error = dtrace_unregister(fbt_id)) != 0) 1091 return (error); 1092 1093 /* Free the probe table. */ 1094 free(fbt_probetab, M_FBT); 1095 fbt_probetab = NULL; 1096 fbt_probetab_mask = 0; 1097 1098 destroy_dev(fbt_cdev); 1099 1100 return (error); 1101} 1102 1103static int 1104fbt_modevent(module_t mod __unused, int type, void *data __unused) 1105{ 1106 int error = 0; 1107 1108 switch (type) { 1109 case MOD_LOAD: 1110 break; 1111 1112 case MOD_UNLOAD: 1113 break; 1114 1115 case MOD_SHUTDOWN: 1116 break; 1117 1118 default: 1119 error = EOPNOTSUPP; 1120 break; 1121 1122 } 1123 1124 return (error); 1125} 1126 1127static int 1128fbt_open(struct cdev *dev __unused, int oflags __unused, int devtype __unused, struct thread *td __unused) 1129{ 1130 return (0); 1131} 1132 1133SYSINIT(fbt_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, fbt_load, NULL); 1134SYSUNINIT(fbt_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, fbt_unload, NULL); 1135 1136DEV_MODULE(fbt, fbt_modevent, NULL); 1137MODULE_VERSION(fbt, 1); 1138MODULE_DEPEND(fbt, dtrace, 1, 1, 1); 1139MODULE_DEPEND(fbt, opensolaris, 1, 1, 1); 1140