【轉】使用GDB調試Coredump文件

來自:http://blog.ddup.us/?p=176html

寫C/C++程序常常要直接和內存打交道,一不當心就會形成程序執行時產生Segment Fault而掛掉。通常這種狀況都是由於數組越界訪問,空指針或是野指針讀寫形成的。程序小的話還比較好辦,對着源代碼仔細檢查就能解決。可是對於代碼量 較大的程序,裏邊包含N多函數調用,N多數組指針訪問,這時想定位問題就不是很容易了(此時牛人依然能夠經過在適當位置打printf加二分查找的方式迅 速定位:P)。懶人的話仍是直接GDB搞起吧。linux

神馬是Core Dump文件

偶爾就能聽見某程序員同窗抱怨「擦,又出Core了!」。簡單來講,core dump說的是操做系統執行的一個動做,當某個進程由於一些緣由意外終止(crash)的時候,操做系統會將這個進程當時的內存信息轉儲(dump)到磁盤上1。產生的文件就是core文件了,通常會以core.xxx形式命名。程序員

如何產生Core Dump

發生doredump通常都是在進程收到某個信號的時候,Linux上如今大概有60多個信號,可使用 kill -l 命令所有列出來。shell

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在其中,通常數組越界或是訪問空指針都會產生這個信號。另外雖然默認是這樣的,可是你也能夠寫本身的信號處理函數改變默認行爲,更多信號相關能夠看參考連接33bash

上述內容只是產生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。fetch

OK, 如今萬事具有,只缺一個能產生Core的程序了,介個對C程序員來講太容易了。spa

 
  
#include <stdio.h>;
#include <stdlib.h>;
 
    int crash()
    {
            char *xxx = "crash!!";
            xxx[1] = 'D'; // 寫只讀存儲區!
            return 2;
    }
 
    int foo()
    {
            return crash();
    }
 
    int main()
    {
            return foo();
    }
 
  

 上手調試操作系統

上邊的程序編譯的時候有一點須要注意,須要帶上參數-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信號。使用where命令,可知道出問題的代碼是如何被調用的。

好比:在查看larbin運行過程當中出現segmentation fault的時候,查看其core文件,發現是site.cc中的調用的newId()函數中的strcpy()這一行出了問題。使用where命令後,可知,通過main() -> fetchDns() -> NamedSite::newQuery() -> newId的過程,larbin程序出錯啦~~

GDB 經常使用操做

上邊的程序比較簡單,不須要另外的操做就能直接找到問題所在。現實卻不是這樣的,經常須要進行單步跟蹤,設置斷點之類的操做才能順利定位問題。下邊列出了GDB一些經常使用的操做。

  • 啓動程序:run
  • 設置斷點:b 行號|函數名
  • 刪除斷點:delete 斷點編號
  • 禁用斷點:disable 斷點編號
  • 啓用斷點:enable 斷點編號
  • 單步跟蹤:next 也能夠簡寫 n
  • 單步跟蹤:step 也能夠簡寫 s
  • 打印變量:print 變量名字
  • 設置變量:set var=value
  • 查看變量類型:ptype var
  • 順序執行到結束:cont
  • 順序執行到某一行: util lineno
  • 打印堆棧信息:bt

bt這個命令重點推薦,尤爲是當函數嵌套很深,調用關係複雜的時候,他可以顯示出整個函數的調用堆棧,調用關係一目瞭然。另外上邊有兩個單步執行的命令,一個是n,一個是s。主要區別是n會將函數調用當成一步執行,而s會跟進調用函數內部。

參考

  1. http://en.wikipedia.org/wiki/Coredump
  2. http://www.kernel.org/doc/man-pages/online/pages/man5/core.5.html
  3. http://www.kernel.org/doc/man-pages/online/pages/man7/signal.7.html
  4. http://cs.baylor.edu/~donahoo/tools/gdb/tutorial.html
  5. http://bloggerdigest.blogspot.com/2006/09/gnu-gdb-core-dump-debugging.html
相關文章
相關標籤/搜索