Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 11 Sep 2014 01:04:56 +0000 (UTC)
From:      Mark Johnston <markj@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r271413 - head/cddl/contrib/opensolaris/lib/libdtrace/common
Message-ID:  <201409110104.s8B14uFq084230@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: markj
Date: Thu Sep 11 01:04:56 2014
New Revision: 271413
URL: http://svnweb.freebsd.org/changeset/base/271413

Log:
  Use the linker to perform relocations in the SUNW_dof section rather than
  doing them in drti during startup. This fixes a number of problems with
  using USDT probes in stripped executables and shared libraries, and with
  USDT probes in static functions.
  
  Reviewed by:	rpaulo
  MFC after:	1 month
  Sponsored by:	EMC / Isilon Storage Division
  Phabric: 	D751

Modified:
  head/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c
  head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c

Modified: head/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c	Thu Sep 11 00:10:54 2014	(r271412)
+++ head/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c	Thu Sep 11 01:04:56 2014	(r271413)
@@ -90,36 +90,6 @@ 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 *)(void *)(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
@@ -145,9 +115,6 @@ dtrace_dof_init(void)
 	Lmid_t lmid;
 #else
 	u_long lmid = 0;
-	dof_sec_t *sec, *secstart, *dofstrtab, *dofprobes;
-	dof_provider_t *dofprovider;
-	size_t i;
 #endif
 	int fd;
 	const char *p;
@@ -157,12 +124,9 @@ dtrace_dof_init(void)
 	Elf_Data *symtabdata = NULL, *dynsymdata = NULL, *dofdata = NULL;
 	dof_hdr_t *dof_next = NULL;
 	GElf_Shdr shdr;
-	int efd, nprobes;
+	int efd;
 	char *s;
-	char *dofstrtabraw;
 	size_t shstridx, symtabidx = 0, dynsymidx = 0;
-	unsigned char *buf;
-	int fixedprobes;
 #endif
 
 	if (getenv("DTRACE_DOF_INIT_DISABLE") != NULL)
@@ -183,7 +147,6 @@ dtrace_dof_init(void)
 	}
 #endif
 
-
 	if ((modname = strrchr(lmp->l_name, '/')) == NULL)
 		modname = lmp->l_name;
 	else
@@ -209,9 +172,9 @@ dtrace_dof_init(void)
 		} else if (shdr.sh_type == SHT_DYNSYM) {
 			dynsymidx = shdr.sh_link;
 			dynsymdata = elf_getdata(scn, NULL);
-		} else if (shdr.sh_type == SHT_PROGBITS) {
+		} else if (shdr.sh_type == SHT_SUNW_dof) {
 			s = elf_strptr(e, shstridx, shdr.sh_name);
-			if  (s && strcmp(s, ".SUNW_dof") == 0) {
+			if  (s != NULL && strcmp(s, ".SUNW_dof") == 0) {
 				dofdata = elf_getdata(scn, NULL);
 				dof = dofdata->d_buf;
 			}
@@ -225,7 +188,6 @@ dtrace_dof_init(void)
 	}
 
 	while ((char *) dof < (char *) dofdata->d_buf + dofdata->d_size) {
-		fixedprobes = 0;
 		dof_next = (void *) ((char *) dof + dof->dofh_filesz);
 #endif
 
@@ -273,76 +235,6 @@ dtrace_dof_init(void)
 		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).
-	 */
-	secstart = sec = (dof_sec_t *)(dof + 1);
-	buf = (char *)dof;
-	for (i = 0; i < dof->dofh_secnum; i++, sec++) {
-		if (sec->dofs_type != DOF_SECT_PROVIDER)
-			continue;
-
-		dofprovider = (void *) (buf + sec->dofs_offset);
-		dofstrtab = secstart + dofprovider->dofpv_strtab;
-		dofprobes = secstart + dofprovider->dofpv_probes;
-
-		if (dofstrtab->dofs_type != DOF_SECT_STRTAB) {
-			fprintf(stderr, "WARNING: expected STRTAB section, but got %d\n",
-					dofstrtab->dofs_type);
-			break;
-		}
-		if (dofprobes->dofs_type != DOF_SECT_PROBES) {
-			fprintf(stderr, "WARNING: expected PROBES section, but got %d\n",
-			    dofprobes->dofs_type);
-			break;
-		}
-
-		dprintf(1, "found provider %p\n", dofprovider);
-		dofstrtabraw = (char *)(buf + dofstrtab->dofs_offset);
-		nprobes = dofprobes->dofs_size / dofprobes->dofs_entsize;
-		fixsymbol(e, symtabdata, symtabidx, nprobes, buf, dofprobes, &fixedprobes,
-				dofstrtabraw);
-		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, dofprobes,
-					&fixedprobes, dofstrtabraw);
-		}
-		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 {

Modified: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c	Thu Sep 11 00:10:54 2014	(r271412)
+++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c	Thu Sep 11 01:04:56 2014	(r271413)
@@ -322,7 +322,11 @@ prepare_elf64(dtrace_hdl_t *dtp, const d
 	char *strtab;
 	int i, j, nrel;
 	size_t strtabsz = 1;
+#if defined(sun)
 	uint32_t count = 0;
+#else
+	uint64_t count = 0;
+#endif
 	size_t base;
 	Elf64_Sym *sym;
 	Elf64_Rela *rel;
@@ -418,7 +422,6 @@ prepare_elf64(dtrace_hdl_t *dtp, const d
 		s = &dofs[dofrh->dofr_tgtsec];
 
 		for (j = 0; j < nrel; j++) {
-#ifdef DOODAD
 #if defined(__arm__)
 /* XXX */
 #elif defined(__mips__)
@@ -431,8 +434,13 @@ prepare_elf64(dtrace_hdl_t *dtp, const d
 #elif defined(__i386) || defined(__amd64)
 			rel->r_offset = s->dofs_offset +
 			    dofr[j].dofr_offset;
+#if defined(sun)
 			rel->r_info = ELF64_R_INFO(count + dep->de_global,
 			    R_AMD64_64);
+#else
+			rel->r_info = ELF64_R_INFO(count + dep->de_global,
+			    R_X86_64_RELATIVE);
+#endif
 #elif defined(__sparc)
 			rel->r_offset = s->dofs_offset +
 			    dofr[j].dofr_offset;
@@ -441,7 +449,6 @@ prepare_elf64(dtrace_hdl_t *dtp, const d
 #else
 #error unknown ISA
 #endif
-#endif
 
 			sym->st_name = base + dofr[j].dofr_name - 1;
 			sym->st_value = 0;
@@ -704,7 +711,11 @@ dump_elf64(dtrace_hdl_t *dtp, const dof_
 
 	shp = &elf_file.shdr[ESHDR_DOF];
 	shp->sh_name = 11; /* DTRACE_SHSTRTAB64[11] = ".SUNW_dof" */
+#if defined(sun)
 	shp->sh_flags = SHF_ALLOC;
+#else
+	shp->sh_flags = SHF_WRITE | SHF_ALLOC;
+#endif
 	shp->sh_type = SHT_SUNW_dof;
 	shp->sh_offset = off;
 	shp->sh_size = dof->dofh_filesz;
@@ -1662,19 +1673,6 @@ 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;
@@ -1810,21 +1808,22 @@ 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 defined(sun)
 	if (status != 0 || lseek(fd, 0, SEEK_SET) != 0) {
 		return (dt_link_error(dtp, NULL, -1, NULL,
 		    "failed to write %s: %s", file, strerror(errno)));
 	}
 #else
-	/* We don't write the ELF header, just the DOF section */
-	if (dt_write(dtp, fd, dof, dof->dofh_filesz) < dof->dofh_filesz)
+	(void)close(fd);
+	if (status != 0)
 		return (dt_link_error(dtp, NULL, -1, NULL,
-		    "failed to write %s: %s", tfile, strerror(errno)));
+		    "failed to write %s: %s", tfile,
+		    strerror(dtrace_errno(dtp))));
 #endif
 
 	if (!dtp->dt_lazyload) {
@@ -1846,7 +1845,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";
+		const char *fmt = "%s -o %s -r %s %s";
 
 #if defined(__amd64__)
 		/*
@@ -1868,10 +1867,9 @@ dtrace_program_link(dtrace_hdl_t *dtp, d
 		len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file, tfile,
 		    drti) + 1;
 
-		len *= 2;
 		cmd = alloca(len);
 
-		(void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file,
+		(void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, tfile,
 		    drti);
 #endif
 		if ((status = system(cmd)) == -1) {
@@ -1894,85 +1892,6 @@ dtrace_program_link(dtrace_hdl_t *dtp, d
 			    file, dtp->dt_ld_path, WEXITSTATUS(status));
 			goto done;
 		}
-#if !defined(sun)
-		/*
-		 * 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.
-		 */
-		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);
-		/*
-		 * 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);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201409110104.s8B14uFq084230>