summaryrefslogtreecommitdiffstats
path: root/lib/libproc/proc_sym.c
diff options
context:
space:
mode:
authormarkj <markj@FreeBSD.org>2014-09-25 19:08:06 +0000
committermarkj <markj@FreeBSD.org>2014-09-25 19:08:06 +0000
commit40cf79ce11ca6b87e354cb9101bbd3f920cc8ac7 (patch)
treea1a4ced15f72ff5b488efe30b9a58b6bf152b233 /lib/libproc/proc_sym.c
parent1cafd48c74f9303040602cb053d2071e3e825440 (diff)
downloadFreeBSD-src-40cf79ce11ca6b87e354cb9101bbd3f920cc8ac7.zip
FreeBSD-src-40cf79ce11ca6b87e354cb9101bbd3f920cc8ac7.tar.gz
Factor out some of the duplicated code in the symbol lookup functions, in
preparation for adding userland CTF support to DTrace. MFC after: 1 month Sponsored by: EMC / Isilon Storage Division
Diffstat (limited to 'lib/libproc/proc_sym.c')
-rw-r--r--lib/libproc/proc_sym.c268
1 files changed, 122 insertions, 146 deletions
diff --git a/lib/libproc/proc_sym.c b/lib/libproc/proc_sym.c
index aa879ec..f5301e6 100644
--- a/lib/libproc/proc_sym.c
+++ b/lib/libproc/proc_sym.c
@@ -26,20 +26,20 @@
* 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>
#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>
#include <libutil.h>
@@ -228,22 +228,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);
@@ -259,6 +293,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.
@@ -275,80 +310,25 @@ proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name,
dynsymscn = scn;
dynsymstridx = shdr.sh_link;
break;
- default:
- break;
}
}
+
+ off = ehdr.e_type == ET_EXEC ? 0 : map->pr_vaddr;
+
/*
- * 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:
- /*
- * 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:
@@ -363,7 +343,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;
@@ -382,30 +362,52 @@ 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)
+{
+ 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));
+ return (0);
}
}
-
- return (NULL);
+ return (1);
}
int
@@ -414,15 +416,12 @@ proc_name2sym(struct proc_handle *p, const char *object, const char *symbol,
{
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);
@@ -456,46 +455,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);
+ if (error == 0)
+ goto out;
+
+ error = lookup_name(e, symtabscn, symtabstridx, symbol, symcopy);
+ 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:
@@ -506,7 +484,6 @@ err0:
return (error);
}
-
int
proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which,
int mask, proc_sym_f *func, void *cd)
@@ -543,7 +520,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;
@@ -560,8 +537,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;
OpenPOWER on IntegriCloud