Linux C程序 dump trace

编译程序时添加 -rdynamic选项,在使用addr2line 命令定位故障发生位置时能够显示发生故障的函数。

编译命令: gcc -g -rdynamic dump_trace.c -o dump_trace
addr2line 0x400fde -e dump_trace -f 能够初步定为出发生故障的位置

暂时考虑信号宏及十进制值如下
SIGABRT[6] SIGSEGV[11] SIGILL[4] SIGTERM[15] SIGFPE[8]

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <execinfo.h>
#include <sys/types.h>
#include <unistd.h>
#include <assert.h>

#define MaxPrintDumpTraceLines 20
void dump_trace(int signal)
{
        const int len = 256;
        void *buffer[len];
        int lines = backtrace(buffer, len);
        char **string = backtrace_symbols(buffer, lines);
        printf("trigger signal:[%d] trace lines:[%d]\n", signal, lines);
        if(!string) return;
        int print_lines = lines > MaxPrintDumpTraceLines ? MaxPrintDumpTraceLines:lines;
        for(int line = 0; line < print_lines; ++line)
        {
                printf("line=%d || trace back=%s\n", line, string[line]);
        }
        free(string);
}

void signal_alarm(int signal)
{
        switch(signal)
        {
        case SIGSEGV:
                printf("pid:%d receive segment fault signal\n", getpid());
                break;
        case SIGABRT:
                printf("pid:%d receive abort signal\n", getpid());
                printf("触发SIGABRT原因:执行abort函数 执行assert断言 多次free内存\n");
                break;
        case SIGILL:
                printf("pid:%d receive illegal instruction signal\n", getpid());
                break;
        case SIGTERM:
                printf("pid:%d receive terminal signal\n", getpid());
                break;
        case SIGFPE:
                printf("pid:%d receive arithmetic fault signal\n", getpid());
                break;
        default:
                break;
        }
        dump_trace(signal);
        exit(0);
}

void register_signal_raise_exception()
{
        printf("SIGABRT[%d] SIGSEGV[%d] SIGILL[%d] SIGTERM[%d] SIGFPE[%d]\n",
            SIGABRT, SIGSEGV, SIGILL, SIGTERM, SIGFPE);
        struct sigaction act;
        act.sa_handler = signal_alarm;
        act.sa_flags = 0;
        
        sigemptyset(&act.sa_mask);
        sigaddset(&act.sa_mask, SIGSEGV | SIGILL);
        sigaction(SIGABRT, &act, NULL);

        sigemptyset(&act.sa_mask);
        sigaddset(&act.sa_mask, SIGILL);
        sigaction(SIGSEGV, &act, NULL);

        sigemptyset(&act.sa_mask);
        sigaddset(&act.sa_mask, SIGSEGV);
        sigaction(SIGILL, &act, NULL);
        
        sigemptyset(&act.sa_mask);
        sigaddset(&act.sa_mask, SIGSEGV | SIGILL | SIGABRT);
        sigaction(SIGTERM, &act, NULL);
        
        sigemptyset(&act.sa_mask);
        sigaddset(&act.sa_mask, SIGTERM);
        sigaction(SIGFPE, &act, NULL);

}

void construct_segment_fault()
{
        // set空地址,产生段错误
        int *segment_fault_addr = NULL;
        *segment_fault_addr = 1;
        /*执行结果:
        SIGABRT[6] SIGSEGV[11] SIGILL[4] SIGTERM[15] SIGFPE[8]
        pid:2553 receive segment fault signal
        trigger signal:[11] trace lines:[7]
        line=0 || trace back=./dump_trace(dump_trace+0xa1) [0x400c77]
        line=1 || trace back=./dump_trace(signal_alarm+0xb3) [0x400de8]
        line=2 || trace back=/lib/x86_64-linux-gnu/libc.so.6(+0x354c0) [0x7f93dcf9f4c0]
        line=3 || trace back=./dump_trace(construct_segment_fault+0x10) [0x400fc3]
        line=4 || trace back=./dump_trace(main+0x23) [0x401047]
        line=5 || trace back=/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0) [0x7f93dcf8a840]
        line=6 || trace back=./dump_trace(_start+0x29) [0x400b09]
        addr2line 0x400fc3 -e dump_trace -f
        construct_segment_fault
        /home/myroot/LinuxC/test/dump_trace.c:86
        */
}

void construct_arithmetic_fault()
{
        // 浮点数运算或者除0会触发算数运算错误信号
        // 直接 1/0 这种形式编译器能够检测,但是换成变量能够正常编译通过,不报告警
        int array[4] = {1, 2, 3, 0};
        int div = 1 / array[3];
        /*执行结果:
        SIGABRT[6] SIGSEGV[11] SIGILL[4] SIGTERM[15] SIGFPE[8]
        pid:2563 receive arithmetic fault signal
        trigger signal:[8] trace lines:[7]
        line=0 || trace back=./dump_trace(dump_trace+0xa1) [0x400c77]
        line=1 || trace back=./dump_trace(signal_alarm+0xb3) [0x400de8]
        line=2 || trace back=/lib/x86_64-linux-gnu/libc.so.6(+0x354c0) [0x7fb21f8134c0]
        line=3 || trace back=./dump_trace(construct_arithmetic_fault+0x3c) [0x401008]
        line=4 || trace back=./dump_trace(main+0x23) [0x401047]
        line=5 || trace back=/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0) [0x7fb21f7fe840]
        line=6 || trace back=./dump_trace(_start+0x29) [0x400b09]
        
        addr2line 0x401008 -e dump_trace -f
        construct_arithmetic_fault
        /home/myroot/LinuxC/test/dump_trace.c:109
        */
}

void construct_abort_fault()
{
        //场景 1 多次free导致的SIGABRT
        //void *ptr = malloc(1024);
        //free(ptr);
        //free(ptr);  //打开注释会导致错误
        //场景 2 执行abort函数
        //abort();
        //场景 3 执行到assert函数
        void *ptr = NULL;
        assert(ptr != NULL);
        /*执行结果:
        SIGABRT[6] SIGSEGV[11] SIGILL[4] SIGTERM[15] SIGFPE[8]
        dump_trace: dump_trace.c:139: construct_abort_fault: Assertion `ptr != NULL' failed.
        pid:2590 receive abort signal
        触发SIGABRT原因:执行abort函数 执行assert断言 多次free内存
        trigger signal:[6] trace lines:[11]
        line=0 || trace back=./dump_trace(dump_trace+0xa1) [0x400cf7]
        line=1 || trace back=./dump_trace(signal_alarm+0xb3) [0x400e68]
        line=2 || trace back=/lib/x86_64-linux-gnu/libc.so.6(+0x354c0) [0x7f929557a4c0]
        line=3 || trace back=/lib/x86_64-linux-gnu/libc.so.6(gsignal+0x38) [0x7f929557a438]
        line=4 || trace back=/lib/x86_64-linux-gnu/libc.so.6(abort+0x16a) [0x7f929557c03a]
        line=5 || trace back=/lib/x86_64-linux-gnu/libc.so.6(+0x2dbe7) [0x7f9295572be7]
        line=6 || trace back=/lib/x86_64-linux-gnu/libc.so.6(+0x2dc92) [0x7f9295572c92]
        line=7 || trace back=./dump_trace(construct_abort_fault+0x30) [0x4010d4]
        line=8 || trace back=./dump_trace(main+0x23) [0x4010fa]
        line=9 || trace back=/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0) [0x7f9295565840]
        line=10 || trace back=./dump_trace(_start+0x29) [0x400b89]
        addr2line 0x4010d4 -e dump_trace -f
        construct_abort_fault
        /home/myroot/LinuxC/test/dump_trace.c:140
        */
}

void construct_terminal_fault()
{
     //暂时不知如何构造
}

void construct_illegal_instruction_fault()
{
        // illegal_instruction暂时不知道如何构造
        typedef void (*function_ptr)(void);
        const static char array[4] = {0xff, 0xff, 0xff, 0xff};
        function_ptr function = (function_ptr)array;
        function();
        /*执行结果:
        SIGABRT[6] SIGSEGV[11] SIGILL[4] SIGTERM[15] SIGFPE[8]
        pid:2179 receive illegal instruction signal
        trigger signal:[4] trace lines:[4]
        line=0 || trace back=./dump_trace(dump_trace+0xa1) [0x400d77]
        line=1 || trace back=./dump_trace(signal_alarm+0xb3) [0x400ee8]
        line=2 || trace back=/lib/x86_64-linux-gnu/libc.so.6(+0x354c0) [0x7faa96d054c0]
        line=3 || trace back=./dump_trace() [0x401466]
        */
}


int main(int argc, char *argv[])
{
        register_signal_raise_exception();
        // 场景1:构造触发SIGSEGV段错误信号
        // construct_segment_fault();
        // 场景2:构造触发SIGFPE算术运算错误信号
        // construct_arithmetic_fault();
        // 场景3:构造触发SIGABRT终止运误信号
        // construct_abort_fault();
        // 场景4:构造触发SIGTERM信号
        // construct_terminal_fault();
        // 场景5:构造触发SIGILL非法指令错误信号
        // construct_illegal_instruction_fault();
        return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值