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 276ff6d951SJohn Birrell #include <unistd.h> 286ff6d951SJohn Birrell #include <fcntl.h> 296ff6d951SJohn Birrell #include <dlfcn.h> 306ff6d951SJohn Birrell #include <link.h> 316ff6d951SJohn Birrell #include <sys/dtrace.h> 326ff6d951SJohn Birrell 336ff6d951SJohn Birrell #include <stdarg.h> 346ff6d951SJohn Birrell #include <stdio.h> 356ff6d951SJohn Birrell #include <stdlib.h> 366ff6d951SJohn Birrell #include <string.h> 376ff6d951SJohn Birrell #include <errno.h> 380f2bd1e8SRui Paulo #include <libelf.h> 396ff6d951SJohn Birrell 406ff6d951SJohn Birrell /* 416ff6d951SJohn Birrell * In Solaris 10 GA, the only mechanism for communicating helper information 426ff6d951SJohn Birrell * is through the DTrace helper pseudo-device node in /devices; there is 436ff6d951SJohn Birrell * no /dev link. Because of this, USDT providers and helper actions don't 446ff6d951SJohn Birrell * work inside of non-global zones. This issue was addressed by adding 456ff6d951SJohn Birrell * the /dev and having this initialization code use that /dev link. If the 466ff6d951SJohn Birrell * /dev link doesn't exist it falls back to looking for the /devices node 476ff6d951SJohn Birrell * as this code may be embedded in a binary which runs on Solaris 10 GA. 486ff6d951SJohn Birrell * 496ff6d951SJohn Birrell * Users may set the following environment variable to affect the way 506ff6d951SJohn Birrell * helper initialization takes place: 516ff6d951SJohn Birrell * 526ff6d951SJohn Birrell * DTRACE_DOF_INIT_DEBUG enable debugging output 536ff6d951SJohn Birrell * DTRACE_DOF_INIT_DISABLE disable helper loading 546ff6d951SJohn Birrell * DTRACE_DOF_INIT_DEVNAME set the path to the helper node 556ff6d951SJohn Birrell */ 566ff6d951SJohn Birrell 575fe26f7cSJohn Birrell static const char *devnamep = "/dev/dtrace/helper"; 58bc96366cSSteven Hartland #ifdef illumos 596ff6d951SJohn Birrell static const char *olddevname = "/devices/pseudo/dtrace@0:helper"; 600f2bd1e8SRui Paulo #endif 616ff6d951SJohn Birrell 626ff6d951SJohn Birrell static const char *modname; /* Name of this load object */ 636ff6d951SJohn Birrell static int gen; /* DOF helper generation */ 646ff6d951SJohn Birrell extern dof_hdr_t __SUNW_dof; /* DOF defined in the .SUNW_dof section */ 65dba0ac63SRui Paulo static boolean_t dof_init_debug = B_FALSE; /* From DTRACE_DOF_INIT_DEBUG */ 666ff6d951SJohn Birrell 676ff6d951SJohn Birrell static void 6825fac4a6SBaptiste Daroussin dbg_printf(int debug, const char *fmt, ...) 696ff6d951SJohn Birrell { 706ff6d951SJohn Birrell va_list ap; 716ff6d951SJohn Birrell 721670a1c2SRui Paulo if (debug && !dof_init_debug) 736ff6d951SJohn Birrell return; 746ff6d951SJohn Birrell 756ff6d951SJohn Birrell va_start(ap, fmt); 766ff6d951SJohn Birrell 776ff6d951SJohn Birrell if (modname == NULL) 786ff6d951SJohn Birrell (void) fprintf(stderr, "dtrace DOF: "); 796ff6d951SJohn Birrell else 806ff6d951SJohn Birrell (void) fprintf(stderr, "dtrace DOF %s: ", modname); 816ff6d951SJohn Birrell 826ff6d951SJohn Birrell (void) vfprintf(stderr, fmt, ap); 836ff6d951SJohn Birrell 846ff6d951SJohn Birrell if (fmt[strlen(fmt) - 1] != '\n') 856ff6d951SJohn Birrell (void) fprintf(stderr, ": %s\n", strerror(errno)); 866ff6d951SJohn Birrell 876ff6d951SJohn Birrell va_end(ap); 886ff6d951SJohn Birrell } 896ff6d951SJohn Birrell 90bc96366cSSteven Hartland #ifdef illumos 916ff6d951SJohn Birrell #pragma init(dtrace_dof_init) 925fe26f7cSJohn Birrell #else 935fe26f7cSJohn Birrell static void dtrace_dof_init(void) __attribute__ ((constructor)); 945fe26f7cSJohn Birrell #endif 955fe26f7cSJohn Birrell 966ff6d951SJohn Birrell static void 976ff6d951SJohn Birrell dtrace_dof_init(void) 986ff6d951SJohn Birrell { 996ff6d951SJohn Birrell dof_hdr_t *dof = &__SUNW_dof; 1006ff6d951SJohn Birrell #ifdef _LP64 1016ff6d951SJohn Birrell Elf64_Ehdr *elf; 1026ff6d951SJohn Birrell #else 1036ff6d951SJohn Birrell Elf32_Ehdr *elf; 1046ff6d951SJohn Birrell #endif 1056ff6d951SJohn Birrell dof_helper_t dh; 1069ad184a9SWill Andrews Link_map *lmp = NULL; 107bc96366cSSteven Hartland #ifdef illumos 1086ff6d951SJohn Birrell Lmid_t lmid; 1095fe26f7cSJohn Birrell #else 1105fe26f7cSJohn Birrell u_long lmid = 0; 1115fe26f7cSJohn Birrell #endif 1126ff6d951SJohn Birrell int fd; 1136ff6d951SJohn Birrell const char *p; 1146ff6d951SJohn Birrell 1156ff6d951SJohn Birrell if (getenv("DTRACE_DOF_INIT_DISABLE") != NULL) 1166ff6d951SJohn Birrell return; 1176ff6d951SJohn Birrell 1181670a1c2SRui Paulo if (getenv("DTRACE_DOF_INIT_DEBUG") != NULL) 1191670a1c2SRui Paulo dof_init_debug = B_TRUE; 1201670a1c2SRui Paulo 1216ff6d951SJohn Birrell if (dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &lmp) == -1 || lmp == NULL) { 12225fac4a6SBaptiste Daroussin dbg_printf(1, "couldn't discover module name or address\n"); 1236ff6d951SJohn Birrell return; 1246ff6d951SJohn Birrell } 1256ff6d951SJohn Birrell 126bc96366cSSteven Hartland #ifdef illumos 1276ff6d951SJohn Birrell if (dlinfo(RTLD_SELF, RTLD_DI_LMID, &lmid) == -1) { 12825fac4a6SBaptiste Daroussin dbg_printf(1, "couldn't discover link map ID\n"); 1296ff6d951SJohn Birrell return; 1306ff6d951SJohn Birrell } 1315fe26f7cSJohn Birrell #endif 1326ff6d951SJohn Birrell 1336ff6d951SJohn Birrell if ((modname = strrchr(lmp->l_name, '/')) == NULL) 1346ff6d951SJohn Birrell modname = lmp->l_name; 1356ff6d951SJohn Birrell else 1366ff6d951SJohn Birrell modname++; 1376ff6d951SJohn Birrell 1386ff6d951SJohn Birrell if (dof->dofh_ident[DOF_ID_MAG0] != DOF_MAG_MAG0 || 1396ff6d951SJohn Birrell dof->dofh_ident[DOF_ID_MAG1] != DOF_MAG_MAG1 || 1406ff6d951SJohn Birrell dof->dofh_ident[DOF_ID_MAG2] != DOF_MAG_MAG2 || 1416ff6d951SJohn Birrell dof->dofh_ident[DOF_ID_MAG3] != DOF_MAG_MAG3) { 14225fac4a6SBaptiste Daroussin dbg_printf(0, ".SUNW_dof section corrupt\n"); 1436ff6d951SJohn Birrell return; 1446ff6d951SJohn Birrell } 1456ff6d951SJohn Birrell 146*d0ca9a7fSKonstantin Belousov #ifdef __FreeBSD__ 147*d0ca9a7fSKonstantin Belousov elf = (void *)lmp->l_base; 148*d0ca9a7fSKonstantin Belousov #else 1496ff6d951SJohn Birrell elf = (void *)lmp->l_addr; 150*d0ca9a7fSKonstantin Belousov #endif 1516ff6d951SJohn Birrell 1526ff6d951SJohn Birrell dh.dofhp_dof = (uintptr_t)dof; 15367cf27b7SMark Johnston #ifdef __FreeBSD__ 154*d0ca9a7fSKonstantin Belousov dh.dofhp_addr = elf->e_type == ET_DYN ? (uintptr_t) lmp->l_base : 0; 15567cf27b7SMark Johnston dh.dofhp_pid = getpid(); 156*d0ca9a7fSKonstantin Belousov #else 157*d0ca9a7fSKonstantin Belousov dh.dofhp_addr = elf->e_type == ET_DYN ? (uintptr_t) lmp->l_addr : 0; 15867cf27b7SMark Johnston #endif 1596ff6d951SJohn Birrell 1606ff6d951SJohn Birrell if (lmid == 0) { 1616ff6d951SJohn Birrell (void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod), 1626ff6d951SJohn Birrell "%s", modname); 1636ff6d951SJohn Birrell } else { 1646ff6d951SJohn Birrell (void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod), 1656ff6d951SJohn Birrell "LM%lu`%s", lmid, modname); 1666ff6d951SJohn Birrell } 1676ff6d951SJohn Birrell 1686ff6d951SJohn Birrell if ((p = getenv("DTRACE_DOF_INIT_DEVNAME")) != NULL) 1695fe26f7cSJohn Birrell devnamep = p; 1706ff6d951SJohn Birrell 1715fe26f7cSJohn Birrell if ((fd = open64(devnamep, O_RDWR)) < 0) { 17225fac4a6SBaptiste Daroussin dbg_printf(1, "failed to open helper device %s", devnamep); 173bc96366cSSteven Hartland #ifdef illumos 1746ff6d951SJohn Birrell /* 1756ff6d951SJohn Birrell * If the device path wasn't explicitly set, try again with 1766ff6d951SJohn Birrell * the old device path. 1776ff6d951SJohn Birrell */ 1786ff6d951SJohn Birrell if (p != NULL) 1796ff6d951SJohn Birrell return; 1806ff6d951SJohn Birrell 1815fe26f7cSJohn Birrell devnamep = olddevname; 1826ff6d951SJohn Birrell 1835fe26f7cSJohn Birrell if ((fd = open64(devnamep, O_RDWR)) < 0) { 18425fac4a6SBaptiste Daroussin dbg_printf(1, "failed to open helper device %s", devnamep); 1856ff6d951SJohn Birrell return; 1866ff6d951SJohn Birrell } 1870f2bd1e8SRui Paulo #else 1880f2bd1e8SRui Paulo return; 1890f2bd1e8SRui Paulo #endif 1906ff6d951SJohn Birrell } 1916ff6d951SJohn Birrell if ((gen = ioctl(fd, DTRACEHIOC_ADDDOF, &dh)) == -1) 19225fac4a6SBaptiste Daroussin dbg_printf(1, "DTrace ioctl failed for DOF at %p", dof); 1930f2bd1e8SRui Paulo else { 19425fac4a6SBaptiste Daroussin dbg_printf(1, "DTrace ioctl succeeded for DOF at %p\n", dof); 19503a5f9f0SMark Johnston #ifdef __FreeBSD__ 19667cf27b7SMark Johnston gen = dh.dofhp_gen; 1970f2bd1e8SRui Paulo #endif 1980f2bd1e8SRui Paulo } 1996ff6d951SJohn Birrell 2006ff6d951SJohn Birrell (void) close(fd); 2016ff6d951SJohn Birrell } 2026ff6d951SJohn Birrell 203bc96366cSSteven Hartland #ifdef illumos 2046ff6d951SJohn Birrell #pragma fini(dtrace_dof_fini) 2055fe26f7cSJohn Birrell #else 2065fe26f7cSJohn Birrell static void dtrace_dof_fini(void) __attribute__ ((destructor)); 2075fe26f7cSJohn Birrell #endif 2085fe26f7cSJohn Birrell 2096ff6d951SJohn Birrell static void 2106ff6d951SJohn Birrell dtrace_dof_fini(void) 2116ff6d951SJohn Birrell { 2126ff6d951SJohn Birrell int fd; 2136ff6d951SJohn Birrell 2145fe26f7cSJohn Birrell if ((fd = open64(devnamep, O_RDWR)) < 0) { 21525fac4a6SBaptiste Daroussin dbg_printf(1, "failed to open helper device %s", devnamep); 2166ff6d951SJohn Birrell return; 2176ff6d951SJohn Birrell } 2186ff6d951SJohn Birrell 2190f2bd1e8SRui Paulo if ((gen = ioctl(fd, DTRACEHIOC_REMOVE, &gen)) == -1) 22025fac4a6SBaptiste Daroussin dbg_printf(1, "DTrace ioctl failed to remove DOF (%d)\n", gen); 2216ff6d951SJohn Birrell else 22225fac4a6SBaptiste Daroussin dbg_printf(1, "DTrace ioctl removed DOF (%d)\n", gen); 2236ff6d951SJohn Birrell 2246ff6d951SJohn Birrell (void) close(fd); 2256ff6d951SJohn Birrell } 226