7

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

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

但是,启用调试符号 ( -g) 后,类似addr2line和的程序gdb仍然可以获取静态函数的名称。有没有办法从进程本身以编程方式获取静态函数的名称?

4

2 回答 2

3

/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=Cand 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.

于 2013-09-08T03:00:56.353 回答
3

如果您的可执行文件(和链接库)是使用调试信息编译的(即带有-g标记为gccor ),那么您可以从 GCC 内部g++使用 Ian Taylor (在此处libbacktrace宣布)-在此处查看其代码

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

请注意,如果您使用优化进行编译,某些函数可能会被内联(即使没有inline在源代码中显式标记,并且static内联函数可能没有任何适当的自己的代码)。然后回溯不会告诉他们太多。

于 2013-09-08T14:22:15.890 回答