ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

Linux 解码backtrace返回信息

2022-02-15 12:32:15  阅读:195  来源: 互联网

标签:bin martin backtrace 解码 Linux c++ demo test


目录

    前一节Linux backtrace()系列函数 ,已经知道可以通过backtrace,backtrace_symbols得到函数的调用栈信息。不过,在C++中,得到的是一堆难以识别的符号,如何解码得到准确的函数名信息?

    如,前面得到的函数调用栈信息:

    $ ./backtrace 2
    backtrace() return 7 address
    ./backtrace(_Z7myfunc3v+0x1f) [0x400a8c]
    ./backtrace() [0x400b45]
    ./backtrace(_Z6myfunci+0x25) [0x400b6c]
    ./backtrace(_Z6myfunci+0x1e) [0x400b65]
    ./backtrace(main+0x59) [0x400bc7]
    /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5) [0x7f7170ed1f45]
    ./backtrace() [0x4009a9]
    

    (_Z7myfunc3v+0x1f) [0x400a8c],晦涩难懂。

    我们可以用glibc提供的abi::__cxa_demangle(),对得到的函数符号信息进行解码。
    __cxa_demangle详细参见:如何在C++中获得完整的类型名称 | CSDN

    下面一段代码来自chensuo muduo,对其做了简单修改,以便打印完整信息。

    // from chensuo muduo project
    // https://github.com/chenshuo/muduo
    #include <string>
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/syscall.h>
    #include <sys/types.h>
    #include <cxxabi.h>
    #include <execinfo.h>
    
    string stackTrace(bool demangle)
    {
        string stack;
        const int max_frames = 200;
        void* frame[max_frames];
        int nptrs = ::backtrace(frame, max_frames); // GNU extensions built-in function
        char** strings = ::backtrace_symbols(frame, nptrs);
        if (strings)
        {
            size_t len = 256;
            char* demangled = demangle ? static_cast<char*>(::malloc(len)) : nullptr;
            for (int i = 1; i < nptrs; ++i)
            { // skipping the 0-th, which is this function
                if (demangle)
                {
                    // https://panthema.net/2008/0901-stacktrace-demangled/
                    // bin/exception_test(_ZN3Bar4testEv+0x79) [0x401909]
                    // demangle "_ZN3Bar4testEv" between "(" and "+" to function name
                    char* left_par = nullptr;
                    char* plus = nullptr;
                    for (char* p = strings[i]; *p; ++p)
                    {
                        if (*p == '(')
                            left_par = p;
                        else if (*p == '+')
                            plus = p;
                    }
    
                    if (left_par && plus)
                    {
                        *plus = '\0';
                        int status = 0;
                        char* ret = abi::__cxa_demangle(left_par+1, demangled, &len, &status);
                        *plus = '+';
                        if (status == 0)
                        { // demangle success
                            demangled = ret;
                            stack.append(strings[i], left_par + 1);
                            stack.append(demangled);
                            stack.push_back(')'); // add ')' to form "(...)"
                            stack.push_back('\n');
                            continue;
                        }
                    }
                }
                // Fallback to mangled names
                stack.append(strings[i]);
                stack.push_back('\n');
            }
            free(demangled);
            free(strings);
        }
        return stack;
    }
    

    还是用来运行前一节的示例,可以得到

    $./test_demo 2
    /home/martin/workspace/CLionProjects/c++/test_demo/bin/test_demo(myfunc3())
    /home/martin/workspace/CLionProjects/c++/test_demo/bin/test_demo() [0x40133d]
    /home/martin/workspace/CLionProjects/c++/test_demo/bin/test_demo(myfunc(int))
    /home/martin/workspace/CLionProjects/c++/test_demo/bin/test_demo(myfunc(int))
    /home/martin/workspace/CLionProjects/c++/test_demo/bin/test_demo(main+0xd2) [0x4017bc]
    /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5) [0x7f8fb1213f45]
    /home/martin/workspace/CLionProjects/c++/test_demo/bin/test_demo() [0x401209]
    

    注意到这里有2个myfunc,而没有myfunc2。检查代码发现myfunc2是static函数,推测可能是static修饰符的影响,导致无法正确解码myfunc2符号信息。

    去掉static限制:

    static void myfunc2()
    {
        myfunc3();
    }
    
    // 修改为
    void myfunc2() // 去掉了static
    {
        myfunc3();
    }
    

    再次运行之

    $./test_demo 2
    /home/martin/workspace/CLionProjects/c++/test_demo/bin/test_demo(myfunc3())
    /home/martin/workspace/CLionProjects/c++/test_demo/bin/test_demo(myfunc2())
    /home/martin/workspace/CLionProjects/c++/test_demo/bin/test_demo(myfunc(int))
    /home/martin/workspace/CLionProjects/c++/test_demo/bin/test_demo(myfunc(int))
    /home/martin/workspace/CLionProjects/c++/test_demo/bin/test_demo(main+0xd2) [0x4017ec]
    /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5) [0x7faf0ff12f45]
    /home/martin/workspace/CLionProjects/c++/test_demo/bin/test_demo() [0x401239]
    

    可以发现,函数名的顺序,已经之前的推测的调用顺序完全一致。

    标签:bin,martin,backtrace,解码,Linux,c++,demo,test
    来源: https://www.cnblogs.com/fortunely/p/15895911.html

    本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
    2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
    3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
    4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
    5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

    专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

    Copyright (C)ICode9.com, All Rights Reserved.

    ICode9版权所有