有人可以帮助我了解如何获取动态加载的库的地址空间吗?
上下文:
我正在使用dlopen
加载共享库,而在其他时候,我想跟踪malloc
调用,但仅跟踪由该库触发的调用。
我现在正在做的是在我拥有的malloc
钩子中,我正在遍历整个调用栈(由backtrace
获得)并使用dladdr
进行检查每个函数指针以查看它是否来自我的共享库,但这非常慢。
我认为,如果我只关心手动加载的一个库,就可以得到它的地址空间,就像它在内存映射输出中一样:
$ 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
...
并查看该地址空间中是否包含来自调用堆栈的函数地址?我猜应该会快得多...我该怎么办?也许我可以使用.text
获得lib的dlsym
符号地址(因为我只关心可执行代码的地址),但是如何计算大小呢?
答案 0 :(得分:1)
在插入的函数中,可以使用uintptr_t caller_address = (uintptr_t)__builtin_extract_return_addr(__builtin_return_address(0));
获取呼叫者的地址。
要找出哪些地址来自哪个ELF文件,请解析/proc/self/maps
或使用dl_iterate_phdr()
。例如:
#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);
}
...