GDB 調試
要進行調試程序首先要生成一個含有調試信息的執行程序命令如下:
- gcc(g++) -g -o 文件名 源文件.c(源文件.cpp)
- gcc(g++) -ggdb3 -o 文件名 源文件.c(源文件.cpp)
此時便會生成一個含有調試信息的可執行文件,然後便可以用 gdb 去調試這個程序了,進入調試程序命令,但是如果用 gdb 去調試一個未包含調試信息的可執行文件則會發生錯誤
- gdb 執行文件名(含調試信息)
運行 GDB
運行 gdb
- gdb <program> -- program也就是你的執行文件,一般在當然目錄下.
- gdb <program> core -- 用 gdb 同時調試一個運行程序和 core 文件,core 是程序非法執行後 core dump 後產生的文件.
- gdb <program> <PID> -- 調試正在運行的程序. program 爲需要調試的程序文件, PID 爲當前正在運行的程序.或是先用 gdb <program> 關聯上源代碼進入 gdb,後用 attach 命令來掛接進程的 PID.並用 detach 來取消掛接的進程
gdb 啓動常用的參數
- 從指定文件中讀取符號表
- -symbols <file>
- -s <file>
- 從指定文件中讀取符號表信息,並把他用在可執行文件中
- -se file
- 調試時 core dump 的 core 文件
- -core <file>
- -c <file>
- 加入一個源文件的搜索路徑.默認搜索路徑是環境變量中 PATH 所定義的路徑
- -directory <directory>
- -d <directory>
- 設置啓動時候參數
- --args arglist
gdb 幫助文檔
- help -- 查看 gdb 的命令種類
- help <CmdType> -- 查看 CmdType 種類的 gdb 命令
- apropos <keyWord> -- 查看關鍵字 keyWord 的相關命令
- info <keyWord> -- 查看關鍵字 keyWord 調試信息
- show <keyWord> -- 查看關鍵字 keyWord gdb 本身設置信息
gdb 中運行 unix 的 shell 程序
- shell <command string> -- 調用 unix 的 shell 來執行 <command string>,環境變量 shell 中定義的 unix 的 shell 將會被用來執行 <command string>,如果 shell 沒有定義,那就使用 unix 的標準 shell:/bin/sh.(在 windows 中使用 command.com 或 cmd.exe)
- make <make-args> -- 等價於 “shell make <make-args>”
歷史記錄
- 當你用 gdb 的 print 查看程序運行時的數據時,你每一個 print 都會被 gdb 記錄下來.gdb 會以 $1, $2, $3 ...這樣的方式爲你每一個 print 命令編上號.於是,你可以使用這個編號訪問以前的表達式,如 $1.這個功能所帶來的好處是,如果你先前輸入了一個比較長的表達式,如果你還想查看這個表達式的值,你可以使用歷史記錄來訪問,省去了重複輸入.
啓動程序
- run <arg ...> -- 啓動程序,<arg ...> 爲程序運行時候需要輸入的參數.也可用 set args 命令去設置運行參數.簡寫爲 r
GDB 環境設置
gdb 設置
- 設置顯示選項
- 地址
- set print address <on/off> -- 打開地址輸出,當程序顯示函數信息時,gdb會顯出函數的參數地址.系統默認爲打開.
- show print address -- 查看 print address 選項信息
- 數組元素單獨行顯示
- set print array <on/off> -- 打開時數組顯示時,每個元素佔一行,如果不打開的話,每個元素則以逗號分隔.這個選項默認是關閉的.
- show print array -- 查看 print array 選項信息
- 顯示數組元素顯示
- set print elements <number-of-elements> -- 設置數組的顯示的最大長度,設置爲 0,則表示不限制.
- show print elements -- 查看 print elements 選項信息.
- 設置字符串顯示
- set print null-stop <on/off> -- 如果打開那麼當顯示字符串時,遇到結束符則停止顯示.這個選項默認爲 off.
- show print null-stop -- 查看 print null-stop 選項信息
- 設置結構體變量顯示
- set print pretty <on/off> -- 結構體優雅顯示
- show print pretty -- 查看 gdb 是如何顯示結構體的.
- 設置字符顯示
- set print sevenbit-strings <on/off> -- 符顯示,是否按“/nnn”的格式顯示,如果打開,則字符串或字符數據按/nnn顯示,如“/065”.
- show print sevenbit-strings -- 查看字符顯示開關是否打開.
- 設置聯合體顯示
- set print union <on/off> -- 設置顯示結構體時,是否顯式其內的聯合體數據.
- show print union -- 查看聯合體數據的顯示方式
- 設置對象顯示
- set print object <on/off> -- 在 C++ 中,如果一個對象指針指向其派生類,如果打開這個選項,gdb 會自動按照虛方法調用的規則顯示輸出,如果關閉這個選項的話,gdb 就不管虛函數表了.這個選項默認是 off.
- show print object -- 查看對象選項的設置.
- 設置靜態成員顯示
- set print static-members <on/off> -- 這個選項表示,當顯示一個 C++ 對象中的內容是,是否顯示其中的靜態數據成員.默認是 on.
- show print static-members -- 查看靜態數據成員選項設置.
- 設置虛函數表顯示
- set print vtbl <on/off> -- 當此選項打開時,gdb 將用比較規整的格式來顯示虛函數表時.其默認是關閉的.
- show print vtbl -- 查看虛函數顯示格式的選項.
- 地址
- 設置運行程序的相關環境及其參數
- 指定源文件的路徑
- directory <dirname ... > -- 加一個源文件路徑到當前路徑的前面.如果你要指定多個路徑,UNIX 下你可以使用“:”,Windows 下你可以使用“;”.縮寫 dir
- directory -- 清除所有的自定義的源文件搜索路徑信息.
- show directories -- 顯示定義了的源文件搜索路徑.
- 運行參數
- set args -- 可指定運行時參數
- show args -- 命令可以查看設置好的運行參數
- 運行環境
- path <dir> -- 可設定程序的運行路徑
- show paths -- 查看程序的運行路徑
- set environment varname=value -- 設置環境變量
- show environment [varname] -- 查看環境變量
- 工作目錄
- cd <dir> -- 相當於shell的cd命令
- pwd -- 顯示當前的所在目錄
- 程序的輸入輸出
- info terminal -- 顯示你程序用到的終端的模式
- tty -- 命令可以指寫輸入輸出的終端設備
- 重定向控制程序輸出
- 堆棧幀設置
- set backtrace <limit> -- 設置堆棧幀的最大顯示數量,默認是沒有限制
- 調試模式
- set step-mode [on | off] -- step-mode 模式,於是,在進行單步跟蹤時,程序不會因爲沒有debug信息而不停住.這個參數有很利於查看機器碼.
- 指定源文件的路徑
GDB 源碼查看
顯示源代碼
- list <linenum> -- 顯示程序第 linenum 行的周圍的源程序.
- list <function> -- 顯示函數名爲 function 的函數的源程序.
- list <filename:linenum> -- 哪個文件的哪一行.
- list <filename:function> -- 哪個文件中的哪個函數.
- list <offset> -- 當前行號的正/負 offset 偏移量那那行.
- list -- 顯示當前行後面的源程序.
- list - -- 顯示當前行前面的源程序.
- list <first>, <last> -- 顯示從 first 行到 last 行之間的源代碼.若無 first 則顯示從當前行到 last 之間的源代碼.
設置和獲得顯示源碼的行數
- set listsize <count> -- 設置一次顯示源代碼的行數.
- show listsize -- 查看當前listsize的設置.
搜索源代碼
- forward-search <regexp> -- 向後面搜索.正則表達式爲 regexp 的關鍵字
- search <regexp> -- 向後面搜索.正則表達式爲 regexp 的關鍵字
- reverse-search <regexp> -- 向前面搜索.正則表達式爲 regexp 的關鍵字
源代碼的內存
- info line <linenum> -- 查看行號爲 linenum 源代碼在內存中的地址.
- info line <function> -- 查看函數在源代碼在內存中的地址.
- info line <filename:linenum> -- 查看 filename 文件的第 linenum 行源代碼在內存中的地址.
- info line <filename:function> -- 查看 filename 文件的 function 函數在源代碼在內存中的地址.
查看彙編代碼
- disassemble -- 查看源程序的當前執行時的機器碼,這個命令會把目前內存中的指令 dump 出來.
GDB 停止點設置及維護
斷點(BreakPoint)
- 設置斷點:(threadno 指定了線程的 ID,注意,這個 ID 是 gdb 分配的,可以通過 "info threads" 命令來查看正在運行程序中的線程信息)
- break thread <threadno> -- break命令沒有參數時,表示在下一條指令處停住.
- break +offset thread <threadno> -- 在當前行號的後面的 offset 行停住.(offiset 爲自然數)
- break -offset thread <threadno> -- 在當前行號的前面的 offset 行停住.(offiset 爲自然數)
- break <linenum> thread <threadno> -- 在指定行號停住.
- break filename:linenum thread <threadno> -- 在源文件filename的linenum行處停住.
- break <function> thread <threadno> -- 在進入指定函數時停住.
- break filename:function thread <threadno> --在源文件filename的function函數的入口處停住.
- break *address -- 在程序運行的內存地址處停住.
- break ... thread <threadno> if <condition> -- ...可以是上述的參數,condition表示條件,在條件成立時停住.比如在循環境體中,可以設置break if i=100,表示當i爲100時停住程序.
- tbreak -- 設置只停止一次的斷點.用法和 break 類似
- 查看斷點
- info breakpoints [n]
- info break [n]
觀察點(WatchPoint) -- 觀察點一般來觀察某個表達式(變量也是一種表達式)的值是否有變化了,如果有變化,馬上停住程序.
- 設在觀察點
- watch <expr> -- 爲表達式(變量)expr設置一個觀察點.一量表達式值有變化時,馬上停住程序.
- rwatch <expr> -- 當表達式(變量)expr被讀時,停住程序.
- awatch <expr> -- 當表達式(變量)的值被讀或被寫時,停住程序.
- 查看觀察點
- info watchpoints -- 列出當前所設置了的所有觀察點.
捕捉點(CatchPoint) -- 設置捕捉點來補捉程序運行時的一些事件.如:載入共享庫(動態鏈接庫)或是 C++ 的異常《/p>
- 設置捕捉點
- catch <event> -- 當event發生時,停住程序.event可以是下面的內容:
- throw 一個 C++ 拋出的異常.(throw 爲關鍵字)
- catch 一個 C++ 捕捉到的異常.(catch 爲關鍵字)
- exec 調用系統調用 exec 時.(exec 爲關鍵字,目前此功能只在 HP-UX 下有用)
- fork 調用系統調用 fork 時.(fork 爲關鍵字,目前此功能只在 HP-UX 下有用)
- vfork 調用系統調用 vfork 時.(vfork 爲關鍵字,目前此功能只在 HP-UX 下有用)
- load 或 load <libname> 載入共享庫(動態鏈接庫)時.(load 爲關鍵字,目前此功能只在 HP-UX 下有用)
- unload 或 unload <libname> 卸載共享庫(動態鏈接庫)時.(unload 爲關鍵字,目前此功能只在 HP-UX 下有用)
- tcatch <event> -- 只設置一次捕捉點,當程序停住以後,應點被自動刪除.
- catch <event> -- 當event發生時,停住程序.event可以是下面的內容:
維護停止點
- 清除停止點
- clear -- 所有的已定義的停止點.
- clear <function> -- 清除所有設置在函數上的停止點.
- clear <filename:function> -- 清除所有設置在函數上的停止點.
- clear <linenum> -- 清除所有設置在指定行上的停止點.
- clear <filename:linenum> -- 清除所有設置在指定行上的停止點.
- 刪除停止點
- delete [range] -- 刪除停止點.其簡寫命令爲 d.
- 禁用停止點
- disable [range] -- 禁用停止點
- 啓用停止點
- enable [range] -- 啓用停止點.
- enable once [rang] -- 啓用停止點一次,當程序停止後,該停止點馬上被 gdb 自動 disable.
- enable count [rang] -- 啓用停止點 count 次,當程序停止後,該停止點馬上被 gdb 自動 disable.
- enable delete [rang] -- 啓用停止點一次,當程序停止後,該停止點馬上被 gdb 自動刪除.
- 停止條件維護 -- 以用 condition 命令來修改斷點的條件.(只有break和watch命令支持if,catch目前暫不支持if)
- condition <bnum> <expression> -- 修改斷點號爲bnum的停止條件爲expression.
- condition <bnum> -- 清除斷點號爲bnum的停止條件.
- 忽略停止點 N 次
- ignore <bnum> <count> -- 表示忽略斷點號爲 bnum 的停止條件 count 次.
- 爲停止點設定運行命令
- 格式:
commands [bnum]
... command-list ...
// 爲斷點號 bnumi寫一個命令列表.當程序被該斷點停住時,gdb 依次運行命令列表中的命令.
end - 例如:
break foo if x>0
commands
printf "x is %d/n",x
continue
end
- 格式:
信號(Signals)
添加信號處理
- handle <signal> <keywords...>在 gdb 中定義一個信號處理.信號 <signal> 可以以 SIG 開頭或不以 SIG 開頭,可以用定義一個要處理信號的範圍(如:SIGIO-SIGKILL,表示處理從 SIGIO 信號到 SIGKILL 的信號,其中包括 SIGIO, SIGIOT, SIGKILL 三個信號),也可以使用關鍵字 all 來標明要處理所有的信號.一旦被調試的程序接收到信號,運行程序馬上會被
gdb 停住,以供調試.其 <keywords> 可以是以下幾種關鍵字的一個或多個.若沒有 keywords 則查看奇信號的處理狀態
- nostop -- 當被調試的程序收到信號時,gdb 不會停住程序的運行,但會打出消息告訴你收到這種信號.
- stop -- 當被調試的程序收到信號時,gdb 會停住你的程序.
- print -- 當被調試的程序收到信號時,gdb 會顯示出一條信息.
- noprint -- 當被調試的程序收到信號時,gdb 不會告訴你收到信號的信息.
- pass -- 當被調試的程序收到信號時,gdb 不處理信號.這表示,gdb 會把這個信號交給被調試程序會處理.
- noignore -- 當被調試的程序收到信號時,gdb 不處理信號.這表示,gdb 會把這個信號交給被調試程序會處理.
- nopass -- 當被調試的程序收到信號時,gdb 不處理信號.這表示,gdb 會把這個信號交給被調試程序會處理.
- 1gnore -- 當被調試的程序收到信號時,gdb 不會讓被調試程序來處理這個信號.
查看處理信號
- info signals -- 查看有哪些信號在被 gdb 檢測中.
- info handle -- 查看有哪些信號在被 gdb 檢測中.
GDB 程序調試
恢復執行
- continue [ignore-count] -- ignore-count 表示忽略其後的斷點次數.恢復程序運行,直到程序結束,或是下一個斷點到來.縮寫 c
- fg [ignore-count] -- ignore-count 表示忽略其後的斷點次數.恢復程序運行,直到程序結束,或是下一個斷點到來.縮寫 c
單步調試
- step <count> -- 單步跟蹤,如果有函數調用,它會進入該函數.count 表示執行後面 count 條語句,不加則默認爲 1.
- next <count> -- 同樣單步跟蹤,如果有函數調用,他不會進入該函數.count 表示執行後面 count 條語句,不加則默認爲 1.
跟蹤機器指令
與之一樣有相同功能的命令是 “display/i $pc” ,當運行完這個命令後,單步跟蹤會在打出程序代碼的同時打出機器指令(也就是彙編代碼)
- stepi 或 si -- 單步跟蹤一條機器指令,簡寫 si
- nexti 或 ni -- 單步跟蹤一條機器指令,簡寫 ni
函數調試
- finish -- 運行程序,直到當前函數完成返回.並打印函數返回時的堆棧地址和返回值及參數值等信息.
- return <expression> -- 使函數以 expression 表達式返回出去,忽略還沒有執行的語句.若無返回 void 出去
- call <expr> -- 表達式中可以一是函數,以此達到強制調用函數的目的.並顯示函數的返回值,如果函數返回值是void,那麼就不顯示.
- print 與 printf 也可以做到類似的功能和 call 的不同是,如果函數返回 void,call 則不顯示,print 則顯示函數返回值,並把該值存入歷史數據中.
循環體調試
- until -- 可以運行程序直到退出循環體.簡寫 u
修改變量值
- print varname=var -- 修改被調試程序運行時的變量值
- set var varname=value -- 修改被調試程序運行時的變變量
- whatis varname -- 查看變量的類型
跳轉執行
- jump <linespec> -- 指定下一條語句的運行點.<linespce> 可以是文件的行號,可以是 file:line 格式,可以是 +num 這種偏移量格式.表式着下一條運行語句從哪裏開始.
- jump <address> -- 跳轉到指定的程序內存地址運行.<address> 是代碼行的內存地址.
- 注意
- jump 指令不會改變當前的程序棧中的內容,所以,當你從一個函數跳到另一個函數時,當函數運行完返回時進行彈棧操作時必然會發生錯誤.
- jump 命令只是改變了指令寄存器中的值.於是可以使用 “set $pc” 來更改跳轉執行的地址.如: set $pc = 0x485
產生信號量
- signal <signal> -- 產生一個 signal 信號.UNIX 的系統信號量通常從 1 到 15.所以 <signal> 取值也在這個範圍.
GDB 運行是數據
查看運行時數據
- print /<f> <expr> -- 查看當前程序的運行數據.簡寫 p.
- <expr> 是表達式
- @ -- 是一個和數組有關的操作符,在後面會有更詳細的說明.在 @ 左邊是數組的地址,右邊是數組的長度,eg: array@len
- :: -- 指定一個在文件或是一個函數中的變量.
- {<type>} <addr> --表示一個指向內存地址<addr>的類型爲type的一個對象.
- <f>是輸出的格式
- d -- 按十進制格式顯示變量.
- u -- 按十六進制格式顯示無符號整型.
- o -- 按八進制格式顯示變量.
- t -- 按二進制格式顯示變量.
- a -- 按十六進制格式顯示變量.
- c -- 按字符格式顯示變量.
- f -- 按浮點數格式顯示變量.
- 注意:
- 1.若出現變量重名,局部變量會隱藏全局變量.若想查看全局變量的值時,可以使用“::”操作符.
- 2.可以通過這種形式指定你所想查看的變量 eg:
*'filename'::variable
*function::variable
- <expr> 是表達式
- printf "fmt",arg,... -- 打印格式化字符燦 fmt.
查看內存
- examine/<n/f/u> <addr> -- 來查看內存地址中的值.簡寫 x
- <n/f/u>
- n 是一個正整數,表示顯示內存的長度,也就是說從當前地址向後顯示幾個地址的內容.
- f 表示顯示的格式
- s -- 按字符串格式顯示內存地址內容.
- i -- 查看內存地址的機器指令內容
- x -- 按十六進制格式顯示地址內容.
- d -- 按十進制格式顯示地址內容.
- u -- 按十六進制格式顯示無符號整型.
- o -- 按八進制格式顯示地址內容.
- t -- 按二進制格式顯示地址內容.
- a -- 按十六進制格式顯示地址內容.
- c -- 按字符格式顯示地址內容.
- f -- 按浮點數格式顯示地址內容.
- u 表示從當前地址往後請求的字節數,如果不指定的話,gdb默認是 4 個 bytes.
- b -- 表示單字節
- h -- 表示雙字節
- w -- 表示四字節
- g -- 表示八字節
- <addr> 表示一個內存地址.
- <n/f/u>
自動顯示
- 設置自動顯示
- display/<fmt> <expr> -- 自動顯示 expr 表達式
- display/<fmt> <addr> -- 自動顯示 addr 地址
- fmt 表示顯示的格式
- i -- 輸出格式爲機器指令碼,也就是彙編.
- s -- 輸出格式爲字符串
- 刪除自動顯示
- undisplay <range> -- 刪除自動顯示
- delete display <range> -- 刪除自動顯示
- 啓用和禁自動顯示
- sable display <range> -- 禁用自動顯示
- enable display <range> -- 啓動自動顯示
查看棧信息
- backtrace <n> -- 擦看函數棧信息,簡寫 bt
- n 若是正數,只打印棧頂上 n 層的棧信息,
- 若是負數,只打印棧頂下 n 層的棧信息,
- 若無則打印當前的函數調用棧的所有信息
- frame -- 會打印出這些信息:棧的層編號,當前的函數名,函數參數值,函數所在文件及行號,函數執行到的語句.
- info frame -- 這個命令會打印出更爲詳細的當前棧層的信息,只不過,大多數都是運行時的內內地址.
- info args -- 打印出當前函數的參數名及其值.
- info locals -- 打印出當前函數中所有局部變量及其值.
- info catch -- 打印出當前的函數中的異常處理信息.
切換函數棧位置
- frame <n> -- 切換到第 n 層函數棧位置,簡寫 f.
- p <n> -- 表示上面移動 n 層,可以不打 n,表示向上移動一層.
- down <n> -- 表示向棧的下面移動 n 層,可以不打 n,表示向下移動一層.
- select-frame <n> -- 類似 frame 命令.不打印出棧層信息.
- up-silently <n> -- 類似 up 命令.不打印出棧層信息.
- down-silently <n> -- 類似 down 命令.不打印出棧層信息.
查看寄存器
- info registers -- 查看寄存器的情況.(除了浮點寄存器)
- info all-registers -- 查看所有寄存器的情況.(包括浮點寄存器)
- info registers <regname> -- 查看所指定的寄存器的情況.
線程查看與切換線程
- info threads -- 查看當前線程
- thread <threadno> -- 切換到 threadno 的線程,簡寫 t
自定義命令
定義一個命令
- 格式
define comdName
...
end - 條件語句
if cond_expr
...
else
...
end - 循環語句
while cond_expr
...
end
定義一個命令的文檔信息(在 help cmdName 的時候顯示)
- document cmdName
...
end
查看自定命令
- help user-define -- 查看所有用戶自定義的命令
- show user cmdName -- 查看用戶定義的 cmdName 的命令.
- help cmdName -- 查看用戶自定義的 cmdName 的幫助文檔
- show max-user-call-depth -- 查看用戶自定義命令的遞歸最大深度,缺省是 1024
- set-user-call-depth <limit>-- 設置用戶自定義命令的遞歸最大深度.