【发布时间】:2013-09-08 01:34:22
【问题描述】:
在手册页中,Linux 上的 backtrace() 函数说:
注意“静态”函数的名称 不会暴露,并且不会在回溯中可用。
但是,启用调试符号 (-g) 后,addr2line 和 gdb 等程序仍然可以获取静态函数的名称。有没有办法从进程本身以编程方式获取静态函数的名称?
【问题讨论】:
标签: c linux debugging backtrace
在手册页中,Linux 上的 backtrace() 函数说:
注意“静态”函数的名称 不会暴露,并且不会在回溯中可用。
但是,启用调试符号 (-g) 后,addr2line 和 gdb 等程序仍然可以获取静态函数的名称。有没有办法从进程本身以编程方式获取静态函数的名称?
【问题讨论】:
标签: c linux debugging backtrace
是的,通过检查它自己的可执行文件 (/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 和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的运行时依赖。
【讨论】: