异常信息转储预研笔记-捕获指定进程的异常信号

信号中断中存储堆栈信息

目的

捕获指定进程的信号,当信号为core中止信号时,则对指定进程的异常堆栈信息转储至指定文件。

demo

demo代码如下:由于环境隔离,以下代码为手敲且未编译,谨慎使用,领会思路即可。

cpp 复制代码
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ptrace.h>
#include <libunwind-ptrace.h>

static pid_t pid;

static void unwind_pid()
{
    unw_addr_space_r as = unw_create_addr_space(&_UPT_accessors, 0);
    
    long errnum = ptrace(PTRACE_ATTACH, pid, 0 ,0);
    if (errnum != 0)
    {
        printf("error: xxx \n");
    }
    void *context = _UPT_create(pid);
    unw_cursor_t cursor;
    if (unw_init_remote(&cursor, as, context) != 0)
    {
        printf("error: cannot initialize cursor for remote unwinding\n");
    }
    FILE *fp;
    fp = fopen("ap.core", "w");
    if (fp == null)
    {
        printf("error: open file failed!\n");
        return;
    }

    do {
        unw_word_t offset, pc;
        char sym[10240];
        if (unw_get_reg(&cursor, UNW_REG_IP, &pc))
            printf("error: xxx\n");

        fprintf(fp, "0x%lx: ", pc);

        if (unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0)
        {
            fprintf(fp, "(%s+0x%lx)\n", sym, offset);
        }else
        {    
            printf("no symbol name found.\n");
        }

    } while (unw_step(&cursor) > 0);

    _UPT_destroy(conteext);
    (void)ptrace(PTRACE_DETACH, pid, 0, 0);

    fclose(fp);
}

static void signal_cb(int32_t signo)
{
    unwind_pid();
    signal(signo, SIG_DFL);
}

int main(int argc, char** argv)
{
    if (argc != 2)
    {
        printf("USAGE: unwind-pid <pid>\n");
    }
    pid = atoi(argv[1]);
    signal(SIGINT, signal_cb);
    while(1)
    {
        sleep(1);
    }
    return 0;
}

大致思路是注册一个信号处理回调,demo中是对SIGINT信号做出事件处理 ,可根据需求替换或增加(这里有个小坑,下面讲),具体信号说明依然查看这篇文章《异常信息转储预研笔记》,里面有具体说明。当内核发送信号给指定进程,demo进程就会捕获到并进入信号回调处理函数,后面就是通过libunwind开源库将指定进程收到信号前一刻的堆栈信息输出至指定文件

小坑

在测试demo中,一开始使用的是SIGKILL信号,这个信号是最了解最方便模拟的,我想当然的使用kill -9 来结束指定进程,内核当然就会发送SIGKILL信号给指定进程。

但是多次测试发现,demo进程无法捕获到任何信号,不知道哪里有问题,只能来回研究代码。

反复测试无果,只能求助谷歌,终于明白!原来!SIGKILL和SIGSTOP这两个信号!既不能被忽略!也不能被捕捉!:)

换了SIGINT信号,终于行了!SIGINT信号通过键盘键入ctrl c即可模拟。

最后

目前使用的方式都非常粗糙,仅仅输出最基本的堆栈信息,边学习边记录,有不对的地方欢迎提出来共同进步。

后续

下一步计划:输出更丰富可读性更强的异常转储core文件,可能通过dladdr转换地址为函数名称和行号。

相关推荐
星轨初途1 分钟前
【C/C++底层修炼】拆解动态内存管理:四大动态内存函数、六大错误与柔性数组
c语言·开发语言·c++·经验分享·笔记·柔性数组
妄汐霜10 小时前
小白学习笔记(spring框架的aop和tx)
笔记·学习
sheeta199811 小时前
LeetCode 每日一题笔记 日期:2025.03.24 题目:2906.构造乘积矩阵
笔记·leetcode·矩阵
Heartache boy12 小时前
野火STM32_HAL库版课程笔记-ADC多通道采集热敏、光敏、反射传感器(轮询)
笔记·stm32·单片机
yoothey13 小时前
Java字节流与字符流核心笔记(问答+考点复盘)
java·开发语言·笔记
老师好,我是刘同学13 小时前
force与deposit在SystemVerilog中的区别详解
笔记
Theodore_102214 小时前
深度学习(11):偏差与方差诊断、学习曲线
人工智能·笔记·深度学习·神经网络·机器学习·计算机视觉
2401_8357925415 小时前
Linux复习笔记
linux·服务器·笔记
C羊驼15 小时前
C语言学习笔记(十五):预处理
c语言·经验分享·笔记·学习·算法
不会聊天真君64715 小时前
基础语法·中(golang笔记第二期)
开发语言·笔记·golang