16ff6d951SJohn Birrell /* 26ff6d951SJohn Birrell * CDDL HEADER START 36ff6d951SJohn Birrell * 46ff6d951SJohn Birrell * The contents of this file are subject to the terms of the 5*1670a1c2SRui Paulo * Common Development and Distribution License (the "License"). 6*1670a1c2SRui 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 /* 22*1670a1c2SRui Paulo * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 236ff6d951SJohn Birrell * Use is subject to license terms. 246ff6d951SJohn Birrell */ 256ff6d951SJohn Birrell 266ff6d951SJohn Birrell #include <unistd.h> 276ff6d951SJohn Birrell #include <fcntl.h> 286ff6d951SJohn Birrell #include <dlfcn.h> 296ff6d951SJohn Birrell #include <link.h> 306ff6d951SJohn Birrell #include <sys/dtrace.h> 316ff6d951SJohn Birrell 326ff6d951SJohn Birrell #include <stdarg.h> 336ff6d951SJohn Birrell #include <stdio.h> 346ff6d951SJohn Birrell #include <stdlib.h> 356ff6d951SJohn Birrell #include <string.h> 366ff6d951SJohn Birrell #include <errno.h> 376ff6d951SJohn Birrell 386ff6d951SJohn Birrell /* 396ff6d951SJohn Birrell * In Solaris 10 GA, the only mechanism for communicating helper information 406ff6d951SJohn Birrell * is through the DTrace helper pseudo-device node in /devices; there is 416ff6d951SJohn Birrell * no /dev link. Because of this, USDT providers and helper actions don't 426ff6d951SJohn Birrell * work inside of non-global zones. This issue was addressed by adding 436ff6d951SJohn Birrell * the /dev and having this initialization code use that /dev link. If the 446ff6d951SJohn Birrell * /dev link doesn't exist it falls back to looking for the /devices node 456ff6d951SJohn Birrell * as this code may be embedded in a binary which runs on Solaris 10 GA. 466ff6d951SJohn Birrell * 476ff6d951SJohn Birrell * Users may set the following environment variable to affect the way 486ff6d951SJohn Birrell * helper initialization takes place: 496ff6d951SJohn Birrell * 506ff6d951SJohn Birrell * DTRACE_DOF_INIT_DEBUG enable debugging output 516ff6d951SJohn Birrell * DTRACE_DOF_INIT_DISABLE disable helper loading 526ff6d951SJohn Birrell * DTRACE_DOF_INIT_DEVNAME set the path to the helper node 536ff6d951SJohn Birrell */ 546ff6d951SJohn Birrell 555fe26f7cSJohn Birrell static const char *devnamep = "/dev/dtrace/helper"; 566ff6d951SJohn Birrell static const char *olddevname = "/devices/pseudo/dtrace@0:helper"; 576ff6d951SJohn Birrell 586ff6d951SJohn Birrell static const char *modname; /* Name of this load object */ 596ff6d951SJohn Birrell static int gen; /* DOF helper generation */ 606ff6d951SJohn Birrell extern dof_hdr_t __SUNW_dof; /* DOF defined in the .SUNW_dof section */ 61*1670a1c2SRui Paulo static boolean_t dof_init_debug = B_FALSE; /* From DTRACE_DOF_INIT_DEBUG */ 626ff6d951SJohn Birrell 636ff6d951SJohn Birrell static void 646ff6d951SJohn Birrell dprintf(int debug, const char *fmt, ...) 656ff6d951SJohn Birrell { 666ff6d951SJohn Birrell va_list ap; 676ff6d951SJohn Birrell 68*1670a1c2SRui Paulo if (debug && !dof_init_debug) 696ff6d951SJohn Birrell return; 706ff6d951SJohn Birrell 716ff6d951SJohn Birrell va_start(ap, fmt); 726ff6d951SJohn Birrell 736ff6d951SJohn Birrell if (modname == NULL) 746ff6d951SJohn Birrell (void) fprintf(stderr, "dtrace DOF: "); 756ff6d951SJohn Birrell else 766ff6d951SJohn Birrell (void) fprintf(stderr, "dtrace DOF %s: ", modname); 776ff6d951SJohn Birrell 786ff6d951SJohn Birrell (void) vfprintf(stderr, fmt, ap); 796ff6d951SJohn Birrell 806ff6d951SJohn Birrell if (fmt[strlen(fmt) - 1] != '\n') 816ff6d951SJohn Birrell (void) fprintf(stderr, ": %s\n", strerror(errno)); 826ff6d951SJohn Birrell 836ff6d951SJohn Birrell va_end(ap); 846ff6d951SJohn Birrell } 856ff6d951SJohn Birrell 865fe26f7cSJohn Birrell #if defined(sun) 876ff6d951SJohn Birrell #pragma init(dtrace_dof_init) 885fe26f7cSJohn Birrell #else 895fe26f7cSJohn Birrell static void dtrace_dof_init(void) __attribute__ ((constructor)); 905fe26f7cSJohn Birrell #endif 915fe26f7cSJohn Birrell 926ff6d951SJohn Birrell static void 936ff6d951SJohn Birrell dtrace_dof_init(void) 946ff6d951SJohn Birrell { 956ff6d951SJohn Birrell dof_hdr_t *dof = &__SUNW_dof; 966ff6d951SJohn Birrell #ifdef _LP64 976ff6d951SJohn Birrell Elf64_Ehdr *elf; 986ff6d951SJohn Birrell #else 996ff6d951SJohn Birrell Elf32_Ehdr *elf; 1006ff6d951SJohn Birrell #endif 1016ff6d951SJohn Birrell dof_helper_t dh; 1025fe26f7cSJohn Birrell #if defined(sun) 1036ff6d951SJohn Birrell Link_map *lmp; 1046ff6d951SJohn Birrell Lmid_t lmid; 1055fe26f7cSJohn Birrell #else 1065fe26f7cSJohn Birrell struct link_map *lmp; 1075fe26f7cSJohn Birrell u_long lmid = 0; 1085fe26f7cSJohn Birrell #endif 1096ff6d951SJohn Birrell int fd; 1106ff6d951SJohn Birrell const char *p; 1116ff6d951SJohn Birrell 1126ff6d951SJohn Birrell if (getenv("DTRACE_DOF_INIT_DISABLE") != NULL) 1136ff6d951SJohn Birrell return; 1146ff6d951SJohn Birrell 115*1670a1c2SRui Paulo if (getenv("DTRACE_DOF_INIT_DEBUG") != NULL) 116*1670a1c2SRui Paulo dof_init_debug = B_TRUE; 117*1670a1c2SRui Paulo 1186ff6d951SJohn Birrell if (dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &lmp) == -1 || lmp == NULL) { 1196ff6d951SJohn Birrell dprintf(1, "couldn't discover module name or address\n"); 1206ff6d951SJohn Birrell return; 1216ff6d951SJohn Birrell } 1226ff6d951SJohn Birrell 1235fe26f7cSJohn Birrell #if defined(sun) 1246ff6d951SJohn Birrell if (dlinfo(RTLD_SELF, RTLD_DI_LMID, &lmid) == -1) { 1256ff6d951SJohn Birrell dprintf(1, "couldn't discover link map ID\n"); 1266ff6d951SJohn Birrell return; 1276ff6d951SJohn Birrell } 1285fe26f7cSJohn Birrell #endif 1296ff6d951SJohn Birrell 1306ff6d951SJohn Birrell if ((modname = strrchr(lmp->l_name, '/')) == NULL) 1316ff6d951SJohn Birrell modname = lmp->l_name; 1326ff6d951SJohn Birrell else 1336ff6d951SJohn Birrell modname++; 1346ff6d951SJohn Birrell 1356ff6d951SJohn Birrell if (dof->dofh_ident[DOF_ID_MAG0] != DOF_MAG_MAG0 || 1366ff6d951SJohn Birrell dof->dofh_ident[DOF_ID_MAG1] != DOF_MAG_MAG1 || 1376ff6d951SJohn Birrell dof->dofh_ident[DOF_ID_MAG2] != DOF_MAG_MAG2 || 1386ff6d951SJohn Birrell dof->dofh_ident[DOF_ID_MAG3] != DOF_MAG_MAG3) { 1396ff6d951SJohn Birrell dprintf(0, ".SUNW_dof section corrupt\n"); 1406ff6d951SJohn Birrell return; 1416ff6d951SJohn Birrell } 1426ff6d951SJohn Birrell 1436ff6d951SJohn Birrell elf = (void *)lmp->l_addr; 1446ff6d951SJohn Birrell 1456ff6d951SJohn Birrell dh.dofhp_dof = (uintptr_t)dof; 1465fe26f7cSJohn Birrell dh.dofhp_addr = elf->e_type == ET_DYN ? (uintptr_t) lmp->l_addr : 0; 1476ff6d951SJohn Birrell 1486ff6d951SJohn Birrell if (lmid == 0) { 1496ff6d951SJohn Birrell (void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod), 1506ff6d951SJohn Birrell "%s", modname); 1516ff6d951SJohn Birrell } else { 1526ff6d951SJohn Birrell (void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod), 1536ff6d951SJohn Birrell "LM%lu`%s", lmid, modname); 1546ff6d951SJohn Birrell } 1556ff6d951SJohn Birrell 1566ff6d951SJohn Birrell if ((p = getenv("DTRACE_DOF_INIT_DEVNAME")) != NULL) 1575fe26f7cSJohn Birrell devnamep = p; 1586ff6d951SJohn Birrell 1595fe26f7cSJohn Birrell if ((fd = open64(devnamep, O_RDWR)) < 0) { 1605fe26f7cSJohn Birrell dprintf(1, "failed to open helper device %s", devnamep); 1616ff6d951SJohn Birrell 1626ff6d951SJohn Birrell /* 1636ff6d951SJohn Birrell * If the device path wasn't explicitly set, try again with 1646ff6d951SJohn Birrell * the old device path. 1656ff6d951SJohn Birrell */ 1666ff6d951SJohn Birrell if (p != NULL) 1676ff6d951SJohn Birrell return; 1686ff6d951SJohn Birrell 1695fe26f7cSJohn Birrell devnamep = olddevname; 1706ff6d951SJohn Birrell 1715fe26f7cSJohn Birrell if ((fd = open64(devnamep, O_RDWR)) < 0) { 1725fe26f7cSJohn Birrell dprintf(1, "failed to open helper device %s", devnamep); 1736ff6d951SJohn Birrell return; 1746ff6d951SJohn Birrell } 1756ff6d951SJohn Birrell } 1766ff6d951SJohn Birrell 1776ff6d951SJohn Birrell if ((gen = ioctl(fd, DTRACEHIOC_ADDDOF, &dh)) == -1) 1786ff6d951SJohn Birrell dprintf(1, "DTrace ioctl failed for DOF at %p", dof); 1796ff6d951SJohn Birrell else 1806ff6d951SJohn Birrell dprintf(1, "DTrace ioctl succeeded for DOF at %p\n", dof); 1816ff6d951SJohn Birrell 1826ff6d951SJohn Birrell (void) close(fd); 1836ff6d951SJohn Birrell } 1846ff6d951SJohn Birrell 1855fe26f7cSJohn Birrell #if defined(sun) 1866ff6d951SJohn Birrell #pragma fini(dtrace_dof_fini) 1875fe26f7cSJohn Birrell #else 1885fe26f7cSJohn Birrell static void dtrace_dof_fini(void) __attribute__ ((destructor)); 1895fe26f7cSJohn Birrell #endif 1905fe26f7cSJohn Birrell 1916ff6d951SJohn Birrell static void 1926ff6d951SJohn Birrell dtrace_dof_fini(void) 1936ff6d951SJohn Birrell { 1946ff6d951SJohn Birrell int fd; 1956ff6d951SJohn Birrell 1965fe26f7cSJohn Birrell if ((fd = open64(devnamep, O_RDWR)) < 0) { 1975fe26f7cSJohn Birrell dprintf(1, "failed to open helper device %s", devnamep); 1986ff6d951SJohn Birrell return; 1996ff6d951SJohn Birrell } 2006ff6d951SJohn Birrell 2016ff6d951SJohn Birrell if ((gen = ioctl(fd, DTRACEHIOC_REMOVE, gen)) == -1) 2026ff6d951SJohn Birrell dprintf(1, "DTrace ioctl failed to remove DOF (%d)\n", gen); 2036ff6d951SJohn Birrell else 2046ff6d951SJohn Birrell dprintf(1, "DTrace ioctl removed DOF (%d)\n", gen); 2056ff6d951SJohn Birrell 2066ff6d951SJohn Birrell (void) close(fd); 2076ff6d951SJohn Birrell } 208