Получить адресное пространство динамически загружаемой библиотеки - PullRequest
0 голосов
/ 16 декабря 2018

Может ли кто-нибудь помочь мне выяснить, как я могу получить адресное пространство динамически загружаемой библиотеки?

Контекст: я загружаю общую библиотеку, используя 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 символьный адрес библиотеки, используя dlsym (поскольку меня интересует только адрес исполняемого кода), но как тогда рассчитать размер?

1 Ответ

0 голосов
/ 16 декабря 2018

В ваших встроенных функциях вы можете использовать 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);
    }

    ...
...