16ff6d951SJohn Birrell /* 26ff6d951SJohn Birrell * CDDL HEADER START 36ff6d951SJohn Birrell * 46ff6d951SJohn Birrell * The contents of this file are subject to the terms of the 56ff6d951SJohn Birrell * Common Development and Distribution License, Version 1.0 only 66ff6d951SJohn Birrell * (the "License"). You may not use this file except in compliance 76ff6d951SJohn Birrell * with the License. 86ff6d951SJohn Birrell * 96ff6d951SJohn Birrell * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 106ff6d951SJohn Birrell * or http://www.opensolaris.org/os/licensing. 116ff6d951SJohn Birrell * See the License for the specific language governing permissions 126ff6d951SJohn Birrell * and limitations under the License. 136ff6d951SJohn Birrell * 146ff6d951SJohn Birrell * When distributing Covered Code, include this CDDL HEADER in each 156ff6d951SJohn Birrell * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 166ff6d951SJohn Birrell * If applicable, add the following below this CDDL HEADER, with the 176ff6d951SJohn Birrell * fields enclosed by brackets "[]" replaced with your own identifying 186ff6d951SJohn Birrell * information: Portions Copyright [yyyy] [name of copyright owner] 196ff6d951SJohn Birrell * 206ff6d951SJohn Birrell * CDDL HEADER END 216ff6d951SJohn Birrell */ 226ff6d951SJohn Birrell /* 236ff6d951SJohn Birrell * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 246ff6d951SJohn Birrell * Use is subject to license terms. 256ff6d951SJohn Birrell */ 266ff6d951SJohn Birrell 276ff6d951SJohn Birrell #pragma ident "%Z%%M% %I% %E% SMI" 286ff6d951SJohn Birrell 296ff6d951SJohn Birrell #include <unistd.h> 306ff6d951SJohn Birrell #include <fcntl.h> 316ff6d951SJohn Birrell #include <dlfcn.h> 326ff6d951SJohn Birrell #include <link.h> 336ff6d951SJohn Birrell #include <sys/dtrace.h> 346ff6d951SJohn Birrell 356ff6d951SJohn Birrell #include <stdarg.h> 366ff6d951SJohn Birrell #include <stdio.h> 376ff6d951SJohn Birrell #include <stdlib.h> 386ff6d951SJohn Birrell #include <string.h> 396ff6d951SJohn Birrell #include <errno.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"; 596ff6d951SJohn Birrell static const char *olddevname = "/devices/pseudo/dtrace@0:helper"; 606ff6d951SJohn Birrell 616ff6d951SJohn Birrell static const char *modname; /* Name of this load object */ 626ff6d951SJohn Birrell static int gen; /* DOF helper generation */ 636ff6d951SJohn Birrell extern dof_hdr_t __SUNW_dof; /* DOF defined in the .SUNW_dof section */ 646ff6d951SJohn Birrell 656ff6d951SJohn Birrell static void 666ff6d951SJohn Birrell dprintf(int debug, const char *fmt, ...) 676ff6d951SJohn Birrell { 686ff6d951SJohn Birrell va_list ap; 696ff6d951SJohn Birrell 706ff6d951SJohn Birrell if (debug && getenv("DTRACE_DOF_INIT_DEBUG") == NULL) 716ff6d951SJohn Birrell return; 726ff6d951SJohn Birrell 736ff6d951SJohn Birrell va_start(ap, fmt); 746ff6d951SJohn Birrell 756ff6d951SJohn Birrell if (modname == NULL) 766ff6d951SJohn Birrell (void) fprintf(stderr, "dtrace DOF: "); 776ff6d951SJohn Birrell else 786ff6d951SJohn Birrell (void) fprintf(stderr, "dtrace DOF %s: ", modname); 796ff6d951SJohn Birrell 806ff6d951SJohn Birrell (void) vfprintf(stderr, fmt, ap); 816ff6d951SJohn Birrell 826ff6d951SJohn Birrell if (fmt[strlen(fmt) - 1] != '\n') 836ff6d951SJohn Birrell (void) fprintf(stderr, ": %s\n", strerror(errno)); 846ff6d951SJohn Birrell 856ff6d951SJohn Birrell va_end(ap); 866ff6d951SJohn Birrell } 876ff6d951SJohn Birrell 885fe26f7cSJohn Birrell #if defined(sun) 896ff6d951SJohn Birrell #pragma init(dtrace_dof_init) 905fe26f7cSJohn Birrell #else 915fe26f7cSJohn Birrell static void dtrace_dof_init(void) __attribute__ ((constructor)); 925fe26f7cSJohn Birrell #endif 935fe26f7cSJohn Birrell 946ff6d951SJohn Birrell static void 956ff6d951SJohn Birrell dtrace_dof_init(void) 966ff6d951SJohn Birrell { 976ff6d951SJohn Birrell dof_hdr_t *dof = &__SUNW_dof; 986ff6d951SJohn Birrell #ifdef _LP64 996ff6d951SJohn Birrell Elf64_Ehdr *elf; 1006ff6d951SJohn Birrell #else 1016ff6d951SJohn Birrell Elf32_Ehdr *elf; 1026ff6d951SJohn Birrell #endif 1036ff6d951SJohn Birrell dof_helper_t dh; 1045fe26f7cSJohn Birrell #if defined(sun) 1056ff6d951SJohn Birrell Link_map *lmp; 1066ff6d951SJohn Birrell Lmid_t lmid; 1075fe26f7cSJohn Birrell #else 1085fe26f7cSJohn Birrell struct link_map *lmp; 1095fe26f7cSJohn Birrell u_long lmid = 0; 1105fe26f7cSJohn Birrell #endif 1116ff6d951SJohn Birrell int fd; 1126ff6d951SJohn Birrell const char *p; 1136ff6d951SJohn Birrell 1146ff6d951SJohn Birrell if (getenv("DTRACE_DOF_INIT_DISABLE") != NULL) 1156ff6d951SJohn Birrell return; 1166ff6d951SJohn Birrell 1176ff6d951SJohn Birrell if (dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &lmp) == -1 || lmp == NULL) { 1186ff6d951SJohn Birrell dprintf(1, "couldn't discover module name or address\n"); 1196ff6d951SJohn Birrell return; 1206ff6d951SJohn Birrell } 1216ff6d951SJohn Birrell 1225fe26f7cSJohn Birrell #if defined(sun) 1236ff6d951SJohn Birrell if (dlinfo(RTLD_SELF, RTLD_DI_LMID, &lmid) == -1) { 1246ff6d951SJohn Birrell dprintf(1, "couldn't discover link map ID\n"); 1256ff6d951SJohn Birrell return; 1266ff6d951SJohn Birrell } 1275fe26f7cSJohn Birrell #endif 1286ff6d951SJohn Birrell 1296ff6d951SJohn Birrell if ((modname = strrchr(lmp->l_name, '/')) == NULL) 1306ff6d951SJohn Birrell modname = lmp->l_name; 1316ff6d951SJohn Birrell else 1326ff6d951SJohn Birrell modname++; 1336ff6d951SJohn Birrell 1346ff6d951SJohn Birrell if (dof->dofh_ident[DOF_ID_MAG0] != DOF_MAG_MAG0 || 1356ff6d951SJohn Birrell dof->dofh_ident[DOF_ID_MAG1] != DOF_MAG_MAG1 || 1366ff6d951SJohn Birrell dof->dofh_ident[DOF_ID_MAG2] != DOF_MAG_MAG2 || 1376ff6d951SJohn Birrell dof->dofh_ident[DOF_ID_MAG3] != DOF_MAG_MAG3) { 1386ff6d951SJohn Birrell dprintf(0, ".SUNW_dof section corrupt\n"); 1396ff6d951SJohn Birrell return; 1406ff6d951SJohn Birrell } 1416ff6d951SJohn Birrell 1426ff6d951SJohn Birrell elf = (void *)lmp->l_addr; 1436ff6d951SJohn Birrell 1446ff6d951SJohn Birrell dh.dofhp_dof = (uintptr_t)dof; 1455fe26f7cSJohn Birrell dh.dofhp_addr = elf->e_type == ET_DYN ? (uintptr_t) lmp->l_addr : 0; 1466ff6d951SJohn Birrell 1476ff6d951SJohn Birrell if (lmid == 0) { 1486ff6d951SJohn Birrell (void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod), 1496ff6d951SJohn Birrell "%s", modname); 1506ff6d951SJohn Birrell } else { 1516ff6d951SJohn Birrell (void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod), 1526ff6d951SJohn Birrell "LM%lu`%s", lmid, modname); 1536ff6d951SJohn Birrell } 1546ff6d951SJohn Birrell 1556ff6d951SJohn Birrell if ((p = getenv("DTRACE_DOF_INIT_DEVNAME")) != NULL) 1565fe26f7cSJohn Birrell devnamep = p; 1576ff6d951SJohn Birrell 1585fe26f7cSJohn Birrell if ((fd = open64(devnamep, O_RDWR)) < 0) { 1595fe26f7cSJohn Birrell dprintf(1, "failed to open helper device %s", devnamep); 1606ff6d951SJohn Birrell 1616ff6d951SJohn Birrell /* 1626ff6d951SJohn Birrell * If the device path wasn't explicitly set, try again with 1636ff6d951SJohn Birrell * the old device path. 1646ff6d951SJohn Birrell */ 1656ff6d951SJohn Birrell if (p != NULL) 1666ff6d951SJohn Birrell return; 1676ff6d951SJohn Birrell 1685fe26f7cSJohn Birrell devnamep = olddevname; 1696ff6d951SJohn Birrell 1705fe26f7cSJohn Birrell if ((fd = open64(devnamep, O_RDWR)) < 0) { 1715fe26f7cSJohn Birrell dprintf(1, "failed to open helper device %s", devnamep); 1726ff6d951SJohn Birrell return; 1736ff6d951SJohn Birrell } 1746ff6d951SJohn Birrell } 1756ff6d951SJohn Birrell 1766ff6d951SJohn Birrell if ((gen = ioctl(fd, DTRACEHIOC_ADDDOF, &dh)) == -1) 1776ff6d951SJohn Birrell dprintf(1, "DTrace ioctl failed for DOF at %p", dof); 1786ff6d951SJohn Birrell else 1796ff6d951SJohn Birrell dprintf(1, "DTrace ioctl succeeded for DOF at %p\n", dof); 1806ff6d951SJohn Birrell 1816ff6d951SJohn Birrell (void) close(fd); 1826ff6d951SJohn Birrell } 1836ff6d951SJohn Birrell 1845fe26f7cSJohn Birrell #if defined(sun) 1856ff6d951SJohn Birrell #pragma fini(dtrace_dof_fini) 1865fe26f7cSJohn Birrell #else 1875fe26f7cSJohn Birrell static void dtrace_dof_fini(void) __attribute__ ((destructor)); 1885fe26f7cSJohn Birrell #endif 1895fe26f7cSJohn Birrell 1906ff6d951SJohn Birrell static void 1916ff6d951SJohn Birrell dtrace_dof_fini(void) 1926ff6d951SJohn Birrell { 1936ff6d951SJohn Birrell int fd; 1946ff6d951SJohn Birrell 1955fe26f7cSJohn Birrell if ((fd = open64(devnamep, O_RDWR)) < 0) { 1965fe26f7cSJohn Birrell dprintf(1, "failed to open helper device %s", devnamep); 1976ff6d951SJohn Birrell return; 1986ff6d951SJohn Birrell } 1996ff6d951SJohn Birrell 2006ff6d951SJohn Birrell if ((gen = ioctl(fd, DTRACEHIOC_REMOVE, gen)) == -1) 2016ff6d951SJohn Birrell dprintf(1, "DTrace ioctl failed to remove DOF (%d)\n", gen); 2026ff6d951SJohn Birrell else 2036ff6d951SJohn Birrell dprintf(1, "DTrace ioctl removed DOF (%d)\n", gen); 2046ff6d951SJohn Birrell 2056ff6d951SJohn Birrell (void) close(fd); 2066ff6d951SJohn Birrell } 207