Linux 如何使 backtrace()/backtrace_symbols() 打印函数名称?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6934659/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 05:27:03  来源:igfitidea点击:

How to make backtrace()/backtrace_symbols() print the function names?

clinuxdebuggingbacktrace

提问by Lyke

The Linux specific backtrace()and backtrace_symbols()allows you to produce a call trace of the program. However, it only prints function addresses, not their names for my program. How can I make them print the function names as well ? I've tried compiling the program with -gas well as -ggdb. The test case below just prints this:

Linux 特定backtrace()backtrace_symbols()允许您生成程序的调用跟踪。但是,它只打印函数地址,而不是我的程序的名称。我怎样才能让他们也打印函数名称?我试过用-g和编译程序-ggdb。下面的测试用例只是打印这个:

    BACKTRACE ------------
    ./a.out() [0x8048616]
    ./a.out() [0x8048623]
    /lib/libc.so.6(__libc_start_main+0xf3) [0x4a937413]
    ./a.out() [0x8048421]
    ----------------------
    

I'd want the first 2 items to also show the function names, fooand main

我希望前 2 个项目也显示函数名称,foo并且main

Code:

代码:

#include <execinfo.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>

static void full_write(int fd, const char *buf, size_t len)
{
        while (len > 0) {
                ssize_t ret = write(fd, buf, len);

                if ((ret == -1) && (errno != EINTR))
                        break;

                buf += (size_t) ret;
                len -= (size_t) ret;
        }
}

void print_backtrace(void)
{
        static const char start[] = "BACKTRACE ------------\n";
        static const char end[] = "----------------------\n";

        void *bt[1024];
        int bt_size;
        char **bt_syms;
        int i;

        bt_size = backtrace(bt, 1024);
        bt_syms = backtrace_symbols(bt, bt_size);
        full_write(STDERR_FILENO, start, strlen(start));
        for (i = 1; i < bt_size; i++) {
                size_t len = strlen(bt_syms[i]);
                full_write(STDERR_FILENO, bt_syms[i], len);
                full_write(STDERR_FILENO, "\n", 1);
        }
        full_write(STDERR_FILENO, end, strlen(end));
    free(bt_syms);
}
void foo()
{
    print_backtrace();
}

int main()
{
    foo();
    return 0;
}

回答by Matthew Slattery

The symbols are taken from the dynamic symbol table; you need the -rdynamicoption to gcc, which makes it pass a flag to the linker which ensures that allsymbols are placed in the table.

符号取自动态符号表;您需要-rdynamic选项 to gcc,这使其将标志传递给链接器,以确保所有符号都放置在表中。

(See the Link Optionspage of the GCC manual, and / or the Backtracespage of the glibc manual.)

(请参阅GCC 手册链接选项页面和/或glibc 手册回溯页面。)

回答by Nemo

Use the addr2line commandto map executable addresses to source code filename+line number. Give the -foption to get function names as well.

使用addr2line 命令将可执行地址映射到源代码文件名+行号。还-f提供获取函数名称的选项。

Alternatively, try libunwind.

或者,尝试libunwind

回答by Erwan Legrand

The excellent Libbacktrace by Ian Lance Taylor solves this issue. It handles stack unwinding and supports both ordinary ELF symbols and DWARF debugging symbols.

Ian Lance Taylor 出色的 Libbacktrace 解决了这个问题。它处理堆栈展开并支持普通 ELF 符号和 DWARF 调试符号。

Libbacktrace does not require exporting all symbols, which would be ugly, and ASLR does not break it.

Libbacktrace 不需要导出所有符号,这会很丑陋,而且 ASLR 不会破坏它。

Libbacktrace was originally part of the GCC distribution. Now, a standalone version can be found on Github:

Libbacktrace 最初是 GCC 发行版的一部分。现在,可以在 Github 上找到一个独立版本:

https://github.com/ianlancetaylor/libbacktrace

https://github.com/ianlancetaylor/libbacktrace

回答by Billg

the answer on the top has a bug if ret == -1 and errno is EINTER you should try again, but not count ret as copied (not going to make an account just for this, if you don't like it tough)

如果 ret == -1 和 errno 是 EINTER,则顶部的答案有一个错误,您应该再试一次,但不要将 ret 视为已复制(如果您不喜欢它,则不会为此创建帐户)

static void full_write(int fd, const char *buf, size_t len)
{
        while (len > 0) {
                ssize_t ret = write(fd, buf, len);

                if ((ret == -1) {
                        if (errno != EINTR))
                                break;
                        //else
                        continue;
                }
                buf += (size_t) ret;
                len -= (size_t) ret;
        }
}