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