在手册页中,Linux 上的 backtrace()
函数说:
Note that names of "static" functions are not exposed, and won't be available in the backtrace.
但是,启用调试符号(-g
)后,addr2line
和gdb
等程序仍然可以获取静态函数的名称。有没有办法从进程本身内部以编程方式获取静态函数的名称?
最佳答案
是的,通过使用例如检查它自己的可执行文件(/proc/self/exe
) libbfd
或 ELF 文件解析库,以解析实际符号本身。本质上,您将编写 C 代码来执行类似
env LANG=C LC_ALL=C readelf -s executable | awk '($5 == "LOCAL" && $8 ~ /^[^_]/ && $8 !~ /\./)'
据我所知,Linux 中的动态链接器接口(interface) ( <dlfcn.h>
) 不返回静态(本地)符号的地址。
一个简单而强大的方法是执行 readelf
或 objdump
从你的程序。请注意,您不能提供 /proc/self/exe
那些的伪文件路径,因为它总是指进程自己的可执行文件。相反,您必须使用例如。 realpath("/proc/self/exe", NULL)
获取可提供给命令的当前可执行文件的动态分配绝对路径。您肯定还想确保环境包含 LANG=C
和 LC_ALL=C
,以便命令的输出易于解析(并且不会本地化为当前用户喜欢的任何语言)。这可能感觉有点笨拙,但它只需要 binutils
安装包即可工作,您无需更新程序或库即可跟上最新发展,因此我认为总体而言这是一种非常好的方法。
你想要一个例子吗?
使它更容易的一种方法是在编译时生成带有符号信息的单独数组。基本上,生成目标文件后,通过运行 objdump
动态生成一个单独的源文件。或 readelf
在相关的目标文件上,生成一个名称和指针数组,类似于
const struct {
const char *const name;
const void *const addr;
} local_symbol_names[] = {
/* Filled in using objdump or readelf and awk, for example */
{ NULL, NULL }
};
也许在头文件中导出一个简单的搜索功能,以便在链接最终可执行文件时,它可以轻松高效地访问本地符号数组。
它确实复制了一些数据,因为相同的信息已经存在于可执行文件中,如果我没记错的话,你必须首先将最终的可执行文件与 stub 数组链接以获得符号的实际地址,然后重新链接使用符号数组,使其在编译时有点麻烦。但它避免了运行时对 binutils
的依赖。 .
关于c - 替代 Linux 上的 backtrace() 可以找到静态函数的符号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18679567/