在Linux上可以使用backtrace()来替代静态函数的符号

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

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

但是,启用debugging符号( -g )后,像addr2linegdb这样的程序仍然可以获得静态函数的名称。 有没有办法从过程本身编程获取静态function的名称?

Solutions Collecting From Web of "在Linux上可以使用backtrace()来替代静态函数的符号"

如果你的可执行文件(和链接库)是用调试信息编译的(例如用-g标志指向gccg++ ),那么你可以在GCC里使用Ian Taylor的libbacktrace ( 在这里宣布) – 在这里看到它的代码

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

请注意,如果您使用优化进行编译,则可以内联某些函数(即使没有在源代码中inline显式标记,并且static内联函数可能没有任何适当的自己的代码)。 那么回溯就不会讲很多关于他们的事情。

是的,通过使用例如libbfd或ELF文件解析库检查自己的可执行文件( /proc/self/exe )来解析实际的符号本身。 从本质上讲,你会写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依赖。