Linux GCC捕获当前调用堆栈信息(打印行号、源文件名、函数名、相对函数RVA偏移等信息)

前置须知:

GCC编译器选项必须提供:

-g 或 -g3,并且需求 -rdynamic 编译器选项开关,可以在 Release 下面使用该函数,实现上不支持捕获其它库的详细符号信息(当然你可以改,别人库的符号如非必要必须要搞那么清楚明白)。

打印结果:

Stack Trace:
  at /home/dev/Server/src/GameServer/main.cpp:50(foo2()+0x19) [0x1289562]
  at /home/dev/Server/src/GameServer/main.cpp:56(foo1()+0x9) [0x128957a]
  at /home/dev/Server/src/GameServer/main.cpp:79(main+0x2ab) [0x128993c]
  at /lib64/libc.so.6(__libc_start_main+0xf5) [0x7ffff5832555]
  at /home/dev/lib/jemalloc-5.3.0/src/prof_recent.c:460 [0xf76ffa]

捕获实现(轻量的):

void printStackTrace(int skip)
{
    if (skip < 1)
    {
        skip = 1;
    }

    std::string stacktraces = captureStackTrace(skip + 1);
    fprintf(stdout, "%s\n", stacktraces.data());
}

std::string extractSymbol(const char* symbol)
{
    if (NULL == symbol || *symbol == '\x0')
    {
        return std::string();
    }

    const char* symbolStart = NULL;
    const char* symbolEnd = NULL;
    const char* strPtr = symbol;
    while (*strPtr)
    {
        if (*strPtr == '(')
        {
            symbolStart = strPtr + 1;
        }
        elif(*strPtr == ')' && symbolStart)
        {
            symbolEnd = strPtr;
            break;
        }
        strPtr++;
    }

    if (symbolStart && symbolEnd)
    {
        char symbolBuf[symbolEnd - symbolStart + 1];
        strncpy(symbolBuf, symbolStart, symbolEnd - symbolStart);

        symbolBuf[symbolEnd - symbolStart] = '\0';
        return symbolBuf;
    }
    else
    {
        return std::string();
    }
}

std::string getExecutablePath()
{
    char path[8192];
    ssize_t count = readlink("/proc/self/exe", path, sizeof(path));
    return std::string(path, count > 0 ? count : 0);
}

std::string captureStackTrace(int skip)
{
    size_t constexpr max_stackframe_size = 3000;
    void* stackframe_addrs[max_stackframe_size];

    if (skip < 1)
    {
        skip = 1;
    }

    size_t stackframe_size = backtrace(stackframe_addrs, max_stackframe_size);
    char** stackframe_symbols = backtrace_symbols(stackframe_addrs, stackframe_size);

    std::string stacktraces = "Stack Trace:";
    if (NULL != stackframe_symbols)
    {
        std::string executable_path = getExecutablePath();
        std::string default_line = "\r\n  at ";
        for (int i = skip; i < stackframe_size; i++)
        {
            char buf[8192];
            sprintf(buf, "addr2line -e %s %p", executable_path.data(), stackframe_addrs[i]);

            FILE* f = popen(buf, "r");
            if (NULL == f)
            {
                continue;
            }

            if (fgets(buf, sizeof(buf), f))
            {
                int symbol_size = strlen(buf);
                if (buf[symbol_size - 1] == '\n')
                {
                    buf[--symbol_size] = '\0';
                }

                std::string line = default_line;
                if (symbol_size > 0)
                {
                    if (*buf != '?')
                    {
                        line += buf;
                    }
                }

                std::string symbol = extractSymbol(stackframe_symbols[i]);
                if (symbol.size() > 0)
                {
                    int status = -1;
                    char* demangle = NULL;
                    char* p = strchr(symbol.data(), '+');
                    if (p)
                    {
                        *p = '\x0';
                        demangle = abi::__cxa_demangle(symbol.data(), NULL, 0, &status);
                    }
                    else
                    {
                        p = "??";
                    }

                    if (status == 0)
                    {
                        snprintf(buf, sizeof(buf), "(%s+%s) [%p]", demangle, p + 1, stackframe_addrs[i]);
                        line += buf;
                    }
                    else
                    {
                        if (default_line.size() == line.size())
                        {
                            line += stackframe_symbols[i];
                        }
                        else
                        {
                            snprintf(buf, sizeof(buf), "(%s+%s) [%p]", symbol.data(), p + 1, stackframe_addrs[i]);
                            line += buf;
                        }
                    }

                    if (NULL != demangle)
                    {
                        std::free(demangle);
                    }
                }
                else
                {
                    snprintf(buf, sizeof(buf), " [%p]", stackframe_addrs[i]);
                    line += buf;
                }

                stacktraces += line;
            }

            pclose(f);
        }

        std::free(stackframe_symbols);
    }
    return stacktraces;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值