在程序不尋常退出時,內核會在當前工作目錄下生成一個core文件(是一個內存映像,同時加上調試信息)。使用gdb來查看core文件,可以指示出導致程序出錯的代碼所在文件和行數。
1.core文件的生成開關和大小限制
(1)使用ulimit -c命令可查看core文件的生成開關。若結果為0,則表示關閉了此功能,不會生成core文件。
通過上面的命令修改后,一般都只是對當前會話起作用,當你下次重新登錄后,還是要重新輸入上面的命令,所以很麻煩。我們可以把通過修改 /etc/profile文件 來使系統每次自動打開。
步驟如下:
1.首先打開/etc/profile文件
一般都可以在文件中找到 這句語句:ulimit -S -c 0 > /dev/null 2>&1.ok,根據上面的例子,我們只要把那個0 改為 unlimited 就ok了。然后保存退出。
2.通過source /etc/profile 使當期設置生效。
3.通過ulimit -c 查看下是否已經打開。
其實不光這個命令可以加入到/etc/profile文件中,一些其他我們需要每次登錄都生效的都可以加入到此文件中,因為登錄時linux都會加載此文件。比如一些環境變量的設置。
還有一種方法可以通過修改/etc/security/limits.conf文件來設置,首先以root權限登陸,然后打開/etc/security/limits.conf文件,進行配置:
#vim /etc/security/limits.conf
<domain> <type> <item> <value>
* soft core unlimited
(2)使用ulimit -c filesize命令,可以限制core文件的大小(filesize的單位為kbyte)。若ulimit -c unlimited,則表示core文件的大小不受限制。如果生成的信息超過此大小,將會被裁剪,最終生成一個不完整的core文件。在調試此core文件的時候,gdb會提示錯誤。
在RH8的環境文件/etc/profile中,我們可以看到系統是如何配置ulimit的:
#grep ulimit /etc/profile
ulimit -S -c 0 > /dev/null 2>&1
這條語句設置了對軟件資源和對core文件大小的設置
2.core文件的名稱和生成路徑
core文件生成路徑:
輸入可執行文件運行命令的同一路徑下。
若系統生成的core文件不帶其它任何擴展名稱,則全部命名為core。新的core文件生成將覆蓋原來的core文件。
(1)/proc/sys/kernel/core_uses_pid可以控制core文件的文件名中是否添加pid作為擴展。文件內容為1,表示添加pid作為擴展名,生成的core文件格式為core.xxxx;為0則表示生成的core文件同一命名為core。
可通過以下命令修改此文件:
echo "1" > /proc/sys/kernel/core_uses_pid
(2)proc/sys/kernel/core_pattern可以控制core文件保存位置和文件名格式。
可通過以下命令修改此文件:
echo "/corefile/core-%e-%p-%t" > 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 添加命令名
3.core文件的查看
core文件需要使用gdb來查看。
gdb ./a.out
core-file core.xxxx
使用bt命令即可看到程序出錯的地方。
以下兩種命令方式具有相同的效果,但是在有些環境下不生效,所以推薦使用上面的命令。
(1)gdb -core=core.xxxx
file ./a.out
bt
(2)gdb -c core.xxxx
file ./a.out
bt
4.開發板上使用core文件調試
如果開發板的操作系統也是linux,core調試方法依然適用。如果開發板上不支持gdb,可將開發板的環境(依賴庫)、可執行文件和core文件拷貝到PC的linux下。
在 PC上調試開發板上產生的core文件,需要使用交叉編譯器自帶的gdb,並且需要在gdb中指定solib-absolute-prefix和 solib-search-path兩個變量以保證gdb能夠找到可執行程序的依賴庫路徑。有一種建立配置文件的方法,不需要每次啟動gdb都配置以上變量,即:在待運行gdb的路徑下建立.gdbinit。
配置文件內容:
set solib-absolute-prefix YOUR_CROSS_COMPILE_PATH
set solib-search-path YOUR_CROSS_COMPILE_PATH
set solib-search-path YOUR_DEVELOPER_TOOLS_LIB_PATH
handle SIG32 nostop noprint pass
注意:待調試的可執行文件,在編譯的時候需要加-g,core文件才能正常顯示出錯信息!有時候core信息很大,超出了開發板的空間限制,生成的core信息會殘缺不全而無法使用,可以通過掛載到PC的方式來規避這一點。
當程序接收到以下UNIX信號會產生core文件:
名字 |
說明 |
ANSI C POSIX.1 |
SVR4 4.3+BSD |
缺省動作 |
SIGABRT |
異常終止(abort) |
. . |
. . |
終止w/core |
SIGBUS |
硬件故障 |
. |
. . |
終止w/core |
SIGEMT |
硬件故障 |
|
. . |
終止w/core |
SIGFPE |
算術異常 |
. . |
. . |
終止w/core |
SIGILL |
非法硬件指令 |
. . |
. . |
終止w/core |
SIGIOT |
硬件故障 |
|
. . |
終止w/core |
SIGQUIT |
終端退出符 |
. |
. . |
終止w/core |
SIGSEGV |
無效存儲訪問 |
. . |
. . |
終止w/core |
SIGSYS |
無效系統調用 |
|
. . |
終止w/core |
SIGTRAP |
硬件故障 |
|
. . |
終止w/core |
SIGXCPU |
超過CPU限制(setrlimit) |
|
. . |
終止w/core |
SIGXFSZ |
超過文件長度限制(setrlimit) |
|
. . |
終止w/core |
在系統默認動作列,“終止w/core”表示在進程當前工作目錄的core文件中復制了該進程的存儲圖像(該文件名為core,由此可以看出這種功能很久之前就是UNIX功能的一部分)。大多數UNIX調試程序都使用core文件以檢查進程在終止時的狀態。
core文件的產生不是POSIX.1所屬部分,而是很多UNIX版本的實現特征。UNIX第6版沒有檢查條件 (a)和(b),並且其源代碼中包含如下說明:“如果你正在找尋保護信號,那么當設置-用戶-ID命令執行時,將可能產生大量的這種信號”。4.3 + BSD產生名為core.prog的文件,其中prog是被執行的程序名的前1 6個字符。它對core文件給予了某種標識,所以是一種改進特征。
表中“硬件故障”對應於實現定義的硬件故障。這些名字中有很多取自UNIX早先在DP-11上的實現。請查看你所使用的系統的手冊,以確切地確定這些信號對應於哪些錯誤類型。
下面比較詳細地說明這些信號。
? SIGABRT 調用abort函數時產生此信號。進程異常終止。
? SIGBUS 指示一個實現定義的硬件故障。
? SIGEMT 指示一個實現定義的硬件故障。
EMT這一名字來自PDP-11的emulator trap 指令。
? SIGFPE 此信號表示一個算術運算異常,例如除以0,浮點溢出等。
? SIGILL 此信號指示進程已執行一條非法硬件指令。
4.3BSD由abort函數產生此信號。SIGABRT現在被用於此。
? SIGIOT 這指示一個實現定義的硬件故障。
IOT這個名字來自於PDP-11對於輸入/輸出TRAP(input/output TRAP)指令的縮寫。系統V的早期版本,由abort函數產生此信號。SIGABRT現在被用於此。
? SIGQUIT 當用戶在終端上按退出鍵(一般采用Ctrl-\)時,產生此信號,並送至前台進
程組中的所有進程。此信號不僅終止前台進程組(如SIGINT所做的那樣),同時產生一個core文件。
? SIGSEGV 指示進程進行了一次無效的存儲訪問。
名字SEGV表示“段違例(segmentation violation)”。
? SIGSYS 指示一個無效的系統調用。由於某種未知原因,進程執行了一條系統調用指令,
但其指示系統調用類型的參數卻是無效的。
? SIGTRAP 指示一個實現定義的硬件故障。
此信號名來自於PDP-11的TRAP指令。
? SIGXCPU SVR4和4.3+BSD支持資源限制的概念。如果進程超過了其軟C P U時間限制,則產生此信號。
? SIGXFSZ 如果進程超過了其軟文件長度限制,則SVR4和4.3+BSD產生此信號。
摘自《UNIX環境高級編程》第10章 信號。
使用core 文件調試程序
看下面的例子:
/*core_dump_test.c*/
1 #include <stdio.h>
2
3 const char *str = "test";
4
5 void core_test()
6 {
7 str[1] = 'T';
8 }
9
10 int main()
11 {
12 core_test();
13
14 return 0;
15 }
編譯:
[zhanghua@localhost core_dump]$ gcc –g core_dump_test.c -o core_dump_test
如果需要調試程序的話,使用gcc 編譯時加上-g 選項,這樣調試core 文件的時候比較容易找到錯誤的地方。
執行:
[zhanghua@localhost core_dump]$ ./core_dump_test
段錯誤
運行core_dump_test 程序出現了“段錯誤”,但沒有產生core 文件。這是因為系統默認core 文件的大小為0 ,所以沒有創建。可以用ulimit 命令查看和修改core 文件的大小。
[zhanghua@localhost core_dump]$ ulimit -c
0
[zhanghua@localhost core_dump]$ ulimit -c 1000
[zhanghua@localhost core_dump]$ ulimit -c
1000
-c 指定修改core 文件的大小,1000 指定了core 文件大小。也可以對core 文件的大小不做限制,如:
[zhanghua@localhost daemon]# ulimit -c unlimited
[zhanghua@localhost daemon]# ulimit -c
unlimited
如果想讓修改永久生效,則需要修改配置文件,如.bash_profile 、/etc/profile 或/etc/security/limits.conf 。
再次執行:
[zhanghua@localhost core_dump]$ ./core_dump_test
段錯誤 (core dumped)
[zhanghua@localhost core_dump]$ ls core.*
core.6133
可以看到已經創建了一個core.6133 的文件.6133是core_dump_test 程序運行的進程ID 。
在Linux 下可以用GDB 來調試core 文件。
[zhanghua@localhost core_dump]$ gdb core_dump_test core.6133
GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...
Core was generated by `./core_dump_test'.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /lib/tls/libc.so.6...done.
Loaded symbols for /lib/tls/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
#0 0x080482fd in core_test () at core_dump_test.c:7
7 str[1] = 'T';
(gdb) bt
#0 0x080482fd in core_test () at core_dump_test.c:7
#1 0x08048317 in main () at core_dump_test.c:12
#2 0x42015574 in __libc_start_main () from /lib/tls/libc.so.6
GDB 中鍵入bt ,就會看到程序崩潰時堆棧信息(當前函數之前的所有已調用函數的列表(包括當前函數),gdb只顯示最近幾個),我們很容易找到我們的程序在最后崩潰的時候調用了core_dump_test.c 第7 行的代碼,導致程序崩潰。注意:在編譯程序的時候要加入選項-g 。您也可以試試其他命令,如 fram 、list 等。更詳細的用法,請查閱GDB 文檔。
什么時候不產生core 文件
( a ) 進程是設置- 用戶-ID ,而且當前用戶並非程序文件的所有者;
( b ) 進程是設置- 組-ID ,而且當前用戶並非該程序文件的組所有者;
( c ) 用戶沒有寫當前工作目錄的許可權;
( d ) 文件太大。core 文件的許可權( 假定該文件在此之前並不存在) 通常是用戶讀/ 寫,組讀和其他讀。