? ? ? ? File/file 裝入想要調試的可執行文件???? run(r) 執行當前被調試的程序? ? ?kill(k) 終止正在調試的程序???? ??quit(q) ?退出gdb? ?shell 使用戶不離開gdb就可以執行Linux的shell命令? ? ? ? ? ? ? ? ? backtrace(bt) 回溯跟蹤(當對代碼進行調試時,run后出現錯誤,則可以使用bt命令查出詳細的錯誤信息? ? ? ? ?frame n? 定位到發生錯誤的代碼段,n為backtrace命令的輸出結果中的行號(位于行首)。? ?
(1)?設置斷點(break) ?
break <function>? ????????在進入指定函數時被停住。C++可以使用class::function或function<type,type>格式來指定函數名。 //在該處停止(斷點),該處不執行,下同
break <linenum> 在指定行號停住
break filename:linenum?? 在源文件filename的linenum行處停止
break filename:function?? 在源文件filename的function函數的入口處停止
break??? 沒有參數,表示在下一條指令處停止
break *address 在程序運行的內存地址處停止
break與step結合使用時,step(s)確認后,執行上一次顯示的未執行命令,并且顯示出將要執行的下一行程序。使用單步調試命令step來跟蹤程序,它一次只執行程序中的一行代碼。
info break(i b)??命令? 可以顯示所有斷點的信息
(2)?查看運行時的數據
在調試程序的過程中,需要查看程序中某些表達式或變量的值,以判斷程序運行是否正確。
- ? ? ? ? print命令(p)
在調試程序時,當程序被停住時(如在斷點處),可以使用print(p)命令或其同義命令inspect來查看當前程序的運行數據。
print <expr>? //輸出表達式的值
print /<f> <expr>? //按某種格式輸出表達式的值,如/x 則為16進制
(gdb) print n1
$1 = 4
(gdb) inspect n1
$2 = 4
(gdb) print n1
$3 = 4
(gdb) print n2
$4 = 5
(gdb) print $2
$5 = 4???? //$2的值
(gdb) print $?? //$5的值
$6 = 4
(gdb) print $ $? //$5的值? ? 注意之間沒有空格? 這是防止CSDN編輯器轉義而加上的空格
$7 = 4
(gdb) print $ $6 //$4的值
$8 = 5
每一個print都會被gdb記錄下來,并且會以$1、$2、$3······這樣的方式為每一個print命令編號。于是,可以使用這個編號訪問以前的表達式。
另外要注意print命令的表達式中兩個具有特殊意義的符號:$、$ $。print $表示顯示當前序號的前一個序號的值;$ $表示給定序號的前兩個序號,如果未給定序號,則默認當前序號為給定序號。
另外,info local命令可以顯示當前本地的所有變量的值。
print命令的功能除了打印表達式或變量的值以外,還有對變量進行賦值和打印內存中某個變量開始的一段區域的內容。
- ? ? ? ? gdb的數據輸出格式
x 十六進制格式???? d 十進制格式?? u 十六進制格式無符號整型
o 八進制格式?????? t 二進制格式??? a 十六進制格式(等價x)
c ?ASCII字符格式???? f 浮點數格式???? s字符串格式?? i指令地址(指令文件)
p /x n1? ? //以十六進制格式顯示n1的值
- ? ? ? ? 自動顯示命令display
當程序停住時,或單步跟蹤時,這些變量會自動顯示。
display <expr>??????? display /<f> <expr>???
display /<f> <addr>? addr表示內存地址
display /i $pc? $pc為gdb的環境變量,表示指令的地址,/i則表示輸出格式為機器指令碼,也就是匯編。該句指令表示,當程序停下后,就會出現源代碼和機器指令碼相對應的情形。 即輸出當前指令的地址(程序運行到當前處),以機器指令碼的格式輸出,從而出現源代碼和機器指令碼(匯編代碼)相對應的情形。
- ? ? ? ? 查看內存examine(x)
examine(簡寫為x)指令可以查看內存地址中的值,格式:
x /<n/f/u> <addr>
n、f、u為可選的參數,可以獨立使用,也可以聯合使用。
n為一個正整數,表示顯示內存的長度,即從當前地址向后顯示幾個地址的內容。
f表示顯示的格式(即地址所指內容以什么樣的格式顯示出),s為字符串,如果所指的內容為指令地址,則為i。
u表示從當前地址往后請求的字節數,如果不指定則默認為4個Bytes。u參數可以用下面的字符代替:b表示單字節,h表示雙字節,w表示四字節,g表示八字節。
<addr>表示一個內存地址
x /4uh 0x48723? // 從內存地址0x48723讀取內容,h表示以雙字節為1個單位,4表示4個單位,u表示按16進制顯示。
- ? ? ? ? gdb的環境變量
可以在gdb的調試環境中定義自己的變量,用來保存一些調試程序中的運行數據。set命令用于定義gdb的環境變量,gdb的環境變量與Linux一樣,都是以$起始。
set $foo=*object_ptr
第一次使用環境變量時,需要創建這個變量(set),以后使用直接對其賦值即可,環境變量沒有類型,可以給環境變量定義任意的類型,包括結構體和數組。
在gdb的調試過程中,show convenience 命令用于查看當前設置的所有環境變量
- ? ? ? ? 查看寄存器
在調試程序的過程中,有時需要查看某些寄存器中的值。寄存器存放了程序運行時的數據,比如程序當前運行時的指令地址(IP),程序的當前堆棧地址(SP)等。可以使用info命令來查看寄存器中的值。
info registers //查看寄存器的情況(不包括浮點寄存器)
info all-registers //查看所有寄存器的情況(包括浮點寄存器)
info registers<name1,name2,······>? //查看指定寄存器的情況(name表示寄存器名)
也可以使用print命令來訪問寄存器的情況,只需要在寄存器名字前加一個$就可以了,如:print $ip。
- ? ? ? ? 查看源程序list(l)
在程序的調試過程中,有時需要查看源程序的內容,以及源代碼在內存中的情況。用list命令可以顯示程序的源代碼。
list linenum 顯示程序第linenum行周圍的源程序
list filename:linenum? 顯示某個.c文件中的第linenum行周圍的源程序(對于多個源文件的編譯)
list function 顯示函數名為function的函數的源程序
list filename:function
list 顯示當前行后面的源程序
list - 顯示當前行前面的源程序
list first,last 顯示從first行到last行之間的源代碼
list ,last 顯示從當前行到last行之間的源代碼
可以使用info line命令來查看源代碼在內存中的地址,info line命令后面也可以跟行號、函數名、文件名:行號、文件名:函數名等,從而顯示指定的源代碼在內存中的地址。如要顯示zsx.c源文件中calculate( )函數在內存中的地址:
info line zsx.c:calculate?
(3) 改變程序的執行
修改變量的值。print命令還可以修改被調試程序中運行時的變量值。如:
print x=9
跳轉執行。可以修改程序的執行順序,讓程序執行隨意跳躍。
jump <linespec>? <linespec>可以是文件的行號,可以是file:linenum格式,表示下一條運行語句從哪里開始。
jump <address>? <address>是代碼行的內存地址
注意jump命令不會改變當前的程序棧中的內容。
程序運行時,有一個寄存器用于保存當前代碼所在的內存地址,所以jump命令也就是改變了這個寄存器中的值。可以使用set $pc來更改跳轉執行的地址:set $pc=0x485。
(4) 具體事例
15?????????? for (i = 0; i < len; ++i)
(gdb) b 15 if i==5
Breakpoint 1 at 0x4008d3: file ../src/main.c, line 15.
(gdb) b 27
Breakpoint 2 at 0x400936: file ../src/main.c, line 27.
(gdb) i b
Num? ???Type?????????? Disp Enb? ? ? ? ? ? ? ?Address? ? ? ? ? ? ? ? ? ? ? What
1?????? breakpoint???? keep y? ? ? ? 0x00000000004008d3? in main at ../src/main.c:15
? ? ? ? ? ? ? ? ? ? ? ? ? stop only if i==5
2?????? breakpoint???? keep y? ? ? ? 0x0000000000400936? in main at ../src/main.c:27
//斷點編號(id) 斷點類型??? 斷點是否可用(y表示可用,n表示不可用) 斷點地址? 斷點的詳細信息
(5) 總結(重點內容)
運行程序:start(開始運行,只執行一步就停住);run(開始運行,在斷點處停住);continue(c)繼續運行,到下一個斷點處停止,step(s)單步執行,進入函數內部;next(n)單步執行,不進入函數內部;u跳出循環體,執行循環體后面的第一個語句。
set var i=10? //將變量i的值設為10,比如在一個循環體中,i為控制變量,當單步執行時,i依次增加,如果想讓變量i循環到10時,才停住,則可以:set var i = 10。
gdb調試:
????????????? 1. 啟動gdb
??????????????????????????? start -- 只執行一步
?????????????????????????????????? n -- next
?????????????????????????????????? s -- step(單步) -- 可以進入到函數體內部
?????????????????????????????????? c - continue -- 直接停在斷點的位置
????????????? 2. 查看代碼:
??????????????????????????? l -- list
??????????????????????????? l 10(或者函數名)
??????????????????????????? l filename:行號(或者函數名)
????????????? 3. 設置斷點:
??????????????????????????? 設置當前文件斷點:
?????????????????????????????????? b -- break
?????????????????????????????????? b 10(或函數名)
??????????????????????????? 設置指定文件斷點:
??????????????????????????? ??? b fileName:行號(或函數名)
??????????????????????????? 設置條件斷點:
?????????????????????????????????? b 10 if value==19
??????????????????????????? 刪除斷點:
?????????????????????????????????? d 斷點編號
??????????????????????????? ??? 獲取編號:i b
????????????? 4. 查看設置的斷點
??????????????????? info break?? i b
????????????? 5. 開始 執行gdb調試
??????????????????????????? 執行一步操作: ?start
?????????????????????????????????? 繼續執行:? n s
??????????????????????????? 執行多步, 直接停在斷點處:? continue
????????????? 5. 單步調試
??????????????????????????? 進入函數體內部: s
?????????????????????????????????? 從函數體內部跳出: finish(如果在循環處有斷點, 需要將斷點刪掉)
??????????????????????????? 不進入函數體內部:n
??????????????????????????? 退出當前循環: u //該退出是指,直接一次性執行完該循環體
????????????? 6. 查看變量的值: p -- print
????????????? 7. 查看變量的類型: ptype 變量名
????????????? 8. 設置變量的值:? set var 變量名 = 賦值? //注意,同理,不是硬性的
????????????? 9. 設置追蹤變量
??????????????????????????? display
??????????????????????????? 取消追蹤變量
??????????????????????????? undisplay 編號
??????????????????????????? 獲取編號: info display
????????????? 10. 退出gdb調試
?????????????????????????????????? quit
?