Как определить, какая динамическая библиотека отвечает за создание указателя?

Предположим, у вас есть программа, которая загружает несколько общих объектов/динамических библиотек с помощью dlopen(). Учитывая указатель на глобальный объект (например, статическую переменную-член), можно ли определить, на границе какой библиотеки расположен указатель?


person CommanderHK    schedule 10.11.2014    source источник
comment
Использовать отладчик, чтобы пройтись по программе и посмотреть, какой код ее выделяет?   -  person deviantfan    schedule 10.11.2014
comment
Единственный способ, который я могу придумать, - это убедиться, что каждая библиотека использует другой распределитель (malloc и свободный). Если вы можете получить доступ к таблице символов (dlopen позволяет вам это сделать) и знать ее структуру, вы, вероятно, сможете исправить импортированный символ для malloc, чтобы он указывал на выделенную функцию.   -  person didierc    schedule 10.11.2014
comment
@sashoalm Вопрос помечен для Linux   -  person simonc    schedule 10.11.2014
comment
Но если в библиотеке используются нетрадиционные распределители, будет намного сложнее. Тем не менее, это может помочь вам различать его распределения.   -  person didierc    schedule 10.11.2014
comment
Valgrind отслеживает выделения, возможно, у него есть средства и для их отладки.   -  person Basilevs    schedule 10.11.2014
comment
@devianfan Очевидно, но я искал более программный метод.   -  person CommanderHK    schedule 11.11.2014
comment
@didierc dlopen и т. д. позволяют разрешать символы и указатели друг к другу. Но когда вам нужно начать ни с того ни с сего, можете ли вы перечислить все указатели и проверить их один за другим? Перегрузка malloc и free кажется практичной идеей, но оставим ее на крайний случай.   -  person CommanderHK    schedule 11.11.2014
comment
@CommanderHK Я просто отвечал на вопрос заголовка и не обращал внимания на тело с упоминанием статической записи. Ответ о /proc/self точен. Что касается malloc отклонений, то это действительно будет работать только в случае dlopen ручного выполнения, что, конечно, не является обычным случаем (хотя обратите внимание, что это будет работать на любой ОС на базе ELF).   -  person didierc    schedule 11.11.2014


Ответы (1)


Вы можете разобрать карты процессов с файлом /proc/self/maps и посмотреть, где ограничен адрес указателя, глобальная переменная будет находиться в сегментах .data или .bss.

Пример библиотеки lib.c:

static int object;

int *
dummy(void)
{
  return &object;
}

Ошибки test.c не обрабатываются для простоты:

#include <stdio.h>
#include <dlfcn.h>
#include <unistd.h>
#include <inttypes.h>
#include <assert.h>
#include <linux/limits.h>

static void which_library(void *p);

int
main(int argc, char **argv)
{
  void *handle;
  void *object;

  handle = dlopen("./lib.so", RTLD_NOW);
  assert(handle);

  object = ((int *(*)(void)) dlsym(handle, "dummy"))();
  which_library(object);
  dlclose(handle);

  return 0;
}

static void
which_library(void *p)
{
  FILE *maps;
  char buffer[49+PATH_MAX+1];

  maps = fopen("/proc/self/maps", "r");
  assert(maps);

  while(fgets(buffer, sizeof(buffer) - 1, maps)) {
    char path[PATH_MAX+1];
    uintptr_t starts;
    uintptr_t ends;

    sscanf(buffer, "%" PRIxPTR "-%" PRIxPTR " %*s %*x %*x:%*x %*d %s", &starts, &ends, path);
    if((uintptr_t)p >= starts && (uintptr_t)p < ends) {
      printf("%p => %s\n", p, path);
      break;
    }
  }

  fclose(maps);
}

Контрольная работа:

$ gcc -Wall -shared lib.c -o lib.so 
$ gcc -Wall test.c -ldl
$ ./a.out 
0xb779f5f8 => /home/barakat/Desktop/lib.so
$ 
person Community    schedule 10.11.2014