Перечислите все функции / символы на лету в коде C на архитектуре Linux?

Предполагать main.c использует символы из общих библиотек и локальных функций, объявленных в main.c,

Есть хороший и элегантный способ напечатать список всех доступных имен функций и символов во время выполнения?

Это должно быть возможно, так как данные загружаются в .code сегмент.

23

Решение

Поскольку у меня была такая же необходимость извлекать все загруженные имена символов во время выполнения, я провел некоторое исследование, основанное на ответе R .. Итак, вот подробное решение для совместно используемых библиотек linux в формате ELF, которое работает с моим gcc 4.3.4, но, надеюсь, также с более новыми версиями.

В основном я использовал следующие источники для разработки этого решения:

А вот и мой код. Я использовал самоочевидные имена переменных и добавил подробные комментарии, чтобы сделать его понятным. Если что-то не так или отсутствует, пожалуйста, дайте мне знать …
(Edit: я только что понял, что вопрос был для C, и мой код для C ++. Но если вы пропустите вектор и строку, это должно работать и для C)

#include <link.h>
#include <string>
#include <vector>

using namespace std;

/* Callback for dl_iterate_phdr.
* Is called by dl_iterate_phdr for every loaded shared lib until something
* else than 0 is returned by one call of this function.
*/
int retrieve_symbolnames(struct dl_phdr_info* info, size_t info_size, void* symbol_names_vector)
{

/* ElfW is a macro that creates proper typenames for the used system architecture
* (e.g. on a 32 bit system, ElfW(Dyn*) becomes "Elf32_Dyn*") */
ElfW(Dyn*) dyn;
ElfW(Sym*) sym;
ElfW(Word*) hash;

char* strtab = 0;
char* sym_name = 0;
ElfW(Word) sym_cnt = 0;

/* the void pointer (3rd argument) should be a pointer to a vector<string>
* in this example -> cast it to make it usable */
vector<string>* symbol_names = reinterpret_cast<vector<string>*>(symbol_names_vector);

/* Iterate over all headers of the current shared lib
* (first call is for the executable itself) */
for (size_t header_index = 0; header_index < info->dlpi_phnum; header_index++)
{

/* Further processing is only needed if the dynamic section is reached */
if (info->dlpi_phdr[header_index].p_type == PT_DYNAMIC)
{

/* Get a pointer to the first entry of the dynamic section.
* It's address is the shared lib's address + the virtual address */
dyn = (ElfW(Dyn)*)(info->dlpi_addr +  info->dlpi_phdr[header_index].p_vaddr);

/* Iterate over all entries of the dynamic section until the
* end of the symbol table is reached. This is indicated by
* an entry with d_tag == DT_NULL.
*
* Only the following entries need to be processed to find the
* symbol names:
*  - DT_HASH   -> second word of the hash is the number of symbols
*  - DT_STRTAB -> pointer to the beginning of a string table that
*                 contains the symbol names
*  - DT_SYMTAB -> pointer to the beginning of the symbols table
*/
while(dyn->d_tag != DT_NULL)
{
if (dyn->d_tag == DT_HASH)
{
/* Get a pointer to the hash */
hash = (ElfW(Word*))dyn->d_un.d_ptr;

/* The 2nd word is the number of symbols */
sym_cnt = hash[1];

}
else if (dyn->d_tag == DT_STRTAB)
{
/* Get the pointer to the string table */
strtab = (char*)dyn->d_un.d_ptr;
}
else if (dyn->d_tag == DT_SYMTAB)
{
/* Get the pointer to the first entry of the symbol table */
sym = (ElfW(Sym*))dyn->d_un.d_ptr;/* Iterate over the symbol table */
for (ElfW(Word) sym_index = 0; sym_index < sym_cnt; sym_index++)
{
/* get the name of the i-th symbol.
* This is located at the address of st_name
* relative to the beginning of the string table. */
sym_name = &strtab[sym[sym_index].st_name];

symbol_names->push_back(string(sym_name));
}
}

/* move pointer to the next entry */
dyn++;
}
}
}

/* Returning something != 0 stops further iterations,
* since only the first entry, which is the executable itself, is needed
* 1 is returned after processing the first entry.
*
* If the symbols of all loaded dynamic libs shall be found,
* the return value has to be changed to 0.
*/
return 1;

}

int main()
{
vector<string> symbolNames;
dl_iterate_phdr(retrieve_symbolnames, &symbolNames);

return 0;
}
19

Другие решения

В динамически связанных системах ELF у вас может быть функция dl_iterate_phdr имеется в наличии. Если это так, его можно использовать для сбора информации о каждом загруженном файле совместно используемой библиотеки, а получаемой информации достаточно для изучения таблиц символов. Процесс в основном:

  1. Получить адрес заголовков программы от dl_phdr_info структура перешла к вам.
  2. Использовать PT_DYNAMIC заголовок программы, чтобы найти _DYNAMIC стол для модуля.
  3. Использовать DT_SYMTAB, DT_STRTAB, а также DT_HASH записи из _DYNAMIC найти список символов. DT_HASH нужен только для получения длины таблицы символов, так как она, кажется, не хранится где-либо еще.

Все типы, которые вам нужны, должны быть в <elf.h> а также <link.h>,

11

Это на самом деле не специфично для C, но для операционной системы и двоичного формата и (для отладки символов и не исправленных имен символов C ++) даже для конкретного вопроса компилятора. Здесь нет общего, а также действительно элегантного способа.

Наиболее переносимым и перспективным способом, вероятно, является запуск внешней программы, такой как nm, который находится в POSIX. Версия GNU найденный в Linux, вероятно, имеет множество расширений, которых вам следует избегать, если вы стремитесь к переносимости и будущему.

Его вывод должен оставаться стабильным, и даже если двоичные форматы изменятся, он также будет обновляться и продолжать работать. Просто запустите его с правильными переключателями, захватите его вывод (возможно, запустив его через popen чтобы избежать временного файла) и разобрать это.

6

Так должно быть dl_iterate_phdr(retrieve_symbolnames, &symbolNames);

1
По вопросам рекламы [email protected]