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
dbg_printf(int debug,const char * fmt,...)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
dtrace_dof_init(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
dtrace_dof_fini(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