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

时间:2012-01-27 18:35:24

标签: c++ c shared-libraries ldd

是否有可能(如果是,如何)确定应用程序在运行时使用的应用程序的共享库?基本上,我可以通过编程方式获得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更改为David的目录,然后使用Bill的libfoo再次运行。

5 个答案:

答案 0 :(得分:4)

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

完整序列是:

  1. 以某种方式迭代所有提交的.so库文件名(也许你有一个目录 studentname.so 或其他东西)
  2. 加载每个库
  3. 获取入口点功能
  4. 称之为
  5. 卸载库(可选,我猜)
  6. 像这样:

    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失败,如果学生lib有一个无法解决的未解析的外部引用(所以你可以通过失败来优雅地处理它):否则你的程序当你拨打doAction时可能会崩溃。

    虽然我认为上面的更好比你直接寻求帮助的解决方案,但我还是在仔细检查文档的同时找到了对dl_iterate_phdr的引用。如果您专门使用Linux,并且dl_phdr_info.dlpi_name实际上是文件名...您可能会这样做。

    但我仍然认为这更加丑陋。

答案 1 :(得分:3)

如果您使用的是Linux,则可以使用dl_iterate_phdr功能:

  

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

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

答案 2 :(得分:2)

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

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

尝试

   grep so /proc/self/maps

了解我的意思。

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

附加物

正如Rob Mayoff answereddl_iterate_phdr可能是Linux上最好的解决方案

答案 3 :(得分:1)

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

答案 4 :(得分:0)

如果您使用的是linux / unix,则可以使用strace -o strace.log -f students_binary之类的strace。 Strace跟踪所有系统调用,包括打开库的调用。然后,您可以为任何文件的所有空缺解析strace.log,并对所有打开的文件执行md5sum