gdb調試之重要命令

一、GDB改變程序的執行

一旦使用GDB掛上被調試程序,當程序運行起來後,你可以根據自己的調試思路來動態地在GDB中更改當前被調試程序的運行線路或是其變量的值,這個強大的功能能夠讓你更好的調試你的程序,比如,你可以在程序的一次運行中走遍程序的所有分支。

修改變量值

修改被調試程序運行時的變量值,在GDB中很容易實現,使用GDB的print命令即可完成。如:

(gdb) print x=4

x=4這個表達式是C/C++的語法,意爲把變量x的值修改爲4,如果你當前調試的語言是Pascal,那麼你可以使用Pascal的語法:x:=4。

在某些時候,很有可能你的變量和GDB中的參數衝突,如:

(gdb) whatis width
type = double
(gdb) p width
$4 = 13
(gdb) set width=47
Invalid syntax in expression.

因爲,set width是GDB的命令,所以,出現了“Invalid syntax in expression”的設置錯誤,此時,你可以使用set var命令來告訴GDB,width不是你GDB的參數,而是程序的變量名,如:

(gdb) set var width=47

另外,還可能有些情況,GDB並不報告這種錯誤,所以保險起見,在你改變程序變量取值時,最好都使用set var格式的GDB命令。

跳轉執行

一般來說,被調試程序會按照程序代碼的運行順序依次執行。GDB提供了亂序執行的功能,也就是說,GDB可以修改程序的執行順序,可以讓程序執行隨意跳躍。這個功能可以由GDB的jump命令來完:

jump <linespec>

指定下一條語句的運行點。<linespce>可以是文件的行號,可以是file:line格式,可以是+num這種偏移量格式。表示着下一條運行語句從哪裏開始。
 
jump <address>

這裏的<address>是代碼行的內存地址
 
注意,jump命令不會改變當前的程序棧中的內容,所以,當你從一個函數跳到另一個函數時,當函數運行完返回時進行彈棧操作時必然會發生錯誤,可能結果還是非常奇怪的,甚至於產生程序Core Dump。所以最好是同一個函數中進行跳轉。

熟悉彙編的人都知道,程序運行時,有一個寄存器用於保存當前代碼所在的內存地址。所以,jump命令也就是改變了這個寄存器中的值。於是,你可以使用“set $pc”來更改跳轉執行的地址。如:

set $pc = 0x485

產生信號量

使用singal命令,可以產生一個信號量給被調試的程序。如:中斷信號Ctrl+C。這非常方便於程序的調試,可以在程序運行的任意位置設置斷點,並在該斷點用GDB產生一個信號量,這種精確地在某處產生信號非常有利程序的調試。

語法是:signal <singal>,UNIX的系統信號量通常從1到15。所以<singal>取值也在這個範圍。

single命令和shell的kill命令不同,系統的kill命令發信號給被調試程序時,是由GDB截獲的,而single命令所發出一信號則是直接發給被調試程序的。

強制函數返回

如果你的調試斷點在某個函數中,並還有語句沒有執行完。你可以使用return命令強制函數忽略還沒有執行的語句並返回。

return
return <expression>

   使用return命令取消當前函數的執行,並立即返回,如果指定了<expression>,那麼該表達式的值會被認作函數的返回值。

強制調用函數

call <expr>

表達式中可以一是函數,以此達到強制調用函數的目的。並顯示函數的返回值,如果函數返回值是void,那麼就不顯示。

另一個相似的命令也可以完成這一功能——print,print後面可以跟表達式,所以也可以用他來調用函數,print和call的不同是,如果函數返回void,call則不顯示,print則顯示函數返回值,並把該值存入歷史數據中。


二、GDB中運行UNIX的shell程序


在gdb環境中,你可以執行UNIX的shell的命令,使用gdb的shell命令來完成:

shell <command string>

調用UNIX的shell來執行<command string>,環境變量SHELL中定義的UNIX的shell將會被用來執行<command string>,如果SHELL沒有定義,那就使用UNIX的標準shell:/bin/sh。(在Windows中使用Command.com或cmd.exe)

還有一個gdb命令是make:

make <make-args>

可以在gdb中執行make命令來重新build自己的程序。這個命令等價於“shell make <make-args>”。




三、GDB查看棧信息


當程序被停住了,你需要做的第一件事就是查看程序是在哪裏停住的。當你的程序調用了一個函數,函數的地址,函數參數,函數內的局部變量都會被壓入“棧”(Stack)中。你可以用GDB命令來查看當前的棧中的信息。

下面是一些查看函數調用棧信息的GDB命令:

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層的棧信息。
 
如果你要查看某一層的信息,你需要切換當前棧,一般來說,程序停止時,最頂層的棧就是當前棧,如果你要查看棧下面層的詳細信息,首先要做的是切換當前棧。

frame <n>
f <n>

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

up <n>

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

down <n>

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

上面的命令,都會打印出移動到的棧層的信息。如果你不想讓其打出信息。你可以使用這三個命令:

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

查看當前棧層的信息,你可以用以下GDB命令:

frame 或 f

會打印出這些信息:棧的層編號,當前的函數名,函數參數值,函數所在文件及行號,函數執行到的語句。
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
           
info args

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

info locals

打印出當前函數中所有局部變量及其值。

info catch

打印出當前的函數中的異常處理信息。


本文轉自:http://www.ithov.com/linux/


發佈了113 篇原創文章 · 獲贊 93 · 訪問量 51萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章