【问题标题】:Alternative to backtrace() on Linux that can find symbols for static functionsLinux 上的 backtrace() 替代方法,可以找到静态函数的符号
【发布时间】:2013-09-08 01:34:22
【问题描述】:

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

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

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

【问题讨论】:

    标签: c linux debugging backtrace


    【解决方案1】:

    是的,通过检查它自己的可执行文件 (/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的运行时依赖。

    【讨论】:

      【解决方案2】:

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

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

      请注意,如果您使用优化进行编译,某些函数可能会被内联(即使没有在源代码中明确标记inline,并且static 内联函数可能没有任何适当的自己的代码)。那么回溯就不会说明太多了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-10-17
        • 1970-01-01
        • 1970-01-01
        • 2022-07-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多