当前位置: 首页 > 面试题库 >

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

戈安翔
2023-03-14
问题内容

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

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

由于数据已加载到.code段中,因此应该可行。


问题答案:

由于我同样需要在运行时检索所有已加载的符号名称,因此我根据R
..的答案进行了一些研究。因此,这里是ELF格式的Linux共享库的详细解决方案,该解决方案可与我的gcc 4.3.4一起使用,但也希望与新版本一起使用。

我主要使用以下资源来开发此解决方案:

  • ELF手册页
  • 一些示例代码(在搜索“ dl_iterate_phdr”时找到了它)

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


 类似资料:
  • 问题内容: 我的系统上安装了python模块,我希望能够看到其中提供了哪些函数/类/方法。 我想在每个函数上调用doc函数。在ruby中,我可以执行类似ClassName.methods之类的操作来获取该类上所有可用方法的列表。python中是否有类似的东西? 例如。就像是: 问题答案: 该模块。另请参阅模块,交互式解释器中的功能以及生成所需文档的命令行工具。你可以为他们提供希望查看其文档的课程。

  • 问题内容: 如何列出Linux中某个组的所有成员(可能还包括其他unice)? 问题答案: 不幸的是,据我所知,没有很好的便携式方法可以做到这一点。如果您尝试解析/ etc / group(如其他人所建议的那样),则会错过以该组为主要组的用户以及通过UNIX平面文件(例如LDAP,NIS, pam-pgsql等)。 如果我绝对必须自己做,则可能相反:使用来获取系统上每个用户的组(这将使NSS看到所

  • 问题内容: 我以这种格式定义了一个.py文件: foo.py 我从另一个文件导入它: main.py 是否可以列出所有功能名称,例如? 感谢您的帮助,我为我想要的课程做了一堂课,如果有建议请发表评论 问题答案: 做这些事情的最干净的方法是使用检查模块。它具有将谓词作为第二个参数的函数。您可以用作谓词。 现在,将是一个元组列表,其中第一个元素是函数的名称,第二个元素是函数本身。

  • 问题内容: 我需要在C编程中递归列出所有目录和文件。我已经研究了FTW,但是我所使用的2个操作系统(Fedora和Minix)中没有包括。在过去的几个小时中,我从阅读的所有不同内容中开始感到头疼。 如果有人知道我的代码片段,那真是太棒了,或者如果有人可以给我很好的指导,我将不胜感激。 问题答案: 这是一个递归版本:

  • 问题内容: 我想建立一个基于php的站点,该站点在我的Ubuntu服务器上(自动)执行一些命令 我要做的第一件事是转到文件(sudoers)并添加用户www-data,以便我可以以root权限执行php命令! 然后我的PHP代码是 它仅返回一个用户(最后一个用户)!如何使其返回所有用户? 谢谢 问题答案: 从exec的PHP手册中: 返回值 命令结果的最后一行。如果您需要执行命令并直接将命令中的所

  • 问题内容: 是否可以编译无需重新编译即可在所有Linux发行版中执行的C / C ++源代码? 如果答案是肯定的,我可以使用任何外部(非标准C / C ++)库吗? 我要分发我的二进制应用程序,而不是分发源代码。 问题答案: 不,您不能编译在所有Linux发行版中执行的可执行文件。但是,您可以编译可在人们倾向于关注的大多数发行版上运行的可执行文件。 编译32位。为您愿意支持的最低CPU级别进行编译