C/C++ backtrace和addr2line 实现堆栈信息追踪

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <unistd.h>
#include <execinfo.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <iostream>
#include <thread>
#include <functional>

using namespace std;

#define BACKTRACE_SIZE   16

// 获取当前运行进程的绝对路径
char *get_current_task_name()
{
    static char task_name[1024] = {0};
    char *pstr = NULL;
    readlink("/proc/self/exe", task_name, 1024);
    pstr = task_name;
    return pstr;
}

void addr2lineAnalyze(const char *paddress, const char *proName)
{
    static char addr2line_str[256] = {0};
    snprintf(addr2line_str, 256, "addr2line %s -e %s -f -p", paddress, proName);

    FILE *pFd = popen(addr2line_str, "r");
    if ( pFd == nullptr )
    {
        return ;
    }
    char buf[512] = {0};
    fread(buf, sizeof(buf)/sizeof (buf[0]), 1, pFd);
    printf("  %s\n", buf);

    pclose(pFd);
}

void dump(void)
{
    int j, nptrs;
    void *buffer[BACKTRACE_SIZE];
    char **strings;

    nptrs = backtrace(buffer, BACKTRACE_SIZE);

    printf("backtrace() returned %d addresses\n", nptrs);

    strings = backtrace_symbols(buffer, nptrs);
    if (strings == NULL)
    {
        perror("backtrace_symbols");
        exit(EXIT_FAILURE);
    }
    char *ptr = nullptr, *ptr_end = nullptr, *pstr = nullptr;
    // 打印堆栈信息, 并且使用addr2line进行分析
    for (j = 0; j < nptrs; j++)
    {
        printf("  [%02d] %s\n", j, strings[j]);
        ptr = strstr(strings[j], "[");
        if (ptr != nullptr)
        {
            ptr++;
            ptr_end = strstr(ptr, "]");
            if (ptr_end != nullptr)
            {
                *ptr_end = '\0';
            }
            addr2lineAnalyze(ptr, get_current_task_name());
        }
    }
    free(strings);
}

void signal_handler(int signo)
{
    printf("<<<<<<<<<<<<<<<<<catch signal %d>>>>>>>>>>>>>>>>>>>>>>>>>\n", signo);
    printf("Dump stack start...\n");
    dump();
    printf("Dump stack end...\n");

    signal(signo, SIG_DFL); /* 恢复信号默认处理 */
    raise(signo);           /* 重新发送信号 */
}


int main(void)
{
    // 注册信号
    signal(SIGSEGV, signal_handler);
    signal(SIGINT, signal_handler);
    signal(SIGABRT, signal_handler);

    // 异常代码段, 抛越界操作
    char *ptr = nullptr;
    memcpy(ptr, "123", 3 );
    printf("ptr: %s\n", ptr);

    return 0;
}
复制代码

运行情况:

 异常抛出进来后,信号注册函数进行回调,分析堆栈信息

参考: [Linux C]使用backtrace+addr2line追踪函数调用栈,实现类似内核中dump_stack的功能_backtrace addr2line-CSDN博客

   linux下定位崩溃,backtrace + addr2line + maps_address2line linux-CSDN博客

 

posted @   蔡头一枚  阅读(318)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示