aboutsummaryrefslogtreecommitdiff
path: root/cddl/contrib/opensolaris/lib/libdtrace
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2020-08-20 19:28:19 +0000
committerMark Johnston <markj@FreeBSD.org>2020-08-20 19:28:19 +0000
commitd2d16e566324f3560c53f85c0b1d4362040df90f (patch)
tree13633684904d8d7fda191ee07e3911cc80f71d49 /cddl/contrib/opensolaris/lib/libdtrace
parent0e15d9fbeba47c947f62d8252ef673a306f7c2fb (diff)
downloadsrc-d2d16e566324f3560c53f85c0b1d4362040df90f.tar.gz
src-d2d16e566324f3560c53f85c0b1d4362040df90f.zip
Enable creation of static userspace probes in incremental builds.
To define USDT probes, dtrace -G makes use of relocations for undefined symbols: the target address is overwritten with NOPs and the location is recorded in the DOF section of the output object file. To avoid link errors, the original relocation is destroyed. However, this means that the same input object file cannot be processed multiple times, as happens during incremental rebuilds. Instead, only set the relocation type to NONE, so that all information required to reconstruct USDT probes is preserved. Reported by: bdrewery MFC after: 3 weeks Sponsored by: The FreeBSD Foundation
Notes
Notes: svn path=/head/; revision=364438
Diffstat (limited to 'cddl/contrib/opensolaris/lib/libdtrace')
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c146
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.c7
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.h1
3 files changed, 89 insertions, 65 deletions
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
index d0977eb638e4..d349f6ea3d6a 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
@@ -773,6 +773,7 @@ dt_symtab_lookup(Elf_Data *data_sym, int start, int end, uintptr_t addr,
#define DT_OP_RET 0xd65f03c0
#define DT_OP_CALL26 0x94000000
#define DT_OP_JUMP26 0x14000000
+#define DT_REL_NONE R_AACH64_NONE
static int
dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
@@ -831,7 +832,8 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
return (0);
}
#elif defined(__arm__)
-/* XXX */
+#define DT_REL_NONE R_ARM_NONE
+
static int
dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
uint32_t *off)
@@ -841,7 +843,8 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
return (-1);
}
#elif defined(__mips__)
-/* XXX */
+#define DT_REL_NONE R_MIPS_NONE
+
static int
dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
uint32_t *off)
@@ -861,7 +864,8 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
#define DT_IS_BRANCH(inst) ((inst & 0xfc000000) == 0x48000000)
#define DT_IS_BL(inst) (DT_IS_BRANCH(inst) && (inst & 0x01))
-/* XXX */
+#define DT_REL_NONE R_PPC_NONE
+
static int
dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
uint32_t *off)
@@ -878,7 +882,8 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
* We only know about some specific relocation types.
*/
if (GELF_R_TYPE(rela->r_info) != R_PPC_REL24 &&
- GELF_R_TYPE(rela->r_info) != R_PPC_PLTREL24)
+ GELF_R_TYPE(rela->r_info) != R_PPC_PLTREL24 &&
+ GELF_R_TYPE(rela->r_info) != R_PPC_NONE)
return (-1);
/*
@@ -932,7 +937,7 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
return (0);
}
#elif defined(__riscv)
-/* XXX */
+#define DT_REL_NONE R_RISCV_NONE
static int
dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
uint32_t *off)
@@ -952,6 +957,8 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
#define DT_OP_XOR_EAX_0 0x33
#define DT_OP_XOR_EAX_1 0xc0
+#define DT_REL_NONE R_386_NONE
+
static int
dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
uint32_t *off)
@@ -974,7 +981,8 @@ dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela,
* x86 architectures.
*/
if (GELF_R_TYPE(rela->r_info) != R_386_PC32 &&
- GELF_R_TYPE(rela->r_info) != R_386_PLT32)
+ GELF_R_TYPE(rela->r_info) != R_386_PLT32 &&
+ GELF_R_TYPE(rela->r_info) != R_386_NONE)
return (-1);
/*
@@ -1273,6 +1281,11 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
* We take a first pass through all the relocations to
* populate our string table and count the number of extra
* symbols we'll require.
+ *
+ * We also handle the case where the object has already been
+ * processed, to support incremental rebuilds. Relocations
+ * of interest are converted to type NONE, but all information
+ * needed to reconstruct the output DOF is retained.
*/
strtab = dt_strtab_create(1);
nsym = 0;
@@ -1280,7 +1293,6 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
istr = data_str->d_size;
for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) {
-
if (shdr_rel.sh_type == SHT_RELA) {
if (gelf_getrela(data_rel, i, &rela) == NULL)
continue;
@@ -1345,7 +1357,12 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
objkey, s);
if (dt_strtab_index(strtab, p) == -1) {
- nsym++;
+ /*
+ * Do not add new symbols if this object file
+ * has already been processed.
+ */
+ if (GELF_R_TYPE(rela.r_info) != DT_REL_NONE)
+ nsym++;
(void) dt_strtab_insert(strtab, p);
}
@@ -1353,13 +1370,14 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
}
/*
- * 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
+ * If any new 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.
*/
+ osym = isym;
if (nsym > 0) {
/*
* The first byte of the string table is reserved for
@@ -1411,9 +1429,8 @@ 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 {
+ } else if (dt_strtab_empty(strtab)) {
dt_strtab_destroy(strtab);
continue;
}
@@ -1423,7 +1440,6 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
* modifications described above.
*/
for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) {
-
if (shdr_rel.sh_type == SHT_RELA) {
if (gelf_getrela(data_rel, i, &rela) == NULL)
continue;
@@ -1490,32 +1506,51 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
bind = GELF_ST_BIND(fsym.st_info) == STB_WEAK ?
STB_WEAK : STB_GLOBAL;
-
- /*
- * Emit an alias for the symbol. It needs to be
- * non-preemptible so that .SUNW_dof relocations
- * may be resolved at static link time. Aliases
- * of weak symbols are given a non-unique name
- * so that they may be merged by the linker.
- */
- dsym = fsym;
- dsym.st_name = istr;
- dsym.st_info = GELF_ST_INFO(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;
s = (char *) data_str->d_buf + fsym.st_name;
- if (bind == STB_WEAK)
- istr += sprintf(r, dt_weaksymfmt,
- dt_symprefix, s);
- else
- istr += sprintf(r, dt_symfmt,
- dt_symprefix, objkey, s);
- istr++;
- isym++;
- assert(isym <= nsym);
- } else
+ if (GELF_R_TYPE(rela.r_info) != DT_REL_NONE) {
+ /*
+ * Emit an alias for the symbol. It
+ * needs to be non-preemptible so that
+ * .SUNW_dof relocations may be resolved
+ * at static link time. Aliases of weak
+ * symbols are given a non-unique name
+ * so that they may be merged by the
+ * linker.
+ */
+ dsym = fsym;
+ dsym.st_name = istr;
+ dsym.st_info = GELF_ST_INFO(bind,
+ STT_FUNC);
+ dsym.st_other =
+ GELF_ST_VISIBILITY(STV_HIDDEN);
+ (void) gelf_update_sym(data_sym, isym,
+ &dsym);
+ isym++;
+ assert(isym <= nsym);
+
+ r = (char *) data_str->d_buf + istr;
+ if (bind == STB_WEAK) {
+ istr += sprintf(r,
+ dt_weaksymfmt, dt_symprefix,
+ s);
+ } else {
+ istr += sprintf(r, dt_symfmt,
+ dt_symprefix, objkey, s);
+ }
+ istr++;
+ } else {
+ if (bind == STB_WEAK) {
+ (void) asprintf(&r,
+ dt_weaksymfmt, dt_symprefix,
+ s);
+ } else {
+ (void) asprintf(&r, dt_symfmt,
+ dt_symprefix, objkey, s);
+ }
+ }
+ } else {
goto err;
+ }
if ((pvp = dt_provider_lookup(dtp, pname)) == NULL) {
return (dt_link_error(dtp, elf, fd, bufs,
@@ -1544,24 +1579,18 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
}
/*
- * 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.
+ * We are done with this relocation, but it must be
+ * preserved in order to support incremental rebuilds.
*/
if (shdr_rel.sh_type == SHT_RELA) {
- rela.r_offset = 0;
- rela.r_info = 0;
- rela.r_addend = 0;
+ rela.r_info =
+ GELF_R_INFO(GELF_R_SYM(rela.r_info), 0);
(void) gelf_update_rela(data_rel, i, &rela);
} else {
GElf_Rel rel;
- rel.r_offset = 0;
- rel.r_info = 0;
+ rel.r_offset = rela.r_offset;
+ rela.r_info =
+ GELF_R_INFO(GELF_R_SYM(rela.r_info), 0);
(void) gelf_update_rel(data_rel, i, &rel);
}
@@ -1614,19 +1643,6 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
size_t len;
int eprobes = 0, ret = 0;
- if (access(file, R_OK) == 0) {
- fprintf(stderr, "dtrace: target object (%s) already exists. "
- "Please remove the target\ndtrace: object and rebuild all "
- "the source objects if you wish to run the DTrace\n"
- "dtrace: linking process again\n", file);
- /*
- * Several build infrastructures run DTrace twice (e.g.
- * postgres) and we don't want the build to fail. Return
- * 0 here since this isn't really a fatal error.
- */
- return (0);
- }
-
/*
* A NULL program indicates a special use in which we just link
* together a bunch of object files specified in objv and then
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.c
index a735b6674a1e..6279ffacdaeb 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.c
@@ -206,6 +206,13 @@ err:
return (-1);
}
+boolean_t
+dt_strtab_empty(dt_strtab_t *sp)
+{
+ /* Always contains "\0". */
+ return (sp->str_nstrs == 1);
+}
+
ssize_t
dt_strtab_index(dt_strtab_t *sp, const char *str)
{
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.h
index 551dabbf6765..80006b6b3962 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.h
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_strtab.h
@@ -58,6 +58,7 @@ typedef ssize_t dt_strtab_write_f(const char *, size_t, size_t, void *);
extern dt_strtab_t *dt_strtab_create(size_t);
extern void dt_strtab_destroy(dt_strtab_t *);
+extern boolean_t dt_strtab_empty(dt_strtab_t *);
extern ssize_t dt_strtab_index(dt_strtab_t *, const char *);
extern ssize_t dt_strtab_insert(dt_strtab_t *, const char *);
extern size_t dt_strtab_size(const dt_strtab_t *);