191eaf3e1SJohn Birrell /* 291eaf3e1SJohn Birrell * CDDL HEADER START 391eaf3e1SJohn Birrell * 491eaf3e1SJohn Birrell * The contents of this file are subject to the terms of the 591eaf3e1SJohn Birrell * Common Development and Distribution License (the "License"). 691eaf3e1SJohn Birrell * You may not use this file except in compliance with the License. 791eaf3e1SJohn Birrell * 891eaf3e1SJohn Birrell * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 991eaf3e1SJohn Birrell * or http://www.opensolaris.org/os/licensing. 1091eaf3e1SJohn Birrell * See the License for the specific language governing permissions 1191eaf3e1SJohn Birrell * and limitations under the License. 1291eaf3e1SJohn Birrell * 1391eaf3e1SJohn Birrell * When distributing Covered Code, include this CDDL HEADER in each 1491eaf3e1SJohn Birrell * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1591eaf3e1SJohn Birrell * If applicable, add the following below this CDDL HEADER, with the 1691eaf3e1SJohn Birrell * fields enclosed by brackets "[]" replaced with your own identifying 1791eaf3e1SJohn Birrell * information: Portions Copyright [yyyy] [name of copyright owner] 1891eaf3e1SJohn Birrell * 1991eaf3e1SJohn Birrell * CDDL HEADER END 2091eaf3e1SJohn Birrell * 2191eaf3e1SJohn Birrell * Portions Copyright 2006-2008 John Birrell jb@freebsd.org 2291eaf3e1SJohn Birrell * 2391eaf3e1SJohn Birrell * $FreeBSD$ 2491eaf3e1SJohn Birrell * 2591eaf3e1SJohn Birrell */ 2691eaf3e1SJohn Birrell 2791eaf3e1SJohn Birrell /* 2891eaf3e1SJohn Birrell * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 2991eaf3e1SJohn Birrell * Use is subject to license terms. 3091eaf3e1SJohn Birrell */ 3191eaf3e1SJohn Birrell 3291eaf3e1SJohn Birrell #include <sys/cdefs.h> 3391eaf3e1SJohn Birrell #include <sys/param.h> 3491eaf3e1SJohn Birrell #include <sys/systm.h> 3591eaf3e1SJohn Birrell #include <sys/conf.h> 3691eaf3e1SJohn Birrell #include <sys/cpuvar.h> 379e5787d2SMatt Macy #include <sys/endian.h> 3891eaf3e1SJohn Birrell #include <sys/fcntl.h> 3991eaf3e1SJohn Birrell #include <sys/filio.h> 4091eaf3e1SJohn Birrell #include <sys/kdb.h> 4191eaf3e1SJohn Birrell #include <sys/kernel.h> 4291eaf3e1SJohn Birrell #include <sys/kmem.h> 4391eaf3e1SJohn Birrell #include <sys/kthread.h> 4491eaf3e1SJohn Birrell #include <sys/limits.h> 4591eaf3e1SJohn Birrell #include <sys/linker.h> 4691eaf3e1SJohn Birrell #include <sys/lock.h> 4791eaf3e1SJohn Birrell #include <sys/malloc.h> 4891eaf3e1SJohn Birrell #include <sys/module.h> 4991eaf3e1SJohn Birrell #include <sys/mutex.h> 5091eaf3e1SJohn Birrell #include <sys/pcpu.h> 5191eaf3e1SJohn Birrell #include <sys/poll.h> 5291eaf3e1SJohn Birrell #include <sys/proc.h> 5391eaf3e1SJohn Birrell #include <sys/selinfo.h> 5491eaf3e1SJohn Birrell #include <sys/smp.h> 5591eaf3e1SJohn Birrell #include <sys/syscall.h> 5691eaf3e1SJohn Birrell #include <sys/sysent.h> 5791eaf3e1SJohn Birrell #include <sys/sysproto.h> 5891eaf3e1SJohn Birrell #include <sys/uio.h> 5991eaf3e1SJohn Birrell #include <sys/unistd.h> 6091eaf3e1SJohn Birrell #include <machine/stdarg.h> 6191eaf3e1SJohn Birrell 6291eaf3e1SJohn Birrell #include <sys/dtrace.h> 6391eaf3e1SJohn Birrell #include <sys/dtrace_bsd.h> 6491eaf3e1SJohn Birrell 65266b4a78SMark Johnston #include "fbt.h" 6691eaf3e1SJohn Birrell 67266b4a78SMark Johnston MALLOC_DEFINE(M_FBT, "fbt", "Function Boundary Tracing"); 6891eaf3e1SJohn Birrell 69266b4a78SMark Johnston dtrace_provider_id_t fbt_id; 70266b4a78SMark Johnston fbt_probe_t **fbt_probetab; 71266b4a78SMark Johnston int fbt_probetab_mask; 7291eaf3e1SJohn Birrell 7391eaf3e1SJohn Birrell static d_open_t fbt_open; 7491eaf3e1SJohn Birrell static int fbt_unload(void); 7591eaf3e1SJohn Birrell static void fbt_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *); 7691eaf3e1SJohn Birrell static void fbt_provide_module(void *, modctl_t *); 7791eaf3e1SJohn Birrell static void fbt_destroy(void *, dtrace_id_t, void *); 7891eaf3e1SJohn Birrell static void fbt_enable(void *, dtrace_id_t, void *); 7991eaf3e1SJohn Birrell static void fbt_disable(void *, dtrace_id_t, void *); 8091eaf3e1SJohn Birrell static void fbt_load(void *); 8191eaf3e1SJohn Birrell static void fbt_suspend(void *, dtrace_id_t, void *); 8291eaf3e1SJohn Birrell static void fbt_resume(void *, dtrace_id_t, void *); 8391eaf3e1SJohn Birrell 8491eaf3e1SJohn Birrell static struct cdevsw fbt_cdevsw = { 8591eaf3e1SJohn Birrell .d_version = D_VERSION, 8691eaf3e1SJohn Birrell .d_open = fbt_open, 8791eaf3e1SJohn Birrell .d_name = "fbt", 8891eaf3e1SJohn Birrell }; 8991eaf3e1SJohn Birrell 9091eaf3e1SJohn Birrell static dtrace_pattr_t fbt_attr = { 9191eaf3e1SJohn Birrell { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, 9291eaf3e1SJohn Birrell { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, 9391eaf3e1SJohn Birrell { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, 9491eaf3e1SJohn Birrell { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, 9591eaf3e1SJohn Birrell { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, 9691eaf3e1SJohn Birrell }; 9791eaf3e1SJohn Birrell 9891eaf3e1SJohn Birrell static dtrace_pops_t fbt_pops = { 9947f11baaSMark Johnston .dtps_provide = NULL, 10047f11baaSMark Johnston .dtps_provide_module = fbt_provide_module, 10147f11baaSMark Johnston .dtps_enable = fbt_enable, 10247f11baaSMark Johnston .dtps_disable = fbt_disable, 10347f11baaSMark Johnston .dtps_suspend = fbt_suspend, 10447f11baaSMark Johnston .dtps_resume = fbt_resume, 10547f11baaSMark Johnston .dtps_getargdesc = fbt_getargdesc, 10647f11baaSMark Johnston .dtps_getargval = NULL, 10747f11baaSMark Johnston .dtps_usermode = NULL, 10847f11baaSMark Johnston .dtps_destroy = fbt_destroy 10991eaf3e1SJohn Birrell }; 11091eaf3e1SJohn Birrell 11191eaf3e1SJohn Birrell static struct cdev *fbt_cdev; 11291eaf3e1SJohn Birrell static int fbt_probetab_size; 11391eaf3e1SJohn Birrell static int fbt_verbose = 0; 11491eaf3e1SJohn Birrell 1150ff41755SRuslan Bukin int 1160ff41755SRuslan Bukin fbt_excluded(const char *name) 1170ff41755SRuslan Bukin { 1180ff41755SRuslan Bukin 1190ff41755SRuslan Bukin if (strncmp(name, "dtrace_", 7) == 0 && 1200ff41755SRuslan Bukin strncmp(name, "dtrace_safe_", 12) != 0) { 1210ff41755SRuslan Bukin /* 1220ff41755SRuslan Bukin * Anything beginning with "dtrace_" may be called 1230ff41755SRuslan Bukin * from probe context unless it explicitly indicates 1240ff41755SRuslan Bukin * that it won't be called from probe context by 1250ff41755SRuslan Bukin * using the prefix "dtrace_safe_". 1260ff41755SRuslan Bukin */ 1270ff41755SRuslan Bukin return (1); 1280ff41755SRuslan Bukin } 1290ff41755SRuslan Bukin 1300ff41755SRuslan Bukin /* 13130b68ecdSRobert Watson * Omit instrumentation of functions that are probably in DDB. It 13230b68ecdSRobert Watson * makes it too hard to debug broken FBT. 13330b68ecdSRobert Watson * 13430b68ecdSRobert Watson * NB: kdb_enter() can be excluded, but its call to printf() can't be. 13530b68ecdSRobert Watson * This is generally OK since we're not yet in debugging context. 13630b68ecdSRobert Watson */ 13730b68ecdSRobert Watson if (strncmp(name, "db_", 3) == 0 || 13830b68ecdSRobert Watson strncmp(name, "kdb_", 4) == 0) 13930b68ecdSRobert Watson return (1); 14030b68ecdSRobert Watson 14130b68ecdSRobert Watson /* 142f99a5172SMark Johnston * Lock owner methods may be called from probe context. 143f99a5172SMark Johnston */ 144f99a5172SMark Johnston if (strcmp(name, "owner_mtx") == 0 || 145f99a5172SMark Johnston strcmp(name, "owner_rm") == 0 || 146f99a5172SMark Johnston strcmp(name, "owner_rw") == 0 || 147f99a5172SMark Johnston strcmp(name, "owner_sx") == 0) 148f99a5172SMark Johnston return (1); 149f99a5172SMark Johnston 150f99a5172SMark Johnston /* 1519b9e7f4cSJohn Baldwin * Stack unwinders may be called from probe context on some 1529b9e7f4cSJohn Baldwin * platforms. 1539b9e7f4cSJohn Baldwin */ 154ae953968SJohn Baldwin #if defined(__aarch64__) || defined(__riscv) 1559b9e7f4cSJohn Baldwin if (strcmp(name, "unwind_frame") == 0) 1569b9e7f4cSJohn Baldwin return (1); 1579b9e7f4cSJohn Baldwin #endif 1589b9e7f4cSJohn Baldwin 1599b9e7f4cSJohn Baldwin /* 1600ff41755SRuslan Bukin * When DTrace is built into the kernel we need to exclude 1610ff41755SRuslan Bukin * the FBT functions from instrumentation. 1620ff41755SRuslan Bukin */ 1630ff41755SRuslan Bukin #ifndef _KLD_MODULE 1640ff41755SRuslan Bukin if (strncmp(name, "fbt_", 4) == 0) 1650ff41755SRuslan Bukin return (1); 1660ff41755SRuslan Bukin #endif 1670ff41755SRuslan Bukin 1680ff41755SRuslan Bukin return (0); 1690ff41755SRuslan Bukin } 1700ff41755SRuslan Bukin 17191eaf3e1SJohn Birrell static void 17291eaf3e1SJohn Birrell fbt_doubletrap(void) 17391eaf3e1SJohn Birrell { 17491eaf3e1SJohn Birrell fbt_probe_t *fbt; 17591eaf3e1SJohn Birrell int i; 17691eaf3e1SJohn Birrell 17791eaf3e1SJohn Birrell for (i = 0; i < fbt_probetab_size; i++) { 17891eaf3e1SJohn Birrell fbt = fbt_probetab[i]; 17991eaf3e1SJohn Birrell 180c208cb99SMark Johnston for (; fbt != NULL; fbt = fbt->fbtp_probenext) 18135127d3cSMark Johnston fbt_patch_tracepoint(fbt, fbt->fbtp_savedval); 18291eaf3e1SJohn Birrell } 18391eaf3e1SJohn Birrell } 18491eaf3e1SJohn Birrell 18591eaf3e1SJohn Birrell static void 18691eaf3e1SJohn Birrell fbt_provide_module(void *arg, modctl_t *lf) 18791eaf3e1SJohn Birrell { 18891eaf3e1SJohn Birrell char modname[MAXPATHLEN]; 18991eaf3e1SJohn Birrell int i; 19091eaf3e1SJohn Birrell size_t len; 19191eaf3e1SJohn Birrell 19291eaf3e1SJohn Birrell strlcpy(modname, lf->filename, sizeof(modname)); 19391eaf3e1SJohn Birrell len = strlen(modname); 19491eaf3e1SJohn Birrell if (len > 3 && strcmp(modname + len - 3, ".ko") == 0) 19591eaf3e1SJohn Birrell modname[len - 3] = '\0'; 19691eaf3e1SJohn Birrell 19791eaf3e1SJohn Birrell /* 19891eaf3e1SJohn Birrell * Employees of dtrace and their families are ineligible. Void 19991eaf3e1SJohn Birrell * where prohibited. 20091eaf3e1SJohn Birrell */ 20191eaf3e1SJohn Birrell if (strcmp(modname, "dtrace") == 0) 20291eaf3e1SJohn Birrell return; 20391eaf3e1SJohn Birrell 20491eaf3e1SJohn Birrell /* 20591eaf3e1SJohn Birrell * To register with DTrace, a module must list 'dtrace' as a 20691eaf3e1SJohn Birrell * dependency in order for the kernel linker to resolve 20791eaf3e1SJohn Birrell * symbols like dtrace_register(). All modules with such a 20891eaf3e1SJohn Birrell * dependency are ineligible for FBT tracing. 20991eaf3e1SJohn Birrell */ 21091eaf3e1SJohn Birrell for (i = 0; i < lf->ndeps; i++) 21191eaf3e1SJohn Birrell if (strncmp(lf->deps[i]->filename, "dtrace", 6) == 0) 21291eaf3e1SJohn Birrell return; 21391eaf3e1SJohn Birrell 21491eaf3e1SJohn Birrell if (lf->fbt_nentries) { 21591eaf3e1SJohn Birrell /* 21691eaf3e1SJohn Birrell * This module has some FBT entries allocated; we're afraid 21791eaf3e1SJohn Birrell * to screw with it. 21891eaf3e1SJohn Birrell */ 21991eaf3e1SJohn Birrell return; 22091eaf3e1SJohn Birrell } 22191eaf3e1SJohn Birrell 22291eaf3e1SJohn Birrell /* 22391eaf3e1SJohn Birrell * List the functions in the module and the symbol values. 22491eaf3e1SJohn Birrell */ 22591eaf3e1SJohn Birrell (void) linker_file_function_listall(lf, fbt_provide_module_function, modname); 22691eaf3e1SJohn Birrell } 22791eaf3e1SJohn Birrell 22891eaf3e1SJohn Birrell static void 229c208cb99SMark Johnston fbt_destroy_one(fbt_probe_t *fbt) 230c208cb99SMark Johnston { 231c208cb99SMark Johnston fbt_probe_t *hash, *hashprev, *next; 232c208cb99SMark Johnston int ndx; 233c208cb99SMark Johnston 234c208cb99SMark Johnston ndx = FBT_ADDR2NDX(fbt->fbtp_patchpoint); 235c208cb99SMark Johnston for (hash = fbt_probetab[ndx], hashprev = NULL; hash != NULL; 236a9d49f9eSMark Johnston hashprev = hash, hash = hash->fbtp_hashnext) { 237c208cb99SMark Johnston if (hash == fbt) { 238c208cb99SMark Johnston if ((next = fbt->fbtp_tracenext) != NULL) 239c208cb99SMark Johnston next->fbtp_hashnext = hash->fbtp_hashnext; 240c208cb99SMark Johnston else 241c208cb99SMark Johnston next = hash->fbtp_hashnext; 242c208cb99SMark Johnston if (hashprev != NULL) 243c208cb99SMark Johnston hashprev->fbtp_hashnext = next; 244c208cb99SMark Johnston else 245c208cb99SMark Johnston fbt_probetab[ndx] = next; 246c208cb99SMark Johnston goto free; 247c208cb99SMark Johnston } else if (hash->fbtp_patchpoint == fbt->fbtp_patchpoint) { 248c208cb99SMark Johnston for (next = hash; next->fbtp_tracenext != NULL; 249c208cb99SMark Johnston next = next->fbtp_tracenext) { 250c208cb99SMark Johnston if (fbt == next->fbtp_tracenext) { 251c208cb99SMark Johnston next->fbtp_tracenext = 252c208cb99SMark Johnston fbt->fbtp_tracenext; 253c208cb99SMark Johnston goto free; 254c208cb99SMark Johnston } 255c208cb99SMark Johnston } 256c208cb99SMark Johnston } 257c208cb99SMark Johnston } 258c208cb99SMark Johnston panic("probe %p not found in hash table", fbt); 259c208cb99SMark Johnston free: 260c208cb99SMark Johnston free(fbt, M_FBT); 261c208cb99SMark Johnston } 262c208cb99SMark Johnston 263c208cb99SMark Johnston static void 26491eaf3e1SJohn Birrell fbt_destroy(void *arg, dtrace_id_t id, void *parg) 26591eaf3e1SJohn Birrell { 266c208cb99SMark Johnston fbt_probe_t *fbt = parg, *next; 26791eaf3e1SJohn Birrell modctl_t *ctl; 26891eaf3e1SJohn Birrell 26991eaf3e1SJohn Birrell do { 27091eaf3e1SJohn Birrell ctl = fbt->fbtp_ctl; 27191eaf3e1SJohn Birrell ctl->fbt_nentries--; 27291eaf3e1SJohn Birrell 273c208cb99SMark Johnston next = fbt->fbtp_probenext; 274c208cb99SMark Johnston fbt_destroy_one(fbt); 27591eaf3e1SJohn Birrell fbt = next; 27691eaf3e1SJohn Birrell } while (fbt != NULL); 27791eaf3e1SJohn Birrell } 27891eaf3e1SJohn Birrell 27991eaf3e1SJohn Birrell static void 28091eaf3e1SJohn Birrell fbt_enable(void *arg, dtrace_id_t id, void *parg) 28191eaf3e1SJohn Birrell { 28291eaf3e1SJohn Birrell fbt_probe_t *fbt = parg; 28391eaf3e1SJohn Birrell modctl_t *ctl = fbt->fbtp_ctl; 28491eaf3e1SJohn Birrell 28591eaf3e1SJohn Birrell ctl->nenabled++; 28691eaf3e1SJohn Birrell 28791eaf3e1SJohn Birrell /* 28891eaf3e1SJohn Birrell * Now check that our modctl has the expected load count. If it 28991eaf3e1SJohn Birrell * doesn't, this module must have been unloaded and reloaded -- and 29091eaf3e1SJohn Birrell * we're not going to touch it. 29191eaf3e1SJohn Birrell */ 29291eaf3e1SJohn Birrell if (ctl->loadcnt != fbt->fbtp_loadcnt) { 29391eaf3e1SJohn Birrell if (fbt_verbose) { 29491eaf3e1SJohn Birrell printf("fbt is failing for probe %s " 29591eaf3e1SJohn Birrell "(module %s reloaded)", 29691eaf3e1SJohn Birrell fbt->fbtp_name, ctl->filename); 29791eaf3e1SJohn Birrell } 29891eaf3e1SJohn Birrell 29991eaf3e1SJohn Birrell return; 30091eaf3e1SJohn Birrell } 30191eaf3e1SJohn Birrell 302c208cb99SMark Johnston for (; fbt != NULL; fbt = fbt->fbtp_probenext) { 303266b4a78SMark Johnston fbt_patch_tracepoint(fbt, fbt->fbtp_patchval); 304c208cb99SMark Johnston fbt->fbtp_enabled++; 305c208cb99SMark Johnston } 30691eaf3e1SJohn Birrell } 30791eaf3e1SJohn Birrell 30891eaf3e1SJohn Birrell static void 30991eaf3e1SJohn Birrell fbt_disable(void *arg, dtrace_id_t id, void *parg) 31091eaf3e1SJohn Birrell { 311c208cb99SMark Johnston fbt_probe_t *fbt = parg, *hash; 31291eaf3e1SJohn Birrell modctl_t *ctl = fbt->fbtp_ctl; 31391eaf3e1SJohn Birrell 31491eaf3e1SJohn Birrell ASSERT(ctl->nenabled > 0); 31591eaf3e1SJohn Birrell ctl->nenabled--; 31691eaf3e1SJohn Birrell 31791eaf3e1SJohn Birrell if ((ctl->loadcnt != fbt->fbtp_loadcnt)) 31891eaf3e1SJohn Birrell return; 31991eaf3e1SJohn Birrell 320c208cb99SMark Johnston for (; fbt != NULL; fbt = fbt->fbtp_probenext) { 321c208cb99SMark Johnston fbt->fbtp_enabled--; 322c208cb99SMark Johnston 323c208cb99SMark Johnston for (hash = fbt_probetab[FBT_ADDR2NDX(fbt->fbtp_patchpoint)]; 324c208cb99SMark Johnston hash != NULL; hash = hash->fbtp_hashnext) { 325c208cb99SMark Johnston if (hash->fbtp_patchpoint == fbt->fbtp_patchpoint) { 326c208cb99SMark Johnston for (; hash != NULL; hash = hash->fbtp_tracenext) 327c208cb99SMark Johnston if (hash->fbtp_enabled > 0) 328c208cb99SMark Johnston break; 329c208cb99SMark Johnston break; 330c208cb99SMark Johnston } 331c208cb99SMark Johnston } 332c208cb99SMark Johnston if (hash == NULL) 33335127d3cSMark Johnston fbt_patch_tracepoint(fbt, fbt->fbtp_savedval); 33491eaf3e1SJohn Birrell } 335c208cb99SMark Johnston } 33691eaf3e1SJohn Birrell 33791eaf3e1SJohn Birrell static void 33891eaf3e1SJohn Birrell fbt_suspend(void *arg, dtrace_id_t id, void *parg) 33991eaf3e1SJohn Birrell { 34091eaf3e1SJohn Birrell fbt_probe_t *fbt = parg; 34191eaf3e1SJohn Birrell modctl_t *ctl = fbt->fbtp_ctl; 34291eaf3e1SJohn Birrell 34391eaf3e1SJohn Birrell ASSERT(ctl->nenabled > 0); 34491eaf3e1SJohn Birrell 34591eaf3e1SJohn Birrell if ((ctl->loadcnt != fbt->fbtp_loadcnt)) 34691eaf3e1SJohn Birrell return; 34791eaf3e1SJohn Birrell 348c208cb99SMark Johnston for (; fbt != NULL; fbt = fbt->fbtp_probenext) 34935127d3cSMark Johnston fbt_patch_tracepoint(fbt, fbt->fbtp_savedval); 35091eaf3e1SJohn Birrell } 35191eaf3e1SJohn Birrell 35291eaf3e1SJohn Birrell static void 35391eaf3e1SJohn Birrell fbt_resume(void *arg, dtrace_id_t id, void *parg) 35491eaf3e1SJohn Birrell { 35591eaf3e1SJohn Birrell fbt_probe_t *fbt = parg; 35691eaf3e1SJohn Birrell modctl_t *ctl = fbt->fbtp_ctl; 35791eaf3e1SJohn Birrell 35891eaf3e1SJohn Birrell ASSERT(ctl->nenabled > 0); 35991eaf3e1SJohn Birrell 36091eaf3e1SJohn Birrell if ((ctl->loadcnt != fbt->fbtp_loadcnt)) 36191eaf3e1SJohn Birrell return; 36291eaf3e1SJohn Birrell 363c208cb99SMark Johnston for (; fbt != NULL; fbt = fbt->fbtp_probenext) 364266b4a78SMark Johnston fbt_patch_tracepoint(fbt, fbt->fbtp_patchval); 36591eaf3e1SJohn Birrell } 36691eaf3e1SJohn Birrell 36791eaf3e1SJohn Birrell static int 36891eaf3e1SJohn Birrell fbt_ctfoff_init(modctl_t *lf, linker_ctf_t *lc) 36991eaf3e1SJohn Birrell { 37091eaf3e1SJohn Birrell const Elf_Sym *symp = lc->symtab;; 37191eaf3e1SJohn Birrell const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab; 37291eaf3e1SJohn Birrell const uint8_t *ctfdata = lc->ctftab + sizeof(ctf_header_t); 37391eaf3e1SJohn Birrell int i; 37491eaf3e1SJohn Birrell uint32_t *ctfoff; 37591eaf3e1SJohn Birrell uint32_t objtoff = hp->cth_objtoff; 37691eaf3e1SJohn Birrell uint32_t funcoff = hp->cth_funcoff; 37791eaf3e1SJohn Birrell ushort_t info; 37891eaf3e1SJohn Birrell ushort_t vlen; 37991eaf3e1SJohn Birrell 38091eaf3e1SJohn Birrell /* Sanity check. */ 38191eaf3e1SJohn Birrell if (hp->cth_magic != CTF_MAGIC) { 38291eaf3e1SJohn Birrell printf("Bad magic value in CTF data of '%s'\n",lf->pathname); 38391eaf3e1SJohn Birrell return (EINVAL); 38491eaf3e1SJohn Birrell } 38591eaf3e1SJohn Birrell 38691eaf3e1SJohn Birrell if (lc->symtab == NULL) { 38791eaf3e1SJohn Birrell printf("No symbol table in '%s'\n",lf->pathname); 38891eaf3e1SJohn Birrell return (EINVAL); 38991eaf3e1SJohn Birrell } 39091eaf3e1SJohn Birrell 391d258fd1dSMark Johnston ctfoff = malloc(sizeof(uint32_t) * lc->nsym, M_LINKER, M_WAITOK); 39291eaf3e1SJohn Birrell *lc->ctfoffp = ctfoff; 39391eaf3e1SJohn Birrell 39491eaf3e1SJohn Birrell for (i = 0; i < lc->nsym; i++, ctfoff++, symp++) { 39591eaf3e1SJohn Birrell if (symp->st_name == 0 || symp->st_shndx == SHN_UNDEF) { 39691eaf3e1SJohn Birrell *ctfoff = 0xffffffff; 39791eaf3e1SJohn Birrell continue; 39891eaf3e1SJohn Birrell } 39991eaf3e1SJohn Birrell 40091eaf3e1SJohn Birrell switch (ELF_ST_TYPE(symp->st_info)) { 40191eaf3e1SJohn Birrell case STT_OBJECT: 40291eaf3e1SJohn Birrell if (objtoff >= hp->cth_funcoff || 40391eaf3e1SJohn Birrell (symp->st_shndx == SHN_ABS && symp->st_value == 0)) { 40491eaf3e1SJohn Birrell *ctfoff = 0xffffffff; 40591eaf3e1SJohn Birrell break; 40691eaf3e1SJohn Birrell } 40791eaf3e1SJohn Birrell 40891eaf3e1SJohn Birrell *ctfoff = objtoff; 40991eaf3e1SJohn Birrell objtoff += sizeof (ushort_t); 41091eaf3e1SJohn Birrell break; 41191eaf3e1SJohn Birrell 41291eaf3e1SJohn Birrell case STT_FUNC: 41391eaf3e1SJohn Birrell if (funcoff >= hp->cth_typeoff) { 41491eaf3e1SJohn Birrell *ctfoff = 0xffffffff; 41591eaf3e1SJohn Birrell break; 41691eaf3e1SJohn Birrell } 41791eaf3e1SJohn Birrell 41891eaf3e1SJohn Birrell *ctfoff = funcoff; 41991eaf3e1SJohn Birrell 42091eaf3e1SJohn Birrell info = *((const ushort_t *)(ctfdata + funcoff)); 42191eaf3e1SJohn Birrell vlen = CTF_INFO_VLEN(info); 42291eaf3e1SJohn Birrell 42391eaf3e1SJohn Birrell /* 42491eaf3e1SJohn Birrell * If we encounter a zero pad at the end, just skip it. 42591eaf3e1SJohn Birrell * Otherwise skip over the function and its return type 42691eaf3e1SJohn Birrell * (+2) and the argument list (vlen). 42791eaf3e1SJohn Birrell */ 42891eaf3e1SJohn Birrell if (CTF_INFO_KIND(info) == CTF_K_UNKNOWN && vlen == 0) 42991eaf3e1SJohn Birrell funcoff += sizeof (ushort_t); /* skip pad */ 43091eaf3e1SJohn Birrell else 43191eaf3e1SJohn Birrell funcoff += sizeof (ushort_t) * (vlen + 2); 43291eaf3e1SJohn Birrell break; 43391eaf3e1SJohn Birrell 43491eaf3e1SJohn Birrell default: 43591eaf3e1SJohn Birrell *ctfoff = 0xffffffff; 43691eaf3e1SJohn Birrell break; 43791eaf3e1SJohn Birrell } 43891eaf3e1SJohn Birrell } 43991eaf3e1SJohn Birrell 44091eaf3e1SJohn Birrell return (0); 44191eaf3e1SJohn Birrell } 44291eaf3e1SJohn Birrell 44391eaf3e1SJohn Birrell static ssize_t 44491eaf3e1SJohn Birrell fbt_get_ctt_size(uint8_t version, const ctf_type_t *tp, ssize_t *sizep, 44591eaf3e1SJohn Birrell ssize_t *incrementp) 44691eaf3e1SJohn Birrell { 44791eaf3e1SJohn Birrell ssize_t size, increment; 44891eaf3e1SJohn Birrell 44991eaf3e1SJohn Birrell if (version > CTF_VERSION_1 && 45091eaf3e1SJohn Birrell tp->ctt_size == CTF_LSIZE_SENT) { 45191eaf3e1SJohn Birrell size = CTF_TYPE_LSIZE(tp); 45291eaf3e1SJohn Birrell increment = sizeof (ctf_type_t); 45391eaf3e1SJohn Birrell } else { 45491eaf3e1SJohn Birrell size = tp->ctt_size; 45591eaf3e1SJohn Birrell increment = sizeof (ctf_stype_t); 45691eaf3e1SJohn Birrell } 45791eaf3e1SJohn Birrell 45891eaf3e1SJohn Birrell if (sizep) 45991eaf3e1SJohn Birrell *sizep = size; 46091eaf3e1SJohn Birrell if (incrementp) 46191eaf3e1SJohn Birrell *incrementp = increment; 46291eaf3e1SJohn Birrell 46391eaf3e1SJohn Birrell return (size); 46491eaf3e1SJohn Birrell } 46591eaf3e1SJohn Birrell 46691eaf3e1SJohn Birrell static int 46791eaf3e1SJohn Birrell fbt_typoff_init(linker_ctf_t *lc) 46891eaf3e1SJohn Birrell { 46991eaf3e1SJohn Birrell const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab; 47091eaf3e1SJohn Birrell const ctf_type_t *tbuf; 47191eaf3e1SJohn Birrell const ctf_type_t *tend; 47291eaf3e1SJohn Birrell const ctf_type_t *tp; 47391eaf3e1SJohn Birrell const uint8_t *ctfdata = lc->ctftab + sizeof(ctf_header_t); 47491eaf3e1SJohn Birrell int ctf_typemax = 0; 47591eaf3e1SJohn Birrell uint32_t *xp; 47691eaf3e1SJohn Birrell ulong_t pop[CTF_K_MAX + 1] = { 0 }; 47791eaf3e1SJohn Birrell 47891eaf3e1SJohn Birrell 47991eaf3e1SJohn Birrell /* Sanity check. */ 48091eaf3e1SJohn Birrell if (hp->cth_magic != CTF_MAGIC) 48191eaf3e1SJohn Birrell return (EINVAL); 48291eaf3e1SJohn Birrell 48391eaf3e1SJohn Birrell tbuf = (const ctf_type_t *) (ctfdata + hp->cth_typeoff); 48491eaf3e1SJohn Birrell tend = (const ctf_type_t *) (ctfdata + hp->cth_stroff); 48591eaf3e1SJohn Birrell 48691eaf3e1SJohn Birrell int child = hp->cth_parname != 0; 48791eaf3e1SJohn Birrell 48891eaf3e1SJohn Birrell /* 48991eaf3e1SJohn Birrell * We make two passes through the entire type section. In this first 49091eaf3e1SJohn Birrell * pass, we count the number of each type and the total number of types. 49191eaf3e1SJohn Birrell */ 49291eaf3e1SJohn Birrell for (tp = tbuf; tp < tend; ctf_typemax++) { 49391eaf3e1SJohn Birrell ushort_t kind = CTF_INFO_KIND(tp->ctt_info); 49491eaf3e1SJohn Birrell ulong_t vlen = CTF_INFO_VLEN(tp->ctt_info); 49591eaf3e1SJohn Birrell ssize_t size, increment; 49691eaf3e1SJohn Birrell 49791eaf3e1SJohn Birrell size_t vbytes; 49891eaf3e1SJohn Birrell uint_t n; 49991eaf3e1SJohn Birrell 50091eaf3e1SJohn Birrell (void) fbt_get_ctt_size(hp->cth_version, tp, &size, &increment); 50191eaf3e1SJohn Birrell 50291eaf3e1SJohn Birrell switch (kind) { 50391eaf3e1SJohn Birrell case CTF_K_INTEGER: 50491eaf3e1SJohn Birrell case CTF_K_FLOAT: 50591eaf3e1SJohn Birrell vbytes = sizeof (uint_t); 50691eaf3e1SJohn Birrell break; 50791eaf3e1SJohn Birrell case CTF_K_ARRAY: 50891eaf3e1SJohn Birrell vbytes = sizeof (ctf_array_t); 50991eaf3e1SJohn Birrell break; 51091eaf3e1SJohn Birrell case CTF_K_FUNCTION: 51191eaf3e1SJohn Birrell vbytes = sizeof (ushort_t) * (vlen + (vlen & 1)); 51291eaf3e1SJohn Birrell break; 51391eaf3e1SJohn Birrell case CTF_K_STRUCT: 51491eaf3e1SJohn Birrell case CTF_K_UNION: 51591eaf3e1SJohn Birrell if (size < CTF_LSTRUCT_THRESH) { 51691eaf3e1SJohn Birrell ctf_member_t *mp = (ctf_member_t *) 51791eaf3e1SJohn Birrell ((uintptr_t)tp + increment); 51891eaf3e1SJohn Birrell 51991eaf3e1SJohn Birrell vbytes = sizeof (ctf_member_t) * vlen; 52091eaf3e1SJohn Birrell for (n = vlen; n != 0; n--, mp++) 52191eaf3e1SJohn Birrell child |= CTF_TYPE_ISCHILD(mp->ctm_type); 52291eaf3e1SJohn Birrell } else { 52391eaf3e1SJohn Birrell ctf_lmember_t *lmp = (ctf_lmember_t *) 52491eaf3e1SJohn Birrell ((uintptr_t)tp + increment); 52591eaf3e1SJohn Birrell 52691eaf3e1SJohn Birrell vbytes = sizeof (ctf_lmember_t) * vlen; 52791eaf3e1SJohn Birrell for (n = vlen; n != 0; n--, lmp++) 52891eaf3e1SJohn Birrell child |= 52991eaf3e1SJohn Birrell CTF_TYPE_ISCHILD(lmp->ctlm_type); 53091eaf3e1SJohn Birrell } 53191eaf3e1SJohn Birrell break; 53291eaf3e1SJohn Birrell case CTF_K_ENUM: 53391eaf3e1SJohn Birrell vbytes = sizeof (ctf_enum_t) * vlen; 53491eaf3e1SJohn Birrell break; 53591eaf3e1SJohn Birrell case CTF_K_FORWARD: 53691eaf3e1SJohn Birrell /* 53791eaf3e1SJohn Birrell * For forward declarations, ctt_type is the CTF_K_* 53891eaf3e1SJohn Birrell * kind for the tag, so bump that population count too. 53991eaf3e1SJohn Birrell * If ctt_type is unknown, treat the tag as a struct. 54091eaf3e1SJohn Birrell */ 54191eaf3e1SJohn Birrell if (tp->ctt_type == CTF_K_UNKNOWN || 54291eaf3e1SJohn Birrell tp->ctt_type >= CTF_K_MAX) 54391eaf3e1SJohn Birrell pop[CTF_K_STRUCT]++; 54491eaf3e1SJohn Birrell else 54591eaf3e1SJohn Birrell pop[tp->ctt_type]++; 54691eaf3e1SJohn Birrell /*FALLTHRU*/ 54791eaf3e1SJohn Birrell case CTF_K_UNKNOWN: 54891eaf3e1SJohn Birrell vbytes = 0; 54991eaf3e1SJohn Birrell break; 55091eaf3e1SJohn Birrell case CTF_K_POINTER: 55191eaf3e1SJohn Birrell case CTF_K_TYPEDEF: 55291eaf3e1SJohn Birrell case CTF_K_VOLATILE: 55391eaf3e1SJohn Birrell case CTF_K_CONST: 55491eaf3e1SJohn Birrell case CTF_K_RESTRICT: 55591eaf3e1SJohn Birrell child |= CTF_TYPE_ISCHILD(tp->ctt_type); 55691eaf3e1SJohn Birrell vbytes = 0; 55791eaf3e1SJohn Birrell break; 55891eaf3e1SJohn Birrell default: 55991eaf3e1SJohn Birrell printf("%s(%d): detected invalid CTF kind -- %u\n", __func__, __LINE__, kind); 56091eaf3e1SJohn Birrell return (EIO); 56191eaf3e1SJohn Birrell } 56291eaf3e1SJohn Birrell tp = (ctf_type_t *)((uintptr_t)tp + increment + vbytes); 56391eaf3e1SJohn Birrell pop[kind]++; 56491eaf3e1SJohn Birrell } 56591eaf3e1SJohn Birrell 566a47016e9SAndriy Gapon /* account for a sentinel value below */ 567a47016e9SAndriy Gapon ctf_typemax++; 56891eaf3e1SJohn Birrell *lc->typlenp = ctf_typemax; 56991eaf3e1SJohn Birrell 570d258fd1dSMark Johnston xp = malloc(sizeof(uint32_t) * ctf_typemax, M_LINKER, 571d258fd1dSMark Johnston M_ZERO | M_WAITOK); 57291eaf3e1SJohn Birrell 57391eaf3e1SJohn Birrell *lc->typoffp = xp; 57491eaf3e1SJohn Birrell 57591eaf3e1SJohn Birrell /* type id 0 is used as a sentinel value */ 57691eaf3e1SJohn Birrell *xp++ = 0; 57791eaf3e1SJohn Birrell 57891eaf3e1SJohn Birrell /* 57991eaf3e1SJohn Birrell * In the second pass, fill in the type offset. 58091eaf3e1SJohn Birrell */ 58191eaf3e1SJohn Birrell for (tp = tbuf; tp < tend; xp++) { 58291eaf3e1SJohn Birrell ushort_t kind = CTF_INFO_KIND(tp->ctt_info); 58391eaf3e1SJohn Birrell ulong_t vlen = CTF_INFO_VLEN(tp->ctt_info); 58491eaf3e1SJohn Birrell ssize_t size, increment; 58591eaf3e1SJohn Birrell 58691eaf3e1SJohn Birrell size_t vbytes; 58791eaf3e1SJohn Birrell uint_t n; 58891eaf3e1SJohn Birrell 58991eaf3e1SJohn Birrell (void) fbt_get_ctt_size(hp->cth_version, tp, &size, &increment); 59091eaf3e1SJohn Birrell 59191eaf3e1SJohn Birrell switch (kind) { 59291eaf3e1SJohn Birrell case CTF_K_INTEGER: 59391eaf3e1SJohn Birrell case CTF_K_FLOAT: 59491eaf3e1SJohn Birrell vbytes = sizeof (uint_t); 59591eaf3e1SJohn Birrell break; 59691eaf3e1SJohn Birrell case CTF_K_ARRAY: 59791eaf3e1SJohn Birrell vbytes = sizeof (ctf_array_t); 59891eaf3e1SJohn Birrell break; 59991eaf3e1SJohn Birrell case CTF_K_FUNCTION: 60091eaf3e1SJohn Birrell vbytes = sizeof (ushort_t) * (vlen + (vlen & 1)); 60191eaf3e1SJohn Birrell break; 60291eaf3e1SJohn Birrell case CTF_K_STRUCT: 60391eaf3e1SJohn Birrell case CTF_K_UNION: 60491eaf3e1SJohn Birrell if (size < CTF_LSTRUCT_THRESH) { 60591eaf3e1SJohn Birrell ctf_member_t *mp = (ctf_member_t *) 60691eaf3e1SJohn Birrell ((uintptr_t)tp + increment); 60791eaf3e1SJohn Birrell 60891eaf3e1SJohn Birrell vbytes = sizeof (ctf_member_t) * vlen; 60991eaf3e1SJohn Birrell for (n = vlen; n != 0; n--, mp++) 61091eaf3e1SJohn Birrell child |= CTF_TYPE_ISCHILD(mp->ctm_type); 61191eaf3e1SJohn Birrell } else { 61291eaf3e1SJohn Birrell ctf_lmember_t *lmp = (ctf_lmember_t *) 61391eaf3e1SJohn Birrell ((uintptr_t)tp + increment); 61491eaf3e1SJohn Birrell 61591eaf3e1SJohn Birrell vbytes = sizeof (ctf_lmember_t) * vlen; 61691eaf3e1SJohn Birrell for (n = vlen; n != 0; n--, lmp++) 61791eaf3e1SJohn Birrell child |= 61891eaf3e1SJohn Birrell CTF_TYPE_ISCHILD(lmp->ctlm_type); 61991eaf3e1SJohn Birrell } 62091eaf3e1SJohn Birrell break; 62191eaf3e1SJohn Birrell case CTF_K_ENUM: 62291eaf3e1SJohn Birrell vbytes = sizeof (ctf_enum_t) * vlen; 62391eaf3e1SJohn Birrell break; 62491eaf3e1SJohn Birrell case CTF_K_FORWARD: 62591eaf3e1SJohn Birrell case CTF_K_UNKNOWN: 62691eaf3e1SJohn Birrell vbytes = 0; 62791eaf3e1SJohn Birrell break; 62891eaf3e1SJohn Birrell case CTF_K_POINTER: 62991eaf3e1SJohn Birrell case CTF_K_TYPEDEF: 63091eaf3e1SJohn Birrell case CTF_K_VOLATILE: 63191eaf3e1SJohn Birrell case CTF_K_CONST: 63291eaf3e1SJohn Birrell case CTF_K_RESTRICT: 63391eaf3e1SJohn Birrell vbytes = 0; 63491eaf3e1SJohn Birrell break; 63591eaf3e1SJohn Birrell default: 63691eaf3e1SJohn Birrell printf("%s(%d): detected invalid CTF kind -- %u\n", __func__, __LINE__, kind); 63791eaf3e1SJohn Birrell return (EIO); 63891eaf3e1SJohn Birrell } 63991eaf3e1SJohn Birrell *xp = (uint32_t)((uintptr_t) tp - (uintptr_t) ctfdata); 64091eaf3e1SJohn Birrell tp = (ctf_type_t *)((uintptr_t)tp + increment + vbytes); 64191eaf3e1SJohn Birrell } 64291eaf3e1SJohn Birrell 64391eaf3e1SJohn Birrell return (0); 64491eaf3e1SJohn Birrell } 64591eaf3e1SJohn Birrell 64691eaf3e1SJohn Birrell /* 64791eaf3e1SJohn Birrell * CTF Declaration Stack 64891eaf3e1SJohn Birrell * 64991eaf3e1SJohn Birrell * In order to implement ctf_type_name(), we must convert a type graph back 65091eaf3e1SJohn Birrell * into a C type declaration. Unfortunately, a type graph represents a storage 65191eaf3e1SJohn Birrell * class ordering of the type whereas a type declaration must obey the C rules 65291eaf3e1SJohn Birrell * for operator precedence, and the two orderings are frequently in conflict. 65391eaf3e1SJohn Birrell * For example, consider these CTF type graphs and their C declarations: 65491eaf3e1SJohn Birrell * 65591eaf3e1SJohn Birrell * CTF_K_POINTER -> CTF_K_FUNCTION -> CTF_K_INTEGER : int (*)() 65691eaf3e1SJohn Birrell * CTF_K_POINTER -> CTF_K_ARRAY -> CTF_K_INTEGER : int (*)[] 65791eaf3e1SJohn Birrell * 65891eaf3e1SJohn Birrell * In each case, parentheses are used to raise operator * to higher lexical 65991eaf3e1SJohn Birrell * precedence, so the string form of the C declaration cannot be constructed by 66091eaf3e1SJohn Birrell * walking the type graph links and forming the string from left to right. 66191eaf3e1SJohn Birrell * 66291eaf3e1SJohn Birrell * The functions in this file build a set of stacks from the type graph nodes 66391eaf3e1SJohn Birrell * corresponding to the C operator precedence levels in the appropriate order. 66491eaf3e1SJohn Birrell * The code in ctf_type_name() can then iterate over the levels and nodes in 66591eaf3e1SJohn Birrell * lexical precedence order and construct the final C declaration string. 66691eaf3e1SJohn Birrell */ 66791eaf3e1SJohn Birrell typedef struct ctf_list { 66891eaf3e1SJohn Birrell struct ctf_list *l_prev; /* previous pointer or tail pointer */ 66991eaf3e1SJohn Birrell struct ctf_list *l_next; /* next pointer or head pointer */ 67091eaf3e1SJohn Birrell } ctf_list_t; 67191eaf3e1SJohn Birrell 67291eaf3e1SJohn Birrell #define ctf_list_prev(elem) ((void *)(((ctf_list_t *)(elem))->l_prev)) 67391eaf3e1SJohn Birrell #define ctf_list_next(elem) ((void *)(((ctf_list_t *)(elem))->l_next)) 67491eaf3e1SJohn Birrell 67591eaf3e1SJohn Birrell typedef enum { 67691eaf3e1SJohn Birrell CTF_PREC_BASE, 67791eaf3e1SJohn Birrell CTF_PREC_POINTER, 67891eaf3e1SJohn Birrell CTF_PREC_ARRAY, 67991eaf3e1SJohn Birrell CTF_PREC_FUNCTION, 68091eaf3e1SJohn Birrell CTF_PREC_MAX 68191eaf3e1SJohn Birrell } ctf_decl_prec_t; 68291eaf3e1SJohn Birrell 68391eaf3e1SJohn Birrell typedef struct ctf_decl_node { 68491eaf3e1SJohn Birrell ctf_list_t cd_list; /* linked list pointers */ 68591eaf3e1SJohn Birrell ctf_id_t cd_type; /* type identifier */ 68691eaf3e1SJohn Birrell uint_t cd_kind; /* type kind */ 68791eaf3e1SJohn Birrell uint_t cd_n; /* type dimension if array */ 68891eaf3e1SJohn Birrell } ctf_decl_node_t; 68991eaf3e1SJohn Birrell 69091eaf3e1SJohn Birrell typedef struct ctf_decl { 69191eaf3e1SJohn Birrell ctf_list_t cd_nodes[CTF_PREC_MAX]; /* declaration node stacks */ 69291eaf3e1SJohn Birrell int cd_order[CTF_PREC_MAX]; /* storage order of decls */ 69391eaf3e1SJohn Birrell ctf_decl_prec_t cd_qualp; /* qualifier precision */ 69491eaf3e1SJohn Birrell ctf_decl_prec_t cd_ordp; /* ordered precision */ 69591eaf3e1SJohn Birrell char *cd_buf; /* buffer for output */ 69691eaf3e1SJohn Birrell char *cd_ptr; /* buffer location */ 69791eaf3e1SJohn Birrell char *cd_end; /* buffer limit */ 69891eaf3e1SJohn Birrell size_t cd_len; /* buffer space required */ 69991eaf3e1SJohn Birrell int cd_err; /* saved error value */ 70091eaf3e1SJohn Birrell } ctf_decl_t; 70191eaf3e1SJohn Birrell 70291eaf3e1SJohn Birrell /* 70391eaf3e1SJohn Birrell * Simple doubly-linked list append routine. This implementation assumes that 70491eaf3e1SJohn Birrell * each list element contains an embedded ctf_list_t as the first member. 70591eaf3e1SJohn Birrell * An additional ctf_list_t is used to store the head (l_next) and tail 70691eaf3e1SJohn Birrell * (l_prev) pointers. The current head and tail list elements have their 70791eaf3e1SJohn Birrell * previous and next pointers set to NULL, respectively. 70891eaf3e1SJohn Birrell */ 70991eaf3e1SJohn Birrell static void 71091eaf3e1SJohn Birrell ctf_list_append(ctf_list_t *lp, void *new) 71191eaf3e1SJohn Birrell { 71291eaf3e1SJohn Birrell ctf_list_t *p = lp->l_prev; /* p = tail list element */ 71391eaf3e1SJohn Birrell ctf_list_t *q = new; /* q = new list element */ 71491eaf3e1SJohn Birrell 71591eaf3e1SJohn Birrell lp->l_prev = q; 71691eaf3e1SJohn Birrell q->l_prev = p; 71791eaf3e1SJohn Birrell q->l_next = NULL; 71891eaf3e1SJohn Birrell 71991eaf3e1SJohn Birrell if (p != NULL) 72091eaf3e1SJohn Birrell p->l_next = q; 72191eaf3e1SJohn Birrell else 72291eaf3e1SJohn Birrell lp->l_next = q; 72391eaf3e1SJohn Birrell } 72491eaf3e1SJohn Birrell 72591eaf3e1SJohn Birrell /* 72691eaf3e1SJohn Birrell * Prepend the specified existing element to the given ctf_list_t. The 72791eaf3e1SJohn Birrell * existing pointer should be pointing at a struct with embedded ctf_list_t. 72891eaf3e1SJohn Birrell */ 72991eaf3e1SJohn Birrell static void 73091eaf3e1SJohn Birrell ctf_list_prepend(ctf_list_t *lp, void *new) 73191eaf3e1SJohn Birrell { 73291eaf3e1SJohn Birrell ctf_list_t *p = new; /* p = new list element */ 73391eaf3e1SJohn Birrell ctf_list_t *q = lp->l_next; /* q = head list element */ 73491eaf3e1SJohn Birrell 73591eaf3e1SJohn Birrell lp->l_next = p; 73691eaf3e1SJohn Birrell p->l_prev = NULL; 73791eaf3e1SJohn Birrell p->l_next = q; 73891eaf3e1SJohn Birrell 73991eaf3e1SJohn Birrell if (q != NULL) 74091eaf3e1SJohn Birrell q->l_prev = p; 74191eaf3e1SJohn Birrell else 74291eaf3e1SJohn Birrell lp->l_prev = p; 74391eaf3e1SJohn Birrell } 74491eaf3e1SJohn Birrell 74591eaf3e1SJohn Birrell static void 74691eaf3e1SJohn Birrell ctf_decl_init(ctf_decl_t *cd, char *buf, size_t len) 74791eaf3e1SJohn Birrell { 74891eaf3e1SJohn Birrell int i; 74991eaf3e1SJohn Birrell 75091eaf3e1SJohn Birrell bzero(cd, sizeof (ctf_decl_t)); 75191eaf3e1SJohn Birrell 75291eaf3e1SJohn Birrell for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++) 75391eaf3e1SJohn Birrell cd->cd_order[i] = CTF_PREC_BASE - 1; 75491eaf3e1SJohn Birrell 75591eaf3e1SJohn Birrell cd->cd_qualp = CTF_PREC_BASE; 75691eaf3e1SJohn Birrell cd->cd_ordp = CTF_PREC_BASE; 75791eaf3e1SJohn Birrell 75891eaf3e1SJohn Birrell cd->cd_buf = buf; 75991eaf3e1SJohn Birrell cd->cd_ptr = buf; 76091eaf3e1SJohn Birrell cd->cd_end = buf + len; 76191eaf3e1SJohn Birrell } 76291eaf3e1SJohn Birrell 76391eaf3e1SJohn Birrell static void 76491eaf3e1SJohn Birrell ctf_decl_fini(ctf_decl_t *cd) 76591eaf3e1SJohn Birrell { 76691eaf3e1SJohn Birrell ctf_decl_node_t *cdp, *ndp; 76791eaf3e1SJohn Birrell int i; 76891eaf3e1SJohn Birrell 76991eaf3e1SJohn Birrell for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++) { 77091eaf3e1SJohn Birrell for (cdp = ctf_list_next(&cd->cd_nodes[i]); 77191eaf3e1SJohn Birrell cdp != NULL; cdp = ndp) { 77291eaf3e1SJohn Birrell ndp = ctf_list_next(cdp); 77391eaf3e1SJohn Birrell free(cdp, M_FBT); 77491eaf3e1SJohn Birrell } 77591eaf3e1SJohn Birrell } 77691eaf3e1SJohn Birrell } 77791eaf3e1SJohn Birrell 77891eaf3e1SJohn Birrell static const ctf_type_t * 77991eaf3e1SJohn Birrell ctf_lookup_by_id(linker_ctf_t *lc, ctf_id_t type) 78091eaf3e1SJohn Birrell { 78191eaf3e1SJohn Birrell const ctf_type_t *tp; 78291eaf3e1SJohn Birrell uint32_t offset; 78391eaf3e1SJohn Birrell uint32_t *typoff = *lc->typoffp; 78491eaf3e1SJohn Birrell 78591eaf3e1SJohn Birrell if (type >= *lc->typlenp) { 78691eaf3e1SJohn Birrell printf("%s(%d): type %d exceeds max %ld\n",__func__,__LINE__,(int) type,*lc->typlenp); 78791eaf3e1SJohn Birrell return(NULL); 78891eaf3e1SJohn Birrell } 78991eaf3e1SJohn Birrell 79091eaf3e1SJohn Birrell /* Check if the type isn't cross-referenced. */ 79191eaf3e1SJohn Birrell if ((offset = typoff[type]) == 0) { 79291eaf3e1SJohn Birrell printf("%s(%d): type %d isn't cross referenced\n",__func__,__LINE__, (int) type); 79391eaf3e1SJohn Birrell return(NULL); 79491eaf3e1SJohn Birrell } 79591eaf3e1SJohn Birrell 79691eaf3e1SJohn Birrell tp = (const ctf_type_t *)(lc->ctftab + offset + sizeof(ctf_header_t)); 79791eaf3e1SJohn Birrell 79891eaf3e1SJohn Birrell return (tp); 79991eaf3e1SJohn Birrell } 80091eaf3e1SJohn Birrell 80191eaf3e1SJohn Birrell static void 80291eaf3e1SJohn Birrell fbt_array_info(linker_ctf_t *lc, ctf_id_t type, ctf_arinfo_t *arp) 80391eaf3e1SJohn Birrell { 80491eaf3e1SJohn Birrell const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab; 80591eaf3e1SJohn Birrell const ctf_type_t *tp; 80691eaf3e1SJohn Birrell const ctf_array_t *ap; 80791eaf3e1SJohn Birrell ssize_t increment; 80891eaf3e1SJohn Birrell 80991eaf3e1SJohn Birrell bzero(arp, sizeof(*arp)); 81091eaf3e1SJohn Birrell 81191eaf3e1SJohn Birrell if ((tp = ctf_lookup_by_id(lc, type)) == NULL) 81291eaf3e1SJohn Birrell return; 81391eaf3e1SJohn Birrell 81491eaf3e1SJohn Birrell if (CTF_INFO_KIND(tp->ctt_info) != CTF_K_ARRAY) 81591eaf3e1SJohn Birrell return; 81691eaf3e1SJohn Birrell 81791eaf3e1SJohn Birrell (void) fbt_get_ctt_size(hp->cth_version, tp, NULL, &increment); 81891eaf3e1SJohn Birrell 81991eaf3e1SJohn Birrell ap = (const ctf_array_t *)((uintptr_t)tp + increment); 82091eaf3e1SJohn Birrell arp->ctr_contents = ap->cta_contents; 82191eaf3e1SJohn Birrell arp->ctr_index = ap->cta_index; 82291eaf3e1SJohn Birrell arp->ctr_nelems = ap->cta_nelems; 82391eaf3e1SJohn Birrell } 82491eaf3e1SJohn Birrell 82591eaf3e1SJohn Birrell static const char * 82691eaf3e1SJohn Birrell ctf_strptr(linker_ctf_t *lc, int name) 82791eaf3e1SJohn Birrell { 82891eaf3e1SJohn Birrell const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab;; 82991eaf3e1SJohn Birrell const char *strp = ""; 83091eaf3e1SJohn Birrell 83191eaf3e1SJohn Birrell if (name < 0 || name >= hp->cth_strlen) 83291eaf3e1SJohn Birrell return(strp); 83391eaf3e1SJohn Birrell 83491eaf3e1SJohn Birrell strp = (const char *)(lc->ctftab + hp->cth_stroff + name + sizeof(ctf_header_t)); 83591eaf3e1SJohn Birrell 83691eaf3e1SJohn Birrell return (strp); 83791eaf3e1SJohn Birrell } 83891eaf3e1SJohn Birrell 83991eaf3e1SJohn Birrell static void 84091eaf3e1SJohn Birrell ctf_decl_push(ctf_decl_t *cd, linker_ctf_t *lc, ctf_id_t type) 84191eaf3e1SJohn Birrell { 84291eaf3e1SJohn Birrell ctf_decl_node_t *cdp; 84391eaf3e1SJohn Birrell ctf_decl_prec_t prec; 84491eaf3e1SJohn Birrell uint_t kind, n = 1; 84591eaf3e1SJohn Birrell int is_qual = 0; 84691eaf3e1SJohn Birrell 84791eaf3e1SJohn Birrell const ctf_type_t *tp; 84891eaf3e1SJohn Birrell ctf_arinfo_t ar; 84991eaf3e1SJohn Birrell 85091eaf3e1SJohn Birrell if ((tp = ctf_lookup_by_id(lc, type)) == NULL) { 85191eaf3e1SJohn Birrell cd->cd_err = ENOENT; 85291eaf3e1SJohn Birrell return; 85391eaf3e1SJohn Birrell } 85491eaf3e1SJohn Birrell 85591eaf3e1SJohn Birrell switch (kind = CTF_INFO_KIND(tp->ctt_info)) { 85691eaf3e1SJohn Birrell case CTF_K_ARRAY: 85791eaf3e1SJohn Birrell fbt_array_info(lc, type, &ar); 85891eaf3e1SJohn Birrell ctf_decl_push(cd, lc, ar.ctr_contents); 85991eaf3e1SJohn Birrell n = ar.ctr_nelems; 86091eaf3e1SJohn Birrell prec = CTF_PREC_ARRAY; 86191eaf3e1SJohn Birrell break; 86291eaf3e1SJohn Birrell 86391eaf3e1SJohn Birrell case CTF_K_TYPEDEF: 86491eaf3e1SJohn Birrell if (ctf_strptr(lc, tp->ctt_name)[0] == '\0') { 86591eaf3e1SJohn Birrell ctf_decl_push(cd, lc, tp->ctt_type); 86691eaf3e1SJohn Birrell return; 86791eaf3e1SJohn Birrell } 86891eaf3e1SJohn Birrell prec = CTF_PREC_BASE; 86991eaf3e1SJohn Birrell break; 87091eaf3e1SJohn Birrell 87191eaf3e1SJohn Birrell case CTF_K_FUNCTION: 87291eaf3e1SJohn Birrell ctf_decl_push(cd, lc, tp->ctt_type); 87391eaf3e1SJohn Birrell prec = CTF_PREC_FUNCTION; 87491eaf3e1SJohn Birrell break; 87591eaf3e1SJohn Birrell 87691eaf3e1SJohn Birrell case CTF_K_POINTER: 87791eaf3e1SJohn Birrell ctf_decl_push(cd, lc, tp->ctt_type); 87891eaf3e1SJohn Birrell prec = CTF_PREC_POINTER; 87991eaf3e1SJohn Birrell break; 88091eaf3e1SJohn Birrell 88191eaf3e1SJohn Birrell case CTF_K_VOLATILE: 88291eaf3e1SJohn Birrell case CTF_K_CONST: 88391eaf3e1SJohn Birrell case CTF_K_RESTRICT: 88491eaf3e1SJohn Birrell ctf_decl_push(cd, lc, tp->ctt_type); 88591eaf3e1SJohn Birrell prec = cd->cd_qualp; 88691eaf3e1SJohn Birrell is_qual++; 88791eaf3e1SJohn Birrell break; 88891eaf3e1SJohn Birrell 88991eaf3e1SJohn Birrell default: 89091eaf3e1SJohn Birrell prec = CTF_PREC_BASE; 89191eaf3e1SJohn Birrell } 89291eaf3e1SJohn Birrell 893d258fd1dSMark Johnston cdp = malloc(sizeof(*cdp), M_FBT, M_WAITOK); 89491eaf3e1SJohn Birrell cdp->cd_type = type; 89591eaf3e1SJohn Birrell cdp->cd_kind = kind; 89691eaf3e1SJohn Birrell cdp->cd_n = n; 89791eaf3e1SJohn Birrell 89891eaf3e1SJohn Birrell if (ctf_list_next(&cd->cd_nodes[prec]) == NULL) 89991eaf3e1SJohn Birrell cd->cd_order[prec] = cd->cd_ordp++; 90091eaf3e1SJohn Birrell 90191eaf3e1SJohn Birrell /* 90291eaf3e1SJohn Birrell * Reset cd_qualp to the highest precedence level that we've seen so 90391eaf3e1SJohn Birrell * far that can be qualified (CTF_PREC_BASE or CTF_PREC_POINTER). 90491eaf3e1SJohn Birrell */ 90591eaf3e1SJohn Birrell if (prec > cd->cd_qualp && prec < CTF_PREC_ARRAY) 90691eaf3e1SJohn Birrell cd->cd_qualp = prec; 90791eaf3e1SJohn Birrell 90891eaf3e1SJohn Birrell /* 90991eaf3e1SJohn Birrell * C array declarators are ordered inside out so prepend them. Also by 91091eaf3e1SJohn Birrell * convention qualifiers of base types precede the type specifier (e.g. 91191eaf3e1SJohn Birrell * const int vs. int const) even though the two forms are equivalent. 91291eaf3e1SJohn Birrell */ 91391eaf3e1SJohn Birrell if (kind == CTF_K_ARRAY || (is_qual && prec == CTF_PREC_BASE)) 91491eaf3e1SJohn Birrell ctf_list_prepend(&cd->cd_nodes[prec], cdp); 91591eaf3e1SJohn Birrell else 91691eaf3e1SJohn Birrell ctf_list_append(&cd->cd_nodes[prec], cdp); 91791eaf3e1SJohn Birrell } 91891eaf3e1SJohn Birrell 91991eaf3e1SJohn Birrell static void 92091eaf3e1SJohn Birrell ctf_decl_sprintf(ctf_decl_t *cd, const char *format, ...) 92191eaf3e1SJohn Birrell { 92291eaf3e1SJohn Birrell size_t len = (size_t)(cd->cd_end - cd->cd_ptr); 92391eaf3e1SJohn Birrell va_list ap; 92491eaf3e1SJohn Birrell size_t n; 92591eaf3e1SJohn Birrell 92691eaf3e1SJohn Birrell va_start(ap, format); 92791eaf3e1SJohn Birrell n = vsnprintf(cd->cd_ptr, len, format, ap); 92891eaf3e1SJohn Birrell va_end(ap); 92991eaf3e1SJohn Birrell 93091eaf3e1SJohn Birrell cd->cd_ptr += MIN(n, len); 93191eaf3e1SJohn Birrell cd->cd_len += n; 93291eaf3e1SJohn Birrell } 93391eaf3e1SJohn Birrell 93491eaf3e1SJohn Birrell static ssize_t 93591eaf3e1SJohn Birrell fbt_type_name(linker_ctf_t *lc, ctf_id_t type, char *buf, size_t len) 93691eaf3e1SJohn Birrell { 93791eaf3e1SJohn Birrell ctf_decl_t cd; 93891eaf3e1SJohn Birrell ctf_decl_node_t *cdp; 93991eaf3e1SJohn Birrell ctf_decl_prec_t prec, lp, rp; 94091eaf3e1SJohn Birrell int ptr, arr; 94191eaf3e1SJohn Birrell uint_t k; 94291eaf3e1SJohn Birrell 94391eaf3e1SJohn Birrell if (lc == NULL && type == CTF_ERR) 94491eaf3e1SJohn Birrell return (-1); /* simplify caller code by permitting CTF_ERR */ 94591eaf3e1SJohn Birrell 94691eaf3e1SJohn Birrell ctf_decl_init(&cd, buf, len); 94791eaf3e1SJohn Birrell ctf_decl_push(&cd, lc, type); 94891eaf3e1SJohn Birrell 94991eaf3e1SJohn Birrell if (cd.cd_err != 0) { 95091eaf3e1SJohn Birrell ctf_decl_fini(&cd); 95191eaf3e1SJohn Birrell return (-1); 95291eaf3e1SJohn Birrell } 95391eaf3e1SJohn Birrell 95491eaf3e1SJohn Birrell /* 95591eaf3e1SJohn Birrell * If the type graph's order conflicts with lexical precedence order 95691eaf3e1SJohn Birrell * for pointers or arrays, then we need to surround the declarations at 95791eaf3e1SJohn Birrell * the corresponding lexical precedence with parentheses. This can 95891eaf3e1SJohn Birrell * result in either a parenthesized pointer (*) as in int (*)() or 95991eaf3e1SJohn Birrell * int (*)[], or in a parenthesized pointer and array as in int (*[])(). 96091eaf3e1SJohn Birrell */ 96191eaf3e1SJohn Birrell ptr = cd.cd_order[CTF_PREC_POINTER] > CTF_PREC_POINTER; 96291eaf3e1SJohn Birrell arr = cd.cd_order[CTF_PREC_ARRAY] > CTF_PREC_ARRAY; 96391eaf3e1SJohn Birrell 96491eaf3e1SJohn Birrell rp = arr ? CTF_PREC_ARRAY : ptr ? CTF_PREC_POINTER : -1; 96591eaf3e1SJohn Birrell lp = ptr ? CTF_PREC_POINTER : arr ? CTF_PREC_ARRAY : -1; 96691eaf3e1SJohn Birrell 96791eaf3e1SJohn Birrell k = CTF_K_POINTER; /* avoid leading whitespace (see below) */ 96891eaf3e1SJohn Birrell 96991eaf3e1SJohn Birrell for (prec = CTF_PREC_BASE; prec < CTF_PREC_MAX; prec++) { 97091eaf3e1SJohn Birrell for (cdp = ctf_list_next(&cd.cd_nodes[prec]); 97191eaf3e1SJohn Birrell cdp != NULL; cdp = ctf_list_next(cdp)) { 97291eaf3e1SJohn Birrell 97391eaf3e1SJohn Birrell const ctf_type_t *tp = 97491eaf3e1SJohn Birrell ctf_lookup_by_id(lc, cdp->cd_type); 97591eaf3e1SJohn Birrell const char *name = ctf_strptr(lc, tp->ctt_name); 97691eaf3e1SJohn Birrell 97791eaf3e1SJohn Birrell if (k != CTF_K_POINTER && k != CTF_K_ARRAY) 97891eaf3e1SJohn Birrell ctf_decl_sprintf(&cd, " "); 97991eaf3e1SJohn Birrell 98091eaf3e1SJohn Birrell if (lp == prec) { 98191eaf3e1SJohn Birrell ctf_decl_sprintf(&cd, "("); 98291eaf3e1SJohn Birrell lp = -1; 98391eaf3e1SJohn Birrell } 98491eaf3e1SJohn Birrell 98591eaf3e1SJohn Birrell switch (cdp->cd_kind) { 98691eaf3e1SJohn Birrell case CTF_K_INTEGER: 98791eaf3e1SJohn Birrell case CTF_K_FLOAT: 98891eaf3e1SJohn Birrell case CTF_K_TYPEDEF: 98991eaf3e1SJohn Birrell ctf_decl_sprintf(&cd, "%s", name); 99091eaf3e1SJohn Birrell break; 99191eaf3e1SJohn Birrell case CTF_K_POINTER: 99291eaf3e1SJohn Birrell ctf_decl_sprintf(&cd, "*"); 99391eaf3e1SJohn Birrell break; 99491eaf3e1SJohn Birrell case CTF_K_ARRAY: 99591eaf3e1SJohn Birrell ctf_decl_sprintf(&cd, "[%u]", cdp->cd_n); 99691eaf3e1SJohn Birrell break; 99791eaf3e1SJohn Birrell case CTF_K_FUNCTION: 99891eaf3e1SJohn Birrell ctf_decl_sprintf(&cd, "()"); 99991eaf3e1SJohn Birrell break; 100091eaf3e1SJohn Birrell case CTF_K_STRUCT: 100191eaf3e1SJohn Birrell case CTF_K_FORWARD: 100291eaf3e1SJohn Birrell ctf_decl_sprintf(&cd, "struct %s", name); 100391eaf3e1SJohn Birrell break; 100491eaf3e1SJohn Birrell case CTF_K_UNION: 100591eaf3e1SJohn Birrell ctf_decl_sprintf(&cd, "union %s", name); 100691eaf3e1SJohn Birrell break; 100791eaf3e1SJohn Birrell case CTF_K_ENUM: 100891eaf3e1SJohn Birrell ctf_decl_sprintf(&cd, "enum %s", name); 100991eaf3e1SJohn Birrell break; 101091eaf3e1SJohn Birrell case CTF_K_VOLATILE: 101191eaf3e1SJohn Birrell ctf_decl_sprintf(&cd, "volatile"); 101291eaf3e1SJohn Birrell break; 101391eaf3e1SJohn Birrell case CTF_K_CONST: 101491eaf3e1SJohn Birrell ctf_decl_sprintf(&cd, "const"); 101591eaf3e1SJohn Birrell break; 101691eaf3e1SJohn Birrell case CTF_K_RESTRICT: 101791eaf3e1SJohn Birrell ctf_decl_sprintf(&cd, "restrict"); 101891eaf3e1SJohn Birrell break; 101991eaf3e1SJohn Birrell } 102091eaf3e1SJohn Birrell 102191eaf3e1SJohn Birrell k = cdp->cd_kind; 102291eaf3e1SJohn Birrell } 102391eaf3e1SJohn Birrell 102491eaf3e1SJohn Birrell if (rp == prec) 102591eaf3e1SJohn Birrell ctf_decl_sprintf(&cd, ")"); 102691eaf3e1SJohn Birrell } 102791eaf3e1SJohn Birrell 102891eaf3e1SJohn Birrell ctf_decl_fini(&cd); 102991eaf3e1SJohn Birrell return (cd.cd_len); 103091eaf3e1SJohn Birrell } 103191eaf3e1SJohn Birrell 103291eaf3e1SJohn Birrell static void 103391eaf3e1SJohn Birrell fbt_getargdesc(void *arg __unused, dtrace_id_t id __unused, void *parg, dtrace_argdesc_t *desc) 103491eaf3e1SJohn Birrell { 103591eaf3e1SJohn Birrell const ushort_t *dp; 103691eaf3e1SJohn Birrell fbt_probe_t *fbt = parg; 103791eaf3e1SJohn Birrell linker_ctf_t lc; 103891eaf3e1SJohn Birrell modctl_t *ctl = fbt->fbtp_ctl; 103991eaf3e1SJohn Birrell int ndx = desc->dtargd_ndx; 104091eaf3e1SJohn Birrell int symindx = fbt->fbtp_symindx; 104191eaf3e1SJohn Birrell uint32_t *ctfoff; 104291eaf3e1SJohn Birrell uint32_t offset; 104391eaf3e1SJohn Birrell ushort_t info, kind, n; 104491eaf3e1SJohn Birrell 1045aaf2546bSAndriy Gapon if (fbt->fbtp_roffset != 0 && desc->dtargd_ndx == 0) { 1046aaf2546bSAndriy Gapon (void) strcpy(desc->dtargd_native, "int"); 1047aaf2546bSAndriy Gapon return; 1048aaf2546bSAndriy Gapon } 1049aaf2546bSAndriy Gapon 105091eaf3e1SJohn Birrell desc->dtargd_ndx = DTRACE_ARGNONE; 105191eaf3e1SJohn Birrell 105291eaf3e1SJohn Birrell /* Get a pointer to the CTF data and it's length. */ 105391eaf3e1SJohn Birrell if (linker_ctf_get(ctl, &lc) != 0) 105491eaf3e1SJohn Birrell /* No CTF data? Something wrong? *shrug* */ 105591eaf3e1SJohn Birrell return; 105691eaf3e1SJohn Birrell 105791eaf3e1SJohn Birrell /* Check if this module hasn't been initialised yet. */ 105891eaf3e1SJohn Birrell if (*lc.ctfoffp == NULL) { 105991eaf3e1SJohn Birrell /* 106091eaf3e1SJohn Birrell * Initialise the CTF object and function symindx to 106191eaf3e1SJohn Birrell * byte offset array. 106291eaf3e1SJohn Birrell */ 106391eaf3e1SJohn Birrell if (fbt_ctfoff_init(ctl, &lc) != 0) 106491eaf3e1SJohn Birrell return; 106591eaf3e1SJohn Birrell 106691eaf3e1SJohn Birrell /* Initialise the CTF type to byte offset array. */ 106791eaf3e1SJohn Birrell if (fbt_typoff_init(&lc) != 0) 106891eaf3e1SJohn Birrell return; 106991eaf3e1SJohn Birrell } 107091eaf3e1SJohn Birrell 107191eaf3e1SJohn Birrell ctfoff = *lc.ctfoffp; 107291eaf3e1SJohn Birrell 107391eaf3e1SJohn Birrell if (ctfoff == NULL || *lc.typoffp == NULL) 107491eaf3e1SJohn Birrell return; 107591eaf3e1SJohn Birrell 107691eaf3e1SJohn Birrell /* Check if the symbol index is out of range. */ 107791eaf3e1SJohn Birrell if (symindx >= lc.nsym) 107891eaf3e1SJohn Birrell return; 107991eaf3e1SJohn Birrell 108091eaf3e1SJohn Birrell /* Check if the symbol isn't cross-referenced. */ 108191eaf3e1SJohn Birrell if ((offset = ctfoff[symindx]) == 0xffffffff) 108291eaf3e1SJohn Birrell return; 108391eaf3e1SJohn Birrell 108491eaf3e1SJohn Birrell dp = (const ushort_t *)(lc.ctftab + offset + sizeof(ctf_header_t)); 108591eaf3e1SJohn Birrell 108691eaf3e1SJohn Birrell info = *dp++; 108791eaf3e1SJohn Birrell kind = CTF_INFO_KIND(info); 108891eaf3e1SJohn Birrell n = CTF_INFO_VLEN(info); 108991eaf3e1SJohn Birrell 109091eaf3e1SJohn Birrell if (kind == CTF_K_UNKNOWN && n == 0) { 109191eaf3e1SJohn Birrell printf("%s(%d): Unknown function!\n",__func__,__LINE__); 109291eaf3e1SJohn Birrell return; 109391eaf3e1SJohn Birrell } 109491eaf3e1SJohn Birrell 109591eaf3e1SJohn Birrell if (kind != CTF_K_FUNCTION) { 109691eaf3e1SJohn Birrell printf("%s(%d): Expected a function!\n",__func__,__LINE__); 109791eaf3e1SJohn Birrell return; 109891eaf3e1SJohn Birrell } 109991eaf3e1SJohn Birrell 1100aaf2546bSAndriy Gapon if (fbt->fbtp_roffset != 0) { 1101aaf2546bSAndriy Gapon /* Only return type is available for args[1] in return probe. */ 1102aaf2546bSAndriy Gapon if (ndx > 1) 1103aaf2546bSAndriy Gapon return; 1104aaf2546bSAndriy Gapon ASSERT(ndx == 1); 1105aaf2546bSAndriy Gapon } else { 110691eaf3e1SJohn Birrell /* Check if the requested argument doesn't exist. */ 110791eaf3e1SJohn Birrell if (ndx >= n) 110891eaf3e1SJohn Birrell return; 110991eaf3e1SJohn Birrell 111091eaf3e1SJohn Birrell /* Skip the return type and arguments up to the one requested. */ 111191eaf3e1SJohn Birrell dp += ndx + 1; 1112aaf2546bSAndriy Gapon } 111391eaf3e1SJohn Birrell 111491eaf3e1SJohn Birrell if (fbt_type_name(&lc, *dp, desc->dtargd_native, sizeof(desc->dtargd_native)) > 0) 111591eaf3e1SJohn Birrell desc->dtargd_ndx = ndx; 111691eaf3e1SJohn Birrell 111791eaf3e1SJohn Birrell return; 111891eaf3e1SJohn Birrell } 111991eaf3e1SJohn Birrell 11208776669bSMark Johnston static int 11218776669bSMark Johnston fbt_linker_file_cb(linker_file_t lf, void *arg) 11228776669bSMark Johnston { 11238776669bSMark Johnston 11248776669bSMark Johnston fbt_provide_module(arg, lf); 11258776669bSMark Johnston 11268776669bSMark Johnston return (0); 11278776669bSMark Johnston } 11288776669bSMark Johnston 112991eaf3e1SJohn Birrell static void 113091eaf3e1SJohn Birrell fbt_load(void *dummy) 113191eaf3e1SJohn Birrell { 113291eaf3e1SJohn Birrell /* Create the /dev/dtrace/fbt entry. */ 113391eaf3e1SJohn Birrell fbt_cdev = make_dev(&fbt_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, 113491eaf3e1SJohn Birrell "dtrace/fbt"); 113591eaf3e1SJohn Birrell 113691eaf3e1SJohn Birrell /* Default the probe table size if not specified. */ 113791eaf3e1SJohn Birrell if (fbt_probetab_size == 0) 113891eaf3e1SJohn Birrell fbt_probetab_size = FBT_PROBETAB_SIZE; 113991eaf3e1SJohn Birrell 114091eaf3e1SJohn Birrell /* Choose the hash mask for the probe table. */ 114191eaf3e1SJohn Birrell fbt_probetab_mask = fbt_probetab_size - 1; 114291eaf3e1SJohn Birrell 114391eaf3e1SJohn Birrell /* Allocate memory for the probe table. */ 114491eaf3e1SJohn Birrell fbt_probetab = 114591eaf3e1SJohn Birrell malloc(fbt_probetab_size * sizeof (fbt_probe_t *), M_FBT, M_WAITOK | M_ZERO); 114691eaf3e1SJohn Birrell 114791eaf3e1SJohn Birrell dtrace_doubletrap_func = fbt_doubletrap; 114891eaf3e1SJohn Birrell dtrace_invop_add(fbt_invop); 114991eaf3e1SJohn Birrell 115091eaf3e1SJohn Birrell if (dtrace_register("fbt", &fbt_attr, DTRACE_PRIV_USER, 115191eaf3e1SJohn Birrell NULL, &fbt_pops, NULL, &fbt_id) != 0) 115291eaf3e1SJohn Birrell return; 115391eaf3e1SJohn Birrell 11548776669bSMark Johnston /* Create probes for the kernel and already-loaded modules. */ 11558776669bSMark Johnston linker_file_foreach(fbt_linker_file_cb, NULL); 11568776669bSMark Johnston } 115791eaf3e1SJohn Birrell 115891eaf3e1SJohn Birrell static int 115991eaf3e1SJohn Birrell fbt_unload() 116091eaf3e1SJohn Birrell { 116191eaf3e1SJohn Birrell int error = 0; 116291eaf3e1SJohn Birrell 116391eaf3e1SJohn Birrell /* De-register the invalid opcode handler. */ 116491eaf3e1SJohn Birrell dtrace_invop_remove(fbt_invop); 116591eaf3e1SJohn Birrell 116691eaf3e1SJohn Birrell dtrace_doubletrap_func = NULL; 116791eaf3e1SJohn Birrell 116891eaf3e1SJohn Birrell /* De-register this DTrace provider. */ 116991eaf3e1SJohn Birrell if ((error = dtrace_unregister(fbt_id)) != 0) 117091eaf3e1SJohn Birrell return (error); 117191eaf3e1SJohn Birrell 117291eaf3e1SJohn Birrell /* Free the probe table. */ 117391eaf3e1SJohn Birrell free(fbt_probetab, M_FBT); 117491eaf3e1SJohn Birrell fbt_probetab = NULL; 117591eaf3e1SJohn Birrell fbt_probetab_mask = 0; 117691eaf3e1SJohn Birrell 117791eaf3e1SJohn Birrell destroy_dev(fbt_cdev); 117891eaf3e1SJohn Birrell 117991eaf3e1SJohn Birrell return (error); 118091eaf3e1SJohn Birrell } 118191eaf3e1SJohn Birrell 118291eaf3e1SJohn Birrell static int 118391eaf3e1SJohn Birrell fbt_modevent(module_t mod __unused, int type, void *data __unused) 118491eaf3e1SJohn Birrell { 118591eaf3e1SJohn Birrell int error = 0; 118691eaf3e1SJohn Birrell 118791eaf3e1SJohn Birrell switch (type) { 118891eaf3e1SJohn Birrell case MOD_LOAD: 118991eaf3e1SJohn Birrell break; 119091eaf3e1SJohn Birrell 119191eaf3e1SJohn Birrell case MOD_UNLOAD: 119291eaf3e1SJohn Birrell break; 119391eaf3e1SJohn Birrell 119491eaf3e1SJohn Birrell case MOD_SHUTDOWN: 119591eaf3e1SJohn Birrell break; 119691eaf3e1SJohn Birrell 119791eaf3e1SJohn Birrell default: 119891eaf3e1SJohn Birrell error = EOPNOTSUPP; 119991eaf3e1SJohn Birrell break; 120091eaf3e1SJohn Birrell 120191eaf3e1SJohn Birrell } 120291eaf3e1SJohn Birrell 120391eaf3e1SJohn Birrell return (error); 120491eaf3e1SJohn Birrell } 120591eaf3e1SJohn Birrell 120691eaf3e1SJohn Birrell static int 120791eaf3e1SJohn Birrell fbt_open(struct cdev *dev __unused, int oflags __unused, int devtype __unused, struct thread *td __unused) 120891eaf3e1SJohn Birrell { 120991eaf3e1SJohn Birrell return (0); 121091eaf3e1SJohn Birrell } 121191eaf3e1SJohn Birrell 121291eaf3e1SJohn Birrell SYSINIT(fbt_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, fbt_load, NULL); 121391eaf3e1SJohn Birrell SYSUNINIT(fbt_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, fbt_unload, NULL); 121491eaf3e1SJohn Birrell 121591eaf3e1SJohn Birrell DEV_MODULE(fbt, fbt_modevent, NULL); 121691eaf3e1SJohn Birrell MODULE_VERSION(fbt, 1); 121791eaf3e1SJohn Birrell MODULE_DEPEND(fbt, dtrace, 1, 1, 1); 121891eaf3e1SJohn Birrell MODULE_DEPEND(fbt, opensolaris, 1, 1, 1); 1219