drti.c revision 178479
1178479Sjb/* 2178479Sjb * CDDL HEADER START 3178479Sjb * 4178479Sjb * The contents of this file are subject to the terms of the 5178479Sjb * Common Development and Distribution License, Version 1.0 only 6178479Sjb * (the "License"). You may not use this file except in compliance 7178479Sjb * with the License. 8178479Sjb * 9178479Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10178479Sjb * or http://www.opensolaris.org/os/licensing. 11178479Sjb * See the License for the specific language governing permissions 12178479Sjb * and limitations under the License. 13178479Sjb * 14178479Sjb * When distributing Covered Code, include this CDDL HEADER in each 15178479Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16178479Sjb * If applicable, add the following below this CDDL HEADER, with the 17178479Sjb * fields enclosed by brackets "[]" replaced with your own identifying 18178479Sjb * information: Portions Copyright [yyyy] [name of copyright owner] 19178479Sjb * 20178479Sjb * CDDL HEADER END 21178479Sjb */ 22178479Sjb/* 23178479Sjb * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24178479Sjb * Use is subject to license terms. 25178479Sjb */ 26178479Sjb 27178479Sjb#pragma ident "%Z%%M% %I% %E% SMI" 28178479Sjb 29178479Sjb#include <unistd.h> 30178479Sjb#include <fcntl.h> 31178479Sjb#include <dlfcn.h> 32178479Sjb#include <link.h> 33178479Sjb#include <sys/dtrace.h> 34178479Sjb 35178479Sjb#include <stdarg.h> 36178479Sjb#include <stdio.h> 37178479Sjb#include <stdlib.h> 38178479Sjb#include <string.h> 39178479Sjb#include <errno.h> 40178479Sjb 41178479Sjb/* 42178479Sjb * In Solaris 10 GA, the only mechanism for communicating helper information 43178479Sjb * is through the DTrace helper pseudo-device node in /devices; there is 44178479Sjb * no /dev link. Because of this, USDT providers and helper actions don't 45178479Sjb * work inside of non-global zones. This issue was addressed by adding 46178479Sjb * the /dev and having this initialization code use that /dev link. If the 47178479Sjb * /dev link doesn't exist it falls back to looking for the /devices node 48178479Sjb * as this code may be embedded in a binary which runs on Solaris 10 GA. 49178479Sjb * 50178479Sjb * Users may set the following environment variable to affect the way 51178479Sjb * helper initialization takes place: 52178479Sjb * 53178479Sjb * DTRACE_DOF_INIT_DEBUG enable debugging output 54178479Sjb * DTRACE_DOF_INIT_DISABLE disable helper loading 55178479Sjb * DTRACE_DOF_INIT_DEVNAME set the path to the helper node 56178479Sjb */ 57178479Sjb 58178479Sjbstatic const char *devnamep = "/dev/dtrace/helper"; 59178479Sjbstatic const char *olddevname = "/devices/pseudo/dtrace@0:helper"; 60178479Sjb 61178479Sjbstatic const char *modname; /* Name of this load object */ 62178479Sjbstatic int gen; /* DOF helper generation */ 63178479Sjbextern dof_hdr_t __SUNW_dof; /* DOF defined in the .SUNW_dof section */ 64178479Sjb 65178479Sjbstatic void 66178479Sjbdprintf(int debug, const char *fmt, ...) 67178479Sjb{ 68178479Sjb va_list ap; 69178479Sjb 70178479Sjb if (debug && getenv("DTRACE_DOF_INIT_DEBUG") == NULL) 71178479Sjb return; 72178479Sjb 73178479Sjb va_start(ap, fmt); 74178479Sjb 75178479Sjb if (modname == NULL) 76178479Sjb (void) fprintf(stderr, "dtrace DOF: "); 77178479Sjb else 78178479Sjb (void) fprintf(stderr, "dtrace DOF %s: ", modname); 79178479Sjb 80178479Sjb (void) vfprintf(stderr, fmt, ap); 81178479Sjb 82178479Sjb if (fmt[strlen(fmt) - 1] != '\n') 83178479Sjb (void) fprintf(stderr, ": %s\n", strerror(errno)); 84178479Sjb 85178479Sjb va_end(ap); 86178479Sjb} 87178479Sjb 88178479Sjb#if defined(sun) 89178479Sjb#pragma init(dtrace_dof_init) 90178479Sjb#else 91178479Sjbstatic void dtrace_dof_init(void) __attribute__ ((constructor)); 92178479Sjb#endif 93178479Sjb 94178479Sjbstatic void 95178479Sjbdtrace_dof_init(void) 96178479Sjb{ 97178479Sjb dof_hdr_t *dof = &__SUNW_dof; 98178479Sjb#ifdef _LP64 99178479Sjb Elf64_Ehdr *elf; 100178479Sjb#else 101178479Sjb Elf32_Ehdr *elf; 102178479Sjb#endif 103178479Sjb dof_helper_t dh; 104178479Sjb#if defined(sun) 105178479Sjb Link_map *lmp; 106178479Sjb Lmid_t lmid; 107178479Sjb#else 108178479Sjb struct link_map *lmp; 109178479Sjb u_long lmid = 0; 110178479Sjb#endif 111178479Sjb int fd; 112178479Sjb const char *p; 113178479Sjb 114178479Sjb if (getenv("DTRACE_DOF_INIT_DISABLE") != NULL) 115178479Sjb return; 116178479Sjb 117178479Sjb if (dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &lmp) == -1 || lmp == NULL) { 118178479Sjb dprintf(1, "couldn't discover module name or address\n"); 119178479Sjb return; 120178479Sjb } 121178479Sjb 122178479Sjb#if defined(sun) 123178479Sjb if (dlinfo(RTLD_SELF, RTLD_DI_LMID, &lmid) == -1) { 124178479Sjb dprintf(1, "couldn't discover link map ID\n"); 125178479Sjb return; 126178479Sjb } 127178479Sjb#endif 128178479Sjb 129178479Sjb if ((modname = strrchr(lmp->l_name, '/')) == NULL) 130178479Sjb modname = lmp->l_name; 131178479Sjb else 132178479Sjb modname++; 133178479Sjb 134178479Sjb if (dof->dofh_ident[DOF_ID_MAG0] != DOF_MAG_MAG0 || 135178479Sjb dof->dofh_ident[DOF_ID_MAG1] != DOF_MAG_MAG1 || 136178479Sjb dof->dofh_ident[DOF_ID_MAG2] != DOF_MAG_MAG2 || 137178479Sjb dof->dofh_ident[DOF_ID_MAG3] != DOF_MAG_MAG3) { 138178479Sjb dprintf(0, ".SUNW_dof section corrupt\n"); 139178479Sjb return; 140178479Sjb } 141178479Sjb 142178479Sjb elf = (void *)lmp->l_addr; 143178479Sjb 144178479Sjb dh.dofhp_dof = (uintptr_t)dof; 145178479Sjb dh.dofhp_addr = elf->e_type == ET_DYN ? (uintptr_t) lmp->l_addr : 0; 146178479Sjb 147178479Sjb if (lmid == 0) { 148178479Sjb (void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod), 149178479Sjb "%s", modname); 150178479Sjb } else { 151178479Sjb (void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod), 152178479Sjb "LM%lu`%s", lmid, modname); 153178479Sjb } 154178479Sjb 155178479Sjb if ((p = getenv("DTRACE_DOF_INIT_DEVNAME")) != NULL) 156178479Sjb devnamep = p; 157178479Sjb 158178479Sjb if ((fd = open64(devnamep, O_RDWR)) < 0) { 159178479Sjb dprintf(1, "failed to open helper device %s", devnamep); 160178479Sjb 161178479Sjb /* 162178479Sjb * If the device path wasn't explicitly set, try again with 163178479Sjb * the old device path. 164178479Sjb */ 165178479Sjb if (p != NULL) 166178479Sjb return; 167178479Sjb 168178479Sjb devnamep = olddevname; 169178479Sjb 170178479Sjb if ((fd = open64(devnamep, O_RDWR)) < 0) { 171178479Sjb dprintf(1, "failed to open helper device %s", devnamep); 172178479Sjb return; 173178479Sjb } 174178479Sjb } 175178479Sjb 176178479Sjb if ((gen = ioctl(fd, DTRACEHIOC_ADDDOF, &dh)) == -1) 177178479Sjb dprintf(1, "DTrace ioctl failed for DOF at %p", dof); 178178479Sjb else 179178479Sjb dprintf(1, "DTrace ioctl succeeded for DOF at %p\n", dof); 180178479Sjb 181178479Sjb (void) close(fd); 182178479Sjb} 183178479Sjb 184178479Sjb#if defined(sun) 185178479Sjb#pragma fini(dtrace_dof_fini) 186178479Sjb#else 187178479Sjbstatic void dtrace_dof_fini(void) __attribute__ ((destructor)); 188178479Sjb#endif 189178479Sjb 190178479Sjbstatic void 191178479Sjbdtrace_dof_fini(void) 192178479Sjb{ 193178479Sjb int fd; 194178479Sjb 195178479Sjb if ((fd = open64(devnamep, O_RDWR)) < 0) { 196178479Sjb dprintf(1, "failed to open helper device %s", devnamep); 197178479Sjb return; 198178479Sjb } 199178479Sjb 200178479Sjb if ((gen = ioctl(fd, DTRACEHIOC_REMOVE, gen)) == -1) 201178479Sjb dprintf(1, "DTrace ioctl failed to remove DOF (%d)\n", gen); 202178479Sjb else 203178479Sjb dprintf(1, "DTrace ioctl removed DOF (%d)\n", gen); 204178479Sjb 205178479Sjb (void) close(fd); 206178479Sjb} 207