Date: Sat, 30 Jul 2016 03:05:23 +0000 (UTC) From: Mark Johnston <markj@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r303531 - in head: . lib/librtld_db share/mk Message-ID: <201607300305.u6U35ORs005889@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: markj Date: Sat Jul 30 03:05:23 2016 New Revision: 303531 URL: https://svnweb.freebsd.org/changeset/base/303531 Log: librtld_db: Use the auxv to figure out where to look up loader symbols. Previously, librtld_db just hardcoded /libexec/ld-elf.so, which isn't correct for processes that aren't using the native ABI. With this change, librtld_db can be used to inspect non-native processes; in particular, dtrace -c now works for 32-bit executables on amd64. MFC after: 1 month Modified: head/Makefile.inc1 head/lib/librtld_db/Makefile head/lib/librtld_db/rtld_db.c head/lib/librtld_db/rtld_db.h head/share/mk/src.libnames.mk Modified: head/Makefile.inc1 ============================================================================== --- head/Makefile.inc1 Sat Jul 30 02:09:11 2016 (r303530) +++ head/Makefile.inc1 Sat Jul 30 03:05:23 2016 (r303531) @@ -2095,7 +2095,9 @@ cddl/lib/libctf__L: lib/libz__L # cddl/lib/libdtrace requires lib/libproc and lib/librtld_db; it's only built # on select architectures though (see cddl/lib/Makefile) .if ${MACHINE_CPUARCH} != "sparc64" -_prebuild_libs+= lib/libproc lib/librtld_db +_prebuild_libs+= lib/libprocstat lib/libproc lib/librtld_db +lib/libproc__L: lib/libprocstat__L +lib/librtld_db__L: lib/libprocstat__L .endif .if ${MK_CRYPT} != "no" Modified: head/lib/librtld_db/Makefile ============================================================================== --- head/lib/librtld_db/Makefile Sat Jul 30 02:09:11 2016 (r303530) +++ head/lib/librtld_db/Makefile Sat Jul 30 03:05:23 2016 (r303531) @@ -14,4 +14,6 @@ CFLAGS+= -I${.CURDIR} # Avoid circular dependency, we only need the libproc.h header here. CFLAGS+= -I${.CURDIR:H}/libproc +LIBADD+= elf procstat + .include <bsd.lib.mk> Modified: head/lib/librtld_db/rtld_db.c ============================================================================== --- head/lib/librtld_db/rtld_db.c Sat Jul 30 02:09:11 2016 (r303530) +++ head/lib/librtld_db/rtld_db.c Sat Jul 30 03:05:23 2016 (r303531) @@ -25,20 +25,30 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - */ + */ + #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <machine/_inttypes.h> -#include <sys/types.h> +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/sysctl.h> #include <sys/user.h> +#include <assert.h> #include <err.h> +#include <fcntl.h> +#include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <limits.h> +#include <unistd.h> + +#include <machine/elf.h> + +#include <libelf.h> #include <libproc.h> +#include <libprocstat.h> #include <libutil.h> #include "rtld_db.h" @@ -55,6 +65,8 @@ void rd_delete(rd_agent_t *rdap) { + if (rdap->rda_procstat != NULL) + procstat_close(rdap->rda_procstat); free(rdap); } @@ -146,9 +158,10 @@ rd_init(int version) rd_err_e rd_loadobj_iter(rd_agent_t *rdap, rl_iter_f *cb, void *clnt_data) { - int cnt, i, lastvn = 0; - rd_loadobj_t rdl; struct kinfo_vmentry *kves, *kve; + rd_loadobj_t rdl; + rd_err_e ret; + int cnt, i, lastvn; DPRINTF("%s\n", __func__); @@ -156,6 +169,9 @@ rd_loadobj_iter(rd_agent_t *rdap, rl_ite warn("ERROR: kinfo_getvmmap() failed"); return (RD_ERR); } + + ret = RD_OK; + lastvn = 0; for (i = 0; i < cnt; i++) { kve = kves + i; if (kve->kve_type == KVME_TYPE_VNODE) @@ -174,12 +190,14 @@ rd_loadobj_iter(rd_agent_t *rdap, rl_ite if (kve->kve_protection & KVME_PROT_EXEC) rdl.rdl_prot |= RD_RDL_X; strlcpy(rdl.rdl_path, kves[lastvn].kve_path, - sizeof(rdl.rdl_path)); - (*cb)(&rdl, clnt_data); + sizeof(rdl.rdl_path)); + if ((*cb)(&rdl, clnt_data) != 0) { + ret = RD_ERR; + break; + } } free(kves); - - return (RD_OK); + return (ret); } void @@ -195,13 +213,18 @@ rd_new(struct proc_handle *php) { rd_agent_t *rdap; - rdap = malloc(sizeof(rd_agent_t)); - if (rdap) { - memset(rdap, 0, sizeof(rd_agent_t)); - rdap->rda_php = php; - rd_reset(rdap); + rdap = malloc(sizeof(*rdap)); + if (rdap == NULL) + return (NULL); + + memset(rdap, 0, sizeof(rd_agent_t)); + rdap->rda_php = php; + rdap->rda_procstat = procstat_open_sysctl(); + + if (rd_reset(rdap) != RD_OK) { + rd_delete(rdap); + rdap = NULL; } - return (rdap); } @@ -231,24 +254,136 @@ rd_plt_resolution(rd_agent_t *rdap, uint return (RD_ERR); } -rd_err_e -rd_reset(rd_agent_t *rdap) +static int +rtld_syms(rd_agent_t *rdap, const char *rtldpath, u_long base) { + GElf_Shdr shdr; GElf_Sym sym; + Elf *e; + Elf_Data *data; + Elf_Scn *scn; + const char *symname; + Elf64_Word strscnidx; + int fd, i, ret; + + ret = 1; + e = NULL; + + fd = open(rtldpath, O_RDONLY); + if (fd < 0) + goto err; + + if (elf_version(EV_CURRENT) == EV_NONE) + goto err; + e = elf_begin(fd, ELF_C_READ, NULL); + if (e == NULL) { + close(fd); + goto err; + } - if (proc_name2sym(rdap->rda_php, "ld-elf.so.1", "r_debug_state", - &sym, NULL) < 0) - return (RD_ERR); - DPRINTF("found r_debug_state at 0x%lx\n", (unsigned long)sym.st_value); - rdap->rda_preinit_addr = sym.st_value; - rdap->rda_dlactivity_addr = sym.st_value; + scn = NULL; + while ((scn = elf_nextscn(e, scn)) != NULL) { + gelf_getshdr(scn, &shdr); + if (shdr.sh_type == SHT_DYNSYM) + break; + } + if (scn == NULL) + goto err; - if (proc_name2sym(rdap->rda_php, "ld-elf.so.1", "_r_debug_postinit", - &sym, NULL) < 0) + strscnidx = shdr.sh_link; + data = elf_getdata(scn, NULL); + if (data == NULL) + goto err; + + for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) { + if (GELF_ST_TYPE(sym.st_info) != STT_FUNC || + GELF_ST_BIND(sym.st_info) != STB_GLOBAL) + continue; + symname = elf_strptr(e, strscnidx, sym.st_name); + if (symname == NULL) + continue; + + if (strcmp(symname, "r_debug_state") == 0) { + rdap->rda_preinit_addr = sym.st_value + base; + rdap->rda_dlactivity_addr = sym.st_value + base; + } else if (strcmp(symname, "_r_debug_postinit") == 0) { + rdap->rda_postinit_addr = sym.st_value + base; + } + } + + if (rdap->rda_preinit_addr != 0 && + rdap->rda_postinit_addr != 0 && + rdap->rda_dlactivity_addr != 0) + ret = 0; + +err: + if (e != NULL) + (void)elf_end(e); + if (fd >= 0) + (void)close(fd); + return (ret); +} + +rd_err_e +rd_reset(rd_agent_t *rdap) +{ + struct kinfo_proc *kp; + struct kinfo_vmentry *kve; + Elf_Auxinfo *auxv; + const char *rtldpath; + u_long base; + rd_err_e rderr; + int count, i; + + kp = NULL; + auxv = NULL; + kve = NULL; + rderr = RD_ERR; + + kp = procstat_getprocs(rdap->rda_procstat, KERN_PROC_PID, + proc_getpid(rdap->rda_php), &count); + if (kp == NULL) return (RD_ERR); - DPRINTF("found _r_debug_postinit at 0x%lx\n", - (unsigned long)sym.st_value); - rdap->rda_postinit_addr = sym.st_value; + assert(count == 1); - return (RD_OK); + auxv = procstat_getauxv(rdap->rda_procstat, kp, &count); + if (auxv == NULL) + goto err; + + base = 0; + for (i = 0; i < count; i++) { + if (auxv[i].a_type == AT_BASE) { + base = auxv[i].a_un.a_val; + break; + } + } + if (i == count) + goto err; + + rtldpath = NULL; + kve = procstat_getvmmap(rdap->rda_procstat, kp, &count); + if (kve == NULL) + goto err; + for (i = 0; i < count; i++) { + if (kve[i].kve_start == base) { + rtldpath = kve[i].kve_path; + break; + } + } + if (i == count) + goto err; + + if (rtld_syms(rdap, rtldpath, base) != 0) + goto err; + + rderr = RD_OK; + +err: + if (kve != NULL) + procstat_freevmmap(rdap->rda_procstat, kve); + if (auxv != NULL) + procstat_freeauxv(rdap->rda_procstat, auxv); + if (kp != NULL) + procstat_freeprocs(rdap->rda_procstat, kp); + return (rderr); } Modified: head/lib/librtld_db/rtld_db.h ============================================================================== --- head/lib/librtld_db/rtld_db.h Sat Jul 30 02:09:11 2016 (r303530) +++ head/lib/librtld_db/rtld_db.h Sat Jul 30 03:05:23 2016 (r303531) @@ -33,9 +33,6 @@ #define _RTLD_DB_H_ #include <sys/param.h> -#include <sys/cdefs.h> -#include <sys/types.h> - #define RD_VERSION 1 @@ -49,11 +46,17 @@ typedef enum { RD_NOMAPS } rd_err_e; +/* XXX struct rd_agent should be private. */ +struct procstat; + typedef struct rd_agent { struct proc_handle *rda_php; + uintptr_t rda_dlactivity_addr; uintptr_t rda_preinit_addr; uintptr_t rda_postinit_addr; + + struct procstat *rda_procstat; } rd_agent_t; typedef struct rd_loadobj { Modified: head/share/mk/src.libnames.mk ============================================================================== --- head/share/mk/src.libnames.mk Sat Jul 30 02:09:11 2016 (r303530) +++ head/share/mk/src.libnames.mk Sat Jul 30 03:05:23 2016 (r303531) @@ -243,6 +243,7 @@ _DP_radius= md .else _DP_radius= crypto .endif +_DP_rtld_db= elf procstat _DP_procstat= kvm util elf .if ${MK_CXX} == "yes" .if ${MK_LIBCPLUSPLUS} != "no"
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201607300305.u6U35ORs005889>