原做者:http://blog.csdn.net/wj_j2ee/article/details/7161586linux
1. 內核轉儲做用shell
(1) 內核轉儲的最大好處是可以保存問題發生時的狀態。ubuntu
(2) 只要有可執行文件和內核轉儲,就能夠知道進程當時的狀態。服務器
(3) 只要獲取內核轉儲,那麼即便沒有復現環境,也能調試。網絡
2. 啓用內核轉儲函數
1.1 查看內核轉儲是否有效測試
在終端中輸入如下命令,查看內核轉儲是否有效。ui
#ulimit -cspa
0.net
-c 表示內核轉儲文件的大小限制,如今顯示爲零,表示不能用。
能夠改成1G
#ulimit -c 1073741824
也能夠改成無限制
#ulimit -c unlimited
2.2 測試一個例子
例子的源代碼:
#include <stdio.h>
int main(void)
{
int *a = NULL;
*a = 0x1;
return 0;
}
把以上源代碼,寫成一個a.c文件後,編譯a.c文件產生一個a.out的可執行文件:
#gcc -g a.c -o a.out
修改a.out文件的權限後,執行它:
#./a.out
就會顯示:
Segmentation fault(core dump)
這表示在當前目錄下, 已經生成了a.out對應的內核轉儲文件。
注意:後面帶有(core dump), 才說明轉儲文件成功生成了。
#file core*
core:ELF 64-bit LSB core file x86-64, version 1(SYSV), SVR4-style, from './a.out'
coreDump: UTF-8 Unicode C program text
要用GDB調試內核轉儲文件,應該使用如下方式啓動GDB:
#gdb -c ./*.core ./a.out
GNU gdb (GDB) 7.1-Ubuntu
...
Core was generated by './a.out'.
Program terminated with signal 11, Segmentation fault.
#0 0x00000000004004dc in main() at a.c:6
6 *a =0x1;
a.c的第6行收到了11號信號。用GDB的list命令能夠查看附近的源代碼。
(gdb) l 5
1 #include <stdio.h>
2
3 int main(void)
4 {
5 int *a = NULL;
6 *a = 0x1;
7 return 0;
8 }
這裏默認都是當前目錄,也能夠給core 和a.out 指定路徑
到這裏測試完成!
2.3 永久生效的辦法
上面所述的方法,只是在當前shell中生效,重啓以後,就再也不有效了。永久生效的辦法是:
#vi /etc/profile 而後,在profile中添加:
ulimit -c 1073741824
(可是,若將產生的轉儲文件大小大於該數字時,將不會產生轉儲文件)
或者
ulimit -c unlimited
這樣重啓機器後生效了。 或者, 使用source命令使之立刻生效。
#source /etc/profile
3. 指定內核轉儲的文件名和目錄
缺省狀況下,內核在coredump時所產生的core文件放在與該程序相同的目錄中,而且文件名固定爲core。很顯然,若是有多個程序產生core文件,或者同一個程序屢次崩潰,就會重複覆蓋同一個core文件。
咱們能夠經過修改kernel的參數,指定內核轉儲所生成的core文件的路徑和文件名。
能夠經過在/etc/sysctl.conf文件中,對sysctl變量kernel.core_pattern的設置。
#vi /etc/sysctl.conf 而後,在sysctl.conf文件中添加下面兩句話:
kernel.core_pattern = /var/core/core_%e_%p
kernel.core_uses_pid = 0
保存後退出。
須要說明的是, /proc/sys/kernel/core_uses_pid。若是這個文件的內容被配置成1,即便core_pattern中沒有設置%p,最後生成的core dump文件名仍會加上進程ID。
這裏%e, %p分別表示:
%c 轉儲文件的大小上限
%e 所dump的文件名
%g 所dump的進程的實際組ID
%h 主機名
%p 所dump的進程PID
%s 致使本次coredump的信號
%t 轉儲時刻(由1970年1月1日起計的秒數)
%u 所dump進程的實際用戶ID
可使用如下命令,使修改結果立刻生效。
#sysctl –p /etc/sysctl.conf
請在/var目錄下先創建core文件夾,而後執行a.out程序,就會在/var/core/下產生以指定格式命名的內核轉儲文件。查看轉儲文件的狀況:
#ls /var/core
core_a.out_2834
4. 手動強制某個進程產生core dump的方法(嘗試)
當某些程序發生crash時,對應進程會產生coredump文件。經過這個coredump文件,開發人員能夠找到bug的緣由。可是coredump的產生,大都是由於程序crash了。
而有些bug是不會致使程序crash的,好比死鎖,這時程序已經不正常了,但是卻沒有coredump產生。若是環境又不容許gdb調試,難道咱們就一籌莫展了嗎?
針對以上這種狀況,通常狀況下,對於這樣的進程能夠利用watchdog監控它們,當發現這些進程很長時間沒有更新其heartbeat時,能夠給這些進程發送能夠致使其產生coredump的信號。根據linux的信號默認的處理行爲,SIGQUIT,SIGABRT, SIGFPE和SIGSEGV均可以讓該進程產生coredump文件。這樣咱們能夠經過coredump來得知死鎖是否發生。 固然, 若是進程添加了這些信號的處理函數,那麼就不會產生coredump了。不過,對於SIGQUIT, SIGABRT, SIGFPE, SIGSEGV,有誰會爲它們加上信號處理函數呢。
還有一種狀況,進程並無死鎖或者block在某個位置,可是咱們須要在某個指定位置進行調試,獲取某些變量或者其它信息。可是,有多是客戶環境或者生產環境,不容許咱們進行長時間的檢測。那麼,咱們就須要經過coredump來得到進程在運行到該點時的快照。 這個時候,能夠利用gdb來手工產生coredump。在attach上這個進程時,在指定位置打上斷點,當斷點觸發時,使用gdb的命令gcore,能夠當即產生一個coredump。 這樣,咱們就拿到了這個位置的進程快照。
1.尋找您要發送信號的進程ID,
# ps -ef | grep qemu
root 3207 3206 44 10:32 pts/1 00:00:18 /usr/local/bin/qemu-system-x86
得出 qemu-system-x86的 PID號是3207
2.使用kill(1)去發送信號。
# /bin/kill -s QUIT 3207
發送其餘的信號也很類似, 只要在命令行中替換QUIT 爲ABRT,TERM 或 KILL 就好了
重要提示: 在系統上隨意殺死進程是一個壞主意,特別是init(8),它的PID是1,它很是特殊。 能夠運行 /bin/kill -s KILL 1 命令來讓系統迅速關機。 當您按下 Return (回車)鍵以前, 必定要 詳細檢查您運行 kill(1) 時所指定的參數。
5 使用core dump進行調試
在Linux下遇到「段錯誤」(segmentation fault),若是段錯誤發生在服務器端,而服務器端要繼續工做,不容許調試,這時「內核轉儲(core dump)」就派上了用場,能夠把生成的內核轉儲複製到本地進行調試。
首先,按照上面的永久生效方法,在服務器上進行相應設置。 而後程序在崩潰時,就會在程序所在目錄(或本身指定的目錄)生成一個core文件,把這個core文件拷到本地(最好與該進程對應的可執行文件放到同一個目錄,若否則,在gdb時指出路徑也能夠)。
具體方法以下:
方法一:
輸入命令 #gdb <程序可執行文件> <coredump轉儲文件>
例如:
# gdb /usr/local/bin/qemu-system-x86_64 /var/core/core-3207-qemu-system-x86
而後,在(gdb)提示符後輸入 l, 會顯示main主函數
方法二:
(1) 在終端輸入命令# gdb [-c] <coredump文件>,
例如: gdb -c /var/core/core-3207-qemu-system-x86
(2)而後,在(gdb)提示符後輸入file <可執行程序>
例如:(gdb) file /usr/local/bin/qemu-system-x86_64
(3) 這時就能夠用backtrace/thread等命令查看當時的錯誤了,就像程序在本地執行到崩潰點同樣
或者用where回車, 也能夠顯示程序在哪一行當掉的
5. 啓用整個系統的內核轉儲
(未完待續......)
(4.1) 編輯/etc/profile, 開啓登陸到系統的全部用戶的內核轉儲功能
首先,看看用的是個什麼機器:
# uname –a
Linux ubuntu240 2.6.32-21-server #32-Ubuntu SMP Fri Apr 16 09:17:34 UTC 2010 x86_64 GNU/Linux
其次,再查看一些默認參數,若core file size是0,即便程序出錯時,也不會產生core文件。
# ulimit -a
core file size (blocks, -c) unlimited
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 20
file size (blocks, -f) unlimited
pending signals (-i) 16382
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) unlimited
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
你可能會由於不但願設置ulimit 的時候太僵硬致使空間不夠沒有獲得完整的轉儲,因此設置ulimit 爲"unlimited" (不限制)。可是若是執行一個佔用內存很恐怖的程序,當這個程序內核轉儲的時候也就會生成體積很恐怖的轉儲文件。
爲了不這種狀況,能夠指定內核轉儲掩碼來排除要轉儲的內存段。
掩碼請查看/usr/src/linux/Documentation/sysctl/kernel.txt 中的3.4 小節,沒有內核源碼能夠到這裏的網絡版,這裏摘錄出來以下:
The following 7 memory types are supported:
- (bit 0) anonymous private memory(匿名私有內存段)
- (bit 1) anonymous shared memory(匿名共享內存段)
- (bit 2) file-backed private memory(file-backed 私有內存段)
- (bit 3) file-backed shared memory(file-bakced 共享內存段)
- (bit 4) ELF header pages in file-backed private memory areas (it is
effective only if the bit 2 is cleared)(ELF 文件映射,只有在bit 2 復位的時候才起做用)
- (bit 5) hugetlb private memory(大頁面私有內存)
- (bit 6) hugetlb shared memory(大頁面共享內存)
設置方法很簡單:找到程序的PID,而後修改/proc/PID/coredump_filter 的值。
若是你要設置某些尚未運行的進程的內核轉儲掩碼,請修改/proc/self/coredump_filter 的值。
PS:
a. 默認的coredump_filter 的值通常是0x23,至於表明什麼,請換成二進制00100011,從右向左看,bit 0、bit 一、bit 5 被置位,也就是說會轉儲全部的匿名內存段和大頁面私有內存段。
b. 共享內存段都是同樣的,能夠沒必要轉儲。
全局設置沒有什麼好說的,把你的配置寫入/etc/profile.d/ 目錄下任意一個新建的文件當中,別忘了設置屬組和全部者爲root:root,權限爲751。
根據上面說的,寫入的要有一條ulimit 指令,可能還有一條sysctl 指令,最後可能還有一條cat 指令。
更多的設置請查看上面提到的kernel.txt 和proc.txt,例如你想把SUID 程序也轉儲,你須要
sysctl -w 'fs.suid_dumpable=1'