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

Kris Van Hees kris.van.hees at oracle.com
Fri May 20 19:25:06 UTC 2022


On Wed, May 11, 2022 at 10:12:44PM +0100, Nick Alcock via DTrace-devel wrote:
> 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>

Reviewed-by: Kris Van Hees <kris.van.hees at oracle.com>

... and I'll put it on dev

> ---
>  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
> 
> 
> _______________________________________________
> DTrace-devel mailing list
> DTrace-devel at oss.oracle.com
> https://oss.oracle.com/mailman/listinfo/dtrace-devel



More information about the DTrace-devel mailing list