Linux下core檔案產生的一些注意問題

來源:互聯網
上載者:User

  前面轉載了一篇文章關於core檔案的產生和調試使用的設定,但在使用有一些需要注意的問題,如 在什麼情況 才會正確地產生core檔案。

      列出一些常見問題:

一,如何使用core檔案

1. 使用core檔案

在core檔案所在目錄下鍵入:

gdb -c core

它會啟動GNU的調試器,來調試core檔案,並且會顯示產生此core檔案的程式名,中止此程式的訊號等等。

如果你已經知道是由什麼程式產生此core檔案的,比如MyServer崩潰了產生core.12345,那麼用此指令調試:

gdb -c core MyServer

以下怎麼辦就該去學習gdb的使用了


2. 一個小方法來測試產生core檔案

直接輸入指令:kill -s SIGSEGV $$


二,程式產生core的原因

造成程式coredump的原因很多,這雷根據以往的經驗總結一下:

1 記憶體訪問越界
  a) 由於使用錯誤的下標,導致數組訪問越界
  b) 搜尋字串時,依靠字串結束符來判斷字串是否結束,但是字串沒有正常的使用結束符
  c) 使用strcpy, strcat, sprintf, strcmp, strcasecmp等字串操作函數,將目標字串讀/寫爆。應該使用strncpy, strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmp等函數防止讀寫越界。
 
2 多線程程式使用了線程不安全的函數。
應該使用下面這些可重新進入的函數,尤其注意紅色標示出來的函數,它們很容易被用錯:
asctime_r(3c) gethostbyname_r(3n) getservbyname_r(3n) ctermid_r(3s) gethostent_r(3n) getservbyport_r(3n) ctime_r(3c) getlogin_r(3c) getservent_r(3n) fgetgrent_r(3c) getnetbyaddr_r(3n) getspent_r(3c) fgetpwent_r(3c) getnetbyname_r(3n) getspnam_r(3c) fgetspent_r(3c)
getnetent_r(3n) gmtime_r(3c) gamma_r(3m) getnetgrent_r(3n) lgamma_r(3m) getauclassent_r(3) getprotobyname_r(3n) localtime_r(3c) getauclassnam_r(3) etprotobynumber_r(3n) nis_sperror_r(3n) getauevent_r(3) getprotoent_r(3n) rand_r(3c) getauevnam_r(3) getpwent_r(3c)
readdir_r(3c) getauevnum_r(3) getpwnam_r(3c) strtok_r(3c) getgrent_r(3c) getpwuid_r(3c) tmpnam_r(3s) getgrgid_r(3c) getrpcbyname_r(3n) ttyname_r(3c) getgrnam_r(3c) getrpcbynumber_r(3n) gethostbyaddr_r(3n) getrpcent_r(3n)
 
3 多線程讀寫的資料未加鎖保護。
對於會被多個線程同時訪問的全域資料,應該注意加鎖保護,否則很容易造成core dump
 
4 非法指標
  a) 使用null 指標
  b) 隨意使用指標轉換。一個指向一段記憶體的指標,除非確定這段記憶體原先就分配為某種結構或類型,或者這種結構或類型的數組,否則不要將它轉換為這種結構或類型的指標,而應該將這段記憶體拷貝到一個這種結構或類型中,再訪問這個結構或類型。這是因為如果這段記憶體的開始地址不是按照這種結構或類型對齊的,那麼訪問它時就很容易因為bus error而core dump.
 
5 堆疊溢位
不要使用大的局部變數(因為局部變數都分配在棧上),這樣容易造成堆疊溢位,破壞系統的棧和堆結構,導致出現莫名其妙的錯誤。


三,注意的問題

 

在Linux下要保證程式崩潰時產生Coredump要注意這些問題:

 

  一、要保證存放Coredump的目錄存在且進程對該目錄有寫入權限。存放Coredump的目錄即進程的目前的目錄,一般就是當初發出命令啟動該進程時所在的目錄。但如果是通過指令碼啟動,則指令碼可能會修改目前的目錄,這時進程真正的目前的目錄就會與當初執行指令碼所在目錄不同。這時可以查看”/proc/<進程pid>/cwd“符號連結的目標來確定進程真正的目前的目錄地址。通過系統服務啟動的進程也可通過這一方法查看。

 

  二、若程式調用了seteuid()/setegid()改變了進程的有效使用者或組,則在預設情況下系統不會為這些進程產生Coredump。很多服務程式都會調用seteuid(),如MySQL,不論你用什麼使用者運行mysqld_safe啟動MySQL,mysqld進行的有效使用者始終是msyql使用者。如果你當初是以使用者A運行了某個程式,但在ps裡看到的這個程式的使用者卻是B的話,那麼這些進程就是調用了seteuid了。為了能夠讓這些進程產生core
dump,需要將/proc/sys/fs /suid_dumpable檔案的內容改為1(一般預設是0)。

 

  三、要設定足夠大的Core檔案大小限制了。程式崩潰時產生的Core檔案大小即為程式運行時佔用的記憶體大小。但程式崩潰時的行為不可按平常時的行為來估計,比如緩衝區溢位等錯誤可能導致堆棧被破壞,因此經常會出現某個變數的值被修改成亂七八糟的,然後程式用這個大小去申請記憶體就可能導致程式比平常時多佔用很多記憶體。因此無論程式正常運行時佔用的記憶體多麼少,要保證產生Core檔案還是將大小限制設為unlimited為好。

            在shell裡使用命令:ulimit -c unlimited,這樣進行修改只是對本次會話有效,是臨時的,如果想讓修改永久生效,則需要修改設定檔,如 .bash_profile、/etc/profile或/etc/security/limits.conf

    如下:

    [root@otctest ~]# vim  /etc/profile

    結果

     
 

    把紅框裡的行注釋,並新加入一行:

    ulimit -c unlimited

    儲存,退出即可。


四,產生core檔案的時機

     當我們的程式崩潰時,核心有可能把該程式當前記憶體映射到core檔案裡,方便程式員找到程式出現問題的地方。最常出現的,幾乎所有C程式員都出現過的錯誤就是“段錯誤”了。也是最難查出問題原因的一個錯誤。下面我們就針對“段錯誤”來分析core檔案的產生、以及我們如何利用core檔案找到出現崩潰的地方。

何謂core檔案

當一個程式崩潰時,在進程當前工作目錄的core檔案中複製了該進程的儲存映像。core檔案僅僅是一個記憶體映象(同時加上調試資訊),主要是用來調試的。

當程式接收到以下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*/
 #include <stdio.h>
const char *str = "test";
void core_test(){
    str[1] = 'T';
}

int main(){
    core_test();
    return 0;
}

編譯:
gcc –g core_dump_test.c -o core_dump_test

如果需要偵錯工具的話,使用gcc編譯時間加上-g選項,這樣調試core檔案的時候比較容易找到錯誤的地方。

執行:
 ./core_dump_test
段錯誤

運行core_dump_test程式出現了“段錯誤”,但沒有產生core檔案。這是因為系統預設core檔案的大小為0,所以沒有建立。可以用ulimit命令查看和修改core檔案的大小。
ulimit -c 0
ulimit -c 1000
ulimit -c 1000

-c 指定修改core檔案的大小,1000指定了core檔案大小。也可以對core檔案的大小不做限制,如:

ulimit -c unlimited
ulimit -c unlimited

如果想讓修改永久生效,則需要修改設定檔,如 .bash_profile、/etc/profile或/etc/security/limits.conf。

再次執行:
./core_dump_test
段錯誤 (core dumped)
ls core.*
core.6133

可以看到已經建立了一個core.6133的檔案.6133是core_dump_test程式啟動並執行進程ID。

調式core檔案
core檔案是個二進位檔案,需要用相應的工具來剖析器崩潰時的記憶體映像。

file core.6133

core.6133: ELF 32-bit LSB core file Intel 80386, version 1 (SYSV), SVR4-style, from 'core_dump_test'

在Linux下可以用GDB來調試core檔案。

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) where
#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中鍵入where,就會看到程式崩潰時堆棧資訊(當前函數之前的所有已調用函數的列表(包括當前函數),gdb只顯示最近幾個),我們很容易找到我們的程式在最後崩潰的時候調用了core_dump_test.c 第7行的代碼,導致程式崩潰。注意:在編譯器的時候要加入選項-g。您也可以試試其他命令, 如 fram、list等。更詳細的用法,請查閱GDB文檔。

core檔案建立在什麼位置

在進程當前工作目錄的下建立。通常與程式在相同的路徑下。但如果程式中調用了chdir函數,則有可能改變了當前工作目錄。這時core檔案建立在chdir指定的路徑下。有好多程式崩潰了,我們卻找不到core檔案放在什麼位置。和chdir函數就有關係。當然程式崩潰了不一定都產生core檔案。

什麼時候不產生core檔案

在下列條件下不產生core檔案:
( a )進程是設定-使用者-ID,而且目前使用者並非程式檔案的所有者;
( b )進程是設定-組-ID,而且目前使用者並非該程式檔案的群組擁有者;
( c )使用者沒有寫當前工作目錄的許可權;
( d )檔案太大。core檔案的許可權(假定該檔案在此之前並不存在)通常是使用者讀/寫,組讀和其他讀。

利用GDB調試core檔案,當遇到程式崩潰時我們不再束手無策。

(轉自:http://blog.csdn.net/fengxinze/article/details/6800175)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.