Can anyone help me with finding out how can I obtain the address space of a dynamically loaded library?
The context:
I'm loading a shared library using dlopen
and at some other point I want to track down malloc
calls, but only these which were triggered by this library.
What I'm doing right now is in the malloc
hook I have, I'm going through the whole callstack (obtained by backtrace
) and using dladdr
I'm checking each function pointer to see if it comes from my shared library or not, but it's extremely slow.
I thought that maybe if I care only about the one lib which I'm loading manually I can just get its address space, like it is in the memory maps output:
$ cat /proc/2049/maps | head
00400000-007a8000 r-xp 00000000 08:01 526896 /usr/bin/python3.5
009a8000-009aa000 r--p 003a8000 08:01 526896 /usr/bin/python3.5
...
and see if the function address from the callstack is contained in this address space? It should be much faster I guess... How can I do that? Maybe I can get .text
symbol address of the lib using dlsym
(since I care only on address of the executable code), but how calculate the size then?
In your interposed functions, you can use uintptr_t caller_address = (uintptr_t)__builtin_extract_return_addr(__builtin_return_address(0));
to obtain the address of the caller.
To find out which addresses are from which ELF files, either parse /proc/self/maps
, or use dl_iterate_phdr()
. For example:
#define _POSIX_C_SOURCE 200809L
#define _GNU_SOURCE
#include <stdlib.h>
#include <link.h>
#include <string.h>
#include <stdio.h>
static int iterator(struct dl_phdr_info *info, size_t size, void *data)
{
const char *name;
size_t headers, h;
/* Empty name refers to the binary itself. */
if (!info->dlpi_name || !info->dlpi_name[0])
name = (const char *)data;
else
name = info->dlpi_name;
headers = info->dlpi_phnum;
for (h = 0; h < headers; h++)
if ((info->dlpi_phdr[h].p_type == PT_LOAD) &&
(info->dlpi_phdr[h].p_memsz > 0) &&
(info->dlpi_phdr[h].p_flags)) {
const uintptr_t first = info->dlpi_addr + info->dlpi_phdr[h].p_vaddr;
const uintptr_t last = first + info->dlpi_phdr[h].p_memsz - 1;
/* Addresses first .. last, inclusive, belong to binary 'name'. */
printf("%s: %lx .. %lx\n", name, (unsigned long)first, (unsigned long)last);
}
return 0;
}
int main(int argc, char *argv[])
{
if (dl_iterate_phdr(iterator, argv[0])) {
fprintf(stderr, "dl_iterate_phdr() failed.\n");
exit(EXIT_FAILURE);
}
...