轉自:https://blog.csdn.net/yhc166188/article/details/85863051
core dump的概念:
A core dump is the recorded state of the working memory of a computer program at a specific time, generally when the program has terminated abnormally (crashed). In practice, other key pieces of program state are usually dumped at the same time, including the processor registers, which may include the program counter and stack pointer, memory management information, and other processor and operating system flags and information. The name comes from the once-standard memory technology core memory. Core dumps are often used to diagnose or debug errors in computer programs.
On many operating systems, a fatal error in a program automatically triggers a core dump, and by extension the phrase "to dump core" has come to mean, in many cases, any fatal error, regardless of whether a record of the program memory is created.
在linux平台下,設置core dump文件生成的方法:
linux coredump調試
1 )如何生成 coredump 文件 ?
登陸 LINUX 服務器,任意位置鍵入
echo "ulimit -c 1024" >> /etc/profile
退出 LINUX 重新登陸 LINUX
鍵入 ulimit -c
如果顯示 1024 那么說明 coredump 已經被開啟。
1024 限制產生的 core 文件的大小不能超過 1024kb,可以使用參數unlimited,取消該限制
ulimit -c unlimited
2 ) . core 文件的簡單介紹
在一個程序崩潰時,它一般會在指定目錄下生成一個 core 文件,一般在/tmp目錄下。 core 文件僅僅是一個內存映象 ( 同時加上調試信息 ) ,主要是用來調試的。
3 ) . 開啟或關閉 core 文件的生成
用以下命令來阻止系統生成 core 文件 :
ulimit -c 0
下面的命令可以檢查生成 core 文件的選項是否打開 :
ulimit -a
該命令將顯示所有的用戶定制,其中選項 -a 代表“ all ”。
也可以修改系統文件來調整 core 選項
在 /etc/profile 通常會有這樣一句話來禁止產生 core 文件,通常這種設置是合理的 :
# No core files by default
ulimit -S -c 0 > /dev/null 2>&1
但是在開發過程中有時為了調試問題,還是需要在特定的用戶環境下打開 core 文件產生的設置。
在用戶的 ~/.bash_profile 里加上 ulimit -c unlimited 來讓特定的用戶可以產生 core 文件。
如果 ulimit -c 0 則也是禁止產生 core 文件,而 ulimit -c 1024 則限制產生的 core 文件的大小不能超過 1024kb
4 ) . 設置 Core Dump 的核心轉儲文件目錄和命名規則
/proc/sys/kernel/core_uses_pid 可以控制產生的 core 文件的文件名中是否添加 pid 作為擴展 ,如果添加則文件內容為 1 ,否則為 0
proc/sys/kernel/core_pattern 可以設置格式化的 core 文件保存位置或文件名 ,比如原來文件內容是 core-%e
可以這樣修改 :
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 添加命令名
6 ) . 一個小方法來測試產生 core 文件
直接輸入指令 :
kill -s SIGSEGV $$
如何產生Core Dump
發生doredump一般都是在進程收到某個信號的時候,Linux上現在大概有60多個信號,可以使用 kill -l 命令全部列出來。
sagi@sagi-laptop:~$ kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 64) SIGRTMAX
針對特定的信號,應用程序可以寫對應的信號處理函數。如果不指定,則采取默認的處理方式, 默認處理是coredump的信號如下:
3)SIGQUIT 4)SIGILL 6)SIGABRT 8)SIGFPE 11)SIGSEGV 7)SIGBUS 31)SIGSYS 5)SIGTRAP 24)SIGXCPU 25)SIGXFSZ 29)SIGIOT
我們看到SIGSEGV在其中,一般數組越界或是訪問空指針都會產生這個信號。另外雖然默認是這樣的,但是你也可以寫自己的信號處理函數改變默認行為,更多信號相關可以看參考鏈接33。
上述內容只是產生coredump的必要條件,而非充分條件。要產生core文件還依賴於程序運行的shell,可以通過ulimit -a命令查看,輸出內容大致如下:
sagi@sagi-laptop:~$ ulimit -a core file size (blocks, -c) 0 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
看到第一行了吧,core file size,這個值用來限制產生的core文件大小,超過這個值就不會保存了。我這里輸出是0,也就是不會保存core文件,即使產生了,也保存不下來==! 要改變這個設置,可以使用ulimit -c unlimited。
OK, 現在萬事具備,只缺一個能產生Core的程序了,介個對C程序員來說太容易了。
#include <stdio.h>; #include <stdlib.h>; int crash() { char *xxx = "crash!!"; xxx[1] = 'D'; // 寫只讀存儲區! return 2; } int foo() { return crash(); } int main() { return foo(); }
上手調試
測試如下代碼
1 2 3 4 5 6 7 8 9 10 11 12 |
|
生成可執行文件並運行
gcc -o main a.c
root@ubuntu:~# ./main
Segmentation fault (core dumped)
<-----這里出現段錯誤並生成core文件了。
在/tmp目錄下發現文件core-main-10815
如何查看進程掛在哪里了?
我們可以用
gdb main /tmp/core-main-10815
查看信息,發現能定位到函數了
Program terminated with signal 11, Segmentation fault.
#0 0x080483ba in func ()
如何定位到行?
在編譯的時候開啟-g調試開關就可以了
gcc -o main -g a.c
gdb main /tmp/core-main-10815
最終看到的結果如下,好棒。
Program terminated with signal 11, Segmentation fault.
#0 0x080483ba in func (p=0x0) at a.c:5
5 *p = 0;
總結一下,需要定位進程掛在哪一行我們只需要4個操作,
ulimit -c unlimited
echo "/tmp/core-%e-%p" > /proc/sys/kernel/core_pattern
gcc -o main -g a.c
gdb main /tmp/core-main-10815
就可以啦。
上邊的程序編譯的時候有一點需要注意,需要帶上參數-g, 這樣生成的可執行程序中會帶上足夠的調試信息。編譯運行之后你就應該能看見期待已久的“Segment Fault(core dumped)”或是“段錯誤 (核心已轉儲)”之類的字眼了。看看當前目錄下是不是有個core或是core.xxx的文件。祭出linux下經典的調試器GDB,首先帶着core文件載入程序:gdb exefile core,這里需要注意的這個core文件必須是exefile產生的,否則符號表會對不上。載入之后大概是這個樣子的:
sagi@sagi-laptop:~$ gdb coredump core Core was generated by ./coredump'. Program terminated with signal 11, Segmentation fault. #0 0x080483a7 in crash () at coredump.c:8 8 xxx[1] = 'D'; (gdb)
我們看到已經能直接定位到出core的地方了,在第8行寫了一個只讀的內存區域導致觸發Segment Fault信號。在載入core的時候有個小技巧,如果你事先不知道這個core文件是由哪個程序產生的,你可以先隨便找個代替一下,比如/usr/bin/w就是不錯的選擇。比如我們采用這種方法載入上邊產生的core,gdb會有類似的輸出:
sagi@sagi-laptop:~$ gdb /usr/bin/w core Core was generated by ./coredump'. Program terminated with signal 11, Segmentation fault. #0 0x080483a7 in ?? () (gdb)
可以看到GDB已經提示你了,這個core是由哪個程序產生的。
GDB 常用操作
上邊的程序比較簡單,不需要另外的操作就能直接找到問題所在。現實卻不是這樣的,常常需要進行單步跟蹤,設置斷點之類的操作才能順利定位問題。下邊列出了GDB一些常用的操作。
- 啟動程序:run
- 設置斷點:b 行號|函數名
- 刪除斷點:delete 斷點編號
- 禁用斷點:disable 斷點編號
- 啟用斷點:enable 斷點編號
- 單步跟蹤:next 也可以簡寫 n
- 單步跟蹤:step 也可以簡寫 s
- 打印變量:print 變量名字
- 設置變量:set var=value
- 查看變量類型:ptype var
- 順序執行到結束:cont
- 順序執行到某一行: util lineno
- 打印堆棧信息:bt