svn commit: r272125 - head/lib/libproc

Mark Johnston markj at FreeBSD.org
Thu Sep 25 19:08:07 UTC 2014


Author: markj
Date: Thu Sep 25 19:08:06 2014
New Revision: 272125
URL: http://svnweb.freebsd.org/changeset/base/272125

Log:
  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

Modified:
  head/lib/libproc/proc_sym.c

Modified: head/lib/libproc/proc_sym.c
==============================================================================
--- head/lib/libproc/proc_sym.c	Thu Sep 25 18:54:36 2014	(r272124)
+++ head/lib/libproc/proc_sym.c	Thu Sep 25 19:08:06 2014	(r272125)
@@ -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, uin
 	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, uin
 		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, uin
 			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:
@@ -363,7 +343,7 @@ proc_name2map(struct proc_handle *p, con
 {
 	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, con
 			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, con
 {
 	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, con
 			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 *
 	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 *
 		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;


More information about the svn-src-head mailing list