From 03a5f9f0fdb9927663c465c37848ad116e39e203 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Wed, 18 Feb 2015 03:54:54 +0000 Subject: [PATCH] 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 --- .../opensolaris/lib/libdtrace/common/drti.c | 65 +------------------ .../lib/libdtrace/common/dt_impl.h | 3 + .../lib/libdtrace/common/dt_link.c | 55 +++++++++++++--- .../lib/libdtrace/common/dt_open.c | 10 +++ .../lib/libdtrace/common/dt_options.c | 25 +++++++ share/mk/bsd.dep.mk | 3 - 6 files changed, 86 insertions(+), 75 deletions(-) diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c b/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c index fdfe416804fc..a75dc02d5ad9 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/drti.c @@ -36,7 +36,6 @@ #include #include #include -#include /* * 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 diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h index c9e8e20d0b71..51bed72556d0 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h @@ -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 */ diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c index 3991714086a7..ae41269afa16 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c @@ -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); } diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c index b8b146732a89..c95224373bcd 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c @@ -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); diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c index e9164d09a857..758422e3407f 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_options.c @@ -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 }, diff --git a/share/mk/bsd.dep.mk b/share/mk/bsd.dep.mk index a43df822917b..407158ca5302 100644 --- a/share/mk/bsd.dep.mk +++ b/share/mk/bsd.dep.mk @@ -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*/*}