替代Linux上的backtrace(),可以找到静态函数的符号

use*_*117 6 c linux debugging backtrace

在手册页中,backtrace()Linux上的函数说:

请注意,"静态"函数的名称不会公开,并且在回溯中不可用.

然而,启用调试符号(-g),程序等addr2line,并gdb仍然可以得到的静态函数的名称.有没有办法从进程内部以编程方式获取静态函数的名称?

Nom*_*mal 3

是的,通过使用例如或 ELF 文件解析库检查其自己的可执行文件 ( /proc/self/exe) libbfd,来解析实际的符号本身。本质上,您将编写 C 代码,其功能相当于

env LANG=C LC_ALL=C readelf -s executable  | awk '($5 == "LOCAL" && $8 ~ /^[^_]/ && $8 !~ /\./)'
Run Code Online (Sandbox Code Playgroud)

据我所知,Linux ( <dlfcn.h>) 中的动态链接器接口不返回静态(本地)符号的地址。

一个简单且相当强大的方法是从您的程序执行readelf或。objdump请注意,您不能/proc/self/exe为这些文件提供伪文件路径,因为它始终引用进程自己的可执行文件。相反,你必须使用例如。realpath("/proc/self/exe", NULL)要获取当前可执行文件的动态分配的绝对路径,您可以提供给命令。您还肯定希望确保环境包含LANG=CLC_ALL=C,以便命令的输出易于解析(并且不会本地化为当前用户喜欢的任何语言)。这可能感觉有点笨拙,但它只需要binutils安装软件包即可工作,并且您不需要更新程序或库来跟上最新的发展,所以我认为这总体上是一个非常好的方法。

你想要一个例子吗?

使其更容易的一种方法是在编译时生成带有符号信息的单独数组。基本上,生成目标文件后,通过运行objdumpreadelf遍历相关目标文件动态生成一个单独的源文件,生成类似于以下内容的名称和指针数组

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 }
};
Run Code Online (Sandbox Code Playgroud)

也许可以在头文件中导出一个简单的搜索函数,这样当链接最终的可执行文件时,它可以轻松有效地访问本地符号数组。

它确实重复了一些数据,因为相同的信息已经存在于可执行文件中,如果我没记错的话,您必须首先将最终的可执行文件与存根数组链接起来以获得符号的实际地址,然后重新链接符号数组,这使得编译时有点麻烦。但它避免了运行时对binutils.