svn commit: r211554 - in head/cddl: contrib/opensolaris/cmd/dtrace
contrib/opensolaris/lib/libdtrace/common
contrib/opensolaris/lib/libdtrace/i386 lib/libdtrace
Rui Paulo
rpaulo at FreeBSD.org
Sat Aug 21 11:50:54 UTC 2010
Author: rpaulo
Date: Sat Aug 21 11:50:53 2010
New Revision: 211554
URL: http://svn.freebsd.org/changeset/base/211554
Log:
Add libdtrace support for tracing userland programs.
Summary of changes:
* Implement a compatibility shim between Solaris libproc and our
libproc and remove several ifdefs because of this.
* Port the drti to FreeBSD.
* Implement the missing DOODAD sections
* Link with libproc and librtld_db
* Support for ustack, jstack and uregs (by sson@)
* Misc bugfixing
When writing the SUWN_dof section, we had to resort to building the ELF
file layout by "hand". This is the job of libelf, but our libelf doesn't
support this yet. When libelf is fixed, we can remove the code under
#ifdef BROKEN_LIBELF.
Sponsored by: The FreeBSD Foundation
Added:
head/cddl/lib/libdtrace/libproc_compat.h (contents, props changed)
head/cddl/lib/libdtrace/regs_x86.d (contents, props changed)
Modified:
head/cddl/contrib/opensolaris/cmd/dtrace/dtrace.c
head/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c
head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_aggregate.c
head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c
head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c
head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c
head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_proc.c
head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_proc.h
head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_subr.c
head/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h
head/cddl/contrib/opensolaris/lib/libdtrace/i386/dt_isadep.c
head/cddl/lib/libdtrace/Makefile
Modified: head/cddl/contrib/opensolaris/cmd/dtrace/dtrace.c
==============================================================================
--- head/cddl/contrib/opensolaris/cmd/dtrace/dtrace.c Sat Aug 21 11:41:32 2010 (r211553)
+++ head/cddl/contrib/opensolaris/cmd/dtrace/dtrace.c Sat Aug 21 11:50:53 2010 (r211554)
@@ -773,19 +773,27 @@ compile_str(dtrace_cmd_t *dcp)
static void
prochandler(struct ps_prochandle *P, const char *msg, void *arg)
{
-fatal("DOODAD in function %s, file %s, line %d\n",__FUNCTION__,__FILE__,__LINE__);
-#ifdef DOODAD
+#if defined(sun)
const psinfo_t *prp = Ppsinfo(P);
int pid = Pstatus(P)->pr_pid;
char name[SIG2STR_MAX];
+#else
+ int wstatus = proc_getwstat(P);
+ int pid = proc_getpid(P);
+#endif
if (msg != NULL) {
notice("pid %d: %s\n", pid, msg);
return;
}
+#if defined(sun)
switch (Pstate(P)) {
+#else
+ switch (proc_state(P)) {
+#endif
case PS_UNDEAD:
+#if defined(sun)
/*
* Ideally we would like to always report pr_wstat here, but it
* isn't possible given current /proc semantics. If we grabbed
@@ -798,9 +806,20 @@ fatal("DOODAD in function %s, file %s, l
notice("pid %d terminated by %s\n", pid,
proc_signame(WTERMSIG(prp->pr_wstat),
name, sizeof (name)));
+#else
+ if (WIFSIGNALED(wstatus)) {
+ notice("pid %d terminated by %d\n", pid,
+ WTERMSIG(wstatus));
+#endif
+#if defined(sun)
} else if (prp != NULL && WEXITSTATUS(prp->pr_wstat) != 0) {
notice("pid %d exited with status %d\n",
pid, WEXITSTATUS(prp->pr_wstat));
+#else
+ } else if (WEXITSTATUS(wstatus) != 0) {
+ notice("pid %d exited with status %d\n",
+ pid, WEXITSTATUS(wstatus));
+#endif
} else {
notice("pid %d has exited\n", pid);
}
@@ -812,7 +831,6 @@ fatal("DOODAD in function %s, file %s, l
g_pslive--;
break;
}
-#endif
}
/*ARGSUSED*/
Modified: head/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c Sat Aug 21 11:41:32 2010 (r211553)
+++ head/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c Sat Aug 21 11:50:53 2010 (r211554)
@@ -34,6 +34,8 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <libelf.h>
+#include <gelf.h>
/*
* In Solaris 10 GA, the only mechanism for communicating helper information
@@ -53,12 +55,16 @@
*/
static const char *devnamep = "/dev/dtrace/helper";
+#if defined(sun)
static const char *olddevname = "/devices/pseudo/dtrace at 0:helper";
+#endif
static const char *modname; /* Name of this load object */
static int gen; /* DOF helper generation */
+#if defined(sun)
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 */
+#endif
+static boolean_t dof_init_debug = B_TRUE; /* From DTRACE_DOF_INIT_DEBUG */
static void
dprintf(int debug, const char *fmt, ...)
@@ -83,6 +89,36 @@ dprintf(int debug, const char *fmt, ...)
va_end(ap);
}
+#if !defined(sun)
+static void
+fixsymbol(Elf *e, Elf_Data *data, size_t idx, int nprobes, char *buf,
+ dof_sec_t *sec, int *fixedprobes, char *dofstrtab)
+{
+ GElf_Sym sym;
+ char *s;
+ unsigned char *funcname;
+ dof_probe_t *prb;
+ int j = 0;
+ int ndx;
+
+ while (gelf_getsym(data, j++, &sym) != NULL) {
+ prb = (dof_probe_t *)(buf + sec->dofs_offset);
+
+ for (ndx = nprobes; ndx; ndx--, prb += 1) {
+ funcname = dofstrtab + prb->dofpr_func;
+ s = elf_strptr(e, idx, sym.st_name);
+ if (strcmp(s, funcname) == 0) {
+ dprintf(1, "fixing %s() symbol\n", s);
+ prb->dofpr_addr = sym.st_value;
+ (*fixedprobes)++;
+ }
+ }
+ if (*fixedprobes == nprobes)
+ break;
+ }
+}
+#endif
+
#if defined(sun)
#pragma init(dtrace_dof_init)
#else
@@ -92,22 +128,39 @@ static void dtrace_dof_init(void) __attr
static void
dtrace_dof_init(void)
{
+#if defined(sun)
dof_hdr_t *dof = &__SUNW_dof;
+#else
+ dof_hdr_t *dof = NULL;
+#endif
#ifdef _LP64
Elf64_Ehdr *elf;
#else
Elf32_Ehdr *elf;
#endif
dof_helper_t dh;
-#if defined(sun)
Link_map *lmp;
+#if defined(sun)
Lmid_t lmid;
#else
- struct link_map *lmp;
u_long lmid = 0;
+ dof_sec_t *sec;
+ size_t i;
#endif
int fd;
const char *p;
+#if !defined(sun)
+ Elf *e;
+ Elf_Scn *scn = NULL;
+ Elf_Data *symtabdata = NULL, *dynsymdata = NULL;
+ GElf_Shdr shdr;
+ int efd, nprobes;
+ char *s;
+ size_t shstridx, symtabidx = 0, dynsymidx = 0;
+ unsigned char *dofstrtab = NULL;
+ unsigned char *buf;
+ int fixedprobes = 0;
+#endif
if (getenv("DTRACE_DOF_INIT_DISABLE") != NULL)
return;
@@ -127,10 +180,46 @@ dtrace_dof_init(void)
}
#endif
+
if ((modname = strrchr(lmp->l_name, '/')) == NULL)
modname = lmp->l_name;
else
modname++;
+#if !defined(sun)
+ elf_version(EV_CURRENT);
+ if ((efd = open(lmp->l_name, O_RDONLY, 0)) < 0) {
+ dprintf(1, "couldn't open file for reading\n");
+ return;
+ }
+ if ((e = elf_begin(efd, ELF_C_READ, NULL)) == NULL) {
+ dprintf(1, "elf_begin failed\n");
+ close(efd);
+ return;
+ }
+ elf_getshdrstrndx(e, &shstridx);
+ dof = NULL;
+ while ((scn = elf_nextscn(e, scn)) != NULL) {
+ gelf_getshdr(scn, &shdr);
+ if (shdr.sh_type == SHT_SYMTAB) {
+ symtabidx = shdr.sh_link;
+ symtabdata = elf_getdata(scn, NULL);
+ } else if (shdr.sh_type == SHT_DYNSYM) {
+ dynsymidx = shdr.sh_link;
+ dynsymdata = elf_getdata(scn, NULL);
+ } else if (shdr.sh_type == SHT_PROGBITS) {
+ s = elf_strptr(e, shstridx, shdr.sh_name);
+ if (s && strcmp(s, ".SUNW_dof") == 0) {
+ dof = elf_getdata(scn, NULL)->d_buf;
+ }
+ }
+ }
+ if (dof == NULL) {
+ dprintf(1, "SUNW_dof section not found\n");
+ elf_end(e);
+ close(efd);
+ return;
+ }
+#endif
if (dof->dofh_ident[DOF_ID_MAG0] != DOF_MAG_MAG0 ||
dof->dofh_ident[DOF_ID_MAG1] != DOF_MAG_MAG1 ||
@@ -158,7 +247,7 @@ dtrace_dof_init(void)
if ((fd = open64(devnamep, O_RDWR)) < 0) {
dprintf(1, "failed to open helper device %s", devnamep);
-
+#if defined(sun)
/*
* If the device path wasn't explicitly set, try again with
* the old device path.
@@ -172,14 +261,79 @@ dtrace_dof_init(void)
dprintf(1, "failed to open helper device %s", devnamep);
return;
}
+#else
+ return;
+#endif
}
-
+#if !defined(sun)
+ /*
+ * We need to fix the base address of each probe since this wasn't
+ * done by ld(1). (ld(1) needs to grow support for parsing the
+ * SUNW_dof section).
+ *
+ * The complexity of this is not that great. The first for loop
+ * iterates over the sections inside the DOF file. There are usually
+ * 10 sections here. We asume the STRTAB section comes first and the
+ * PROBES section comes after. Since we are only interested in fixing
+ * data inside the PROBES section we quit the for loop after processing
+ * the PROBES section. It's usually the case that the first section
+ * is the STRTAB section and the second section is the PROBES section,
+ * so this for loop is not meaningful when doing complexity analysis.
+ *
+ * After finding the probes section, we iterate over the symbols
+ * in the symtab section. When we find a symbol name that matches
+ * the probe function name, we fix it. If we have fixed all the
+ * probes, we exit all the loops and we are done.
+ * The number of probes is given by the variable 'nprobes' and this
+ * depends entirely on the user, but some optimizations were done.
+ *
+ * We are assuming the number of probes is less than the number of
+ * symbols (libc can have 4k symbols, for example).
+ */
+ sec = (dof_sec_t *)(dof + 1);
+ buf = (char *)dof;
+ for (i = 0; i < dof->dofh_secnum; i++, sec++) {
+ if (sec->dofs_type == DOF_SECT_STRTAB)
+ dofstrtab = (unsigned char *)(buf + sec->dofs_offset);
+ else if (sec->dofs_type == DOF_SECT_PROBES && dofstrtab)
+ break;
+
+ }
+ nprobes = sec->dofs_size / sec->dofs_entsize;
+ fixsymbol(e, symtabdata, symtabidx, nprobes, buf, sec, &fixedprobes,
+ dofstrtab);
+ if (fixedprobes != nprobes) {
+ /*
+ * If we haven't fixed all the probes using the
+ * symtab section, look inside the dynsym
+ * section.
+ */
+ fixsymbol(e, dynsymdata, dynsymidx, nprobes, buf, sec,
+ &fixedprobes, dofstrtab);
+ }
+ if (fixedprobes != nprobes) {
+ fprintf(stderr, "WARNING: number of probes "
+ "fixed does not match the number of "
+ "defined probes (%d != %d, "
+ "respectively)\n", fixedprobes, nprobes);
+ fprintf(stderr, "WARNING: some probes might "
+ "not fire or your program might crash\n");
+ }
+#endif
if ((gen = ioctl(fd, DTRACEHIOC_ADDDOF, &dh)) == -1)
dprintf(1, "DTrace ioctl failed for DOF at %p", dof);
- else
+ else {
dprintf(1, "DTrace ioctl succeeded for DOF at %p\n", dof);
+#if !defined(sun)
+ gen = dh.gen;
+#endif
+ }
(void) close(fd);
+#if !defined(sun)
+ elf_end(e);
+ (void) close(efd);
+#endif
}
#if defined(sun)
@@ -198,7 +352,7 @@ dtrace_dof_fini(void)
return;
}
- if ((gen = ioctl(fd, DTRACEHIOC_REMOVE, gen)) == -1)
+ 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);
Modified: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_aggregate.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_aggregate.c Sat Aug 21 11:41:32 2010 (r211553)
+++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_aggregate.c Sat Aug 21 11:50:53 2010 (r211554)
@@ -36,6 +36,7 @@
#include <alloca.h>
#else
#include <sys/sysctl.h>
+#include <libproc_compat.h>
#endif
#include <limits.h>
@@ -264,11 +265,7 @@ dt_aggregate_usym(dtrace_hdl_t *dtp, uin
dt_proc_lock(dtp, P);
-#if defined(sun)
if (Plookup_by_addr(P, *pc, NULL, 0, &sym) == 0)
-#else
- if (proc_addr2sym(P, *pc, NULL, 0, &sym) == 0)
-#endif
*pc = sym.st_value;
dt_proc_unlock(dtp, P);
@@ -291,11 +288,7 @@ dt_aggregate_umod(dtrace_hdl_t *dtp, uin
dt_proc_lock(dtp, P);
-#if defined(sun)
if ((map = Paddr_to_map(P, *pc)) != NULL)
-#else
- if ((map = proc_addr2map(P, *pc)) != NULL)
-#endif
*pc = map->pr_vaddr;
dt_proc_unlock(dtp, P);
Modified: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c Sat Aug 21 11:41:32 2010 (r211553)
+++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c Sat Aug 21 11:50:53 2010 (r211554)
@@ -34,6 +34,9 @@
#include <alloca.h>
#endif
#include <dt_impl.h>
+#if !defined(sun)
+#include <libproc_compat.h>
+#endif
#define DT_MASK_LO 0x00000000FFFFFFFFULL
@@ -952,17 +955,9 @@ dt_print_ustack(dtrace_hdl_t *dtp, FILE
if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0)
break;
-#if defined(sun)
if (P != NULL && Plookup_by_addr(P, pc[i],
-#else
- if (P != NULL && proc_addr2sym(P, pc[i],
-#endif
name, sizeof (name), &sym) == 0) {
-#if defined(sun)
(void) Pobjname(P, pc[i], objname, sizeof (objname));
-#else
- (void) proc_objname(P, pc[i], objname, sizeof (objname));
-#endif
if (pc[i] > sym.st_value) {
(void) snprintf(c, sizeof (c),
@@ -973,12 +968,8 @@ dt_print_ustack(dtrace_hdl_t *dtp, FILE
"%s`%s", dt_basename(objname), name);
}
} else if (str != NULL && str[0] != '\0' && str[0] != '@' &&
-#if defined(sun)
(P != NULL && ((map = Paddr_to_map(P, pc[i])) == NULL ||
(map->pr_mflags & MA_WRITE)))) {
-#else
- (P != NULL && ((map = proc_addr2map(P, pc[i])) == NULL))) {
-#endif
/*
* If the current string pointer in the string table
* does not point to an empty string _and_ the program
@@ -994,11 +985,7 @@ dt_print_ustack(dtrace_hdl_t *dtp, FILE
*/
(void) snprintf(c, sizeof (c), "%s", str);
} else {
-#if defined(sun)
if (P != NULL && Pobjname(P, pc[i], objname,
-#else
- if (P != NULL && proc_objname(P, pc[i], objname,
-#endif
sizeof (objname)) != 0) {
(void) snprintf(c, sizeof (c), "%s`0x%llx",
dt_basename(objname), (u_longlong_t)pc[i]);
@@ -1068,11 +1055,7 @@ dt_print_usym(dtrace_hdl_t *dtp, FILE *f
dt_proc_lock(dtp, P);
-#if defined(sun)
if (Plookup_by_addr(P, pc, NULL, 0, &sym) == 0)
-#else
- if (proc_addr2sym(P, pc, NULL, 0, &sym) == 0)
-#endif
pc = sym.st_value;
dt_proc_unlock(dtp, P);
@@ -1115,11 +1098,7 @@ dt_print_umod(dtrace_hdl_t *dtp, FILE *f
if (P != NULL)
dt_proc_lock(dtp, P); /* lock handle while we perform lookups */
-#if defined(sun)
if (P != NULL && Pobjname(P, pc, objname, sizeof (objname)) != 0) {
-#else
- if (P != NULL && proc_objname(P, pc, objname, sizeof (objname)) != 0) {
-#endif
(void) snprintf(c, sizeof (c), "%s", dt_basename(objname));
} else {
(void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc);
Modified: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c Sat Aug 21 11:41:32 2010 (r211553)
+++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c Sat Aug 21 11:50:53 2010 (r211554)
@@ -51,6 +51,9 @@
#include <wait.h>
#else
#include <sys/wait.h>
+#include <libelf.h>
+#include <gelf.h>
+#include <sys/mman.h>
#endif
#include <assert.h>
#include <sys/ipc.h>
@@ -412,7 +415,6 @@ prepare_elf64(dtrace_hdl_t *dtp, const d
s = &dofs[dofrh->dofr_tgtsec];
for (j = 0; j < nrel; j++) {
-printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
#ifdef DOODAD
#if defined(__arm__)
/* XXX */
@@ -1519,14 +1521,29 @@ process_obj(dtrace_hdl_t *dtp, const cha
off = rela.r_offset - fsym.st_value;
if (dt_modtext(dtp, data_tgt->d_buf, eprobe,
- &rela, &off) != 0) {
+ &rela, &off) != 0)
goto err;
- }
if (dt_probe_define(pvp, prp, s, r, off, eprobe) != 0) {
return (dt_link_error(dtp, elf, fd, bufs,
"failed to allocate space for probe"));
}
+#if !defined(sun)
+ /*
+ * Our linker doesn't understand the SUNW_IGNORE ndx and
+ * will try to use this relocation when we build the
+ * final executable. Since we are done processing this
+ * relocation, mark it as inexistant and let libelf
+ * remove it from the file.
+ * If this wasn't done, we would have garbage added to
+ * the executable file as the symbol is going to be
+ * change from UND to ABS.
+ */
+ rela.r_offset = 0;
+ rela.r_info = 0;
+ rela.r_addend = 0;
+ (void) gelf_update_rela(data_rel, i, &rela);
+#endif
mod = 1;
(void) elf_flagdata(data_tgt, ELF_C_SET, ELF_F_DIRTY);
@@ -1538,13 +1555,13 @@ process_obj(dtrace_hdl_t *dtp, const cha
* already been processed by an earlier link
* invocation.
*/
-printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
-#ifdef DOODAD
+#if !defined(sun)
+#define SHN_SUNW_IGNORE SHN_ABS
+#endif
if (rsym.st_shndx != SHN_SUNW_IGNORE) {
rsym.st_shndx = SHN_SUNW_IGNORE;
(void) gelf_update_sym(data_sym, ndx, &rsym);
}
-#endif
}
}
@@ -1554,6 +1571,9 @@ printf("%s:%s(%d): DOODAD\n",__FUNCTION_
(void) elf_end(elf);
(void) close(fd);
+#if !defined(sun)
+ if (nsym > 0)
+#endif
while ((pair = bufs) != NULL) {
bufs = pair->dlp_next;
dt_free(dtp, pair->dlp_str);
@@ -1574,6 +1594,19 @@ dtrace_program_link(dtrace_hdl_t *dtp, d
{
#if !defined(sun)
char tfile[PATH_MAX];
+ Elf *e;
+ Elf_Scn *scn;
+ Elf_Data *data;
+ GElf_Shdr shdr;
+ int efd;
+ size_t stridx;
+ unsigned char *buf;
+ char *s;
+ int loc;
+ GElf_Ehdr ehdr;
+ Elf_Scn *scn0;
+ GElf_Shdr shdr0;
+ uint64_t off, rc;
#endif
char drti[PATH_MAX];
dof_hdr_t *dof;
@@ -1697,12 +1730,17 @@ dtrace_program_link(dtrace_hdl_t *dtp, d
(void) unlink(file);
#endif
+#if defined(sun)
if (dtp->dt_oflags & DTRACE_O_LP64)
status = dump_elf64(dtp, dof, fd);
else
status = dump_elf32(dtp, dof, fd);
if (status != 0 || lseek(fd, 0, SEEK_SET) != 0) {
+#else
+ /* We don't write the ELF header, just the DOF section */
+ if (dt_write(dtp, fd, dof, dof->dofh_filesz) < dof->dofh_filesz) {
+#endif
return (dt_link_error(dtp, NULL, -1, NULL,
"failed to write %s: %s", file, strerror(errno)));
}
@@ -1726,7 +1764,7 @@ dtrace_program_link(dtrace_hdl_t *dtp, d
(void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, fd, drti);
#else
- const char *fmt = "%s -o %s -r %s %s";
+ const char *fmt = "%s -o %s -r %s";
#if defined(__amd64__)
/*
@@ -1748,11 +1786,14 @@ dtrace_program_link(dtrace_hdl_t *dtp, d
len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file, tfile,
drti) + 1;
+#if !defined(sun)
+ len *= 2;
+#endif
cmd = alloca(len);
- (void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, tfile, drti);
+ (void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file,
+ drti);
#endif
-
if ((status = system(cmd)) == -1) {
ret = dt_link_error(dtp, NULL, -1, NULL,
"failed to run %s: %s", dtp->dt_ld_path,
@@ -1760,8 +1801,6 @@ dtrace_program_link(dtrace_hdl_t *dtp, d
goto done;
}
- (void) close(fd); /* release temporary file */
-
if (WIFSIGNALED(status)) {
ret = dt_link_error(dtp, NULL, -1, NULL,
"failed to link %s: %s failed due to signal %d",
@@ -1775,6 +1814,138 @@ dtrace_program_link(dtrace_hdl_t *dtp, d
file, dtp->dt_ld_path, WEXITSTATUS(status));
goto done;
}
+#if !defined(sun)
+#define BROKEN_LIBELF
+ /*
+ * FreeBSD's ld(1) is not instructed to interpret and add
+ * correctly the SUNW_dof section present in tfile.
+ * We use libelf to add this section manually and hope the next
+ * ld invocation won't remove it.
+ */
+ elf_version(EV_CURRENT);
+ if ((efd = open(file, O_RDWR, 0)) < 0) {
+ ret = dt_link_error(dtp, NULL, -1, NULL,
+ "failed to open file %s: %s",
+ file, strerror(errno));
+ goto done;
+ }
+ if ((e = elf_begin(efd, ELF_C_RDWR, NULL)) == NULL) {
+ close(efd);
+ ret = dt_link_error(dtp, NULL, -1, NULL,
+ "failed to open elf file: %s",
+ elf_errmsg(elf_errno()));
+ goto done;
+ }
+ /*
+ * Add the string '.SUWN_dof' to the shstrtab section.
+ */
+#ifdef BROKEN_LIBELF
+ elf_flagelf(e, ELF_C_SET, ELF_F_LAYOUT);
+#endif
+ elf_getshdrstrndx(e, &stridx);
+ scn = elf_getscn(e, stridx);
+ gelf_getshdr(scn, &shdr);
+ data = elf_newdata(scn);
+ data->d_off = shdr.sh_size;
+ data->d_buf = ".SUNW_dof";
+ data->d_size = 10;
+ data->d_type = ELF_T_BYTE;
+ loc = shdr.sh_size;
+ shdr.sh_size += data->d_size;
+ gelf_update_shdr(scn, &shdr);
+#ifdef BROKEN_LIBELF
+ off = shdr.sh_offset;
+ rc = shdr.sh_offset + shdr.sh_size;
+ gelf_getehdr(e, &ehdr);
+ if (ehdr.e_shoff > off) {
+ off = ehdr.e_shoff + ehdr.e_shnum * ehdr.e_shentsize;
+ rc = roundup(rc, 8);
+ ehdr.e_shoff = rc;
+ gelf_update_ehdr(e, &ehdr);
+ rc += ehdr.e_shnum * ehdr.e_shentsize;
+ }
+ for (;;) {
+ scn0 = NULL;
+ scn = NULL;
+ while ((scn = elf_nextscn(e, scn)) != NULL) {
+ gelf_getshdr(scn, &shdr);
+ if (shdr.sh_type == SHT_NOBITS ||
+ shdr.sh_offset < off)
+ continue;
+ /* Find the immediately adjcent section. */
+ if (scn0 == NULL ||
+ shdr.sh_offset < shdr0.sh_offset) {
+ scn0 = scn;
+ gelf_getshdr(scn0, &shdr0);
+ }
+ }
+ if (scn0 == NULL)
+ break;
+ /* Load section data to work around another bug */
+ elf_getdata(scn0, NULL);
+ /* Update section header, assure section alignment */
+ off = shdr0.sh_offset + shdr0.sh_size;
+ rc = roundup(rc, shdr0.sh_addralign);
+ shdr0.sh_offset = rc;
+ gelf_update_shdr(scn0, &shdr0);
+ rc += shdr0.sh_size;
+ }
+ if (elf_update(e, ELF_C_WRITE) < 0) {
+ ret = dt_link_error(dtp, NULL, -1, NULL,
+ "failed to add append the shstrtab section: %s",
+ elf_errmsg(elf_errno()));
+ elf_end(e);
+ close(efd);
+ goto done;
+ }
+ elf_end(e);
+ e = elf_begin(efd, ELF_C_RDWR, NULL);
+#endif
+ /*
+ * Construct the .SUNW_dof section.
+ */
+ scn = elf_newscn(e);
+ data = elf_newdata(scn);
+ buf = mmap(NULL, dof->dofh_filesz, PROT_READ, MAP_SHARED,
+ fd, 0);
+ if (buf == MAP_FAILED) {
+ ret = dt_link_error(dtp, NULL, -1, NULL,
+ "failed to mmap buffer %s", strerror(errno));
+ elf_end(e);
+ close(efd);
+ goto done;
+ }
+ data->d_buf = buf;
+ data->d_align = 4;
+ data->d_size = dof->dofh_filesz;
+ data->d_version = EV_CURRENT;
+ gelf_getshdr(scn, &shdr);
+ shdr.sh_name = loc;
+ shdr.sh_flags = SHF_ALLOC;
+ /*
+ * Actually this should be SHT_SUNW_dof, but FreeBSD's ld(1)
+ * will remove this 'unknown' section when we try to create an
+ * executable using the object we are modifying, so we stop
+ * playing by the rules and use SHT_PROGBITS.
+ * Also, note that our drti has modifications to handle this.
+ */
+ shdr.sh_type = SHT_PROGBITS;
+ shdr.sh_addralign = 4;
+ gelf_update_shdr(scn, &shdr);
+ if (elf_update(e, ELF_C_WRITE) < 0) {
+ ret = dt_link_error(dtp, NULL, -1, NULL,
+ "failed to add the SUNW_dof section: %s",
+ elf_errmsg(elf_errno()));
+ munmap(buf, dof->dofh_filesz);
+ elf_end(e);
+ close(efd);
+ goto done;
+ }
+ munmap(buf, dof->dofh_filesz);
+ elf_end(e);
+ close(efd);
+#endif
+ (void) close(fd); /* release temporary file */
} else {
(void) close(fd);
}
Modified: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c Sat Aug 21 11:41:32 2010 (r211553)
+++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c Sat Aug 21 11:50:53 2010 (r211554)
@@ -283,10 +283,8 @@ static const dt_ident_t _dtrace_globals[
DT_VERS_1_5, &dt_idops_func, "string(int, void *)" },
{ "ipl", DT_IDENT_SCALAR, 0, DIF_VAR_IPL, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_type, "uint_t" },
-#if defined(sun)
{ "jstack", DT_IDENT_ACTFUNC, 0, DT_ACT_JSTACK, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "stack(...)" },
-#endif
{ "lltostr", DT_IDENT_FUNC, 0, DIF_SUBR_LLTOSTR, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "string(int64_t)" },
{ "lquantize", DT_IDENT_AGGFUNC, 0, DTRACEAGG_LQUANTIZE,
@@ -465,8 +463,10 @@ static const dt_ident_t _dtrace_globals[
#if defined(sun)
{ "uaddr", DT_IDENT_ACTFUNC, 0, DT_ACT_UADDR, DT_ATTR_STABCMN,
DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
+#endif
{ "ucaller", DT_IDENT_SCALAR, 0, DIF_VAR_UCALLER, DT_ATTR_STABCMN,
DT_VERS_1_2, &dt_idops_type, "uint64_t" },
+#if defined(sun)
{ "ufunc", DT_IDENT_ACTFUNC, 0, DT_ACT_USYM, DT_ATTR_STABCMN,
DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
#endif
@@ -475,6 +475,7 @@ static const dt_ident_t _dtrace_globals[
#if defined(sun)
{ "umod", DT_IDENT_ACTFUNC, 0, DT_ACT_UMOD, DT_ATTR_STABCMN,
DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
+#endif
{ "uregs", DT_IDENT_ARRAY, 0, DIF_VAR_UREGS, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_regs, NULL },
{ "ustack", DT_IDENT_ACTFUNC, 0, DT_ACT_USTACK, DT_ATTR_STABCMN, DT_VERS_1_0,
@@ -482,6 +483,7 @@ static const dt_ident_t _dtrace_globals[
{ "ustackdepth", DT_IDENT_SCALAR, 0, DIF_VAR_USTACKDEPTH,
DT_ATTR_STABCMN, DT_VERS_1_2,
&dt_idops_type, "uint32_t" },
+#if defined(sun)
{ "usym", DT_IDENT_ACTFUNC, 0, DT_ACT_USYM, DT_ATTR_STABCMN,
DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
#endif
@@ -760,9 +762,7 @@ int _dtrace_argmax = 32; /* default maxi
int _dtrace_debug = 0; /* debug messages enabled (off) */
const char *const _dtrace_version = DT_VERS_STRING; /* API version string */
-#if defined(sun)
int _dtrace_rdvers = RD_VERSION; /* rtld_db feature version */
-#endif
typedef struct dt_fdlist {
int *df_fds; /* array of provider driver file descriptors */
@@ -780,12 +780,10 @@ _dtrace_init(void)
{
_dtrace_debug = getenv("DTRACE_DEBUG") != NULL;
-#if defined(sun)
for (; _dtrace_rdvers > 0; _dtrace_rdvers--) {
if (rd_init(_dtrace_rdvers) == RD_OK)
break;
}
-#endif
#if defined(__i386__)
/* make long doubles 64 bits -sson */
(void) fpsetprec(FP_PE);
@@ -1102,7 +1100,11 @@ alloc:
bzero(dtp, sizeof (dtrace_hdl_t));
dtp->dt_oflags = flags;
+#if defined(sun)
dtp->dt_prcmode = DT_PROC_STOP_PREINIT;
+#else
+ dtp->dt_prcmode = DT_PROC_STOP_POSTINIT;
+#endif
dtp->dt_linkmode = DT_LINK_KERNEL;
dtp->dt_linktype = DT_LTYP_ELF;
dtp->dt_xlatemode = DT_XL_STATIC;
Modified: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c Sat Aug 21 11:41:32 2010 (r211553)
+++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c Sat Aug 21 11:50:53 2010 (r211554)
@@ -40,6 +40,9 @@
#include <dt_program.h>
#include <dt_pid.h>
#include <dt_string.h>
+#if !defined(sun)
+#include <libproc_compat.h>
+#endif
typedef struct dt_pid_probe {
dtrace_hdl_t *dpp_dtp;
@@ -142,7 +145,6 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const
pp->dpp_obj);
if (!isdash && gmatch("return", pp->dpp_name)) {
-#ifdef DOODAD
if (dt_pid_create_return_probe(pp->dpp_pr, dtp, ftp, symp,
pp->dpp_stret) < 0) {
return (dt_pid_error(dtp, pcb, dpr, ftp,
@@ -150,20 +152,17 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const
"for '%s': %s", func,
dtrace_errmsg(dtp, dtrace_errno(dtp))));
}
-#endif
nmatches++;
}
if (!isdash && gmatch("entry", pp->dpp_name)) {
-#ifdef DOODAD
if (dt_pid_create_entry_probe(pp->dpp_pr, dtp, ftp, symp) < 0) {
return (dt_pid_error(dtp, pcb, dpr, ftp,
D_PROC_CREATEFAIL, "failed to create entry probe "
"for '%s': %s", func,
dtrace_errmsg(dtp, dtrace_errno(dtp))));
}
-#endif
nmatches++;
}
@@ -182,10 +181,8 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const
(u_longlong_t)off, func));
}
-#ifdef DOODAD
err = dt_pid_create_offset_probe(pp->dpp_pr, pp->dpp_dtp, ftp,
symp, off);
-#endif
if (err == DT_PROC_ERR) {
return (dt_pid_error(dtp, pcb, dpr, ftp,
@@ -203,7 +200,6 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const
nmatches++;
} else if (glob && !isdash) {
-#ifdef DOODAD
if (dt_pid_create_glob_offset_probes(pp->dpp_pr,
pp->dpp_dtp, ftp, symp, pp->dpp_name) < 0) {
return (dt_pid_error(dtp, pcb, dpr, ftp,
@@ -211,7 +207,6 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const
"failed to create offset probes in '%s': %s", func,
dtrace_errmsg(dtp, dtrace_errno(dtp))));
}
-#endif
nmatches++;
}
@@ -279,7 +274,6 @@ dt_pid_per_mod(void *arg, const prmap_t
pp->dpp_obj = obj;
else
pp->dpp_obj++;
-
#if defined(sun)
if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj, ".stret1", &sym,
NULL) == 0)
@@ -305,25 +299,10 @@ dt_pid_per_mod(void *arg, const prmap_t
else
pp->dpp_stret[3] = 0;
#else
- if (proc_name2sym(pp->dpp_pr, obj, ".stret1", &sym) == 0)
- pp->dpp_stret[0] = sym.st_value;
- else
- pp->dpp_stret[0] = 0;
-
- if (proc_name2sym(pp->dpp_pr, obj, ".stret2", &sym) == 0)
- pp->dpp_stret[1] = sym.st_value;
- else
- pp->dpp_stret[1] = 0;
-
- if (proc_name2sym(pp->dpp_pr, obj, ".stret4", &sym) == 0)
- pp->dpp_stret[2] = sym.st_value;
- else
- pp->dpp_stret[2] = 0;
-
- if (proc_name2sym(pp->dpp_pr, obj, ".stret8", &sym) == 0)
- pp->dpp_stret[3] = sym.st_value;
- else
- pp->dpp_stret[3] = 0;
+ pp->dpp_stret[0] = 0;
+ pp->dpp_stret[1] = 0;
+ pp->dpp_stret[2] = 0;
+ pp->dpp_stret[3] = 0;
#endif
dt_dprintf("%s stret %llx %llx %llx %llx\n", obj,
@@ -345,12 +324,8 @@ dt_pid_per_mod(void *arg, const prmap_t
* just fail silently in the hopes that some other object will
* contain the desired symbol.
*/
-#if defined(sun)
if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj,
pp->dpp_func, &sym, NULL) != 0) {
-#else
- if (proc_name2sym(pp->dpp_pr, obj, pp->dpp_func, &sym) != 0) {
-#endif
if (strcmp("-", pp->dpp_func) == 0) {
sym.st_name = 0;
sym.st_info =
@@ -390,16 +365,11 @@ dt_pid_per_mod(void *arg, const prmap_t
return (0);
#endif
-#if defined(sun)
(void) Plookup_by_addr(pp->dpp_pr, sym.st_value, pp->dpp_func,
-#else
- (void) proc_addr2sym(pp->dpp_pr, sym.st_value, pp->dpp_func,
-#endif
DTRACE_FUNCNAMELEN, &sym);
return (dt_pid_per_sym(pp, &sym, pp->dpp_func));
} else {
-#ifdef DOODAD
uint_t nmatches = pp->dpp_nmatches;
if (Psymbol_iter_by_addr(pp->dpp_pr, obj, PR_SYMTAB,
@@ -415,7 +385,6 @@ dt_pid_per_mod(void *arg, const prmap_t
BIND_ANY | TYPE_FUNC, dt_pid_sym_filt, pp) == 1)
return (1);
}
-#endif
}
return (0);
@@ -459,14 +428,16 @@ dt_pid_mod_filt(void *arg, const prmap_t
static const prmap_t *
dt_pid_fix_mod(dtrace_probedesc_t *pdp, struct ps_prochandle *P)
{
-#ifdef DOODAD
char m[MAXPATHLEN];
+#if defined(sun)
Lmid_t lmid = PR_LMID_EVERY;
- const char *obj;
+#else
+ Lmid_t lmid = 0;
#endif
+ const char *obj;
const prmap_t *pmp;
-#ifdef DOODAD
+#if defined(sun)
/*
* Pick apart the link map from the library name.
*/
@@ -487,10 +458,14 @@ dt_pid_fix_mod(dtrace_probedesc_t *pdp,
} else {
obj = pdp->dtpd_mod;
}
+#else
+ obj = pdp->dtpd_mod;
+#endif
if ((pmp = Plmid_to_map(P, lmid, obj)) == NULL)
return (NULL);
+#if defined(sun)
(void) Pobjname(P, pmp->pr_vaddr, m, sizeof (m));
if ((obj = strrchr(m, '/')) == NULL)
obj = &m[0];
@@ -498,11 +473,9 @@ dt_pid_fix_mod(dtrace_probedesc_t *pdp,
obj++;
(void) Plmid(P, pmp->pr_vaddr, &lmid);
+#endif
dt_pid_objname(pdp->dtpd_mod, sizeof (pdp->dtpd_mod), lmid, obj);
-#else
-pmp = NULL;
-#endif
return (pmp);
}
@@ -544,13 +517,8 @@ dt_pid_create_pid_probes(dtrace_probedes
pp.dpp_mod = pdp->dtpd_mod;
(void) strcpy(pdp->dtpd_mod, "a.out");
} else if (strisglob(pp.dpp_mod) ||
-#if defined(sun)
(aout = Pname_to_map(pp.dpp_pr, "a.out")) == NULL ||
(pmp = Pname_to_map(pp.dpp_pr, pp.dpp_mod)) == NULL ||
-#else
- (aout = proc_name2map(pp.dpp_pr, "a.out")) == NULL ||
- (pmp = proc_name2map(pp.dpp_pr, pp.dpp_mod)) == NULL ||
-#endif
aout->pr_vaddr != pmp->pr_vaddr) {
return (dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_LIB,
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-head
mailing list