在手册页中,backtrace()
Linux 上的函数说:
请注意,“静态”函数的名称不会公开,并且不会在回溯中可用。
但是,启用调试符号 ( -g
) 后,类似addr2line
和的程序gdb
仍然可以获取静态函数的名称。有没有办法从进程本身以编程方式获取静态函数的名称?
/proc/self/exe
是的,通过使用例如libbfd
或 ELF 文件解析库检查其自己的可执行文件 ( ) 来解析实际符号本身。本质上,你会编写 C 代码来做类似的事情
env LANG=C LC_ALL=C readelf -s executable | awk '($5 == "LOCAL" && $8 ~ /^[^_]/ && $8 !~ /\./)'
据我所知,Linux ( <dlfcn.h>
) 中的动态链接器接口不返回静态(本地)符号的地址。
一种简单且相当健壮的方法是执行readelf
或objdump
从您的程序中执行。请注意,您不能为这些提供/proc/self/exe
伪文件路径,因为它始终引用进程自己的可执行文件。相反,您必须使用例如。realpath("/proc/self/exe", NULL)
要获得当前可执行文件的动态分配绝对路径,您可以提供给命令。您还绝对希望确保环境包含LANG=C
and 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 }
};
也许在头文件中导出一个简单的搜索功能,这样当最终的可执行文件被链接时,它可以轻松有效地访问本地符号数组。
它确实复制了一些数据,因为相同的信息已经在可执行文件中,如果我没记错的话,您必须首先将最终的可执行文件与存根数组链接以获得符号的实际地址,然后与符号重新链接数组,在编译时有点麻烦。但它避免了运行时对binutils
.