linux core文件調試

在完成公司項目,測試進程的時候,經常會發現日誌到了某一段特定的代碼的時候就沒了,進程直接退出,也沒有捕獲到任何的異常信息,如果日誌打印的較多還可能比較容易發現問題,如果日誌較少,就很難進行進一步的查錯了。

但是發現在該目錄下生成了一個core文件,可以幫助我們查找程序崩潰的原因。

 

1. 什麼是core文件


在linux系統下,如果進程不能正常運行,就可能會產生core文件。core文件就是當前內存狀態的一個映像,同時加上一些調試信息。

bug和操作系統或硬件的保護機制都會導致程序異常終止,操作系統會kill掉這些進程併產生core文件。

 

2. 爲什麼我的linux不會生成core文件


使用 ulimit -a 命令可以查看當前系統資源的一些限制信息,如下圖所示:

 

其中的core file size 如果設置爲0的話,當程序崩潰的時候就不會產生core文件。

 

#設置core文件大小爲無限

ulimit -c unlimited

 

#阻止系統生成core文件

ulimit -c 0

 

注意:這條命令只在當前生效,如果希望永久生效,就需要在.bash_profile中加上這條命令。


3. 設置Core Dump的核心轉儲文件目錄和命名規則


/proc/sys/kernel/core_uses_pid可以控制產生的core文件的文件名中是否添加pid作爲擴展,如果添加則文件內容爲1,否則爲0。需要有超級用戶的權限才能進行修改。

 

/proc/sys/kernel/core_pattern 可以設置格式化的 core文件保存位置或文件名,默認的是|/usr/libexec/abrt-hook-ccpp %s %c %p %u %g %t e。需要修改的話,可以使用如下命令:

 

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 - insertcoredumping executable name into filename 添加命令名

 

4. 使用core文件


在linux上可以使用gdb來調試core文件,格式爲:

 

gdb [程序名] [core文件名]

 

如果你不知道這個core文件到底是哪個程序生成的,可以使用

 

gdb -c[core 文件名] 來查看生成此core文件的程序名。

 

顯示結果中可以看出程序名,可能像下面這樣

Core wasgenerated by `./test'.

 

之後進入gdb調試狀態,輸入 where就可以看到程序崩潰時堆棧信息(當前函數之前的所有已調用函數的列表(包括當前函數),我們可以藉此找出是程序中的哪個部分導致了程序崩潰。注意:在編譯程序的時候要加入選項-g。


5. 一個簡單的例子


編譯如下的程序:

 

#include <iostream>

using namespace std;

 

class A

{

public:

   int a;

};

 

void fun()

{

    A*t = new A();

   t->a = 1;

   cout << t->a << endl;

   delete t;

   delete t;

}

 

int main()

{

   fun();

   return 0;

}

 

執行:

./test

 

結果爲:

1

*** glibc detected *** ./test: double freeor corruption (fasttop): 0x09fd7008 ***

======= Backtrace: =========

/lib/libc.so.6[0x3ebe31]

/usr/lib/libstdc++.so.6(_ZdlPv+0x22)[0x43fc552]

./test[0x8048705]

./test[0x8048712]

/lib/libc.so.6(__libc_start_main+0xe6)[0x391d26]

./test[0x8048611]

======= Memory map: ========

00327000-00328000 r-xp 00000000 00:000          [vdso]

00334000-00351000 r-xp 00000000 08:02926955    /lib/libgcc_s-4.4.7-20120601.so.1

00351000-00352000 rw-p 0001d000 08:02926955    /lib/libgcc_s-4.4.7-20120601.so.1

00355000-00373000 r-xp 00000000 08:02926876     /lib/ld-2.12.so

00373000-00374000 r--p 0001d000 08:02926876     /lib/ld-2.12.so

00374000-00375000 rw-p 0001e000 08:02926876     /lib/ld-2.12.so

0037b000-0050c000 r-xp 00000000 08:02926877     /lib/libc-2.12.so

0050c000-0050e000 r--p 00191000 08:02926877     /lib/libc-2.12.so

0050e000-0050f000 rw-p 00193000 08:02926877     /lib/libc-2.12.so

0050f000-00512000 rw-p 00000000 00:00 0

00543000-0056b000 r-xp 00000000 08:02926889     /lib/libm-2.12.so

0056b000-0056c000 r--p 00027000 08:02926889     /lib/libm-2.12.so

0056c000-0056d000 rw-p 00028000 08:02926889     /lib/libm-2.12.so

0434d000-0442e000 r-xp 00000000 08:02155001     /usr/lib/libstdc++.so.6.0.13

0442e000-04432000 r--p 000e0000 08:02155001     /usr/lib/libstdc++.so.6.0.13

04432000-04434000 rw-p 000e4000 08:02155001     /usr/lib/libstdc++.so.6.0.13

04434000-0443a000 rw-p 00000000 00:00 0

08048000-08049000 r-xp 00000000 08:02419326    /home/wcl/fate/src/app/test/test

08049000-0804a000 rw-p 00000000 08:02419326    /home/wcl/fate/src/app/test/test

09fd7000-09ff8000 rw-p 00000000 00:000          [heap]

b7719000-b771c000 rw-p 00000000 00:00 0

b7727000-b772a000 rw-p 00000000 00:00 0

bfd2a000-bfd3f000 rw-p 00000000 00:000          [stack]

Aborted (core dumped)

 

因爲我們對一個已經delete過了的指針再次delete,所以程序down掉了,可以看到在當前目錄下已經生成了一個core.4377的文件,4377就是之前程序啓動的PID。

 

調試core文件:

gdb test core.4377

進入gdb調試後,鍵入where命令:

 

(gdb) where

#0 0x00327424 in __kernel_vsyscall ()

#1 0x003a5b11 in raise () from /lib/libc.so.6

#2 0x003a73ea in abort () from /lib/libc.so.6

#3 0x003e59d5 in __libc_message () from /lib/libc.so.6

#4  0x003ebe31in malloc_printerr () from /lib/libc.so.6

#5  0x043fc552 in operator delete(void*) () from/usr/lib/libstdc++.so.6

#6  0x08048705 in fun() ()

#7  0x08048712 in main ()

 

可以很明顯的看出是在main函數中調用fun函數,之後delete指針的時候出錯了,後面的函數調用棧就是程序輸出錯誤信息的部分了,和我們的用戶代碼無關。到這一步,我們就能推斷是是fun()這個函數中delete某個指針的時候出現了錯誤,就可以有的放矢地查找具體的問題了。

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