编译程序时添加 -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;
}