通过运行应用程序以程序方式确定正在使用的共享库
Programatically determine shared libraries in use by running application
是否可以(如果可以,如何)确定应用程序在运行时使用的应用程序的共享库?基本上,我可以通过编程获得ldd
的输出吗?首选的C/C++解决方案不仅仅是跳转到命令行上执行ldd。
考虑以下内容:我有一个驱动程序应用程序,它从共享库libfoo
调用doAction()
。我编译了一次应用程序,然后将LD_LIBRARY_PATH
设置到一个适当的目录中,该目录包含定义了doAction()
符号的libfoo
。这样,我可以在不同的libfoo
中实现多个doAction()
,但只能编译一个应用程序一次。
一个真实世界的例子是一位教授让一班学生实现doAction()
。学生们提交了一个共享库,教授可以简单地更改LD_LIBRARY_PATH
来评估每个学生,而不是针对每个学生的doAction()
实现编写一个测试工具。
我获取当前使用的库的目标是在运行时对库执行md5sum
,以确保我调用的是正确的库。在这个设计的例子中,所有学生都会提交他们图书馆的md5sum
,教授可以将正在运行的可执行文件+共享图书馆(数据库查找、日志到文件…)匹配给学生,以防止设置LD_LIBRARY_PATH
时发生意外影响另一个学生的成绩(忘记将LD_LIBRARY_PATH
更改为David的目录,并使用Bill的libfoo
再次运行)。
因为看起来你在使用UNIX-y,所以只需使用dlopen
,而不是针对缺失的符号动态链接驱动程序应用程序。
完整序列为:
- 以某种方式迭代所有提交的.so库文件名(也许您有一个带有studentname.so之类的目录)
- 加载每个库
- 获取入口点函数
- 称之为
- 卸载库(我想是可选的)
像这样:
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
失败(所以你可以通过失败来优雅地处理它):否则,当你调用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
。
- Android NDK:用于第三方Java库的静态或共享C++运行时
- 当 2 个线程共享同一物理内核时,具有错误共享的易失性增量在发布中的运行速度比在调试中慢
- 运行程序时找不到共享对象库,但在编译过程中链接了它
- 运行可执行文件时找不到共享库,即使共享库存在于指定的路径中
- 使用运行时参数与编译时参数在类之间共享代码
- Qt应用程序在运行时找不到共享库
- 当从共享库运行时,为什么此Android NDK代码崩溃
- 根据用户配置在运行时链接共享对象
- 在运行时动态加载共享库
- 在运行时找不到共享对象.克尔普克
- 运行配置以生成共享库 [Ubuntu]
- 管理Boost::运行时共享库之间的任意
- 如何在linux x64上创建共享库对象,该对象内部使用C++异常,并且可以在旧平台上运行
- 运行时共享库是否可以调用现有符号
- 在64位Ubuntu 12.04上运行aapt:加载共享库时出错:libc++.所以:没有这样的文件或目录
- C++:运行时将共享对象与主机应用程序链接,符号表问题
- 需要有关在类之间共享变量的 OOP 设计的帮助,这些变量单独使用计时器运行
- 动态提升线程运行存储在具有共享指针的向量中的对象的方法
- 使用nVIDIA编译器为我的GNU编译器生成要链接的共享库时发生运行时错误
- log4cplus库是否支持Android的c++共享运行库