libdtrace: add support for lazyload mode.

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
This commit is contained in:
markj 2015-04-08 02:36:37 +00:00
parent 245de71cf8
commit 1d6ffde4f4
7 changed files with 119 additions and 41 deletions

View File

@ -147,6 +147,9 @@ dtrace_dof_init(void)
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),
@ -184,7 +187,7 @@ dtrace_dof_init(void)
else {
dprintf(1, "DTrace ioctl succeeded for DOF at %p\n", dof);
#ifdef __FreeBSD__
gen = dh.gen;
gen = dh.dofhp_gen;
#endif
}

View File

@ -1785,11 +1785,17 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
"failed to open %s: %s", file, strerror(errno)));
}
#else
if (dtp->dt_lazyload) {
if ((fd = open(file, O_RDWR | O_CREAT | O_TRUNC, 0666)) < 0)
return (dt_link_error(dtp, NULL, -1, NULL,
"failed to open %s: %s", file, strerror(errno)));
} else {
snprintf(tfile, sizeof(tfile), "%s.XXXXXX", file);
if ((fd = mkstemp(tfile)) == -1)
return (dt_link_error(dtp, NULL, -1, NULL,
"failed to create temporary file %s: %s",
tfile, strerror(errno)));
}
#endif
/*

View File

@ -44,11 +44,16 @@
#include <dt_program.h>
#include <dt_pid.h>
#include <dt_string.h>
#ifndef illumos
#include <libproc_compat.h>
#endif
#include <dt_module.h>
#ifndef illumos
#include <sys/sysctl.h>
#include <unistd.h>
#include <libproc_compat.h>
#include <libelf.h>
#include <gelf.h>
#endif
typedef struct dt_pid_probe {
dtrace_hdl_t *dpp_dtp;
dt_pcb_t *dpp_pcb;
@ -566,6 +571,12 @@ dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname)
prsyminfo_t sip;
dof_helper_t dh;
GElf_Half e_type;
#ifdef __FreeBSD__
dof_hdr_t hdr;
size_t sz;
uint64_t dofmax;
void *dof;
#endif
const char *mname;
const char *syms[] = { "___SUNW_dof", "__SUNW_dof" };
int i, fd = -1;
@ -595,17 +606,61 @@ dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname)
continue;
}
#ifdef __FreeBSD__
dh.dofhp_addr = (e_type == ET_EXEC) ? 0 : pmp->pr_vaddr;
if (Pread(P, &hdr, sizeof (hdr), sym.st_value) !=
sizeof (hdr)) {
dt_dprintf("read of DOF header failed\n");
continue;
}
sz = sizeof(dofmax);
if (sysctlbyname("kern.dtrace.dof_maxsize", &dofmax, &sz,
NULL, 0) != 0) {
dt_dprintf("failed to read dof_maxsize: %s\n",
strerror(errno));
continue;
}
if (dofmax < hdr.dofh_loadsz) {
dt_dprintf("DOF load size exceeds maximum\n");
continue;
}
if ((dof = malloc(hdr.dofh_loadsz)) == NULL)
return (-1);
if (Pread(P, dof, hdr.dofh_loadsz, sym.st_value) !=
hdr.dofh_loadsz) {
free(dof);
dt_dprintf("read of DOF section failed\n");
continue;
}
dh.dofhp_dof = (uintptr_t)dof;
dh.dofhp_pid = proc_getpid(P);
dt_pid_objname(dh.dofhp_mod, sizeof (dh.dofhp_mod),
sip.prs_lmid, mname);
if (fd == -1 &&
(fd = open("/dev/dtrace/helper", O_RDWR, 0)) < 0) {
dt_dprintf("open of helper device failed: %s\n",
strerror(errno));
free(dof);
return (-1); /* errno is set for us */
}
if (ioctl(fd, DTRACEHIOC_ADDDOF, &dh, sizeof (dh)) < 0)
dt_dprintf("DOF was rejected for %s\n", dh.dofhp_mod);
free(dof);
#else
dh.dofhp_dof = sym.st_value;
dh.dofhp_addr = (e_type == ET_EXEC) ? 0 : pmp->pr_vaddr;
dt_pid_objname(dh.dofhp_mod, sizeof (dh.dofhp_mod),
#ifdef illumos
sip.prs_lmid, mname);
#else
0, mname);
#endif
#ifdef illumos
if (fd == -1 &&
(fd = pr_open(P, "/dev/dtrace/helper", O_RDWR, 0)) < 0) {
dt_dprintf("pr_open of helper device failed: %s\n",
@ -618,8 +673,10 @@ dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname)
#endif
}
#ifdef illumos
if (fd != -1)
#ifdef __FreeBSD__
(void) close(fd);
#else
(void) pr_close(P, fd);
#endif
@ -634,7 +691,6 @@ dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
int ret = 0;
assert(DT_MUTEX_HELD(&dpr->dpr_lock));
#ifdef illumos
(void) Pupdate_maps(P);
if (Pobject_iter(P, dt_pid_usdt_mapping, P) != 0) {
ret = -1;
@ -646,9 +702,6 @@ dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
(int)proc_getpid(P), strerror(errno));
#endif
}
#else
ret = 0;
#endif
/*
* Put the module name in its canonical form.

View File

@ -59,6 +59,6 @@
#define Pstate proc_state
#define Psymbol_iter_by_addr proc_iter_symbyaddr
#define Punsetflags proc_clearflags
#define Pupdate_maps(p) do { } while (0)
#define Pupdate_maps proc_rdagent
#define Pupdate_syms proc_updatesyms
#define Pxecbkpt proc_bkptexec

View File

@ -15374,13 +15374,15 @@ dtrace_helper_action_destroy(dtrace_helper_action_t *helper,
}
static int
dtrace_helper_destroygen(int gen)
dtrace_helper_destroygen(dtrace_helpers_t *help, int gen)
{
proc_t *p = curproc;
dtrace_helpers_t *help = p->p_dtrace_helpers;
dtrace_vstate_t *vstate;
int i;
if (help == NULL)
help = p->p_dtrace_helpers;
ASSERT(MUTEX_HELD(&dtrace_lock));
if (help == NULL || gen > help->dthps_generation)
@ -15478,9 +15480,9 @@ dtrace_helper_validate(dtrace_helper_action_t *helper)
}
static int
dtrace_helper_action_add(int which, dtrace_ecbdesc_t *ep)
dtrace_helper_action_add(int which, dtrace_ecbdesc_t *ep,
dtrace_helpers_t *help)
{
dtrace_helpers_t *help;
dtrace_helper_action_t *helper, *last;
dtrace_actdesc_t *act;
dtrace_vstate_t *vstate;
@ -15490,7 +15492,6 @@ dtrace_helper_action_add(int which, dtrace_ecbdesc_t *ep)
if (which < 0 || which >= DTRACE_NHELPER_ACTIONS)
return (EINVAL);
help = curproc->p_dtrace_helpers;
last = help->dthps_actions[which];
vstate = &help->dthps_vstate;
@ -15614,15 +15615,12 @@ dtrace_helper_provider_register(proc_t *p, dtrace_helpers_t *help,
}
static int
dtrace_helper_provider_add(dof_helper_t *dofhp, int gen)
dtrace_helper_provider_add(dof_helper_t *dofhp, dtrace_helpers_t *help, int gen)
{
dtrace_helpers_t *help;
dtrace_helper_provider_t *hprov, **tmp_provs;
uint_t tmp_maxprovs, i;
ASSERT(MUTEX_HELD(&dtrace_lock));
help = curproc->p_dtrace_helpers;
ASSERT(help != NULL);
/*
@ -15914,13 +15912,28 @@ dtrace_helper_slurp(dof_hdr_t *dof, dof_helper_t *dhp)
dtrace_helpers_t *help;
dtrace_vstate_t *vstate;
dtrace_enabling_t *enab = NULL;
proc_t *p = curproc;
int i, gen, rv, nhelpers = 0, nprovs = 0, destroy = 1;
uintptr_t daddr = (uintptr_t)dof;
ASSERT(MUTEX_HELD(&dtrace_lock));
if ((help = curproc->p_dtrace_helpers) == NULL)
help = dtrace_helpers_create(curproc);
#ifdef __FreeBSD__
if (dhp->dofhp_pid != p->p_pid) {
if ((p = pfind(dhp->dofhp_pid)) == NULL)
return (-1);
if (!P_SHOULDSTOP(p) ||
(p->p_flag & P_TRACED) == 0 ||
p->p_pptr->p_pid != curproc->p_pid) {
PROC_UNLOCK(p);
return (-1);
}
PROC_UNLOCK(p);
}
#endif
if ((help = p->p_dtrace_helpers) == NULL)
help = dtrace_helpers_create(p);
vstate = &help->dthps_vstate;
@ -15968,12 +15981,13 @@ dtrace_helper_slurp(dof_hdr_t *dof, dof_helper_t *dhp)
continue;
if ((rv = dtrace_helper_action_add(DTRACE_HELPER_ACTION_USTACK,
ep)) != 0) {
ep, help)) != 0) {
/*
* Adding this helper action failed -- we are now going
* to rip out the entire generation and return failure.
*/
(void) dtrace_helper_destroygen(help->dthps_generation);
(void) dtrace_helper_destroygen(help,
help->dthps_generation);
dtrace_enabling_destroy(enab);
dtrace_dof_destroy(dof);
return (-1);
@ -15990,9 +16004,9 @@ dtrace_helper_slurp(dof_hdr_t *dof, dof_helper_t *dhp)
if (dhp != NULL && nprovs > 0) {
dhp->dofhp_dof = (uint64_t)(uintptr_t)dof;
if (dtrace_helper_provider_add(dhp, gen) == 0) {
if (dtrace_helper_provider_add(dhp, help, gen) == 0) {
mutex_exit(&dtrace_lock);
dtrace_helper_provider_register(curproc, help, dhp);
dtrace_helper_provider_register(p, help, dhp);
mutex_enter(&dtrace_lock);
destroy = 0;
@ -16956,7 +16970,7 @@ dtrace_ioctl_helper(int cmd, intptr_t arg, int *rv)
case DTRACEHIOC_REMOVE: {
mutex_enter(&dtrace_lock);
rval = dtrace_helper_destroygen(arg);
rval = dtrace_helper_destroygen(NULL, arg);
mutex_exit(&dtrace_lock);
return (rval);

View File

@ -1423,8 +1423,9 @@ typedef struct dof_helper {
char dofhp_mod[DTRACE_MODNAMELEN]; /* executable or library name */
uint64_t dofhp_addr; /* base address of object */
uint64_t dofhp_dof; /* address of helper DOF */
#ifndef illumos
int gen;
#ifdef __FreeBSD__
pid_t dofhp_pid; /* target process ID */
int dofhp_gen;
#endif
} dof_helper_t;

View File

@ -32,9 +32,9 @@ static int
dtrace_ioctl_helper(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
struct thread *td)
{
int rval;
dof_helper_t *dhp = NULL;
dof_hdr_t *dof = NULL;
int rval;
switch (cmd) {
case DTRACEHIOC_ADDDOF:
@ -51,7 +51,7 @@ dtrace_ioctl_helper(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
mutex_enter(&dtrace_lock);
if ((rval = dtrace_helper_slurp((dof_hdr_t *)dof, dhp)) != -1) {
if (dhp) {
dhp->gen = rval;
dhp->dofhp_gen = rval;
copyout(dhp, addr, sizeof(*dhp));
}
rval = 0;
@ -59,10 +59,11 @@ dtrace_ioctl_helper(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
rval = EINVAL;
}
mutex_exit(&dtrace_lock);
return (rval);
case DTRACEHIOC_REMOVE:
mutex_enter(&dtrace_lock);
rval = dtrace_helper_destroygen((int)*addr);
rval = dtrace_helper_destroygen(NULL, (int)*addr);
mutex_exit(&dtrace_lock);
return (rval);