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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章