段錯誤(核心已轉儲)問題的分析方法
問題現象
今天在研究linux kernel中typedef的用法時,寫了一個程式test_typedef.c,內容如下:
#include<stdio.h>
typedef int size;
typedef unsigned int word;
typedef char line[81];
typedef void (*printStr)(line text);
typedef printStr * pprintStr;
typedef char * pstr;
void printText(line text){
printf("%s\n", text);
}
void * pppPrintText(line text){
printf("%s\n", text);
}
pprintStr pprintText(){
//return &printText;
printStr temp = printText;
return (printStr *)temp;
}
/*void (*pprintText)(line text){
printf("%s\n", text);
}*/
void main(){
size i=10;
word w = 20;
line text;
printf ("%d, %d, %d\n",i, w, sizeof(text)/sizeof(char));
printStr printFun = printText;
pprintStr pprintFun = pprintText();
printFun("test typedef");
//((printStr)pprintFun)("test pointer typedef");
(*pprintFun)("test pointer typedef");
char string[4] = "abc";
pstr p1 = string;
const char *p2 = string;
p1++;
p2++;
printf("%s, %s\n", p1, p2);
}
加上37行的程式碼(*pprintFun)(“test pointer typedef”);後,通過gcc –o typedef test_typdef.c命令編譯成typedef可執行檔案後執行,出現段錯誤:
之前也遇見過“段錯誤(核心已轉儲)”(Segmentation fault(core dumped)),但是沒有進行分析,今天藉著這個機會學習一下這類問題的分析方法。
段錯誤的分析方法
段錯誤一般藉助於可除錯(使用-g選項進行編譯)的原程式和核心轉儲後的core file來進行分析,如針對我寫的程式,其步驟為:
- gcc –g –o typedef test_typedef.c (生成可除錯的可執行程式)
- ./typedef (產生段錯誤,生成core file)
- gdb –c core_file typdef (使用core file除錯產生段錯誤的可執行程式)
- 在gdb除錯環境中執行bt或where命令定位到問題行
按如上步驟對typedef可執行程式的分析結果如下:
由上圖可以看出,通過core file定位出來的問題程式碼行也是37行,說明分析結果的準確性。
core file的產生
core file檔案是在程式異常退出時產生的,程式的異常退出往往是通過訊號(signal)產生的,但並不是所有的訊號都能夠產生core file,在signal.h的標頭檔案中定義了哪些signal可以產生core file,如下:
上圖中所有default action為coredump的中斷訊號都可以產生core file。
除了中斷訊號必須能夠產生coredump外,還必須進行如下設定:
- ulimit –c unlimited (設定core file的大小,相當於使能core file的生成)
- ulimit unlimited (設定file的大小)
其他問題
1. core file存放在哪個目錄
存放core file一般存放在程序的當前工作目錄,一般就是當初發出命令啟動該程序時所在的目錄。但如果是通過指令碼啟動,則指令碼可能會修改當前目錄,這時程序真正的當前目錄就會與當初執行指令碼所在目錄不同。這時可以檢視“/proc/pid/cwd”符號連結的目標來確定程序真正的當前目錄地址。
2. core file的檔名
一般core file的檔名即為core,可能通過
echo "1" > /proc/sys/kernel/core_uses_pid
將core file的檔名改為core.pid
3. 如何修改core file的檔名格式和儲存位置
/proc/sys/kernel /core_pattern可以控制core檔案儲存位置和檔名格式。可通過以下命令修改此檔案:
echo "/corefile/core-%e-%p-%t" >/proc/sys/kernel /core_pattern
可以將core檔案統一生成到/corefile目錄下,產生的檔名為core-命令名-pid-時間戳
以下是引數列表:
%p - insert pid into filename 新增pid
%u - insert current uid into filename 添加當前uid
%g - insert current gid into filename 添加當前gid
%s - insert signal that caused the coredump into the filename 新增導致產生core的訊號
%t - insert UNIX time that the coredump occurred into filename 新增core檔案生成時的unix時間
%h - insert hostname where the coredump happened into filename 新增主機名
%e - insert coredumping executable name into filename 新增命令名
4. 如果你當初是以使用者A運行了某個程式,但在ps裡看到的這個程式的使用者卻是B的話,那麼這些程序就是呼叫了seteuid了。為了能夠讓這些程序生成core dump,需要將/proc/sys/fs/suid_dumpable 檔案的內容改為1(一般預設是0)