如何在Linux架构上即时列出C代码中可用的所有功能/符号?

问题描述 投票:24回答:5

假定main.c使用来自共享库的符号和在main.c中声明的局部函数。

是否有一种很好的,优雅的方法可以在运行时打印所有可用函数名称和符号的列表?

由于数据已加载到.code段,因此应该是可能的。

c++ c linux symbols elf
5个回答
26
投票
我主要使用以下资源来开发此解决方案:

ELF Manpage

  • 这是我的代码。我使用自解释变量名并添加了详细注释以使其易于理解。如果有问题或遗失,请通知我...(编辑:我刚刚意识到问题是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; }

  • 11
    投票

    从传递回给您的dl_phdr_info结构中获取程序头的地址。

      使用PT_DYNAMIC程序头查找模块的_DYNAMIC表。
    1. 使用DT_SYMTABDT_STRTABDT_HASH_DYNAMIC条目查找符号列表。仅需要DT_HASH即可获得符号表的长度,因为它似乎没有存储在其他任何地方。
  • 您需要的类型都应该在<elf.h><link.h>中。

  • 6
    投票
    最可移植且面向未来的方法可能正在运行外部程序,例如POSIX中的nm。在Linuxes中发现的nm可能有许多扩展,如果您希望实现可移植性和面向未来,则应避免使用这些扩展。

    其输出应保持稳定,即使二进制格式发生更改,它也将得到更新并继续工作。只需使用正确的开关运行它,捕获其输出(可能是通过GNU version运行它以避免生成临时文件),然后对其进行解析。


    1
    投票

    1
    投票
    dl_iterate_phdr(retrieve_symbolnames, &symbolNames);
    © www.soinside.com 2019 - 2024. All rights reserved.