天天看點

linux下使用backtrace函數捕定位段錯誤問題

Linux下C語言下程式設計時不時會錯遇到段錯誤問題,段錯誤常常由于指針通路了非法的記憶體位址所造成的,但是系統并沒有給我們指出通路哪個地方的記憶體位址出錯。下面我們使用信号捕捉的方法,利用backtrace函數得到段錯誤的資訊,進而定位段錯誤所處的位置。

這裡使用到兩個函數:backtrace和backtrace_symbols;

int backtrace (void **buffer, int size);  

擷取堆棧函數調用清單

char **backtrace_symbols (void *const *buffer, int size); 

擷取的位址轉為描述這些位址的字元串數組。

1. 編寫segfault.c程式,使用signal信号函數捕捉SIGSEGV信号,然後用backtrace函數擷取清單。

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

void test1(int number) {
	char *p= (char *)number;
	*p = 's';
	printf("%s: test1\n", __FUNCTION__);
}


void DebugBacktrace(void) {
	#define SIZE 100
	void *array[SIZE];
	int size, i;
	char **strings;

    fprintf(stderr, "\n Segmentation fault \n");
    size = backtrace(array, SIZE);
    fprintf(stderr, "Backtrace (%d deef):\n", size);

    strings =backtrace_symbols(array, size);

    for(i =0; i < size; i++)
    	fprintf(stderr, "%d: %s\n", i, strings[i]);

 	free(strings);
 	exit(-1);
}

int main(void) {
	char data = 1;

	signal(SIGSEGV, DebugBacktrace);
	test1(data);
}
           

2. 編譯運作

gcc -o seg segfault.c 
./seg
           

得到段錯誤資訊

Segmentation fault 
Backtrace (6 deef):
0: ./seg() [0x4007eb]
1: /lib/x86_64-linux-gnu/libc.so.6(+0x36cb0) [0x7fde9eb9bcb0]
2: ./seg() [0x400795]
3: ./seg() [0x4008ca]
4: /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5) [0x7fde9eb86f45]
5: ./seg() [0x4006b9]
           

3. 使用objdump定位段錯誤的位址

objdump -S seg
           

    可以檢視到Backtrace得到個6個位址中第2個位址(0x400795)輸出為test1的内部調用,如下

linux下使用backtrace函數捕定位段錯誤問題

至此,可初步定位到段錯誤的位址。

另外總線錯誤可使用SEGBUS信号捕捉。

繼續閱讀