代码之家  ›  专栏  ›  技术社区  ›  Alana Storm

如何使用-rdynamic链接器标志?

  •  1
  • Alana Storm  · 技术社区  · 7 年前

    如何使用 -rdynamic 确保glibc的回溯函数将在回溯中报告实际函数/符号名称的标志?

    我想用 C's backtrace functions 创建回溯。在我的MacOS机器上,如果我使用该程序 from this question

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

    然后对其进行编译,最终得到一个程序,该程序输出一个包含函数名的堆栈跟踪。

    $ clang main.c 
    $ ./a.out 
    BACKTRACE ------------
    1   a.out                               0x0000000100c9fec9 foo + 9
    2   a.out                               0x0000000100c9fee4 main + 20
    3   libdyld.dylib                       0x00007fff9669f235 start + 1
    ----------------------
    

    然而,如果我尝试使用gcc在Ubuntu虚拟机上编译程序,则不会得到函数名。

    $ gcc-5 main.c 
    $ ./a.out 
    BACKTRACE ------------
    ./a.out() [0x4008c3]
    ./a.out() [0x4008d4]
    /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0) [0x7fbc9fee2830]
    ./a.out() [0x400649]
    ----------------------
    

    前面提到的问题说 -rdynamic flag是我的救世主,但当我尝试使用该flag时,我仍然无法在回溯中获得函数名

    $ gcc-5 -rdynamic main.c
    $ ./a.out 
    BACKTRACE ------------
    ./a.out(foo+0x9) [0x400b63]
    ./a.out(main+0xe) [0x400b74]
    /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0) [0x7f8cbbf20830]
    ./a.out(_start+0x29) [0x4008e9]
    

    我有点不知所措,下一步该怎么办——我是不是用错了旗子?或者我是否正确使用了它,还有其他一些东西可能会阻止符号显示在这个简单的程序中。

    2 回复  |  直到 7 年前
        1
  •  3
  •   Alana Storm    7 年前

    根据上面的评论 -rdynamic 标志正常工作。问题是MacOS上的clang以不同于我的ubuntu VM上的GCC的格式生成其输出。

    函数名一直存在。

    # notice the function name `foo`
    ./a.out(foo+0x9) [0x400b63]
    
        2
  •  2
  •   Basile Starynkevitch    7 年前

    你可以考虑使用伊恩·泰勒的 libbacktrace (这也是最近 GCC )用于回溯目标。它希望使用 DWARF 信息(因此您可以使用 -g 传递给 gcc ,可以与优化标志混合使用,如 -O2 ). 但它提供了更精确的输出(包括调用堆栈帧的行号)。