Passing "-x lazyload" to dtrace -G during compilation causes dtrace(1) to not link drti.o into the output object file, so the USDT probes are not created during process startup. Instead, dtrace(1) will automatically discover and create probes on the process' behalf when attaching. Differential Revision: https://reviews.freebsd.org/D2203 Reviewed by: rpaulo MFC after: 1 month
220 lines
5.4 KiB
C
220 lines
5.4 KiB
C
/*
|
|
* CDDL HEADER START
|
|
*
|
|
* The contents of this file are subject to the terms of the
|
|
* Common Development and Distribution License (the "License").
|
|
* You may not use this file except in compliance with the License.
|
|
*
|
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
|
* or http://www.opensolaris.org/os/licensing.
|
|
* See the License for the specific language governing permissions
|
|
* and limitations under the License.
|
|
*
|
|
* When distributing Covered Code, include this CDDL HEADER in each
|
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
|
* If applicable, add the following below this CDDL HEADER, with the
|
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
|
*
|
|
* CDDL HEADER END
|
|
*/
|
|
/*
|
|
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
|
|
* Copyright 2013 Voxer Inc. All rights reserved.
|
|
* Use is subject to license terms.
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <dlfcn.h>
|
|
#include <link.h>
|
|
#include <sys/dtrace.h>
|
|
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <libelf.h>
|
|
|
|
/*
|
|
* In Solaris 10 GA, the only mechanism for communicating helper information
|
|
* is through the DTrace helper pseudo-device node in /devices; there is
|
|
* no /dev link. Because of this, USDT providers and helper actions don't
|
|
* work inside of non-global zones. This issue was addressed by adding
|
|
* the /dev and having this initialization code use that /dev link. If the
|
|
* /dev link doesn't exist it falls back to looking for the /devices node
|
|
* as this code may be embedded in a binary which runs on Solaris 10 GA.
|
|
*
|
|
* Users may set the following environment variable to affect the way
|
|
* helper initialization takes place:
|
|
*
|
|
* DTRACE_DOF_INIT_DEBUG enable debugging output
|
|
* DTRACE_DOF_INIT_DISABLE disable helper loading
|
|
* DTRACE_DOF_INIT_DEVNAME set the path to the helper node
|
|
*/
|
|
|
|
static const char *devnamep = "/dev/dtrace/helper";
|
|
#ifdef illumos
|
|
static const char *olddevname = "/devices/pseudo/dtrace@0:helper";
|
|
#endif
|
|
|
|
static const char *modname; /* Name of this load object */
|
|
static int gen; /* DOF helper generation */
|
|
extern dof_hdr_t __SUNW_dof; /* DOF defined in the .SUNW_dof section */
|
|
static boolean_t dof_init_debug = B_FALSE; /* From DTRACE_DOF_INIT_DEBUG */
|
|
|
|
static void
|
|
dprintf(int debug, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
if (debug && !dof_init_debug)
|
|
return;
|
|
|
|
va_start(ap, fmt);
|
|
|
|
if (modname == NULL)
|
|
(void) fprintf(stderr, "dtrace DOF: ");
|
|
else
|
|
(void) fprintf(stderr, "dtrace DOF %s: ", modname);
|
|
|
|
(void) vfprintf(stderr, fmt, ap);
|
|
|
|
if (fmt[strlen(fmt) - 1] != '\n')
|
|
(void) fprintf(stderr, ": %s\n", strerror(errno));
|
|
|
|
va_end(ap);
|
|
}
|
|
|
|
#ifdef illumos
|
|
#pragma init(dtrace_dof_init)
|
|
#else
|
|
static void dtrace_dof_init(void) __attribute__ ((constructor));
|
|
#endif
|
|
|
|
static void
|
|
dtrace_dof_init(void)
|
|
{
|
|
dof_hdr_t *dof = &__SUNW_dof;
|
|
#ifdef _LP64
|
|
Elf64_Ehdr *elf;
|
|
#else
|
|
Elf32_Ehdr *elf;
|
|
#endif
|
|
dof_helper_t dh;
|
|
Link_map *lmp = NULL;
|
|
#ifdef illumos
|
|
Lmid_t lmid;
|
|
#else
|
|
u_long lmid = 0;
|
|
#endif
|
|
int fd;
|
|
const char *p;
|
|
|
|
if (getenv("DTRACE_DOF_INIT_DISABLE") != NULL)
|
|
return;
|
|
|
|
if (getenv("DTRACE_DOF_INIT_DEBUG") != NULL)
|
|
dof_init_debug = B_TRUE;
|
|
|
|
if (dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &lmp) == -1 || lmp == NULL) {
|
|
dprintf(1, "couldn't discover module name or address\n");
|
|
return;
|
|
}
|
|
|
|
#ifdef illumos
|
|
if (dlinfo(RTLD_SELF, RTLD_DI_LMID, &lmid) == -1) {
|
|
dprintf(1, "couldn't discover link map ID\n");
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if ((modname = strrchr(lmp->l_name, '/')) == NULL)
|
|
modname = lmp->l_name;
|
|
else
|
|
modname++;
|
|
|
|
if (dof->dofh_ident[DOF_ID_MAG0] != DOF_MAG_MAG0 ||
|
|
dof->dofh_ident[DOF_ID_MAG1] != DOF_MAG_MAG1 ||
|
|
dof->dofh_ident[DOF_ID_MAG2] != DOF_MAG_MAG2 ||
|
|
dof->dofh_ident[DOF_ID_MAG3] != DOF_MAG_MAG3) {
|
|
dprintf(0, ".SUNW_dof section corrupt\n");
|
|
return;
|
|
}
|
|
|
|
elf = (void *)lmp->l_addr;
|
|
|
|
dh.dofhp_dof = (uintptr_t)dof;
|
|
dh.dofhp_addr = elf->e_type == ET_DYN ? (uintptr_t) lmp->l_addr : 0;
|
|
#ifdef __FreeBSD__
|
|
dh.dofhp_pid = getpid();
|
|
#endif
|
|
|
|
if (lmid == 0) {
|
|
(void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod),
|
|
"%s", modname);
|
|
} else {
|
|
(void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod),
|
|
"LM%lu`%s", lmid, modname);
|
|
}
|
|
|
|
if ((p = getenv("DTRACE_DOF_INIT_DEVNAME")) != NULL)
|
|
devnamep = p;
|
|
|
|
if ((fd = open64(devnamep, O_RDWR)) < 0) {
|
|
dprintf(1, "failed to open helper device %s", devnamep);
|
|
#ifdef illumos
|
|
/*
|
|
* If the device path wasn't explicitly set, try again with
|
|
* the old device path.
|
|
*/
|
|
if (p != NULL)
|
|
return;
|
|
|
|
devnamep = olddevname;
|
|
|
|
if ((fd = open64(devnamep, O_RDWR)) < 0) {
|
|
dprintf(1, "failed to open helper device %s", devnamep);
|
|
return;
|
|
}
|
|
#else
|
|
return;
|
|
#endif
|
|
}
|
|
if ((gen = ioctl(fd, DTRACEHIOC_ADDDOF, &dh)) == -1)
|
|
dprintf(1, "DTrace ioctl failed for DOF at %p", dof);
|
|
else {
|
|
dprintf(1, "DTrace ioctl succeeded for DOF at %p\n", dof);
|
|
#ifdef __FreeBSD__
|
|
gen = dh.dofhp_gen;
|
|
#endif
|
|
}
|
|
|
|
(void) close(fd);
|
|
}
|
|
|
|
#ifdef illumos
|
|
#pragma fini(dtrace_dof_fini)
|
|
#else
|
|
static void dtrace_dof_fini(void) __attribute__ ((destructor));
|
|
#endif
|
|
|
|
static void
|
|
dtrace_dof_fini(void)
|
|
{
|
|
int fd;
|
|
|
|
if ((fd = open64(devnamep, O_RDWR)) < 0) {
|
|
dprintf(1, "failed to open helper device %s", devnamep);
|
|
return;
|
|
}
|
|
|
|
if ((gen = ioctl(fd, DTRACEHIOC_REMOVE, &gen)) == -1)
|
|
dprintf(1, "DTrace ioctl failed to remove DOF (%d)\n", gen);
|
|
else
|
|
dprintf(1, "DTrace ioctl removed DOF (%d)\n", gen);
|
|
|
|
(void) close(fd);
|
|
}
|