通过运行应用程序以编程方式确定正在使用的共享库

是否有可能(以及如果是这样,如何)确定应用程序在运行时使用的应用程序的共享库? 基本上,我可以通过编程方式获得ldd的输出吗? 首选的C / C ++解决方案不仅仅是跳转到命令行执行ldd。

请考虑以下内容:我有一个驱动程序应用程序从共享库libfoo调用doAction() 。 我编译应用程序一次,然后将LD_LIBRARY_PATH设置为包含定义了doAction()符号的libfoo的相应目录。 这样,我可以在不同的libfoo有多个doAction()实现,但只能编译一次应用程序。

一个现实世界的例子是教授有一类学生实现doAction() 。 学生不是为每个学生的doAction()实现编译测试工具,而是提交一个共享库,教授可以简单地改变LD_LIBRARY_PATH来评估每个学生。

我获取当前正在使用的库的目标是在运行时对库执行md5sum以确保我调用正确的库。 在人为设计的例子中,所有学生都会提交他们图书馆的md5sum ,教授可以将正在运行的可执行文件+共享库(数据库查找,登录文件,…)与学生相匹配,以防止设置LD_LIBRARY_PATH影响另一个人时发生意外学生的成绩(忘记将LD_LIBRARY_PATH更改为David的目录并使用Bill的libfoo再次libfoo )。

由于看起来你正在使用UNIX-y,只需使用dlopen而不是动态链接你的驱动程序应用程序与丢失的符号。

完整序列是:

  1. 以某种方式迭代所有提交的.so库文件名(也许你有一个带有studentname.so的目录)
  2. 加载每个库
  3. 获得入口点function
  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标志应该阻止一个学生的库中的任何内容干扰另一个(如果你没有卸载),但是有其他标志可能是明智的添加
    • 具体来说,如果学生lib有一个无法解决的未解析的外部引用, RTLD_NOW将导致dlopen失败(所以你可以通过失败来优雅地处理它):否则你的程序可能会在你调用doAction时崩溃。

虽然我认为上述内容比您直接寻求帮助的解决方案更好 ,但我还在重复检查文档时找到了对dl_iterate_phdr的引用。 如果您专门使用Linux,并且dl_phdr_info.dlpi_name实际上是文件名...您可能能够以这种方式获得它。

不过,我仍然认为这更加丑陋。

如果您使用的是Linux,则可以使用dl_iterate_phdr函数:

dl_iterate_phdr()函数允许应用程序在运行时查询以找出它已加载的共享对象。

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

在运行时,它不是一个应用程序,它是一个过程。

如果进程有pid 1234,你可以通过读取/proc/1234/maps (或/proc/1234/smaps更详细)来获取其内存映射。 该映射特别列出了mmap -ed文件(特别是共享库)。 从应用程序内部,读取/proc/self/maps

尝试

  grep so /proc/self/maps 

了解我的意思。

顺便说一下,如果你有一个地址, dladdr函数会提供有关最近的符号和共享对象的信息……

附加物

正如Rob Mayoff 回答的那样 , dl_iterate_phdr可能是Linux上最好的解决方案

如果这是Linux(我怀疑有一种通用的POSIX方法可以做到这一点,但我可能错了),你可能会对/ proc /(pid)/ maps的内容感兴趣。 这为您的进程提供了映射的内存范围,您可以搜索md5sum()函数的地址属于哪个范围。

如果你在linux / unix中,你可以像strace -o strace.log -f students_binary一样使用strace 。 Strace跟踪所有系统调用,包括打开库的调用。 然后你可以解析任何文件的所有开口的strace.log并在所有打开的文件上执行md5sum