aboutsummaryrefslogtreecommitdiff
path: root/lib/libproc
diff options
context:
space:
mode:
authorSimon J. Gerraty <sjg@FreeBSD.org>2014-11-19 01:07:58 +0000
committerSimon J. Gerraty <sjg@FreeBSD.org>2014-11-19 01:07:58 +0000
commit9268022b74279434ed6300244e3f977e56a8ceb5 (patch)
tree377ac0ac449528621eb192cd245adadb5fd53668 /lib/libproc
parent29c34e9d2781cf25403647fb5af7d7ddb23be7e1 (diff)
parent8c3d6a4ab2a4a95d864d9a32d0157d7de90498a4 (diff)
Notes
Diffstat (limited to 'lib/libproc')
-rw-r--r--lib/libproc/Makefile17
-rw-r--r--lib/libproc/libproc.h13
-rw-r--r--lib/libproc/proc_sym.c319
-rw-r--r--lib/libproc/test/Makefile5
-rw-r--r--lib/libproc/test/t1-bkpt/Makefile12
-rw-r--r--lib/libproc/test/t1-bkpt/t1-bkpt.c71
-rw-r--r--lib/libproc/test/t2-name2map/Makefile12
-rw-r--r--lib/libproc/test/t3-name2sym/Makefile12
-rw-r--r--lib/libproc/test/t3-name2sym/t3-name2sym.c51
-rw-r--r--lib/libproc/tests/Makefile21
-rw-r--r--lib/libproc/tests/proc_test.c349
-rw-r--r--lib/libproc/tests/target_prog.c (renamed from lib/libproc/test/t2-name2map/t2-name2map.c)89
12 files changed, 608 insertions, 363 deletions
diff --git a/lib/libproc/Makefile b/lib/libproc/Makefile
index 5e5babffee70..bfb9492d703a 100644
--- a/lib/libproc/Makefile
+++ b/lib/libproc/Makefile
@@ -27,8 +27,23 @@ LDADD+= -lsupc++
DPADD+= ${LIBSTDCPLUSPLUS}
.endif
-SHLIB_MAJOR= 2
+.if ${MK_CDDL} != "no"
+LDADD+= -lctf
+DPADD+= ${LIBCTF}
+IGNORE_PRAGMA= YES
+CFLAGS+= -I${.CURDIR}/../../cddl/contrib/opensolaris/lib/libctf/common \
+ -I${.CURDIR}/../../sys/cddl/contrib/opensolaris/uts/common \
+ -I${.CURDIR}/../../sys/cddl/compat/opensolaris
+.else
+CFLAGS+= -DNO_CTF
+.endif
+
+SHLIB_MAJOR= 3
MAN=
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
.include <bsd.lib.mk>
diff --git a/lib/libproc/libproc.h b/lib/libproc/libproc.h
index be77e4b59214..5d81c2bf4505 100644
--- a/lib/libproc/libproc.h
+++ b/lib/libproc/libproc.h
@@ -37,6 +37,7 @@
#include <rtld_db.h>
#include <limits.h>
+struct ctf_file;
struct proc_handle;
typedef void (*proc_child_func)(void *);
@@ -67,6 +68,11 @@ typedef struct prmap {
#define MA_NOCOREDUMP 0x20
} prmap_t;
+typedef struct prsyminfo {
+ u_int prs_lmid; /* Map id. */
+ u_int prs_id; /* Symbol id. */
+} prsyminfo_t;
+
typedef int proc_map_f(void *, const prmap_t *, const char *);
typedef int proc_sym_f(void *, const GElf_Sym *, const char *);
@@ -125,7 +131,9 @@ int proc_create(const char *, char * const *, proc_child_func *, void *,
struct proc_handle **);
int proc_detach(struct proc_handle *, int);
int proc_getflags(struct proc_handle *);
-int proc_name2sym(struct proc_handle *, const char *, const char *, GElf_Sym *);
+int proc_name2sym(struct proc_handle *, const char *, const char *,
+ GElf_Sym *, prsyminfo_t *);
+struct ctf_file *proc_name2ctf(struct proc_handle *, const char *);
int proc_setflags(struct proc_handle *, int);
int proc_state(struct proc_handle *);
pid_t proc_getpid(struct proc_handle *);
@@ -133,8 +141,7 @@ int proc_wstatus(struct proc_handle *);
int proc_getwstat(struct proc_handle *);
char * proc_signame(int, char *, size_t);
int proc_read(struct proc_handle *, void *, size_t, size_t);
-const lwpstatus_t *
- proc_getlwpstatus(struct proc_handle *);
+const lwpstatus_t *proc_getlwpstatus(struct proc_handle *);
void proc_free(struct proc_handle *);
rd_agent_t *proc_rdagent(struct proc_handle *);
void proc_updatesyms(struct proc_handle *);
diff --git a/lib/libproc/proc_sym.c b/lib/libproc/proc_sym.c
index 4d600436c676..766ff73446e2 100644
--- a/lib/libproc/proc_sym.c
+++ b/lib/libproc/proc_sym.c
@@ -26,26 +26,37 @@
* 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.
- *
- * $FreeBSD$
*/
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include <sys/types.h>
+#ifndef NO_CTF
+#include <sys/ctf.h>
+#include <sys/ctf_api.h>
+#endif
#include <sys/user.h>
#include <assert.h>
#include <err.h>
-#include <stdio.h>
+#include <fcntl.h>
#include <libgen.h>
-#include <string.h>
+#include <stdio.h>
#include <stdlib.h>
-#include <fcntl.h>
#include <string.h>
#include <unistd.h>
+#ifndef NO_CTF
+#include <libctf.h>
+#endif
#include <libutil.h>
#include "_libproc.h"
+#ifdef NO_CTF
+typedef struct ctf_file ctf_file_t;
+#endif
+
#ifndef NO_CXA_DEMANGLE
extern char *__cxa_demangle(const char *, char *, size_t *, int *);
#endif /* NO_CXA_DEMANGLE */
@@ -57,21 +68,15 @@ demangle(const char *symbol, char *buf, size_t len)
{
#ifndef NO_CXA_DEMANGLE
char *dembuf;
- size_t demlen;
if (symbol[0] == '_' && symbol[1] == 'Z' && symbol[2]) {
- dembuf = malloc(len);
- if (!dembuf)
- goto fail;
- demlen = len;
- dembuf = __cxa_demangle(symbol, dembuf, &demlen, NULL);
+ dembuf = __cxa_demangle(symbol, NULL, NULL, NULL);
if (!dembuf)
goto fail;
strlcpy(buf, dembuf, len);
free(dembuf);
+ return;
}
-
- return;
fail:
#endif /* NO_CXA_DEMANGLE */
strlcpy(buf, symbol, len);
@@ -127,10 +132,12 @@ proc_obj2map(struct proc_handle *p, const char *objname)
break;
}
}
- if (rdl == NULL && strcmp(objname, "a.out") == 0 && p->rdexec != NULL)
- rdl = p->rdexec;
- else
- return (NULL);
+ if (rdl == NULL) {
+ if (strcmp(objname, "a.out") == 0 && p->rdexec != NULL)
+ rdl = p->rdexec;
+ else
+ return (NULL);
+ }
if ((map = malloc(sizeof(*map))) == NULL)
return (NULL);
@@ -232,22 +239,56 @@ proc_addr2map(struct proc_handle *p, uintptr_t addr)
return (NULL);
}
+/*
+ * Look up the symbol at addr, returning a copy of the symbol and its name.
+ */
+static int
+lookup_addr(Elf *e, Elf_Scn *scn, u_long stridx, uintptr_t off, uintptr_t addr,
+ const char **name, GElf_Sym *symcopy)
+{
+ GElf_Sym sym;
+ Elf_Data *data;
+ const char *s;
+ uint64_t rsym;
+ int i;
+
+ if ((data = elf_getdata(scn, NULL)) == NULL) {
+ DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
+ return (1);
+ }
+ for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) {
+ rsym = off + sym.st_value;
+ if (addr >= rsym && addr < rsym + sym.st_size) {
+ s = elf_strptr(e, stridx, sym.st_name);
+ if (s != NULL) {
+ *name = s;
+ memcpy(symcopy, &sym, sizeof(*symcopy));
+ /*
+ * DTrace expects the st_value to contain
+ * only the address relative to the start of
+ * the function.
+ */
+ symcopy->st_value = rsym;
+ return (0);
+ }
+ }
+ }
+ return (1);
+}
+
int
proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name,
size_t namesz, GElf_Sym *symcopy)
{
+ GElf_Ehdr ehdr;
+ GElf_Shdr shdr;
Elf *e;
Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
- Elf_Data *data;
- GElf_Shdr shdr;
- GElf_Sym sym;
- GElf_Ehdr ehdr;
- int fd, error = -1;
- size_t i;
- uint64_t rsym;
prmap_t *map;
- char *s;
- unsigned long symtabstridx = 0, dynsymstridx = 0;
+ const char *s;
+ uintptr_t off;
+ u_long symtabstridx = 0, dynsymstridx = 0;
+ int fd, error = -1;
if ((map = proc_addr2map(p, addr)) == NULL)
return (-1);
@@ -263,6 +304,7 @@ proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name,
DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
goto err2;
}
+
/*
* Find the index of the STRTAB and SYMTAB sections to locate
* symbol names.
@@ -279,80 +321,25 @@ proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name,
dynsymscn = scn;
dynsymstridx = shdr.sh_link;
break;
- default:
- break;
- }
- }
- /*
- * Iterate over the Dynamic Symbols table to find the symbol.
- * Then look up the string name in STRTAB (.dynstr)
- */
- if ((data = elf_getdata(dynsymscn, NULL)) == NULL) {
- DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
- goto symtab;
- }
- i = 0;
- while (gelf_getsym(data, i++, &sym) != NULL) {
- /*
- * Calculate the address mapped to the virtual memory
- * by rtld.
- */
- if (ehdr.e_type != ET_EXEC)
- rsym = map->pr_vaddr + sym.st_value;
- else
- rsym = sym.st_value;
- if (addr >= rsym && addr < rsym + sym.st_size) {
- s = elf_strptr(e, dynsymstridx, sym.st_name);
- if (s) {
- demangle(s, name, namesz);
- memcpy(symcopy, &sym, sizeof(sym));
- /*
- * DTrace expects the st_value to contain
- * only the address relative to the start of
- * the function.
- */
- symcopy->st_value = rsym;
- error = 0;
- goto out;
- }
}
}
-symtab:
+
+ off = ehdr.e_type == ET_EXEC ? 0 : map->pr_vaddr;
+
/*
- * Iterate over the Symbols Table to find the symbol.
- * Then look up the string name in STRTAB (.dynstr)
+ * First look up the symbol in the dynsymtab, and fall back to the
+ * symtab if the lookup fails.
*/
- if ((data = elf_getdata(symtabscn, NULL)) == NULL) {
- DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
- goto err2;
- }
- i = 0;
- while (gelf_getsym(data, i++, &sym) != NULL) {
- /*
- * Calculate the address mapped to the virtual memory
- * by rtld.
- */
- if (ehdr.e_type != ET_EXEC)
- rsym = map->pr_vaddr + sym.st_value;
- else
- rsym = sym.st_value;
- if (addr >= rsym && addr < rsym + sym.st_size) {
- s = elf_strptr(e, symtabstridx, sym.st_name);
- if (s) {
- demangle(s, name, namesz);
- memcpy(symcopy, &sym, sizeof(sym));
- /*
- * DTrace expects the st_value to contain
- * only the address relative to the start of
- * the function.
- */
- symcopy->st_value = rsym;
- error = 0;
- goto out;
- }
- }
- }
+ error = lookup_addr(e, dynsymscn, dynsymstridx, off, addr, &s, symcopy);
+ if (error == 0)
+ goto out;
+
+ error = lookup_addr(e, symtabscn, symtabstridx, off, addr, &s, symcopy);
+ if (error == 0)
+ goto out;
+
out:
+ demangle(s, name, namesz);
err2:
elf_end(e);
err1:
@@ -367,7 +354,7 @@ proc_name2map(struct proc_handle *p, const char *name)
{
size_t i;
int cnt;
- prmap_t *map;
+ prmap_t *map = NULL;
char tmppath[MAXPATHLEN];
struct kinfo_vmentry *kves, *kve;
rd_loadobj_t *rdl;
@@ -386,47 +373,68 @@ proc_name2map(struct proc_handle *p, const char *name)
basename_r(kve->kve_path, tmppath);
if (strcmp(tmppath, name) == 0) {
map = proc_addr2map(p, kve->kve_start);
- free(kves);
- return (map);
+ break;
}
}
free(kves);
- return (NULL);
- }
- if ((name == NULL || strcmp(name, "a.out") == 0) &&
- p->rdexec != NULL) {
+ } else
+ for (i = 0; i < p->nobjs; i++) {
+ rdl = &p->rdobjs[i];
+ basename_r(rdl->rdl_path, tmppath);
+ if (strcmp(tmppath, name) == 0) {
+ if ((map = malloc(sizeof(*map))) == NULL)
+ return (NULL);
+ proc_rdl2prmap(rdl, map);
+ break;
+ }
+ }
+
+ if (map == NULL && strcmp(name, "a.out") == 0 && p->rdexec != NULL)
map = proc_addr2map(p, p->rdexec->rdl_saddr);
- return (map);
+
+ return (map);
+}
+
+/*
+ * Look up the symbol with the given name and return a copy of it.
+ */
+static int
+lookup_name(Elf *e, Elf_Scn *scn, u_long stridx, const char *symbol,
+ GElf_Sym *symcopy, prsyminfo_t *si)
+{
+ GElf_Sym sym;
+ Elf_Data *data;
+ char *s;
+ int i;
+
+ if ((data = elf_getdata(scn, NULL)) == NULL) {
+ DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
+ return (1);
}
- for (i = 0; i < p->nobjs; i++) {
- rdl = &p->rdobjs[i];
- basename_r(rdl->rdl_path, tmppath);
- if (strcmp(tmppath, name) == 0) {
- if ((map = malloc(sizeof(*map))) == NULL)
- return (NULL);
- proc_rdl2prmap(rdl, map);
- return (map);
+ for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) {
+ s = elf_strptr(e, stridx, sym.st_name);
+ if (s != NULL && strcmp(s, symbol) == 0) {
+ memcpy(symcopy, &sym, sizeof(*symcopy));
+ if (si != NULL)
+ si->prs_id = i;
+ return (0);
}
}
-
- return (NULL);
+ return (1);
}
int
proc_name2sym(struct proc_handle *p, const char *object, const char *symbol,
- GElf_Sym *symcopy)
+ GElf_Sym *symcopy, prsyminfo_t *si)
{
Elf *e;
Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
- Elf_Data *data;
GElf_Shdr shdr;
- GElf_Sym sym;
GElf_Ehdr ehdr;
- int fd, error = -1;
- size_t i;
prmap_t *map;
- char *s;
- unsigned long symtabstridx = 0, dynsymstridx = 0;
+ uintptr_t off;
+ u_long symtabstridx = 0, dynsymstridx = 0;
+ int fd, error = -1;
if ((map = proc_name2map(p, object)) == NULL) {
DPRINTFX("ERROR: couldn't find object %s", object);
@@ -460,46 +468,25 @@ proc_name2sym(struct proc_handle *p, const char *object, const char *symbol,
dynsymscn = scn;
dynsymstridx = shdr.sh_link;
break;
- default:
- break;
- }
- }
- /*
- * Iterate over the Dynamic Symbols table to find the symbol.
- * Then look up the string name in STRTAB (.dynstr)
- */
- if ((data = elf_getdata(dynsymscn, NULL))) {
- i = 0;
- while (gelf_getsym(data, i++, &sym) != NULL) {
- s = elf_strptr(e, dynsymstridx, sym.st_name);
- if (s && strcmp(s, symbol) == 0) {
- memcpy(symcopy, &sym, sizeof(sym));
- if (ehdr.e_type != ET_EXEC)
- symcopy->st_value += map->pr_vaddr;
- error = 0;
- goto out;
- }
}
}
+
/*
- * Iterate over the Symbols Table to find the symbol.
- * Then look up the string name in STRTAB (.dynstr)
+ * First look up the symbol in the dynsymtab, and fall back to the
+ * symtab if the lookup fails.
*/
- if ((data = elf_getdata(symtabscn, NULL))) {
- i = 0;
- while (gelf_getsym(data, i++, &sym) != NULL) {
- s = elf_strptr(e, symtabstridx, sym.st_name);
- if (s && strcmp(s, symbol) == 0) {
- memcpy(symcopy, &sym, sizeof(sym));
- if (ehdr.e_type != ET_EXEC)
- symcopy->st_value += map->pr_vaddr;
- error = 0;
- goto out;
- }
- }
- }
+ error = lookup_name(e, dynsymscn, dynsymstridx, symbol, symcopy, si);
+ if (error == 0)
+ goto out;
+
+ error = lookup_name(e, symtabscn, symtabstridx, symbol, symcopy, si);
+ if (error == 0)
+ goto out;
+
out:
- DPRINTFX("found addr 0x%lx for %s", symcopy->st_value, symbol);
+ off = ehdr.e_type == ET_EXEC ? 0 : map->pr_vaddr;
+ symcopy->st_value += off;
+
err2:
elf_end(e);
err1:
@@ -510,6 +497,23 @@ err0:
return (error);
}
+ctf_file_t *
+proc_name2ctf(struct proc_handle *p, const char *name)
+{
+#ifndef NO_CTF
+ prmap_t *map;
+ int error;
+
+ if ((map = proc_name2map(p, name)) == NULL)
+ return (NULL);
+
+ return (ctf_open(map->pr_mapname, &error));
+#else
+ (void)p;
+ (void)name;
+ return (NULL);
+#endif
+}
int
proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which,
@@ -547,7 +551,7 @@ proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which,
scn = NULL;
while ((scn = elf_nextscn(e, scn)) != NULL) {
gelf_getshdr(scn, &shdr);
- if (which == PR_SYMTAB &&
+ if (which == PR_SYMTAB &&
shdr.sh_type == SHT_SYMTAB) {
foundscn = scn;
break;
@@ -564,8 +568,7 @@ proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which,
DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
goto err2;
}
- i = 0;
- while (gelf_getsym(data, i++, &sym) != NULL) {
+ for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) {
if (GELF_ST_BIND(sym.st_info) == STB_LOCAL &&
(mask & BIND_LOCAL) == 0)
continue;
diff --git a/lib/libproc/test/Makefile b/lib/libproc/test/Makefile
deleted file mode 100644
index e4d33f82ce44..000000000000
--- a/lib/libproc/test/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-# $FreeBSD$
-
-SUBDIR= t1-bkpt t2-name2map t3-name2sym
-
-.include <bsd.subdir.mk>
diff --git a/lib/libproc/test/t1-bkpt/Makefile b/lib/libproc/test/t1-bkpt/Makefile
deleted file mode 100644
index eb5b37f94936..000000000000
--- a/lib/libproc/test/t1-bkpt/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# $FreeBSD$
-
-PROG= t1-bkpt
-
-SRCS= t1-bkpt.c
-
-LDADD= -lproc -lelf -lrtld_db -lutil
-DPADD= ${LIBPROC} ${LIBELF}
-
-MAN=
-
-.include <bsd.prog.mk>
diff --git a/lib/libproc/test/t1-bkpt/t1-bkpt.c b/lib/libproc/test/t1-bkpt/t1-bkpt.c
deleted file mode 100644
index 1cd4d17f5612..000000000000
--- a/lib/libproc/test/t1-bkpt/t1-bkpt.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2010 The FreeBSD Foundation
- * All rights reserved.
- *
- * This software was developed by Rui Paulo under sponsorship from the
- * FreeBSD Foundation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * 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.
- *
- * $FreeBSD$
- */
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-#include <libproc.h>
-
-int __noinline
-t1_bkpt_t()
-{
- printf("TEST OK\n");
-}
-
-int
-t1_bkpt_d()
-{
- struct proc_handle *phdl;
- char *targv[] = { "t1-bkpt-t", NULL};
- unsigned long saved;
-
- proc_create("./t1-bkpt", targv, NULL, NULL, &phdl);
- assert(proc_bkptset(phdl, (uintptr_t)t1_bkpt_t, &saved) == 0);
- proc_continue(phdl);
- assert(proc_wstatus(phdl) == PS_STOP);
- proc_bkptexec(phdl, saved);
- proc_continue(phdl);
- proc_wstatus(phdl);
- proc_free(phdl);
-}
-
-
-int
-main(int argc, char **argv)
-{
- if (!strcmp(argv[0], "t1-bkpt-t"))
- t1_bkpt_t();
- else
- t1_bkpt_d();
-}
-
diff --git a/lib/libproc/test/t2-name2map/Makefile b/lib/libproc/test/t2-name2map/Makefile
deleted file mode 100644
index 9002accf6904..000000000000
--- a/lib/libproc/test/t2-name2map/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# $FreeBSD$
-
-PROG= t2-name2map
-
-SRCS= t2-name2map.c
-
-LDADD= -lproc -lelf -lrtld_db -lutil
-DPADD= ${LIBPROC} ${LIBELF}
-
-MAN=
-
-.include <bsd.prog.mk>
diff --git a/lib/libproc/test/t3-name2sym/Makefile b/lib/libproc/test/t3-name2sym/Makefile
deleted file mode 100644
index 68e23c6199d9..000000000000
--- a/lib/libproc/test/t3-name2sym/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# $FreeBSD$
-
-PROG= t3-name2sym
-
-SRCS= t3-name2sym.c
-
-LDADD= -lproc -lelf -lrtld_db -lutil
-DPADD= ${LIBPROC} ${LIBELF}
-
-MAN=
-
-.include <bsd.prog.mk>
diff --git a/lib/libproc/test/t3-name2sym/t3-name2sym.c b/lib/libproc/test/t3-name2sym/t3-name2sym.c
deleted file mode 100644
index 0be8653d4a49..000000000000
--- a/lib/libproc/test/t3-name2sym/t3-name2sym.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2010 The FreeBSD Foundation
- * All rights reserved.
- *
- * This software was developed by Rui Paulo under sponsorship from the
- * FreeBSD Foundation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * 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.
- *
- * $FreeBSD$
- */
-#include <sys/types.h>
-#include <assert.h>
-#include <stdio.h>
-#include <libproc.h>
-#include <gelf.h>
-#include <string.h>
-
-int
-main(int argc, char *argv[])
-{
- prmap_t *map = NULL;
- struct proc_handle *phdl;
- GElf_Sym sym;
-
- proc_create("./t3-name2sym", argv, NULL, NULL, &phdl);
- memset(&sym, 0, sizeof(sym));
- assert(proc_name2sym(phdl, "ld-elf.so.1", "r_debug_state", &sym) == 0);
- printf("0x%lx\n", sym.st_value);
- assert(proc_name2sym(phdl, "t3-name2sym", "main", &sym) == 0);
- printf("0x%lx\n", sym.st_value);
-}
diff --git a/lib/libproc/tests/Makefile b/lib/libproc/tests/Makefile
new file mode 100644
index 000000000000..1f98467df24f
--- /dev/null
+++ b/lib/libproc/tests/Makefile
@@ -0,0 +1,21 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/lib/libproc
+
+ATF_TESTS_C+= proc_test
+
+PROGS= target_prog
+SRCS_target_prog= target_prog.c
+BINDIR_target_prog= ${TESTSDIR}
+
+LDADD+= -lelf -lproc -lrtld_db -lutil
+DPADD+= ${LIBELF} ${LIBPROC} ${LIBRTLD_DB} ${LIBUTIL}
+
+# Ensure that symbols aren't stripped from the test program, as they're needed
+# for testing symbol lookup.
+STRIP=
+
+MAN=
+WARNS?= 6
+
+.include <bsd.test.mk>
diff --git a/lib/libproc/tests/proc_test.c b/lib/libproc/tests/proc_test.c
new file mode 100644
index 000000000000..0242b5b5ee96
--- /dev/null
+++ b/lib/libproc/tests/proc_test.c
@@ -0,0 +1,349 @@
+/*-
+ * Copyright (c) 2014 Mark Johnston <markj@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * 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 <sys/types.h>
+#include <sys/wait.h>
+
+#include <libgen.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <atf-c.h>
+#include <libelf.h>
+#include <libproc.h>
+
+static const char *aout_object = "a.out";
+static const char *ldelf_object = "ld-elf.so.1";
+static const char *target_prog_file = "target_prog";
+
+/*
+ * Run the test program. If the sig parameter is set to true, the test program
+ * will deliver SIGUSR1 to itself during execution.
+ */
+static struct proc_handle *
+start_prog(const struct atf_tc *tc, bool sig)
+{
+ char *argv[3];
+ struct proc_handle *phdl;
+ int error;
+
+ asprintf(&argv[0], "%s/%s", atf_tc_get_config_var(tc, "srcdir"),
+ target_prog_file);
+ ATF_REQUIRE(argv[0] != NULL);
+
+ if (sig) {
+ argv[1] = strdup("-s");
+ argv[2] = NULL;
+ } else {
+ argv[1] = NULL;
+ }
+
+ error = proc_create(argv[0], argv, NULL, NULL, &phdl);
+ ATF_REQUIRE_EQ_MSG(error, 0, "failed to run '%s'", target_prog_file);
+ ATF_REQUIRE(phdl != NULL);
+
+ free(argv[0]);
+ free(argv[1]);
+
+ return (phdl);
+}
+
+static void
+set_bkpt(struct proc_handle *phdl, uintptr_t addr, u_long *saved)
+{
+ int error;
+
+ error = proc_bkptset(phdl, addr, saved);
+ ATF_REQUIRE_EQ_MSG(error, 0, "failed to set breakpoint at 0x%jx",
+ (uintmax_t)addr);
+}
+
+static void
+remove_bkpt(struct proc_handle *phdl, uintptr_t addr, u_long val)
+{
+ int error;
+
+ error = proc_bkptdel(phdl, addr, val);
+ ATF_REQUIRE_EQ_MSG(error, 0,
+ "failed to delete breakpoint at 0x%jx", (uintmax_t)addr);
+
+ error = proc_regset(phdl, REG_PC, addr);
+ ATF_REQUIRE_EQ_MSG(error, 0, "failed to reset program counter");
+}
+
+/*
+ * Wait for the specified process to hit a breakpoint at the specified symbol.
+ */
+static void
+verify_bkpt(struct proc_handle *phdl, GElf_Sym *sym, const char *symname,
+ const char *mapname)
+{
+ char mapbname[MAXPATHLEN], *name;
+ GElf_Sym tsym;
+ prmap_t *map;
+ size_t namesz;
+ u_long addr;
+ int error, state;
+
+ state = proc_wstatus(phdl);
+ ATF_REQUIRE_EQ_MSG(state, PS_STOP, "process has state %d", state);
+
+ /* Get the program counter and decrement it. */
+ error = proc_regget(phdl, REG_PC, &addr);
+ ATF_REQUIRE_EQ_MSG(error, 0, "failed to obtain PC for '%s'",
+ target_prog_file);
+ proc_bkptregadj(&addr);
+
+ /*
+ * Make sure the PC matches the expected value obtained from the symbol
+ * definition we looked up earlier.
+ */
+ ATF_CHECK_EQ_MSG(addr, sym->st_value,
+ "program counter 0x%lx doesn't match expected value 0x%jx",
+ addr, (uintmax_t)sym->st_value);
+
+ /*
+ * Ensure we can look up the r_debug_state symbol using its starting
+ * address and that the resulting symbol matches the one we found using
+ * a name lookup.
+ */
+ namesz = strlen(symname) + 1;
+ name = malloc(namesz);
+ ATF_REQUIRE(name != NULL);
+
+ error = proc_addr2sym(phdl, addr, name, namesz, &tsym);
+ ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up symbol at 0x%lx", addr);
+ ATF_REQUIRE_EQ(memcmp(sym, &tsym, sizeof(*sym)), 0);
+ ATF_REQUIRE_EQ(strcmp(symname, name), 0);
+ free(name);
+
+ map = proc_addr2map(phdl, addr);
+ ATF_REQUIRE_MSG(map != NULL, "failed to look up map for address 0x%lx",
+ addr);
+ basename_r(map->pr_mapname, mapbname);
+ ATF_REQUIRE_EQ_MSG(strcmp(mapname, mapbname), 0,
+ "expected map name '%s' doesn't match '%s'", mapname, mapbname);
+}
+
+ATF_TC(map_alias_obj2map);
+ATF_TC_HEAD(map_alias_obj2map, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Callers are supposed to be able to use \"a.out\" as an alias for "
+ "the program executable. Make sure that proc_obj2map() handles "
+ "this properly.");
+}
+ATF_TC_BODY(map_alias_obj2map, tc)
+{
+ struct proc_handle *phdl;
+ prmap_t *map1, *map2;
+
+ phdl = start_prog(tc, false);
+
+ /* Initialize the rtld_db handle. */
+ (void)proc_rdagent(phdl);
+
+ /* Ensure that "target_prog" and "a.out" return the same map. */
+ map1 = proc_obj2map(phdl, target_prog_file);
+ ATF_REQUIRE_MSG(map1 != NULL, "failed to look up map for '%s'",
+ target_prog_file);
+ map2 = proc_obj2map(phdl, aout_object);
+ ATF_REQUIRE_MSG(map2 != NULL, "failed to look up map for '%s'",
+ aout_object);
+ ATF_CHECK_EQ(strcmp(map1->pr_mapname, map2->pr_mapname), 0);
+
+ ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
+
+ proc_free(phdl);
+}
+
+ATF_TC(map_alias_name2map);
+ATF_TC_HEAD(map_alias_name2map, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Callers are supposed to be able to use \"a.out\" as an alias for "
+ "the program executable. Make sure that proc_name2map() handles "
+ "this properly.");
+}
+ATF_TC_BODY(map_alias_name2map, tc)
+{
+ struct proc_handle *phdl;
+ prmap_t *map1, *map2;
+
+ phdl = start_prog(tc, false);
+
+ /* Initialize the rtld_db handle. */
+ (void)proc_rdagent(phdl);
+
+ /* Ensure that "target_prog" and "a.out" return the same map. */
+ map1 = proc_name2map(phdl, target_prog_file);
+ ATF_REQUIRE_MSG(map1 != NULL, "failed to look up map for '%s'",
+ target_prog_file);
+ map2 = proc_name2map(phdl, aout_object);
+ ATF_REQUIRE_MSG(map2 != NULL, "failed to look up map for '%s'",
+ aout_object);
+ ATF_CHECK_EQ(strcmp(map1->pr_mapname, map2->pr_mapname), 0);
+
+ ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
+
+ proc_free(phdl);
+}
+
+ATF_TC(map_alias_name2sym);
+ATF_TC_HEAD(map_alias_name2sym, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Callers are supposed to be able to use \"a.out\" as an alias for "
+ "the program executable. Make sure that proc_name2sym() handles "
+ "this properly.");
+}
+ATF_TC_BODY(map_alias_name2sym, tc)
+{
+ GElf_Sym sym1, sym2;
+ prsyminfo_t si1, si2;
+ struct proc_handle *phdl;
+ int error;
+
+ phdl = start_prog(tc, false);
+
+ /* Initialize the rtld_db handle. */
+ (void)proc_rdagent(phdl);
+
+ /*
+ * Make sure that "target_prog:main" and "a.out:main" return the same
+ * symbol.
+ */
+ error = proc_name2sym(phdl, target_prog_file, "main", &sym1, &si1);
+ ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'main' via %s",
+ target_prog_file);
+ error = proc_name2sym(phdl, aout_object, "main", &sym2, &si2);
+ ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'main' via %s",
+ aout_object);
+
+ ATF_CHECK_EQ(memcmp(&sym1, &sym2, sizeof(sym1)), 0);
+ ATF_CHECK_EQ(si1.prs_id, si2.prs_id);
+
+ ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
+
+ proc_free(phdl);
+}
+
+ATF_TC(symbol_lookup);
+ATF_TC_HEAD(symbol_lookup, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Look up a couple of well-known symbols in the test program, place "
+ "breakpoints on them, and verify that we hit the breakpoints. Also "
+ "make sure that we can use the breakpoint address to look up the "
+ "corresponding symbol.");
+}
+ATF_TC_BODY(symbol_lookup, tc)
+{
+ GElf_Sym main_sym, r_debug_state_sym;
+ struct proc_handle *phdl;
+ u_long saved;
+ int error;
+
+ phdl = start_prog(tc, false);
+
+ error = proc_name2sym(phdl, target_prog_file, "main", &main_sym, NULL);
+ ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'main'");
+
+ error = proc_name2sym(phdl, ldelf_object, "r_debug_state",
+ &r_debug_state_sym, NULL);
+ ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'r_debug_state'");
+
+ set_bkpt(phdl, r_debug_state_sym.st_value, &saved);
+ ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
+ verify_bkpt(phdl, &r_debug_state_sym, "r_debug_state", ldelf_object);
+ remove_bkpt(phdl, r_debug_state_sym.st_value, saved);
+
+ set_bkpt(phdl, main_sym.st_value, &saved);
+ ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
+ verify_bkpt(phdl, &main_sym, "main", target_prog_file);
+ remove_bkpt(phdl, main_sym.st_value, saved);
+
+ ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
+
+ proc_free(phdl);
+}
+
+ATF_TC(signal_forward);
+ATF_TC_HEAD(signal_forward, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Run the test program in a mode which causes it to send a signal "
+ "to itself. Make sure that we intercept the signal and that "
+ "proc_continue() forwards it to the process.");
+}
+ATF_TC_BODY(signal_forward, tc)
+{
+ struct proc_handle *phdl;
+ int state, status;
+
+ phdl = start_prog(tc, true);
+ ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
+
+ /* The process should have been interrupted by a signal. */
+ state = proc_wstatus(phdl);
+ ATF_REQUIRE_EQ_MSG(state, PS_STOP, "process has unexpected state %d",
+ state);
+
+ /* Continue execution and allow the signal to be delivered. */
+ ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
+
+ /*
+ * Make sure the process exited with status 0. If it didn't receive the
+ * SIGUSR1 that it sent to itself, it'll exit with a non-zero exit
+ * status, causing the test to fail.
+ */
+ state = proc_wstatus(phdl);
+ ATF_REQUIRE_EQ_MSG(state, PS_UNDEAD, "process has unexpected state %d",
+ state);
+
+ status = proc_getwstat(phdl);
+ ATF_REQUIRE(status >= 0);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE_EQ(WEXITSTATUS(status), 0);
+
+ proc_free(phdl);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, map_alias_obj2map);
+ ATF_TP_ADD_TC(tp, map_alias_name2map);
+ ATF_TP_ADD_TC(tp, map_alias_name2sym);
+ ATF_TP_ADD_TC(tp, symbol_lookup);
+ ATF_TP_ADD_TC(tp, signal_forward);
+
+ return (atf_no_error());
+}
diff --git a/lib/libproc/test/t2-name2map/t2-name2map.c b/lib/libproc/tests/target_prog.c
index 825963d3f504..1edf0ded6122 100644
--- a/lib/libproc/test/t2-name2map/t2-name2map.c
+++ b/lib/libproc/tests/target_prog.c
@@ -1,46 +1,59 @@
-/*
- * Copyright (c) 2010 The FreeBSD Foundation
- * All rights reserved.
- *
- * This software was developed by Rui Paulo under sponsorship from the
- * FreeBSD Foundation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * 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.
+/*-
+ * Copyright (c) 2014 Mark Johnston <markj@FreeBSD.org>
+ * All rights reserved.
*
- * $FreeBSD$
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * 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/types.h>
-#include <assert.h>
-#include <stdio.h>
-#include <libproc.h>
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static volatile sig_atomic_t saw;
+
+static void
+usr1(int sig __unused)
+{
+
+ saw = 1;
+}
int
-main(int argc, char *argv[])
+main(int argc, char **argv)
{
- prmap_t *map = NULL;
- struct proc_handle *phdl;
- proc_create("./t2-name2map", argv, NULL, NULL, &phdl);
- map = proc_name2map(phdl, "ld-elf.so.1");
- assert(map);
+ if (argc == 1)
+ return (EXIT_SUCCESS);
+ if (argc == 2 && strcmp(argv[1], "-s") == 0) {
+ if (signal(SIGUSR1, usr1) == SIG_ERR)
+ err(1, "signal");
+ if (kill(getpid(), SIGUSR1) != 0)
+ err(1, "kill");
+ return (saw == 1 ? EXIT_SUCCESS : EXIT_FAILURE);
+ }
+ return (EXIT_FAILURE);
}