[DTrace-devel] [PATCH 02/20] proc: refactor find_link_maps out of find_l_searchlist

Nick Alcock nick.alcock at oracle.com
Wed May 11 21:12:44 UTC 2022


I originally thought I'd be using this in the dl_nns search;
after doing it, it was so much clearer than what was there before that I
left it refactored out even though I ended up not using it in the dl_nns
search after all.

A purely mechanical transformation other than varible-name changes
(because 'loadobj' is a terrible name I've long wanted to change).

Signed-off-by: Nick Alcock <nick.alcock at oracle.com>
---
 libproc/rtld_db.c | 128 +++++++++++++++++++++++++++++-----------------
 1 file changed, 81 insertions(+), 47 deletions(-)

diff --git a/libproc/rtld_db.c b/libproc/rtld_db.c
index 1b0d1f73c6f4..77f67b05b679 100644
--- a/libproc/rtld_db.c
+++ b/libproc/rtld_db.c
@@ -276,6 +276,77 @@ ascending_uintptrs(const void *onep, const void *twop)
 		return 0;
 }
 
+/*
+ * Get all the link map addresses in the child: return them as an array NMAPS
+ * long.  This may not include all link maps: we stop as soon as a fetch fails.
+ * (All users are happy with only some maps and will usually return the right
+ * results with only one.)  The map should not be persisted, because the
+ * addresses of entries can change over time.
+ *
+ * Return the number of maps in NMAPS.
+ *
+ * Return NULL if no link maps can be fetched.
+ */
+static uintptr_t *
+find_link_maps(rd_agent_t *rd, size_t *nmaps)
+{
+	uintptr_t first_map_addr, map_addr;
+	uintptr_t *map_addrs;
+	uintptr_t *addrp;
+	struct link_map map;
+
+	/*
+	 * Iterate through the link maps twice: once to count the number of
+	 * maps, the second time to remember their addresses.
+	 */
+	*nmaps = 0;
+
+	if ((first_map_addr = first_link_map(rd, 0)) == 0)
+		return NULL;
+
+	for (map_addr = first_map_addr; map_addr != 0;
+	     map_addr = (uintptr_t)map.l_next) {
+		(*nmaps)++;
+		if (rd_get_link_map(rd, &map, map_addr) == NULL)
+			break;
+	}
+
+	_dprintf("%i: Counted %zi link maps\n", rd->P->pid, *nmaps);
+	if (*nmaps == 0)
+		return NULL;
+
+	map_addrs = calloc(*nmaps, sizeof(uintptr_t));
+	if (!map_addrs) {
+		_dprintf("Out of memory scanning for glibc structures "
+		    "when allocating room for %li link maps\n", *nmaps);
+		*nmaps = 0;
+		return NULL;
+	}
+
+	for (addrp = map_addrs,
+		 map_addr = first_link_map(rd, 0);
+	     map_addr != 0;
+	     map_addr = (uintptr_t)map.l_next, addrp++) {
+
+		_dprintf("%i: Noted map at %lx\n", rd->P->pid, map_addr);
+
+		*addrp = map_addr;
+		if (rd_get_link_map(rd, &map, map_addr) == NULL)
+			break;
+	}
+
+	if (addrp == map_addrs) {
+		free(map_addrs);
+		*nmaps = 0;
+		return NULL;
+	}
+
+	qsort(map_addrs, *nmaps, sizeof(uintptr_t), ascending_uintptrs);
+
+	return map_addrs;
+
+}
+
 /*
  * Find the offset of the l_searchlist in the link_map structure.
  *
@@ -298,61 +369,24 @@ find_l_searchlist(rd_agent_t *rd)
 	 * We search in the primary link map, because we know this must exist if
 	 * any do, and that all the link maps will use the same offset for
 	 * l_seachlist.
-	 *
-	 * Iterate through the link maps twice: once to count the number of
-	 * maps, the second time to remember their addresses.
 	 */
-	size_t nmaps = 0;
-	uintptr_t first_loadobj, loadobj;
-	struct link_map map;
+	uintptr_t first_map_addr;
+	uintptr_t *map_addrs;
+	size_t nmaps;
 
 	_dprintf("%i: Finding l_searchlist\n", rd->P->pid);
 
-	if ((first_loadobj = first_link_map(rd, 0)) == 0)
+	if ((first_map_addr = first_link_map(rd, 0)) == 0)
 		return -1;
 
-	for (loadobj = first_loadobj; loadobj != 0;
-	     loadobj = (uintptr_t)map.l_next) {
-		nmaps++;
-		if (rd_get_link_map(rd, &map, loadobj) == NULL)
-			break;
-	}
-
-	_dprintf("%i: Counted %zi link maps\n", rd->P->pid, nmaps);
-	if (nmaps == 0)
+	if ((map_addrs = find_link_maps(rd, &nmaps)) == NULL)
 		return -1;
 
 	/*
 	 * After this point, we must not call anything which, even transitively,
 	 * calls Pwait(), since that may longjmp out if an execve() is detected,
 	 * and leak map_addrs.
-	 */
-
-	uintptr_t *map_addrs;
-	uintptr_t *mapp;
-
-	map_addrs = calloc(nmaps, sizeof(uintptr_t));
-	if (!map_addrs) {
-		_dprintf("Out of memory locating glibc searchlist "
-		    "when allocating room for %li link maps\n", nmaps);
-		return -1;
-	}
-
-	for (mapp = map_addrs,
-		 loadobj = first_link_map(rd, 0);
-	     loadobj != 0;
-	     loadobj = (uintptr_t)map.l_next, mapp++) {
-
-		_dprintf("%i: Noted map at %lx\n", rd->P->pid, loadobj);
-
-		*mapp = loadobj;
-		if (rd_get_link_map(rd, &map, loadobj) == NULL)
-			break;
-	}
-
-	qsort(map_addrs, nmaps, sizeof(uintptr_t), ascending_uintptrs);
-
-	/*
+	 *
 	 * We now have the primary link maps' addresses in a rapidly searchable
 	 * form.  Search forward in the first link map from the offset of
 	 * l_searchlist in glibc 2.12 (an optimization, since it is implausible
@@ -389,7 +423,7 @@ find_l_searchlist(rd_agent_t *rd)
 	uintptr_t scan;
 	uintptr_t scan_next;
 
-	scan = first_loadobj;
+	scan = first_map_addr;
 	scan += rd->P->elf64 ? L_SEARCHLIST_64_OFFSET : L_SEARCHLIST_32_OFFSET;
 	scan_next = scan + (rd->P->elf64 ? L_NEXT_64_SIZE : L_NEXT_32_SIZE);
 
@@ -400,9 +434,9 @@ find_l_searchlist(rd_agent_t *rd)
 		unsigned int poss_l_searchlist_r_nlist;
 
 		_dprintf("%i: scanning from link_map offset %lx\n", rd->P->pid,
-		    scan - first_loadobj);
+		    scan - first_map_addr);
 
-		if ((scan - first_loadobj) > 65535)
+		if ((scan - first_map_addr) > 65535)
 			break;
 
 		if (Pread_scalar_quietly(rd->P, &poss_l_searchlist_r_list,
@@ -464,7 +498,7 @@ find_l_searchlist(rd_agent_t *rd)
 
 		if (!unmatched) {
 			free(map_addrs);
-			rd->l_searchlist_offset = scan - first_loadobj;
+			rd->l_searchlist_offset = scan - first_map_addr;
 			_dprintf("%i: found l_searchlist at offset %zi\n",
 			    rd->P->pid, rd->l_searchlist_offset);
 			return 0;
-- 
2.36.1.263.g194b774378.dirty




More information about the DTrace-devel mailing list