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的内部調用,如下
至此,可初步定位到段錯誤的位址。
另外總線錯誤可使用SEGBUS信号捕捉。