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