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

时间:2013-09-08 01:34:22

标签: c linux debugging backtrace

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

  

请注意“静态”功能的名称       没有暴露,并且在回溯中不可用。

但是,启用调试符号(-g)后,addr2linegdb等程序仍可获取静态函数的名称。有没有办法从过程本身中以编程方式获取静态函数的名称?

2 个答案:

答案 0 :(得分:3)

如果您的可执行文件(和链接库)使用调试信息进行编译(即-g标记为gccg++),那么您可以使用Ian Taylor的libbacktrace(从GCC内部宣布here) - 请参阅其代码here

该库(BSD许可的免费软件)正在使用来自该进程链接的可执行文件和共享库的DWARF调试信息。请参阅其README文件。

请注意,如果使用优化进行编译,则可以内联某些函数(即使没有在源代码中明确标记inline,并且static内联函数可能没有任何适当的自己的代码)。然后回溯不会说明它们。

答案 1 :(得分:2)

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

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

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

一种简单而强大的方法是从您的程序中执行readelfobjdump。请注意,您不能将/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 }
};

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

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