svn commit: r303531 - in head: . lib/librtld_db share/mk

Mark Johnston markj at FreeBSD.org
Sat Jul 30 03:05:25 UTC 2016


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"


More information about the svn-src-all mailing list