aboutsummaryrefslogtreecommitdiff
path: root/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
diff options
context:
space:
mode:
Diffstat (limited to 'cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c')
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c155
1 files changed, 101 insertions, 54 deletions
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
index 597fef47f982..f9b9625d6af6 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
@@ -30,7 +30,7 @@
#include <elf.h>
#include <sys/types.h>
-#if defined(sun)
+#ifdef illumos
#include <sys/sysmacros.h>
#else
#define P2ROUNDUP(x, align) (-(-(x) & -(align)))
@@ -38,7 +38,7 @@
#include <unistd.h>
#include <strings.h>
-#if defined(sun)
+#ifdef illumos
#include <alloca.h>
#endif
#include <limits.h>
@@ -47,7 +47,7 @@
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
-#if defined(sun)
+#ifdef illumos
#include <wait.h>
#else
#include <sys/wait.h>
@@ -281,7 +281,11 @@ 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++;
@@ -322,7 +326,7 @@ 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)
+#ifdef illumos
uint32_t count = 0;
#else
uint64_t count = 0;
@@ -434,7 +438,7 @@ 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)
+#ifdef illumos
rel->r_info = ELF64_R_INFO(count + dep->de_global,
R_AMD64_64);
#else
@@ -471,7 +475,11 @@ 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++;
@@ -685,8 +693,8 @@ dump_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd)
elf_file.ehdr.e_machine = EM_ARM;
#elif defined(__mips__)
elf_file.ehdr.e_machine = EM_MIPS;
-#elif defined(__powerpc__)
- elf_file.ehdr.e_machine = EM_PPC;
+#elif defined(__powerpc64__)
+ elf_file.ehdr.e_machine = EM_PPC64;
#elif defined(__sparc)
elf_file.ehdr.e_machine = EM_SPARCV9;
#elif defined(__i386) || defined(__amd64)
@@ -711,11 +719,7 @@ 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;
@@ -784,21 +788,32 @@ 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)
+ 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;
for (i = 0; i < nsym && gelf_getsym(data_sym, i, sym) != NULL; i++) {
- if (GELF_ST_TYPE(sym->st_info) == STT_FUNC &&
- shn == sym->st_shndx &&
- sym->st_value <= addr &&
- addr < sym->st_value + sym->st_size) {
- if (GELF_ST_BIND(sym->st_info) == STB_GLOBAL)
- return (0);
-
- ret = 0;
- s = *sym;
+ if (GELF_ST_TYPE(sym->st_info) == STT_FUNC) {
+ symval = sym->st_value;
+ if (uses_funcdesc) {
+ opd_scn = elf_getscn(elf, sym->st_shndx);
+ opd_desc = elf_rawdata(opd_scn, NULL);
+ symval =
+ *(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;
+ }
}
}
@@ -1375,7 +1390,8 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
continue;
if (dt_symtab_lookup(data_sym, isym, rela.r_offset,
- shdr_rel.sh_info, &fsym) != 0) {
+ shdr_rel.sh_info, &fsym,
+ (emachine1 == EM_PPC64), elf) != 0) {
dt_strtab_destroy(strtab);
goto err;
}
@@ -1536,7 +1552,8 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
p = strhyphenate(p + 3); /* strlen("___") */
if (dt_symtab_lookup(data_sym, isym, rela.r_offset,
- shdr_rel.sh_info, &fsym) != 0)
+ shdr_rel.sh_info, &fsym,
+ (emachine1 == EM_PPC64), elf) != 0)
goto err;
if (fsym.st_name > data_str->d_size)
@@ -1600,7 +1617,7 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
return (dt_link_error(dtp, elf, fd, bufs,
"failed to allocate space for probe"));
}
-#if !defined(sun)
+#ifndef illumos
/*
* Our linker doesn't understand the SUNW_IGNORE ndx and
* will try to use this relocation when we build the
@@ -1634,7 +1651,7 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
* already been processed by an earlier link
* invocation.
*/
-#if !defined(sun)
+#ifndef illumos
#define SHN_SUNW_IGNORE SHN_ABS
#endif
if (rsym.st_shndx != SHN_SUNW_IGNORE) {
@@ -1650,7 +1667,7 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
(void) elf_end(elf);
(void) close(fd);
-#if !defined(sun)
+#ifndef illumos
if (nsym > 0)
#endif
while ((pair = bufs) != NULL) {
@@ -1671,7 +1688,7 @@ int
dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
const char *file, int objc, char *const objv[])
{
-#if !defined(sun)
+#ifndef illumos
char tfile[PATH_MAX];
#endif
char drti[PATH_MAX];
@@ -1681,7 +1698,7 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
size_t len;
int eprobes = 0, ret = 0;
-#if !defined(sun)
+#ifndef illumos
if (access(file, R_OK) == 0) {
fprintf(stderr, "dtrace: target object (%s) already exists. "
"Please remove the target\ndtrace: object and rebuild all "
@@ -1757,7 +1774,7 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
if ((dof = dtrace_dof_create(dtp, pgp, dflags)) == NULL)
return (-1); /* errno is set for us */
-#if defined(sun)
+#ifdef illumos
/*
* Create a temporary file and then unlink it if we're going to
* combine it with drti.o later. We can still refer to it in child
@@ -1769,7 +1786,7 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
}
#else
snprintf(tfile, sizeof(tfile), "%s.XXXXXX", file);
- if ((fd = mkstemp(tfile)) == -1)
+ if ((fd = mkostemp(tfile, O_CLOEXEC)) == -1)
return (dt_link_error(dtp, NULL, -1, NULL,
"failed to create temporary file %s: %s",
tfile, strerror(errno)));
@@ -1803,7 +1820,7 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
}
-#if defined(sun)
+#ifdef illumos
if (!dtp->dt_lazyload)
(void) unlink(file);
#endif
@@ -1813,7 +1830,7 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
else
status = dump_elf32(dtp, dof, fd);
-#if defined(sun)
+#ifdef illumos
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)));
@@ -1826,7 +1843,7 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
#endif
if (!dtp->dt_lazyload) {
-#if defined(sun)
+#ifdef illumos
const char *fmt = "%s -o %s -r -Blocal -Breduce /dev/fd/%d %s";
if (dtp->dt_oflags & DTRACE_O_LP64) {
@@ -1845,23 +1862,9 @@ 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 %s";
+ dt_dirpath_t *dp = dt_list_next(&dtp->dt_lib_path);
-#if defined(__amd64__)
- /*
- * Arches which default to 64-bit need to explicitly use
- * the 32-bit library path.
- */
- int use_32 = (dtp->dt_oflags & DTRACE_O_ILP32);
-#else
- /*
- * Arches which are 32-bit only just use the normal
- * library path.
- */
- int use_32 = 0;
-#endif
-
- (void) snprintf(drti, sizeof (drti), "/usr/lib%s/dtrace/drti.o",
- use_32 ? "32":"");
+ (void) snprintf(drti, sizeof (drti), "%s/drti.o", dp->dir_path);
len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file, tfile,
drti) + 1;
@@ -1872,35 +1875,79 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
drti);
#endif
if ((status = system(cmd)) == -1) {
- ret = dt_link_error(dtp, NULL, -1, NULL,
+ ret = dt_link_error(dtp, NULL, fd, NULL,
"failed to run %s: %s", dtp->dt_ld_path,
strerror(errno));
goto done;
}
if (WIFSIGNALED(status)) {
- ret = dt_link_error(dtp, NULL, -1, NULL,
+ ret = dt_link_error(dtp, NULL, fd, NULL,
"failed to link %s: %s failed due to signal %d",
file, dtp->dt_ld_path, WTERMSIG(status));
goto done;
}
if (WEXITSTATUS(status) != 0) {
- ret = dt_link_error(dtp, NULL, -1, NULL,
+ ret = dt_link_error(dtp, NULL, fd, NULL,
"failed to link %s: %s exited with status %d\n",
file, dtp->dt_ld_path, WEXITSTATUS(status));
goto done;
}
(void) close(fd); /* release temporary file */
+
+#ifdef __FreeBSD__
+ /*
+ * Now that we've linked drti.o, reduce the global __SUNW_dof
+ * symbol to a local symbol. This is needed to so that multiple
+ * generated object files (for different providers, for
+ * instance) can be linked together. This is accomplished using
+ * the -Blocal flag with Sun's linker, but GNU ld doesn't appear
+ * to have an equivalent option.
+ */
+ asprintf(&cmd, "%s --localize-hidden %s", dtp->dt_objcopy_path,
+ file);
+ if ((status = system(cmd)) == -1) {
+ ret = dt_link_error(dtp, NULL, -1, NULL,
+ "failed to run %s: %s", dtp->dt_objcopy_path,
+ strerror(errno));
+ free(cmd);
+ goto done;
+ }
+ free(cmd);
+
+ if (WIFSIGNALED(status)) {
+ ret = dt_link_error(dtp, NULL, -1, NULL,
+ "failed to link %s: %s failed due to signal %d",
+ file, dtp->dt_objcopy_path, WTERMSIG(status));
+ goto done;
+ }
+
+ if (WEXITSTATUS(status) != 0) {
+ ret = dt_link_error(dtp, NULL, -1, NULL,
+ "failed to link %s: %s exited with status %d\n",
+ file, dtp->dt_objcopy_path, WEXITSTATUS(status));
+ goto done;
+ }
+#endif
} else {
+#ifdef __FreeBSD__
+ if (rename(tfile, file) != 0) {
+ ret = dt_link_error(dtp, NULL, fd, NULL,
+ "failed to rename %s to %s: %s", tfile, file,
+ strerror(errno));
+ goto done;
+ }
+#endif
(void) close(fd);
}
done:
dtrace_dof_destroy(dtp, dof);
-#if !defined(sun)
- unlink(tfile);
+#ifdef __FreeBSD__
+ if (!dtp->dt_lazyload)
+ (void) unlink(tfile);
#endif
return (ret);
}