Linux環境下經常遇到某個進程掛掉而找不到原因,我們可以通過生成core file文件加上gdb來定位。
如何產生core file?
我們可以使用ulimit這條命令對core file文件的大小進行設定。
一般默認情況下,core file的大小被設置爲了0,這樣系統就不dump出core file了。
這時用如下命令進行設置:
ulimit -c unlimited
這樣便把core file的大小設置爲了無限大,同時也可以使用數字來替代unlimited,對core file的上限值做更精確的設定。
ulimit -c unlimited
這樣便把core file的大小設置爲了無限大,同時也可以使用數字來替代unlimited,對core file的上限值做更精確的設定。
生成的core file在哪裏?
core file生成的地方是在/proc/sys/kernel/core_pattern文件定義的。
改動到生成到自己定義的目錄的方法是:
echo "pattern" > /proc/sys/kernel/core_pattern
並且只有超級用戶可以修改這兩個文件。
echo "pattern" > /proc/sys/kernel/core_pattern
並且只有超級用戶可以修改這兩個文件。
"pattern"類似我們C語言打印字符串的格式,相關標識如下:
%%: 相當於%
%p: 相當於<pid>
%u: 相當於<uid>
%g: 相當於<gid>
%s: 相當於導致dump的信號的數字
%t: 相當於dump的時間
%h: 相當於hostname
%e: 相當於執行文件的名稱
%p: 相當於<pid>
%u: 相當於<uid>
%g: 相當於<gid>
%s: 相當於導致dump的信號的數字
%t: 相當於dump的時間
%h: 相當於hostname
%e: 相當於執行文件的名稱
這時用如下命令設置生成的core file到系統/tmp目錄下,並記錄pid以及執行文件名
echo "/tmp/core-%e-%p" > /proc/sys/kernel/core_pattern
測試如下代碼
1
2
3
4
5
6
7
8
9
10
11
12
|
#include
<stdio.h> int func( int *p) { *p
= 0; } int main() { func(NULL); return 0; } |
生成可執行文件並運行
gcc -o main a.c
root@ubuntu:~# ./main
Segmentation fault (core dumped)
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 ()
#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;
#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
就可以啦。
補充說明:
相關常用gdb命令
1,(gdb) backtrace /* 查看當前線程函數棧回溯 */
以上面的例子爲例
Program terminated with signal 11, Segmentation fault.
#0 0x080483ba in func (p=0x0) at main.c:5
5*p = 0;
(gdb) backtrace
#0 0x080483ba in func (p=0x0) at main.c:5
#1 0x080483d4 in main () at main.c:10
如果是多線程環境下(gdb) thread apply all backtrace /* 顯示所有線程棧回溯 */
2,(gdb) print [var] /* 查看變量值 */
(gdb) print p
$1 = (int *) 0x0
(gdb) print &p
$2 = (int **) 0xbf96d4d4
3,(gdb) x/FMT [Address] /* 根據格式查看地址指向的值 */
其中
FMT is a repeat count followed by a format letter and a size letter.
Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),
t(binary), f(float), a(address), i(instruction), c(char) and s(string).
Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).
The specified number of objects of the specified size are printed
according to the format.
(gdb) x/d 0xbf96d4d4
0xbf96d4d4:0
(gdb) x/c 0xbf96d4d4
0xbf96d4d4:0 '\000'
另外能導致產生core file文件的信號有以下10種
SIGQUIT:終端退出符
SIGILL:非法硬件指令
SIGTRAP:平臺相關的硬件錯誤,現在多用在實現調試時的斷點
SIGBUS:與平臺相關的硬件錯誤,一般是內存錯誤
SIGABRT:調用abort函數時產生此信號,進程異常終止
SIGFPE:算術異常
SIGSEGV:segment violation,無效內存引用
SIGXCPU:超過了cpu使用資源限制(setrlimit)
SIGXFSZ:超過了文件長度限制(setrlimit)
SIGSYS:無效的系統調用
使用GDB可能會提示錯誤:
第二次安裝總結: 1、需要先修改“/etc/yum.repos.d/CentOS-Debuginfo.repo”文件的enable=1; 2、使用 sudo yum install glibc 安裝; 3、使用 debuginfo-install glibc-2.12-1.166.el6_7.7.x86_64安裝。 測試,安裝成功。