16ff6d951SJohn Birrell /* 26ff6d951SJohn Birrell * CDDL HEADER START 36ff6d951SJohn Birrell * 46ff6d951SJohn Birrell * The contents of this file are subject to the terms of the 51670a1c2SRui Paulo * Common Development and Distribution License (the "License"). 61670a1c2SRui Paulo * You may not use this file except in compliance with the License. 76ff6d951SJohn Birrell * 86ff6d951SJohn Birrell * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 96ff6d951SJohn Birrell * or http://www.opensolaris.org/os/licensing. 106ff6d951SJohn Birrell * See the License for the specific language governing permissions 116ff6d951SJohn Birrell * and limitations under the License. 126ff6d951SJohn Birrell * 136ff6d951SJohn Birrell * When distributing Covered Code, include this CDDL HEADER in each 146ff6d951SJohn Birrell * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 156ff6d951SJohn Birrell * If applicable, add the following below this CDDL HEADER, with the 166ff6d951SJohn Birrell * fields enclosed by brackets "[]" replaced with your own identifying 176ff6d951SJohn Birrell * information: Portions Copyright [yyyy] [name of copyright owner] 186ff6d951SJohn Birrell * 196ff6d951SJohn Birrell * CDDL HEADER END 206ff6d951SJohn Birrell */ 216ff6d951SJohn Birrell /* 221670a1c2SRui Paulo * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 2344c25a3dSMark Johnston * Copyright 2013 Voxer Inc. All rights reserved. 246ff6d951SJohn Birrell * Use is subject to license terms. 256ff6d951SJohn Birrell */ 266ff6d951SJohn Birrell 27*9e5787d2SMatt Macy #include <sys/types.h> 286ff6d951SJohn Birrell #include <unistd.h> 296ff6d951SJohn Birrell #include <fcntl.h> 306ff6d951SJohn Birrell #include <dlfcn.h> 316ff6d951SJohn Birrell #include <link.h> 326ff6d951SJohn Birrell #include <sys/dtrace.h> 336ff6d951SJohn Birrell 346ff6d951SJohn Birrell #include <stdarg.h> 356ff6d951SJohn Birrell #include <stdio.h> 366ff6d951SJohn Birrell #include <stdlib.h> 376ff6d951SJohn Birrell #include <string.h> 386ff6d951SJohn Birrell #include <errno.h> 390f2bd1e8SRui Paulo #include <libelf.h> 406ff6d951SJohn Birrell 416ff6d951SJohn Birrell /* 426ff6d951SJohn Birrell * In Solaris 10 GA, the only mechanism for communicating helper information 436ff6d951SJohn Birrell * is through the DTrace helper pseudo-device node in /devices; there is 446ff6d951SJohn Birrell * no /dev link. Because of this, USDT providers and helper actions don't 456ff6d951SJohn Birrell * work inside of non-global zones. This issue was addressed by adding 466ff6d951SJohn Birrell * the /dev and having this initialization code use that /dev link. If the 476ff6d951SJohn Birrell * /dev link doesn't exist it falls back to looking for the /devices node 486ff6d951SJohn Birrell * as this code may be embedded in a binary which runs on Solaris 10 GA. 496ff6d951SJohn Birrell * 506ff6d951SJohn Birrell * Users may set the following environment variable to affect the way 516ff6d951SJohn Birrell * helper initialization takes place: 526ff6d951SJohn Birrell * 536ff6d951SJohn Birrell * DTRACE_DOF_INIT_DEBUG enable debugging output 546ff6d951SJohn Birrell * DTRACE_DOF_INIT_DISABLE disable helper loading 556ff6d951SJohn Birrell * DTRACE_DOF_INIT_DEVNAME set the path to the helper node 566ff6d951SJohn Birrell */ 576ff6d951SJohn Birrell 585fe26f7cSJohn Birrell static const char *devnamep = "/dev/dtrace/helper"; 59bc96366cSSteven Hartland #ifdef illumos 606ff6d951SJohn Birrell static const char *olddevname = "/devices/pseudo/dtrace@0:helper"; 610f2bd1e8SRui Paulo #endif 626ff6d951SJohn Birrell 636ff6d951SJohn Birrell static const char *modname; /* Name of this load object */ 646ff6d951SJohn Birrell static int gen; /* DOF helper generation */ 656ff6d951SJohn Birrell extern dof_hdr_t __SUNW_dof; /* DOF defined in the .SUNW_dof section */ 66dba0ac63SRui Paulo static boolean_t dof_init_debug = B_FALSE; /* From DTRACE_DOF_INIT_DEBUG */ 676ff6d951SJohn Birrell 686ff6d951SJohn Birrell static void 6925fac4a6SBaptiste Daroussin dbg_printf(int debug, const char *fmt, ...) 706ff6d951SJohn Birrell { 716ff6d951SJohn Birrell va_list ap; 726ff6d951SJohn Birrell 731670a1c2SRui Paulo if (debug && !dof_init_debug) 746ff6d951SJohn Birrell return; 756ff6d951SJohn Birrell 766ff6d951SJohn Birrell va_start(ap, fmt); 776ff6d951SJohn Birrell 786ff6d951SJohn Birrell if (modname == NULL) 796ff6d951SJohn Birrell (void) fprintf(stderr, "dtrace DOF: "); 806ff6d951SJohn Birrell else 816ff6d951SJohn Birrell (void) fprintf(stderr, "dtrace DOF %s: ", modname); 826ff6d951SJohn Birrell 836ff6d951SJohn Birrell (void) vfprintf(stderr, fmt, ap); 846ff6d951SJohn Birrell 856ff6d951SJohn Birrell if (fmt[strlen(fmt) - 1] != '\n') 866ff6d951SJohn Birrell (void) fprintf(stderr, ": %s\n", strerror(errno)); 876ff6d951SJohn Birrell 886ff6d951SJohn Birrell va_end(ap); 896ff6d951SJohn Birrell } 906ff6d951SJohn Birrell 91bc96366cSSteven Hartland #ifdef illumos 926ff6d951SJohn Birrell #pragma init(dtrace_dof_init) 935fe26f7cSJohn Birrell #else 945fe26f7cSJohn Birrell static void dtrace_dof_init(void) __attribute__ ((constructor)); 955fe26f7cSJohn Birrell #endif 965fe26f7cSJohn Birrell 976ff6d951SJohn Birrell static void 986ff6d951SJohn Birrell dtrace_dof_init(void) 996ff6d951SJohn Birrell { 1006ff6d951SJohn Birrell dof_hdr_t *dof = &__SUNW_dof; 1016ff6d951SJohn Birrell #ifdef _LP64 1026ff6d951SJohn Birrell Elf64_Ehdr *elf; 1036ff6d951SJohn Birrell #else 1046ff6d951SJohn Birrell Elf32_Ehdr *elf; 1056ff6d951SJohn Birrell #endif 1066ff6d951SJohn Birrell dof_helper_t dh; 1079ad184a9SWill Andrews Link_map *lmp = NULL; 108bc96366cSSteven Hartland #ifdef illumos 1096ff6d951SJohn Birrell Lmid_t lmid; 1105fe26f7cSJohn Birrell #else 1115fe26f7cSJohn Birrell u_long lmid = 0; 1125fe26f7cSJohn Birrell #endif 1136ff6d951SJohn Birrell int fd; 1146ff6d951SJohn Birrell const char *p; 1156ff6d951SJohn Birrell 1166ff6d951SJohn Birrell if (getenv("DTRACE_DOF_INIT_DISABLE") != NULL) 1176ff6d951SJohn Birrell return; 1186ff6d951SJohn Birrell 1191670a1c2SRui Paulo if (getenv("DTRACE_DOF_INIT_DEBUG") != NULL) 1201670a1c2SRui Paulo dof_init_debug = B_TRUE; 1211670a1c2SRui Paulo 1226ff6d951SJohn Birrell if (dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &lmp) == -1 || lmp == NULL) { 12325fac4a6SBaptiste Daroussin dbg_printf(1, "couldn't discover module name or address\n"); 1246ff6d951SJohn Birrell return; 1256ff6d951SJohn Birrell } 1266ff6d951SJohn Birrell 127bc96366cSSteven Hartland #ifdef illumos 1286ff6d951SJohn Birrell if (dlinfo(RTLD_SELF, RTLD_DI_LMID, &lmid) == -1) { 12925fac4a6SBaptiste Daroussin dbg_printf(1, "couldn't discover link map ID\n"); 1306ff6d951SJohn Birrell return; 1316ff6d951SJohn Birrell } 1325fe26f7cSJohn Birrell #endif 1336ff6d951SJohn Birrell 1346ff6d951SJohn Birrell if ((modname = strrchr(lmp->l_name, '/')) == NULL) 1356ff6d951SJohn Birrell modname = lmp->l_name; 1366ff6d951SJohn Birrell else 1376ff6d951SJohn Birrell modname++; 1386ff6d951SJohn Birrell 1396ff6d951SJohn Birrell if (dof->dofh_ident[DOF_ID_MAG0] != DOF_MAG_MAG0 || 1406ff6d951SJohn Birrell dof->dofh_ident[DOF_ID_MAG1] != DOF_MAG_MAG1 || 1416ff6d951SJohn Birrell dof->dofh_ident[DOF_ID_MAG2] != DOF_MAG_MAG2 || 1426ff6d951SJohn Birrell dof->dofh_ident[DOF_ID_MAG3] != DOF_MAG_MAG3) { 14325fac4a6SBaptiste Daroussin dbg_printf(0, ".SUNW_dof section corrupt\n"); 1446ff6d951SJohn Birrell return; 1456ff6d951SJohn Birrell } 1466ff6d951SJohn Birrell 147d0ca9a7fSKonstantin Belousov #ifdef __FreeBSD__ 148d0ca9a7fSKonstantin Belousov elf = (void *)lmp->l_base; 149d0ca9a7fSKonstantin Belousov #else 1506ff6d951SJohn Birrell elf = (void *)lmp->l_addr; 151d0ca9a7fSKonstantin Belousov #endif 1526ff6d951SJohn Birrell 1536ff6d951SJohn Birrell dh.dofhp_dof = (uintptr_t)dof; 15467cf27b7SMark Johnston #ifdef __FreeBSD__ 155d0ca9a7fSKonstantin Belousov dh.dofhp_addr = elf->e_type == ET_DYN ? (uintptr_t) lmp->l_base : 0; 15667cf27b7SMark Johnston dh.dofhp_pid = getpid(); 157d0ca9a7fSKonstantin Belousov #else 158d0ca9a7fSKonstantin Belousov dh.dofhp_addr = elf->e_type == ET_DYN ? (uintptr_t) lmp->l_addr : 0; 15967cf27b7SMark Johnston #endif 1606ff6d951SJohn Birrell 1616ff6d951SJohn Birrell if (lmid == 0) { 1626ff6d951SJohn Birrell (void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod), 1636ff6d951SJohn Birrell "%s", modname); 1646ff6d951SJohn Birrell } else { 1656ff6d951SJohn Birrell (void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod), 1666ff6d951SJohn Birrell "LM%lu`%s", lmid, modname); 1676ff6d951SJohn Birrell } 1686ff6d951SJohn Birrell 1696ff6d951SJohn Birrell if ((p = getenv("DTRACE_DOF_INIT_DEVNAME")) != NULL) 1705fe26f7cSJohn Birrell devnamep = p; 1716ff6d951SJohn Birrell 1725fe26f7cSJohn Birrell if ((fd = open64(devnamep, O_RDWR)) < 0) { 17325fac4a6SBaptiste Daroussin dbg_printf(1, "failed to open helper device %s", devnamep); 174bc96366cSSteven Hartland #ifdef illumos 1756ff6d951SJohn Birrell /* 1766ff6d951SJohn Birrell * If the device path wasn't explicitly set, try again with 1776ff6d951SJohn Birrell * the old device path. 1786ff6d951SJohn Birrell */ 1796ff6d951SJohn Birrell if (p != NULL) 1806ff6d951SJohn Birrell return; 1816ff6d951SJohn Birrell 1825fe26f7cSJohn Birrell devnamep = olddevname; 1836ff6d951SJohn Birrell 1845fe26f7cSJohn Birrell if ((fd = open64(devnamep, O_RDWR)) < 0) { 18525fac4a6SBaptiste Daroussin dbg_printf(1, "failed to open helper device %s", devnamep); 1866ff6d951SJohn Birrell return; 1876ff6d951SJohn Birrell } 1880f2bd1e8SRui Paulo #else 1890f2bd1e8SRui Paulo return; 1900f2bd1e8SRui Paulo #endif 1916ff6d951SJohn Birrell } 1926ff6d951SJohn Birrell if ((gen = ioctl(fd, DTRACEHIOC_ADDDOF, &dh)) == -1) 19325fac4a6SBaptiste Daroussin dbg_printf(1, "DTrace ioctl failed for DOF at %p", dof); 1940f2bd1e8SRui Paulo else { 19525fac4a6SBaptiste Daroussin dbg_printf(1, "DTrace ioctl succeeded for DOF at %p\n", dof); 19603a5f9f0SMark Johnston #ifdef __FreeBSD__ 19767cf27b7SMark Johnston gen = dh.dofhp_gen; 1980f2bd1e8SRui Paulo #endif 1990f2bd1e8SRui Paulo } 2006ff6d951SJohn Birrell 2016ff6d951SJohn Birrell (void) close(fd); 2026ff6d951SJohn Birrell } 2036ff6d951SJohn Birrell 204bc96366cSSteven Hartland #ifdef illumos 2056ff6d951SJohn Birrell #pragma fini(dtrace_dof_fini) 2065fe26f7cSJohn Birrell #else 2075fe26f7cSJohn Birrell static void dtrace_dof_fini(void) __attribute__ ((destructor)); 2085fe26f7cSJohn Birrell #endif 2095fe26f7cSJohn Birrell 2106ff6d951SJohn Birrell static void 2116ff6d951SJohn Birrell dtrace_dof_fini(void) 2126ff6d951SJohn Birrell { 2136ff6d951SJohn Birrell int fd; 2146ff6d951SJohn Birrell 2155fe26f7cSJohn Birrell if ((fd = open64(devnamep, O_RDWR)) < 0) { 21625fac4a6SBaptiste Daroussin dbg_printf(1, "failed to open helper device %s", devnamep); 2176ff6d951SJohn Birrell return; 2186ff6d951SJohn Birrell } 2196ff6d951SJohn Birrell 2200f2bd1e8SRui Paulo if ((gen = ioctl(fd, DTRACEHIOC_REMOVE, &gen)) == -1) 22125fac4a6SBaptiste Daroussin dbg_printf(1, "DTrace ioctl failed to remove DOF (%d)\n", gen); 2226ff6d951SJohn Birrell else 22325fac4a6SBaptiste Daroussin dbg_printf(1, "DTrace ioctl removed DOF (%d)\n", gen); 2246ff6d951SJohn Birrell 2256ff6d951SJohn Birrell (void) close(fd); 2266ff6d951SJohn Birrell } 227