我有一个现代的 Linux 桌面,其中有许多进程同时运行。其中一个进程(我不知道是哪一个)调用some_func
流行动态库中的函数some_lib
(想想libc
或libx11
,所以一个很多的进程使用它),我想知道哪个进程执行此操作(理想情况下,有每次调用的堆栈跟踪)。
如何确定哪个进程调用some_lib
?
到目前为止我考虑过的选项:
- 使用
ltrace
orlatrace
:有一个ltrace
-style 详细列表,列出我感兴趣的函数调用的进程以及哪些参数将是完美的,但ltrace
仅适用于单个进程或进程组。我不能只输入ltrace -e some_func@some_lib -fp 1
并查看系统范围内的所有用途。 - 找到哪些进程使用我的库
lsof
,然后继续步骤1:这将非常麻烦,因为有太多进程使用同一个库,但不调用所述函数。 grep -r some_func /usr
,然后看看是否只有几个二进制文件能够调用该函数,然后从那里开始工作。虽然那可以在某些有限的情况下工作,这绝不是一个通用的解决方案,并且如果egsome_func
在各种二进制文件中普遍存在但很少被调用,则不会工作。- 使用内核审计系统。如果我正在跟踪系统调用,我可以输入
auditctl -S some_syscall ...
,这将在记录系统范围的调用中发挥作用。然而,auditctl
似乎无法做到与库函数。 - 终于,我可以重建库,向我感兴趣的函数添加一个新行,该行将记录其所有调用。虽然这可以保证解决我的问题,但该解决方案会很麻烦,需要修改/重新编译库,并且需要至少重新启动两次才能推出检测库并在找到罪魁祸首后将其回滚。
有更容易的方法吗?
(我想指出,这是一个一般性问题,并且我最感兴趣的是可行的一般解决方案。)
我找到了一个不错的比较文章提到一些我不知道的追踪设施,这些设施可能值得探索。
答案1
带有debuginfo的SystemTap可以跟踪库中的函数调用;在 Centos 7 系统上:
$ sudo stap -L 'process("/lib64/libglib*").function("*strndup*")'
process("/usr/lib64/libglib-2.0.so.0.5000.3").function("g_strndup")
$
这可以用作probe
打印回溯或任何您想要的可以用 SystemTap 编写的点:
probe begin {
printf("ok\n")
}
probe process("/usr/lib64/libglib-2.0.so.0.5000.3").function("g_strndup") {
/* printf("%s[%d]\n", execname(), pid()) */
print_usyms(ubacktrace())
}
保存为probelibraryfunc.stp
可以通过以下方式运行
$ sudo stap probelibraryfunc.stp
尽管如果调用很常见,可能会产生大量的输出......