目錄
- (一)什么是coredump
- (二)coredump產生的條件
- (1)coredump產生主要原因:
- (2)如何生成coredump
- (三)gdb使用
- (四)實例調試coredump文件
- (五)總結
(一)什么是coredump
應用程序運行出錯或異常退出時,在滿足一定條件下產生一個core文件,例如程序收到SIGABRT、SIGEMT等信號時(注:在signal.h里說明了哪些新號會產生coredump)都會出現coredump,我們平時見到最多的應該就是段錯誤。
core文件包含了程序運行時內存、寄存器狀態、堆棧指針、內存管理信息以及函數調用堆棧信息。
我們通過分析core文件可以找到應用程序崩潰的地方
(二)coredump產生的條件
(1)coredump產生主要原因:
1、內存訪問越界
2、多線程程序使用了線程不安全的函數。
3、多線程讀寫的數據未加鎖保護。
4、非法指針
5、堆棧溢出
(2)如何生成coredump
1. 首先需要內核支持kernel選項
2. 設置ulimit -c unlimited
可以通過ulimit -a查看core文件大小限制,core文件大小不能太小,否則不能生成core文件
3. 默認core文件生成在當前目錄,可以通過下面命令修改生成位置
可以通過/proc/sys/kernel/core_pattern進行設置。%p 出Core進程的PID
%u 出Core進程的UID
%s 造成Core的signal號
%t 出Core的時間,從1970-01-0100:00:00開始的秒數
%e 出Core進程對應的可執行文件名
eg:echo "core-%e-%p-%s-%t" > /proc/sys/kernel/core_pattern。
在每個進程下都有coredump_filter節點/proc/pid/coredump_filter。
通過配置coredump_filter可以選擇需在coredump的時候,將哪些內容dump到core文件中。
(三)gdb使用
這里介紹gdb命令,下一小節直接實例介紹使用流程,這里可以跳過,用的時候回來看
gdb 源程序 core文件
命令 | 解釋 |
---|---|
list/l | 查看程序 list +函數名稱/行號 list 顯示當前行后面的源程序 list -顯示當前行前面的源程序 |
run/r | 運行程序,設置運行參數 |
help | 顯示幫助信息 |
start | 單步執行,運行程序,停在第一條執行語句 |
break/b | break function在指定的函數停止 break 行號 在指定代碼行打斷 break +offset/break -offset在當前行的前面或后面的offset行打斷點,offset為自然數 break 在下一條命令處停止運行 break … if < condition>如設置break if i=100表示當i為100時程序停止運行 |
info | 查看信息 info break [n]其中n 表示斷點號來查看斷點信息 info signals info handle: 查看有哪些信號正在被gdb檢測 |
next < count> | 單步跟蹤,如果有函數調用不會進入函數,如果后面不加count表示一條一條的執行,加count表示執行后面的count條指令 |
step < count> | 單步跟蹤,如果有函數調用則進入該函數(進入該函數前提是此函數編譯有Debug信息),與next類似,其不加count表示一條一條執行,加上count表示自當前行開始執行count條代碼指令 |
finish | 運行程序直到當前函數完成并打印函數返回時的堆棧地址和返回值及參數值等信息 |
until | 運行程序直到退出循環體 |
continue/c | 當程序遇到斷點停止運行后可以使用continue命令恢復程序的運行到下一個斷點或直到程序結束 |
print命令 | 查看變量 |
set | 設置變量的值 |
x | 查看內存 格式x /nfu addr |
watch命令 | watch命令一般來觀察某個表達式(變量也可視為一種表達式)的值是否發生了變化,如果由變化則程序立即停止運行 |
return命令 | 如果在函數中設置了調試斷點,在斷點后還有語句沒有執行完,這個時候我們可以使用return命令強制函數忽略還沒有執行的語句并返回。 |
quit/q | 退出gdb調試 |
whatis/ptype | 顯示變量的類型 |
bt | 顯示函數調用路徑 |
(四)實例調試coredump文件
用一個最簡單的例子模擬一下coredump
#include <stdio.h>
#include <unistd.h>int main(int argc,char * argv[])
{char * pStr="helloworld\n";printf("%s\n",pStr);pStr[1] = 'y';return 0;
}
運行一下
root@l-virtual-machine:~/hc# gcc coretest.c
root@l-virtual-machine:~/hc# ./a.out
helloworld段錯誤 (核心已轉儲)
root@l-virtual-machine:~/hc# ls
a.out core coretest.c
編譯的時候一定要加入-g選項,要不然在最后顯示錯誤的時候只會顯示錯的地址,而不會顯示錯誤的具體信息
這個時候有了core文件,我們查看這個文件類型,使用file或readelf -h
命令 file core //將core這個文件的具體信息給顯示出來,命令最后會顯示這個core文件是通過哪個文件產生的root@l-virtual-machine:~/hc# file core
core: ELF 64-bit LSB core file x86-64, version 1 (SYSV), SVR4-style, from './a.out'
從紅色方框截圖可以看到,程序中止是因為信號SIGSEGV,且從bt(backtrace)命令(或者where)可以看到函數的調用棧,即程序執行到coretest.c的第8行,修改pStr導致的
(五)總結
在我們編譯程序時要使用-g選項保留一份程序,方便出問題時我們定位問題所在,core文件使用時注意:
(1)保證進程對生成core的目錄有讀寫權限
(2)若程序調用seteuid()/setegid() 改變了進程的有效用戶或組,則默認情況下系統不為這些進程生成 core 文件。除非將 /proc/sys/fs /suid_dumpable 文件的內容改為1(一般默認是0)。
(3)設置足夠大的Core文件大小限制,否則不能生成core文件。