Remove drti.o's dependency on libelf. This makes it possible to add DTrace
probes to userland programs and libraries without also needing to link libelf. dtrace -G places the __SUNW_dof symbol at the beginning of the DOF (DTrace probe and provider metdata) section in the generated object file; drti.o now just uses this symbol to locate the section. A complication occurs when multiple dtrace-generated object files are linked together, since the __SUNW_dof symbol defined in each file is global. This is handled by using objcopy(1) to convert __SUNW_dof to a local symbol once drti.o has been linked with the generated object file. Upstream, this is done using a linker feature not present in GNU ld. Differential Revision: https://reviews.freebsd.org/D1757 Reviewed by: rpaulo MFC after: 1 month Relnotes: yes
This commit is contained in:
parent
70f82314c2
commit
03a5f9f0fd
@ -36,7 +36,6 @@
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <libelf.h>
|
||||
#include <gelf.h>
|
||||
|
||||
/*
|
||||
* In Solaris 10 GA, the only mechanism for communicating helper information
|
||||
@ -62,9 +61,7 @@ static const char *olddevname = "/devices/pseudo/dtrace@0:helper";
|
||||
|
||||
static const char *modname; /* Name of this load object */
|
||||
static int gen; /* DOF helper generation */
|
||||
#ifdef illumos
|
||||
extern dof_hdr_t __SUNW_dof; /* DOF defined in the .SUNW_dof section */
|
||||
#endif
|
||||
static boolean_t dof_init_debug = B_FALSE; /* From DTRACE_DOF_INIT_DEBUG */
|
||||
|
||||
static void
|
||||
@ -99,11 +96,7 @@ static void dtrace_dof_init(void) __attribute__ ((constructor));
|
||||
static void
|
||||
dtrace_dof_init(void)
|
||||
{
|
||||
#ifdef illumos
|
||||
dof_hdr_t *dof = &__SUNW_dof;
|
||||
#else
|
||||
dof_hdr_t *dof = NULL;
|
||||
#endif
|
||||
#ifdef _LP64
|
||||
Elf64_Ehdr *elf;
|
||||
#else
|
||||
@ -118,17 +111,6 @@ dtrace_dof_init(void)
|
||||
#endif
|
||||
int fd;
|
||||
const char *p;
|
||||
#ifndef illumos
|
||||
Elf *e;
|
||||
Elf_Scn *scn = NULL;
|
||||
Elf_Data *dofdata = NULL;
|
||||
dof_hdr_t *dof_next = NULL;
|
||||
GElf_Shdr shdr;
|
||||
int efd;
|
||||
char *s;
|
||||
size_t shstridx;
|
||||
uint64_t aligned_filesz;
|
||||
#endif
|
||||
|
||||
if (getenv("DTRACE_DOF_INIT_DISABLE") != NULL)
|
||||
return;
|
||||
@ -152,42 +134,6 @@ dtrace_dof_init(void)
|
||||
modname = lmp->l_name;
|
||||
else
|
||||
modname++;
|
||||
#ifndef illumos
|
||||
elf_version(EV_CURRENT);
|
||||
if ((efd = open(lmp->l_name, O_RDONLY, 0)) < 0) {
|
||||
dprintf(1, "couldn't open file for reading\n");
|
||||
return;
|
||||
}
|
||||
if ((e = elf_begin(efd, ELF_C_READ, NULL)) == NULL) {
|
||||
dprintf(1, "elf_begin failed\n");
|
||||
close(efd);
|
||||
return;
|
||||
}
|
||||
elf_getshdrstrndx(e, &shstridx);
|
||||
dof = NULL;
|
||||
while ((scn = elf_nextscn(e, scn)) != NULL) {
|
||||
gelf_getshdr(scn, &shdr);
|
||||
if (shdr.sh_type == SHT_SUNW_dof) {
|
||||
s = elf_strptr(e, shstridx, shdr.sh_name);
|
||||
if (s != NULL && strcmp(s, ".SUNW_dof") == 0) {
|
||||
dofdata = elf_getdata(scn, NULL);
|
||||
dof = dofdata->d_buf;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dof == NULL) {
|
||||
dprintf(1, "SUNW_dof section not found\n");
|
||||
elf_end(e);
|
||||
close(efd);
|
||||
return;
|
||||
}
|
||||
|
||||
while ((char *) dof < (char *) dofdata->d_buf + dofdata->d_size) {
|
||||
aligned_filesz = (shdr.sh_addralign == 0 ? dof->dofh_filesz :
|
||||
roundup2(dof->dofh_filesz, shdr.sh_addralign));
|
||||
dof_next = (void *) ((char *) dof + aligned_filesz);
|
||||
#endif
|
||||
|
||||
if (dof->dofh_ident[DOF_ID_MAG0] != DOF_MAG_MAG0 ||
|
||||
dof->dofh_ident[DOF_ID_MAG1] != DOF_MAG_MAG1 ||
|
||||
@ -237,21 +183,12 @@ dtrace_dof_init(void)
|
||||
dprintf(1, "DTrace ioctl failed for DOF at %p", dof);
|
||||
else {
|
||||
dprintf(1, "DTrace ioctl succeeded for DOF at %p\n", dof);
|
||||
#ifndef illumos
|
||||
#ifdef __FreeBSD__
|
||||
gen = dh.gen;
|
||||
#endif
|
||||
}
|
||||
|
||||
(void) close(fd);
|
||||
|
||||
#ifndef illumos
|
||||
/* End of while loop */
|
||||
dof = dof_next;
|
||||
}
|
||||
|
||||
elf_end(e);
|
||||
(void) close(efd);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef illumos
|
||||
|
@ -275,6 +275,9 @@ struct dtrace_hdl {
|
||||
int dt_cpp_argc; /* count of initialized cpp(1) arguments */
|
||||
int dt_cpp_args; /* size of dt_cpp_argv[] array */
|
||||
char *dt_ld_path; /* pathname of ld(1) to invoke if needed */
|
||||
#ifdef __FreeBSD__
|
||||
char *dt_objcopy_path; /* pathname of objcopy(1) to invoke if needed */
|
||||
#endif
|
||||
dt_list_t dt_lib_path; /* linked-list forming library search path */
|
||||
uint_t dt_lazyload; /* boolean: set via -xlazyload */
|
||||
uint_t dt_droptags; /* boolean: set via -xdroptags */
|
||||
|
@ -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++;
|
||||
|
||||
@ -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++;
|
||||
|
||||
@ -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" */
|
||||
#ifdef illumos
|
||||
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;
|
||||
@ -1874,7 +1878,7 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
|
||||
#endif
|
||||
|
||||
(void) snprintf(drti, sizeof (drti), "/usr/lib%s/dtrace/drti.o",
|
||||
use_32 ? "32":"");
|
||||
use_32 ? "32" : "");
|
||||
|
||||
len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file, tfile,
|
||||
drti) + 1;
|
||||
@ -1885,26 +1889,61 @@ 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 {
|
||||
(void) close(fd);
|
||||
}
|
||||
|
@ -785,6 +785,7 @@ const char *_dtrace_defld = "/usr/ccs/bin/ld"; /* default ld(1) to invoke */
|
||||
#else
|
||||
const char *_dtrace_defcpp = "cpp"; /* default cpp(1) to invoke */
|
||||
const char *_dtrace_defld = "ld"; /* default ld(1) to invoke */
|
||||
const char *_dtrace_defobjcopy = "objcopy"; /* default objcopy(1) to invoke */
|
||||
#endif
|
||||
|
||||
const char *_dtrace_libdir = "/usr/lib/dtrace"; /* default library directory */
|
||||
@ -1185,6 +1186,9 @@ dt_vopen(int version, int flags, int *errp,
|
||||
dtp->dt_cpp_argc = 1;
|
||||
dtp->dt_cpp_args = 1;
|
||||
dtp->dt_ld_path = strdup(_dtrace_defld);
|
||||
#ifdef __FreeBSD__
|
||||
dtp->dt_objcopy_path = strdup(_dtrace_defobjcopy);
|
||||
#endif
|
||||
dtp->dt_provmod = provmod;
|
||||
dtp->dt_vector = vector;
|
||||
dtp->dt_varg = arg;
|
||||
@ -1193,6 +1197,9 @@ dt_vopen(int version, int flags, int *errp,
|
||||
|
||||
if (dtp->dt_mods == NULL || dtp->dt_provs == NULL ||
|
||||
dtp->dt_procs == NULL || dtp->dt_ld_path == NULL ||
|
||||
#ifdef __FreeBSD__
|
||||
dtp->dt_objcopy_path == NULL ||
|
||||
#endif
|
||||
dtp->dt_cpp_path == NULL || dtp->dt_cpp_argv == NULL)
|
||||
return (set_open_errno(dtp, errp, EDT_NOMEM));
|
||||
|
||||
@ -1673,6 +1680,9 @@ dtrace_close(dtrace_hdl_t *dtp)
|
||||
free(dtp->dt_cpp_argv);
|
||||
free(dtp->dt_cpp_path);
|
||||
free(dtp->dt_ld_path);
|
||||
#ifdef __FreeBSD__
|
||||
free(dtp->dt_objcopy_path);
|
||||
#endif
|
||||
|
||||
free(dtp->dt_mods);
|
||||
free(dtp->dt_provs);
|
||||
|
@ -280,6 +280,28 @@ dt_opt_ld_path(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
static int
|
||||
dt_opt_objcopy_path(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
|
||||
{
|
||||
char *objcopy;
|
||||
|
||||
if (arg == NULL)
|
||||
return (dt_set_errno(dtp, EDT_BADOPTVAL));
|
||||
|
||||
if (dtp->dt_pcb != NULL)
|
||||
return (dt_set_errno(dtp, EDT_BADOPTCTX));
|
||||
|
||||
if ((objcopy = strdup(arg)) == NULL)
|
||||
return (dt_set_errno(dtp, EDT_NOMEM));
|
||||
|
||||
free(dtp->dt_objcopy_path);
|
||||
dtp->dt_objcopy_path = objcopy;
|
||||
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*ARGSUSED*/
|
||||
static int
|
||||
dt_opt_libdir(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
|
||||
@ -960,6 +982,9 @@ static const dt_option_t _dtrace_ctoptions[] = {
|
||||
{ "linkmode", dt_opt_linkmode },
|
||||
{ "linktype", dt_opt_linktype },
|
||||
{ "nolibs", dt_opt_cflags, DTRACE_C_NOLIBS },
|
||||
#ifdef __FreeBSD__
|
||||
{ "objcopypath", dt_opt_objcopy_path },
|
||||
#endif
|
||||
{ "pgmax", dt_opt_pgmax },
|
||||
{ "pspec", dt_opt_cflags, DTRACE_C_PSPEC },
|
||||
{ "setenv", dt_opt_setenv, 1 },
|
||||
|
@ -121,10 +121,7 @@ ${_YC:R}.o: ${_YC}
|
||||
.endfor
|
||||
|
||||
# DTrace probe definitions
|
||||
# libelf is currently needed for drti.o
|
||||
.if ${SRCS:M*.d}
|
||||
LDADD+= -lelf
|
||||
DPADD+= ${LIBELF}
|
||||
CFLAGS+= -I${.OBJDIR}
|
||||
.endif
|
||||
.for _DSRC in ${SRCS:M*.d:N*/*}
|
||||
|
Loading…
Reference in New Issue
Block a user