1. 程式人生 > >gdb 檢視堆疊資訊、載入core檔案、連線到其它程序

gdb 檢視堆疊資訊、載入core檔案、連線到其它程序

當程式被停住了,你需要做的第一件事就是檢視程式是在哪裡停住的。當你的程式呼叫了一個函式,函式的地址,函式引數,函式內的區域性變數都會被壓入“棧”(Stack)中。你可以用GDB命令來檢視當前的棧中的資訊。

一、gdb 檢視堆疊資訊
下面是一些檢視函式呼叫棧資訊的GDB命令:
1、backtrace、bt

列印當前的函式呼叫棧的所有資訊。如:

(gdb) bt
#0 func (n=250) at tst.c:6
#1 0x08048524 in main (argc=1, argv=0xbffff674) at tst.c:30
#2 0x400409ed in __libc_start_main () from /lib/libc.so.6

從上可以看出函式的呼叫棧資訊:__libc_start_main --> main()--> func()

backtrace <n>
bt <n>
n是一個正整數,表示只打印棧頂上n層的棧資訊。

backtrace <-n>
bt <-n>
-n表一個負整數,表示只打印棧底下n層的棧資訊。

如果你要檢視某一層的資訊,你需要在切換當前的棧,一般來說,程式停止時,最頂層的棧就是當前棧,如果你要檢視棧下面層的詳細資訊,首先要做的是切換當前棧。


2、frame、f

n是一個從0開始的整數,是棧中的層編號。比如:frame 0,表示棧頂,frame 1,表示棧的第二層。

檢視當前棧層的資訊,你可以用以下GDB命令:
frame 或 f

會打印出這些資訊:棧的層編號,當前的函式名,函式引數值,函式所在檔案及行號,函式執行到的語句。

up
表示向棧的上面移動n層,可以不打n,表示向上移動一層。

down
表示向棧的下面移動n層,可以不打n,表示向下移動一層。
上面的命令,都會打印出移動到的棧層的資訊。如果你不想讓其打出資訊。你可以使用這三個命令:

select-frame 對應於 frame 命令。
up-silently 對應於 up 命令。
down-silently 對應於 down 命令。

3、info frame、info f

這個命令會打印出更為詳細的當前棧層的資訊,只不過,大多數都是執行時的記憶體地址。比如:函式地址,呼叫函式的地址,被呼叫函式的地址,目前的函式是由什麼樣的程式語言寫成的、函式引數地址及值、區域性變數的地址等等。如:

(gdb) info f
Stack level 0, frame at 0xbffff5d4:
eip = 0x804845d in func (tst.c:6); saved eip 0x8048524
called by frame at 0xbffff60c
source language c.
Arglist at 0xbffff5d4, args: n=250
Locals at 0xbffff5d4, Previous frame's sp is 0x0
Saved registers:
ebp at 0xbffff5d4, eip at 0xbffff5d8

4、info args

打印出當前函式的引數名及其值。

5、info locals
打印出當前函式中所有區域性變數及其值。

6、info catch

打印出當前的函式中的異常處理資訊。

:

程式“呼叫堆疊”是當前函式之前的所有已呼叫函式的列表(包括當前函式)。每個函式及其變數都被分配了一個“幀”,最近呼叫的函式在 0 號幀中(“底部”幀)。要列印堆疊,發出命令 'bt'('backtrace' [回溯] 的縮寫):

(gdb) bt
#0  0x80483ea in wib (no1=8, no2=8) at eg1.c:7
#1  0x8048435 in main (argc=1, argv=0xbffff9c4) at eg1.c:21

此結果顯示了在 main() 的第 21 行中呼叫了函式 wib()(只要使用 'list 21' 就能證實這一點),而且 wib() 在 0 號幀中,main() 在 1 號幀中。由於 wib() 在 0 號幀中,那麼它就是執行程式時發生算術錯誤的函式。
實際上,發出 'info locals' 命令時,gdb 會打印出當前幀中的區域性變數,預設情況下,這個幀中的函式就是被中斷的函式(0 號幀)。可以使用命令 'frame' 列印當前幀。要檢視 main 函式(在 1 號幀中)中的變數,可以發出 'frame 1' 切換到 1 號幀,然後發出 'info locals' 命令:

(gdb) frame 1
#1  0x8048435 in main (argc=1, argv=0xbffff9c4) at eg1.c:21
21          result = wib(value, div);
(gdb) info locals
value = 8
div = 8
result = 4
i = 2
total = 6
   
此資訊顯示了在第三次執行 "for" 迴圈時(i 等於 2)發生了錯誤,此時 "value" 等於 "div"。可以通過如上所示在 'frame' 命令中明確指定號碼,或者使用 'up' 命令在堆疊中上移以及 'down' 命令在堆疊中下移來切換幀。要獲取有關幀的進一步資訊,如它的地址和程式語言,可以使用命令 'info frame'。
gdb 堆疊命令可以在程式執行期間使用,也可以在 core 檔案中使用,因此對於複雜的程式,可以在程式執行時跟蹤它是如何轉到函式的。

二、載入core檔案

產生core dump之後, 用gdb進行檢視core檔案的內容, 以定位檔案中激發core dump的行.
gdb [exec file] [core file]
如:
gdb ./test test.core

載入後,可以發出 'info locals'、'print'、'info args' 和 'list' 等 gdb 命令或堆疊命令來檢視除錯資訊。'info variables' 命令將打印出所有程式變數的值,但這要進行很長時間,因為 gdb 將列印 C 庫和程式程式碼中的變數。

三、gdb連線到其它程序
除了除錯 core 檔案或程式之外,gdb 還可以連線到已經執行的程序(它的程式已經過編譯,並加入了除錯資訊),並中斷該程序。只需用希望 gdb 連線的程序標識替換 core 檔名就可以執行此操作。

以下是一個執行迴圈並睡眠的 示例程式:
eg2 示例程式碼
------------------------------------------------------------------------

#include 
int main(int argc, char *argv[])
{
     int i;
     for(i = 0; i < 60; i++)
     {
         sleep(1);
     }
return 0;
}

------------------------------------------------------------------------

1、編譯並執行程式
使用 'gcc -g eg2.c -o eg2' 編譯該程式並使用 './eg2 &' 執行該程式。請留意在啟動該程式時在背景上列印的程序標識,在本例中是 1283:
------------------------------------------------------------------------
./eg2 &
[3] 1283
------------------------------------------------------------------------

2、發起連線
連線到程序: ‘gdb [被除錯檔案] -c [程序號]' ,也可以不要 -c。
啟動 gdb 並指定程序標識,在我舉的這個例子中是 'gdb eg2 1283'。gdb 會查詢一個叫作 "1283" 的 core 檔案。如果沒有找到,那麼只要程序 1283 正在執行(在本例中可能在 sleep() 中),gdb 就會連線並中斷該程序:
------------------------------------------------------------------------
...
/home/seager/gdb/1283: No such file or directory.
Attaching to program: /home/seager/gdb/eg2, Pid 1283
...
0x400a87f1 in __libc_nanosleep () from /lib/libc.so.6
(gdb)
------------------------------------------------------------------------

3、gdb除錯( gdb 命令或堆疊命令來檢視除錯資訊)
此時,可以發出所有常用 gdb 命令。可以使用 'backtrace' 來檢視當前位置與 main() 的相對關係,以及 mian() 的幀號是什麼,然後切換到 main() 所在的幀,檢視已經在 "for" 迴圈中運行了多少次:
------------------------------------------------------------------------
(gdb) backtrace
#0 0x400a87f1 in __libc_nanosleep () from /lib/libc.so.6
#1 0x400a877d in __sleep (seconds=1) at ../sysdeps/unix/sysv/linux/sleep.c:78
#2 0x80483ef in main (argc=1, argv=0xbffff9c4) at eg2.c:7
(gdb) frame 2
#2 0x80483ef in main (argc=1, argv=0xbffff9c4) at eg2.c:7
7 sleep(1);
(gdb) print i
$1 = 50
------------------------------------------------------------------------

4、除錯完、斷開連線等
detach / kill:輸入'detach' or 'kill',不需要程序號。
如果已經完成了對程式的修改,可以 'detach' 命令繼續執行程式,或者 'kill' 命令殺死程序。
attach:先輸入'file eg2',然後輸入'attach 1283'
還可以首先使用 'file eg2' 裝入檔案,然後發出 'attach 1283' 命令連線到程序標識 1283 下的 eg2。


轉自:http://blog.csdn.net/azr22005/article/details/6927420
         http://www.cppblog.com/BlueSky/archive/2007/11/20/37012.html
         http://hi.baidu.com/andrewhome/blog/item/bb90fadf09b43a1049540326.html