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

☆樱花仙子☆ 提交于 2019-11-26 10:12:53

问题


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 -g as well as -ggdb. The test case below just prints this:


    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, foo and 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;
}

回答1:


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

(See the Link Options page of the GCC manual, and / or the Backtraces page of the glibc manual.)




回答2:


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

Alternatively, try libunwind.




回答3:


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

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

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

https://github.com/ianlancetaylor/libbacktrace




回答4:


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)

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;
        }
}



回答5:


Boost backtrace

Very convenient because it prints both:

  • unmangled C++ function names
  • line numbers

automatically for you.

Usage summary:

#define BOOST_STACKTRACE_USE_ADDR2LINE
#include <boost/stacktrace.hpp>

std::cout << boost::stacktrace::stacktrace() << std::endl;

I have provided a minimal runnable example for it and many other methods at: print call stack in C or C++



来源:https://stackoverflow.com/questions/6934659/how-to-make-backtrace-backtrace-symbols-print-the-function-names

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!