aboutsummaryrefslogtreecommitdiff
path: root/cddl/contrib/opensolaris/lib/libdtrace
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2017-02-05 02:39:12 +0000
committerMark Johnston <markj@FreeBSD.org>2017-02-05 02:39:12 +0000
commite801af6fba428bbac170018f9ff69e4596d06b3b (patch)
treea1a0c9bbc3d50cb8455ca8758ece6a33b6bd6ee7 /cddl/contrib/opensolaris/lib/libdtrace
parent69d2418faa53965ed4523876bb499bac5c9c7611 (diff)
downloadsrc-e801af6fba428bbac170018f9ff69e4596d06b3b.tar.gz
src-e801af6fba428bbac170018f9ff69e4596d06b3b.zip
Use PC-relative relocations for USDT probe sites on i386 and amd64.
When recording probe site addresses in the output DOF file, dtrace -G needs to emit relocations for the .SUNW_dof section in order to obtain the addresses of functions containing probe sites. DTrace expects the addresses to be relative to the base address of the final ELF file, and the amd64 USDT implementation was relying on some unspecified and incorrect behaviour in the base system GNU ld to achieve this. This change reimplements the probe site relocation handling to allow USDT to be used with lld and newer GNU binutils. Specifically, it makes use of R_X86_64_PC64/R_386_PC32 relocations to obtain the probe site address relative to the DOF file address, and adds and uses a new DOF relocation type which computes the final probe site address using these relative offsets. Reported by and discussed with: Rafael EspĂ­ndola MFC after: 1 month Differential Revision: https://reviews.freebsd.org/D9374
Notes
Notes: svn path=/head/; revision=313262
Diffstat (limited to 'cddl/contrib/opensolaris/lib/libdtrace')
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c14
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c140
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c8
3 files changed, 55 insertions, 107 deletions
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c
index a4e325671f9f..3d1d976bd3dd 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c
@@ -462,18 +462,8 @@ dof_add_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
dt_buf_write(dtp, &ddo->ddo_enoffs, pip->pi_enoffs,
pip->pi_nenoffs * sizeof (uint32_t), sizeof (uint32_t));
- /*
- * If pi_rname isn't set, the relocation will be against the
- * function name. If it is, the relocation will be against
- * pi_rname. This will be used if the function is scoped
- * locally so an alternate symbol is added for the purpose
- * of this relocation.
- */
- if (pip->pi_rname == NULL)
- dofr.dofr_name = dofpr.dofpr_func;
- else
- dofr.dofr_name = dof_add_string(ddo, pip->pi_rname);
- dofr.dofr_type = DOF_RELO_SETX;
+ dofr.dofr_name = dof_add_string(ddo, pip->pi_rname);
+ dofr.dofr_type = DOF_RELO_DOFREL;
dofr.dofr_offset = dt_buf_len(&ddo->ddo_probes);
dofr.dofr_data = 0;
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
index f13e10769250..ac4af00ee4f2 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
@@ -237,7 +237,7 @@ printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
rel->r_offset = s->dofs_offset +
dofr[j].dofr_offset;
rel->r_info = ELF32_R_INFO(count + dep->de_global,
- R_386_32);
+ R_386_PC32);
#elif defined(__mips__)
/* XXX */
printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
@@ -253,15 +253,6 @@ printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
#elif defined(__riscv__)
/* XXX */
printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
-#elif defined(__sparc)
- /*
- * Add 4 bytes to hit the low half of this 64-bit
- * big-endian address.
- */
- rel->r_offset = s->dofs_offset +
- dofr[j].dofr_offset + 4;
- rel->r_info = ELF32_R_INFO(count + dep->de_global,
- R_SPARC_32);
#else
#error unknown ISA
#endif
@@ -270,7 +261,7 @@ printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
sym->st_value = 0;
sym->st_size = 0;
sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_FUNC);
- sym->st_other = 0;
+ sym->st_other = ELF32_ST_VISIBILITY(STV_HIDDEN);
sym->st_shndx = SHN_UNDEF;
rel++;
@@ -287,11 +278,7 @@ printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
sym->st_value = 0;
sym->st_size = dof->dofh_filesz;
sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT);
-#ifdef illumos
- sym->st_other = 0;
-#else
sym->st_other = ELF32_ST_VISIBILITY(STV_HIDDEN);
-#endif
sym->st_shndx = ESHDR_DOF;
sym++;
@@ -448,18 +435,8 @@ 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;
-#ifdef illumos
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;
- rel->r_info = ELF64_R_INFO(count + dep->de_global,
- R_SPARC_64);
+ R_X86_64_PC64);
#else
#error unknown ISA
#endif
@@ -468,7 +445,7 @@ prepare_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf64_t *dep)
sym->st_value = 0;
sym->st_size = 0;
sym->st_info = GELF_ST_INFO(STB_GLOBAL, STT_FUNC);
- sym->st_other = 0;
+ sym->st_other = ELF64_ST_VISIBILITY(STV_HIDDEN);
sym->st_shndx = SHN_UNDEF;
rel++;
@@ -485,11 +462,7 @@ prepare_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf64_t *dep)
sym->st_value = 0;
sym->st_size = dof->dofh_filesz;
sym->st_info = GELF_ST_INFO(STB_GLOBAL, STT_OBJECT);
-#ifdef illumos
- sym->st_other = 0;
-#else
sym->st_other = ELF64_ST_VISIBILITY(STV_HIDDEN);
-#endif
sym->st_shndx = ESHDR_DOF;
sym++;
@@ -797,16 +770,15 @@ dump_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd)
}
static int
-dt_symtab_lookup(Elf_Data *data_sym, int nsym, uintptr_t addr, uint_t shn,
- GElf_Sym *sym, int uses_funcdesc, Elf *elf)
+dt_symtab_lookup(Elf_Data *data_sym, int start, int end, uintptr_t addr,
+ uint_t shn, GElf_Sym *sym, int uses_funcdesc, Elf *elf)
{
- int i, ret = -1;
Elf64_Addr symval;
Elf_Scn *opd_scn;
Elf_Data *opd_desc;
- GElf_Sym s;
+ int i;
- for (i = 0; i < nsym && gelf_getsym(data_sym, i, sym) != NULL; i++) {
+ for (i = start; i < end && gelf_getsym(data_sym, i, sym) != NULL; i++) {
if (GELF_ST_TYPE(sym->st_info) == STT_FUNC) {
symval = sym->st_value;
if (uses_funcdesc) {
@@ -816,20 +788,12 @@ dt_symtab_lookup(Elf_Data *data_sym, int nsym, uintptr_t addr, uint_t shn,
*(uint64_t*)((char *)opd_desc->d_buf + symval);
}
if ((uses_funcdesc || shn == sym->st_shndx) &&
- symval <= addr &&
- addr < symval + sym->st_size) {
- if (GELF_ST_BIND(sym->st_info) == STB_GLOBAL)
- return (0);
-
- ret = 0;
- s = *sym;
- }
+ symval <= addr && addr < symval + sym->st_size)
+ return (0);
}
}
- if (ret == 0)
- *sym = s;
- return (ret);
+ return (-1);
}
#if defined(__aarch64__)
@@ -1237,7 +1201,7 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
dt_provider_t *pvp;
dt_probe_t *prp;
uint32_t off, eclass, emachine1, emachine2;
- size_t symsize, nsym, isym, istr, len;
+ size_t symsize, osym, nsym, isym, istr, len;
key_t objkey;
dt_link_pair_t *pair, *bufs = NULL;
dt_strtab_t *strtab;
@@ -1374,12 +1338,13 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
* target (text) section to replace the call instruction with
* one or more nops.
*
- * If the function containing the probe is locally scoped
- * (static), we create an alias used by the relocation in the
- * generated object. The alias, a new symbol, will be global
- * (so that the relocation from the generated object can be
- * resolved), and hidden (so that it is converted to a local
- * symbol at link time). Such aliases have this form:
+ * To avoid runtime overhead, the relocations added to the
+ * generated object should be resolved at static link time. We
+ * therefore create aliases for the functions that contain
+ * probes. An alias is global (so that the relocation from the
+ * generated object can be resolved), and hidden (so that its
+ * address is known at static link time). Such aliases have this
+ * form:
*
* $dtrace<key>.<function>
*
@@ -1417,16 +1382,13 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
if (strncmp(s, dt_prefix, sizeof (dt_prefix) - 1) != 0)
continue;
- if (dt_symtab_lookup(data_sym, isym, rela.r_offset,
- shdr_rel.sh_info, &fsym,
- (emachine1 == EM_PPC64), elf) != 0) {
+ if (dt_symtab_lookup(data_sym, 0, isym, rela.r_offset,
+ shdr_rel.sh_info, &fsym, (emachine1 == EM_PPC64),
+ elf) != 0) {
dt_strtab_destroy(strtab);
goto err;
}
- if (GELF_ST_BIND(fsym.st_info) != STB_LOCAL)
- continue;
-
if (fsym.st_name > data_str->d_size) {
dt_strtab_destroy(strtab);
goto err;
@@ -1462,12 +1424,12 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
}
/*
- * If needed, allocate the additional space for the symbol
- * table and string table copying the old data into the new
- * buffers, and marking the buffers as dirty. We inject those
- * newly allocated buffers into the libelf data structures, but
- * are still responsible for freeing them once we're done with
- * the elf handle.
+ * If any probes were found, allocate the additional space for
+ * the symbol table and string table, copying the old data into
+ * the new buffers, and marking the buffers as dirty. We inject
+ * those newly allocated buffers into the libelf data
+ * structures, but are still responsible for freeing them once
+ * we're done with the elf handle.
*/
if (nsym > 0) {
/*
@@ -1516,9 +1478,11 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
shdr_sym.sh_size += nsym * symsize;
(void) gelf_update_shdr(scn_sym, &shdr_sym);
+ osym = isym;
nsym += isym;
} else {
dt_strtab_destroy(strtab);
+ continue;
}
/*
@@ -1577,8 +1541,11 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
bcopy(s, pname, p - s);
pname[p - s] = '\0';
- if (dt_symtab_lookup(data_sym, isym, rela.r_offset,
- shdr_rel.sh_info, &fsym,
+ if (dt_symtab_lookup(data_sym, osym, isym,
+ rela.r_offset, shdr_rel.sh_info, &fsym,
+ (emachine1 == EM_PPC64), elf) != 0 &&
+ dt_symtab_lookup(data_sym, 0, osym,
+ rela.r_offset, shdr_rel.sh_info, &fsym,
(emachine1 == EM_PPC64), elf) != 0)
goto err;
@@ -1588,37 +1555,30 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
assert(GELF_ST_TYPE(fsym.st_info) == STT_FUNC);
/*
- * If a NULL relocation name is passed to
- * dt_probe_define(), the function name is used for the
- * relocation. The relocation needs to use a mangled
- * name if the symbol is locally scoped; the function
- * name may need to change if we've found the global
- * alias for the locally scoped symbol (we prefer
- * global symbols to locals in dt_symtab_lookup()).
+ * If this is our first time encountering this symbol,
+ * emit an alias.
*/
s = (char *)data_str->d_buf + fsym.st_name;
- r = NULL;
- if (GELF_ST_BIND(fsym.st_info) == STB_LOCAL) {
+ if (strncmp(s, dt_symprefix,
+ sizeof (dt_symprefix) - 1) != 0) {
+ u_int bind = GELF_ST_BIND(fsym.st_info);
+
dsym = fsym;
dsym.st_name = istr;
- dsym.st_info = GELF_ST_INFO(STB_GLOBAL,
- STT_FUNC);
- dsym.st_other =
- ELF64_ST_VISIBILITY(STV_ELIMINATE);
+ dsym.st_info = GELF_ST_INFO(bind == STB_LOCAL ?
+ STB_GLOBAL : bind, STT_FUNC);
+ dsym.st_other = GELF_ST_VISIBILITY(STV_HIDDEN);
(void) gelf_update_sym(data_sym, isym, &dsym);
-
- r = (char *)data_str->d_buf + istr;
- istr += 1 + sprintf(r, dt_symfmt,
- dt_symprefix, objkey, s);
+ r = (char *) data_str->d_buf + istr;
+ istr += 1 + sprintf(r, dt_symfmt, dt_symprefix, objkey,
+ s);
isym++;
assert(isym <= nsym);
-
- } else if (strncmp(s, dt_symprefix,
- strlen(dt_symprefix)) == 0) {
+ } else {
r = s;
- if ((s = strchr(s, '.')) == NULL)
- goto err;
+ s = strchr(s, '.');
+ assert(s != NULL);
s++;
}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c
index 29138746cfd9..7cf352d4d505 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c
@@ -545,9 +545,7 @@ dt_probe_define(dt_provider_t *pvp, dt_probe_t *prp,
for (pip = prp->pr_inst; pip != NULL; pip = pip->pi_next) {
if (strcmp(pip->pi_fname, fname) == 0 &&
- ((rname == NULL && pip->pi_rname == NULL) ||
- (rname != NULL && pip->pi_rname != NULL &&
- strcmp(pip->pi_rname, rname) == 0)))
+ strcmp(pip->pi_rname, rname) == 0)
break;
}
@@ -565,7 +563,7 @@ dt_probe_define(dt_provider_t *pvp, dt_probe_t *prp,
if ((pip->pi_fname = strdup(fname)) == NULL)
goto nomem;
- if (rname != NULL && (pip->pi_rname = strdup(rname)) == NULL)
+ if ((pip->pi_rname = strdup(rname)) == NULL)
goto nomem;
pip->pi_noffs = 0;
@@ -605,7 +603,7 @@ dt_probe_define(dt_provider_t *pvp, dt_probe_t *prp,
dt_dprintf("defined probe %s %s:%s %s() +0x%x (%s)\n",
isenabled ? "(is-enabled)" : "",
pvp->pv_desc.dtvd_name, prp->pr_ident->di_name, fname, offset,
- rname != NULL ? rname : fname);
+ rname);
assert(*noffs < *maxoffs);
(*offs)[(*noffs)++] = offset;