From 67cf27b70f80c25edfc6f0c57be9b2dd413ea97c Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Wed, 8 Apr 2015 02:36:37 +0000 Subject: [PATCH] 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 --- .../opensolaris/lib/libdtrace/common/drti.c | 5 +- .../lib/libdtrace/common/dt_link.c | 16 ++-- .../opensolaris/lib/libdtrace/common/dt_pid.c | 79 ++++++++++++++++--- cddl/lib/libdtrace/libproc_compat.h | 2 +- .../opensolaris/uts/common/dtrace/dtrace.c | 46 +++++++---- .../opensolaris/uts/common/sys/dtrace.h | 5 +- sys/cddl/dev/dtrace/dtrace_ioctl.c | 7 +- 7 files changed, 119 insertions(+), 41 deletions(-) diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c b/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c index a75dc02d5ad9..5fab935ee94e 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c @@ -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 } diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c index ae41269afa16..eaf0961c90c8 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c @@ -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 - 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))); + 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 /* diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c index e628e62e9cc4..c61a7106e239 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c @@ -44,11 +44,16 @@ #include #include #include -#ifndef illumos -#include -#endif #include +#ifndef illumos +#include +#include +#include +#include +#include +#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. diff --git a/cddl/lib/libdtrace/libproc_compat.h b/cddl/lib/libdtrace/libproc_compat.h index 0d99d967553a..8704b820df58 100644 --- a/cddl/lib/libdtrace/libproc_compat.h +++ b/cddl/lib/libdtrace/libproc_compat.h @@ -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 diff --git a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c index 818f18064f89..dc7c283fdd7f 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c +++ b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c @@ -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); diff --git a/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h b/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h index 4605ee52b4c6..dfcdbbfc4e9d 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h +++ b/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h @@ -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; diff --git a/sys/cddl/dev/dtrace/dtrace_ioctl.c b/sys/cddl/dev/dtrace/dtrace_ioctl.c index ef9bed561c15..524e9379ec60 100644 --- a/sys/cddl/dev/dtrace/dtrace_ioctl.c +++ b/sys/cddl/dev/dtrace/dtrace_ioctl.c @@ -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);