Программно определить общие библиотеки в использовании, запустив приложение - PullRequest
2 голосов
/ 27 января 2012

Можно ли (и если да, то как) определить общие библиотеки приложения, которые используются приложением во время выполнения ?В принципе, могу ли я программно получить вывод ldd?Предпочтительное решение C / C ++ не просто переходит к выполнению ldd в командной строке.

Обратите внимание на следующее: у меня есть приложение драйвера, которое вызывает doAction() из общей библиотеки libfoo.Я компилирую приложение один раз, а затем устанавливаю LD_LIBRARY_PATH в соответствующий каталог, содержащий libfoo с определенным символом doAction().Таким образом, у меня может быть несколько реализаций doAction() в разных libfoo с, но я могу скомпилировать приложение только один раз.

Реальным примером может быть профессор, у которого класс студентов реализует doAction().Вместо того, чтобы составлять тестовый комплект для реализации каждого ученика doAction(), студенты отправляют общую библиотеку, и профессор может просто изменить LD_LIBRARY_PATH, чтобы оценить каждого ученика.

Моя цель в получении библиотеки, используемой в настоящее времявыполнить md5sum в библиотеке во время выполнения, чтобы убедиться, что я вызываю правильную библиотеку.В надуманном примере все учащиеся передали бы md5sum своей библиотеки, и профессор мог сопоставить студенту выполняемый исполняемый файл + совместно используемую библиотеку (поиск в базе данных, запись в файл, ...), чтобы предотвратить несчастный случай при настройке LD_LIBRARY_PATH влияет на оценку другого ученика (забыл изменить LD_LIBRARY_PATH на каталог Дэвида и снова побежал с libfoo Билла).

Ответы [ 5 ]

4 голосов
/ 27 января 2012

Поскольку похоже, что вы используете что-то UNIX-y, просто используйте dlopen вместо динамического связывания приложения драйвера с отсутствующим символом.

Полная последовательность:

  1. перебирать все представленные имена файлов .so библиотеки (возможно, у вас есть один каталог с studentname.so или чем-то еще)
  2. загрузить каждую библиотеку
  3. получить функцию точки входа
  4. назовите это
  5. выгрузить библиотеку (необязательно, я думаю)

вроде так:

void *lib = dlopen(filename, RTLD_LOCAL);
void *libfun = dlsym(lib, "doAction");
if (libfun == NULL)
    cout << "student failed by not providing doAction() in " << filename << endl;
else {
    void (*doAction)(void) = (void (*)(void)) libfun;
    // no, I can't remember the correct syntax for casting to function pointer
    cout << "calling " << filename << ":doAction()" << endl;
    doAction();
    // is there some way to tell if it succeeded?
    cout << "unloading " << filename << endl;
    dlclose(lib);
}

Примечания:

  • если интерфейс в каждом случае один и тот же (т. Е. void (*)()), вы можете сделать это настраиваемым по имени каталога и имени символа, и он будет работать более чем для одного теста
  • на самом деле, если интерфейс НЕ тот, который вы ожидаете, приведение указателя функции будет делать ужасные вещи, поэтому будьте осторожны с этим
  • наконец, если ученик использовал C ++, его символ имени функции будет искажен. Скажите им объявить точку входа как extern "C" void doAction(), чтобы избежать этого.
  • флаг RTLD_LOCAL должен остановить что-либо в библиотеке одного студента, мешающее другому (если вы не выгружаете), но есть другие флаги, которые может быть разумно добавить
    • в частности, RTLD_NOW приведет к сбою dlopen, если в библиотеке ученика есть неразрешенная внешняя ссылка, которую он не может выяснить (так что вы можете справиться с ней изящно, отказав им): в противном случае ваша программа может просто аварийно завершиться, когда Вы звоните doAction.

Хотя я думаю, что вышеупомянутое лучше , чем решение, с которым вы напрямую обращаетесь за помощью, я также нашел ссылку на dl_iterate_phdr при двойной проверке документации. Если вы используете Linux специально, и если dl_phdr_info.dlpi_name - это имя файла ... вы можете получить его таким образом.

Я все еще думаю, что это намного уродливее.

3 голосов
/ 27 января 2012

Если вы используете Linux, вы можете использовать функцию dl_iterate_phdr:

Функция dl_iterate_phdr () позволяет приложению запрашивать во время выполнения, чтобы выяснить, какие общие объекты оно загрузило.

http://linux.die.net/man/3/dl_iterate_phdr

2 голосов
/ 27 января 2012

Во время выполнения это не приложение, это процесс.

Если процесс имеет pid 1234, вы можете получить его карту памяти, прочитав /proc/1234/maps (или /proc/1234/smaps, что более подробно). На этой карте перечислены, в частности, файлы mmap (в частности, общие библиотеки). Из приложения прочитайте /proc/self/maps

Попробуйте

   grep so /proc/self/maps

чтобы понять, что я имею в виду.

Кстати, если у вас есть адрес, функция dladdr дает информацию о ближайшем символе и общем объекте ...

1019 * добавления * И как ответил Роб Мэйофф , dl_iterate_phdr , вероятно, лучшее решение для Linux

1 голос
/ 27 января 2012

Если это Linux (я сомневаюсь, что для этого есть общий способ POSIX, но я могу ошибаться), вас может заинтересовать содержимое / proc / (pid) / maps.Это дает диапазоны отображаемой памяти для вашего процесса, и вы можете искать, в какие диапазоны попадает адрес вашей функции md5sum ().

0 голосов
/ 27 января 2012

Если вы используете Linux / Unix, вы можете использовать strace , как strace -o strace.log -f students_binary.Strace отслеживает все системные вызовы, включая вызовы для открытия библиотеки.Затем вы можете проанализировать strace.log для всех открытий любого файла и выполнить md5sum для всех открытых файлов.

...