Linux系統中段錯誤信號sigsegv的捕獲和調試使用

本文介紹了在Linux系統中通過捕獲信號sigsegv信號debug segmentation fault的方法。

要在程序的執行過程中能捕獲段錯誤發出的信號sigsegv,需要在程序的開始的時候註冊信號的處理函數signal(SIGSEGV, sigsegv_handler);並且在信號的處理函數sigsegv_handler中需要調用系統調用backtrace和bacetrace_symbols打印出回溯信息。接下來還需要通過objdump 的命令將程序反彙編成一個.s的彙編文件。然後根據回溯信息和彙編文件的內容從而定義出產生段錯誤的位置。

下面是一個示例的程序,程序在執行幾秒後就會因爲向一個空指針中賦值而產生段錯誤。

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <execinfo.h>

#define BACKTRACE_SIZE 16

void ShowStack(void)
{
	int i;
	void *buffer[BACKTRACE_SIZE];

	int n = backtrace(buffer, BACKTRACE_SIZE);
	printf("[%s]:[%d] n = %d\n", __func__, __LINE__, n);
	char **symbols = backtrace_symbols(buffer, n);
	if(NULL == symbols){
		perror("backtrace symbols");
		exit(EXIT_FAILURE);
	}
	printf("[%s]:[%d]\n", __func__, __LINE__);
	for (i = 0; i < n; i++) {
		printf("%d: %s\n", i, symbols[i]);
	}

	free(symbols);
}

void sigsegv_handler(int signo)
{
	if (signo == SIGSEGV) {
		printf("Receive SIGSEGV signal\n");
		printf("-----call stack-----\n");
		ShowStack();
		exit(-1);
	} else {
		printf("this is sig %d", signo);
	}
}

int main(int argc, char *argv[])
{
	printf("The code compile date:[%s]:[%s] !!!\n", __DATE__, __TIME__);
	signal(SIGSEGV, sigsegv_handler);
	int i = 0;
	char *p = NULL;
	while(1)
	{
		printf("%s:[%s]:[%d]\n", __DATE__, __func__, __LINE__);
		sleep(1);
		i++;
		if(3 == i){
			*p = 0x55;
		}
	}
	return -1;
}

下面是在Ubuntu中執行的效果:

The code compile date:[Jun 19 2020]:[15:44:07] !!!
Jun 19 2020:[main]:[49]
Jun 19 2020:[main]:[49]
Jun 19 2020:[main]:[49]
Receive SIGSEGV signal
-----call stack-----
[ShowStack]:[15] n = 6
[ShowStack]:[21]
0: ./test(ShowStack+0x1c) [0x400a59]
1: ./test(sigsegv_handler+0x2a) [0x400b62]
2: /lib/x86_64-linux-gnu/libc.so.6(+0x36cb0) [0x7f2547ea2cb0]
3: ./test(main+0x7c) [0x400bfe]
4: /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5) [0x7f2547e8df45]
5: ./test() [0x400979]

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章