summaryrefslogtreecommitdiffstats
path: root/cddl
diff options
context:
space:
mode:
authormarkj <markj@FreeBSD.org>2014-09-11 01:04:56 +0000
committermarkj <markj@FreeBSD.org>2014-09-11 01:04:56 +0000
commitb4971501637a88d7c7d1f0eeb9b569903ddf1c95 (patch)
treecdde74689c562f7f07c5a7b738449882e8a5fa87 /cddl
parent08cd0ead43d723a7735bd3ea281c20c8fb381579 (diff)
downloadFreeBSD-src-b4971501637a88d7c7d1f0eeb9b569903ddf1c95.zip
FreeBSD-src-b4971501637a88d7c7d1f0eeb9b569903ddf1c95.tar.gz
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
Diffstat (limited to 'cddl')
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/drti.c114
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c121
2 files changed, 23 insertions, 212 deletions
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c b/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c
index bb02d8c..3c64f87 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c
@@ -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 {
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
index 13300b0..106878c 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
@@ -322,7 +322,11 @@ prepare_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf64_t *dep)
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 dof_hdr_t *dof, dof_elf64_t *dep)
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 dof_hdr_t *dof, dof_elf64_t *dep)
#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 dof_hdr_t *dof, dof_elf64_t *dep)
#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_hdr_t *dof, int fd)
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, dtrace_prog_t *pgp, uint_t dflags,
{
#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, dtrace_prog_t *pgp, uint_t dflags,
(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, dtrace_prog_t *pgp, uint_t dflags,
(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, dtrace_prog_t *pgp, uint_t dflags,
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, dtrace_prog_t *pgp, uint_t dflags,
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);
OpenPOWER on IntegriCloud