cmake和gdb調試程序
由於出發點是想要在cmake后使用gdb,因此先寫一下cmake和gdb的簡單的一個流程,此部分轉自:WELEN
1. cmake支持gdb的實現,
首先在CMakeLists.txt下加入
SET(CMAKE_BUILD_TYPE "Debug")
在下面加入:
SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
原因是CMake 中有一個變量 CMAKE_BUILD_TYPE ,可以的取值是 Debug Release RelWithDebInfo >和 MinSizeRel。
當這個變量值為 Debug 的時候,CMake 會使用變量 CMAKE_CXX_FLAGS_DEBUG 和 CMAKE_C_FLAGS_DEBUG 中的字符串作為編譯選項生成 Makefile;
2. 在GDB中間加入程序啟動參數
比如我們需要調試一個可執行文件./a.out help
這時
$gdb ./a.out
進入到gdb的命令行模式下,然后:
(gdb) set args help
就能加上可執行文件需要的參數,如果要看argc[1]到argc[N]的參數,只需要
(gdb) show args
3. gdb中查看字符串,地址的操作,數據類型
比始有一個int型的變量i,相要知道他的相關信息,可以
(gdb) print i
打印出變量i的當前值
(gdb)x &i
與上面的命令等價。
如果有x命令看時,需要看一片內存區域,(如果某個地方的值為0,用x時會自動截斷了)
(gdb) x/16bx address
單字節16進制打印address地址處的長度為16的空間的內存,16表示空間長度,不是16進制,x表示16進制,b表示byte單字節
gdb看變量是哪個數據類型
(gdb) whatis i
即可知道i是什么類型的變量
gdb調試利器
接下來介紹一下gdb本身以及一些常用的指令,轉自: Linux Tools Quick Tutorial
GDB是一個由GNU開源組織發布的、UNIX/LINUX操作系統下的、基於命令行的、功能強大的程序調試工具。 對於一名Linux下工作的c++程序員,gdb是必不可少的工具;
1. 啟動gdb
對C/C++程序的調試,需要在編譯前就加上-g選項:
$g++ -g hello.cpp -o hello
調試可執行文件:
$gdb <program>
program也就是你的執行文件,一般在當前目錄下。
調試core文件(core是程序非法執行后core dump后產生的文件):
$gdb <program> <core dump file>
$gdb program core.11127
調試服務程序:
$gdb <program> <PID>
$gdb hello 11127
如果你的程序是一個服務程序,那么你可以指定這個服務程序運行時的進程ID。gdb會自動attach上去,並調試他。program應該在PATH環境變量中搜索得到。
2. gdb交互命令
啟動gdb后,進入到交互模式,通過以下命令完成對程序的調試;注意高頻使用的命令一般都會有縮寫,熟練使用這些縮寫命令能提高調試的效率;
運行
- run:簡記為 r ,其作用是運行程序,當遇到斷點后,程序會在斷點處停止運行,等待用戶輸入下一步的命令。
- continue (簡寫c ):繼續執行,到下一個斷點處(或運行結束)
- next:(簡寫 n),單步跟蹤程序,當遇到函數調用時,也不進入此函數體;此命令同 step 的主要區別是,step 遇到用戶自定義的函數,將步進到函數中去運行,而 next 則直接調用函數,不會進入到函數體內。
- step (簡寫s):單步調試如果有函數調用,則進入函數;與命令n不同,n是不進入調用的函數的
- until:當你厭倦了在一個循環體內單步跟蹤時,這個命令可以運行程序直到退出循環體。
- until+行號: 運行至某行,不僅僅用來跳出循環
- finish: 運行程序,直到當前函數完成返回,並打印函數返回時的堆棧地址和返回值及參數值等信息。
- call 函數(參數):調用程序中可見的函數,並傳遞“參數”,如:call gdb_test(55)
- quit:簡記為 q ,退出gdb
設置斷點
-
- break n (簡寫b n):在第n行處設置斷點
- (可以帶上代碼路徑和代碼名稱: b OAGUPDATE.cpp:578)
- b fn1 if a>b:條件斷點設置
- break func(break縮寫為b):在函數func()的入口處設置斷點,如:break cb_button
- delete 斷點號n:刪除第n個斷點
- disable 斷點號n:暫停第n個斷點
- enable 斷點號n:開啟第n個斷點
- clear 行號n:清除第n行的斷點
- info b (info breakpoints) :顯示當前程序的斷點設置情況
- delete breakpoints:清除所有斷點:
查看源代碼
- list :簡記為 l ,其作用就是列出程序的源代碼,默認每次顯示10行。
- list 行號:將顯示當前文件以“行號”為中心的前后10行代碼,如:list 12
- list 函數名:將顯示“函數名”所在函數的源代碼,如:list main
- list :不帶參數,將接着上一次 list 命令的,輸出下邊的內容。
打印表達式
- print 表達式:簡記為 p ,其中“表達式”可以是任何當前正在被測試程序的有效表達式,比如當前正在調試C語言的程序,那么“表達式”可以是任何C語言的有效表達式,包括數字,變量甚至是函數調用。
- print a:將顯示整數 a 的值
- print ++a:將把 a 中的值加1,並顯示出來
- print name:將顯示字符串 name 的值
- print gdb_test(22):將以整數22作為參數調用 gdb_test() 函數
- print gdb_test(a):將以變量 a 作為參數調用 gdb_test() 函數
- display 表達式:在單步運行時將非常有用,使用display命令設置一個表達式后,它將在每次單步進行指令后,緊接着輸出被設置的表達式及值。如: display a
- watch 表達式:設置一個監視點,一旦被監視的“表達式”的值改變,gdb將強行終止正在被調試的程序。如: watch a
- whatis :查詢變量或函數
- info function: 查詢函數
- 擴展info locals: 顯示當前堆棧頁的所有變量
查詢運行信息
- where/bt :當前運行的堆棧列表;
- bt backtrace 顯示當前調用堆棧
- up/down 改變堆棧顯示的深度
- set args 參數:指定運行時的參數
- show args:查看設置好的參數
- info program: 來查看程序的是否在運行,進程號,被暫停的原因。
分割窗口
- layout:用於分割窗口,可以一邊查看代碼,一邊測試:
- layout src:顯示源代碼窗口
- layout asm:顯示反匯編窗口
- layout regs:顯示源代碼/反匯編和CPU寄存器窗口
- layout split:顯示源代碼和反匯編窗口
- Ctrl + L:刷新窗口
注解
交互模式下直接回車的作用是重復上一指令,對於單步調試非常方便;
3. 更強大的工具
cgdb
cgdb可以看作gdb的界面增強版,用來替代gdb的 gdb -tui。cgdb主要功能是在調試時進行代碼的同步顯示,這無疑增加了調試的方便性,提高了調試效率。界面類似vi,符合unix/linux下開發人員習慣;如果熟悉gdb和vi,幾乎可以立即使用cgdb。
基礎用法
接下來來一個更詳細的介紹和使用方法,轉自:大頭雨山
1. 簡介
GDB(GNU Debugger)是GCC的調試工具。其功能強大,現描述如下:
GDB主要幫忙你完成下面四個方面的功能:
1.啟動你的程序,可以按照你的自定義的要求隨心所欲的運行程序。
2.可讓被調試的程序在你所指定的調置的斷點處停住。(斷點可以是條件表達式)
3.當程序被停住時,可以檢查此時你的程序中所發生的事。
4.動態的改變你程序的執行環境。
2 生成調試信息
一般來說GDB主要調試的是C/C++的程序。要調試C/C++的程序,首先在編譯時,我們必須要把調試信息加到可執行文件中。使用編譯器(cc/gcc/g++)的 -g 參數可以做到這一點。如:
gcc -g hello.c -o hello g++ -g hello.cpp -o hello
- 1
- 2
- 1
- 2
- 1
- 2
如果沒有-g,你將看不見程序的函數名、變量名,所代替的全是運行時的內存地址。當你用-g把調試信息加入之后,並成功編譯目標代碼以后,讓我們來看看如何用gdb來調試他。
3 啟動GDB 的方法
1、gdb program
program 也就是你的執行文件,一般在當前目錄下。
2、gdb program core
用gdb同時調試一個運行程序和core文件,core是程序非法執行后core dump后產生的文件。
3、gdb program 1234
如果你的程序是一個服務程序,那么你可以指定這個服務程序運行時的進程ID。gdb會自動attach上去,並調試他。program應該在PATH環境變量中搜索得到。
4 程序運行上下文
4.1 程序運行參數
set args
可指定運行時參數。(如:set args 10 20 30 40 50 )
show args
命令可以查看設置好的運行參數。
run (r)
啟動程序
不指定運行參數 r
指定運行參數r 10 20 30 40 50
4.2 工作目錄
cd
相當於shell的cd命令。
pwd
顯示當前的所在目錄。
4.3 程序的輸入輸出
info terminal
顯示你程序用到的終端的模式。
使用重定向控制程序輸出。如:run > outfile
tty
命令可以設置輸入輸出使用的終端設備。如:tty /dev/tty1
5 設置斷點
5.1 簡單斷點
break
設置斷點,可以簡寫為b
b 10
設置斷點,在源程序第10行
b func
設置斷點,在func
函數入口處
5.2 多文件設置斷點
在進入指定函數時停住:
C++中可以使用
class::function或function(type,type)
格式來指定函數名。如果有名稱空間,可以使用namespace::class::function
或者function(type,type)
格式來指定函數名。
break filename:linenum
在源文件filename
的linenum
行處停住
break filename:function
在源文件filename
的function
函數的入口處停住
break class::function
或function(type,type)
在類class的function函數的入口處停住
break namespace::class::function
在名稱空間為namespace的類class的function函數的入口處停住
5.3 查詢所有斷點
info b
6 觀察點
watch
為表達式(變量)expr設置一個觀察點。當表達式值有變化時,馬上停住程序。
rwatch
表達式(變量)expr被讀時,停住程序。
awatch
表達式(變量)的值被讀或被寫時,停住程序。
info watchpoints
列出當前所設置了的所有觀察點。
7 條件斷點
一般來說,為斷點設置一個條件,我們使用if關鍵詞,后面跟其斷點條件。並且,條件設置好后,我們可以用condition命令來修改斷點的條件。並且,條件設置好后,我們可以用condition命令來修改斷點的條件。(只有break 和 watch命令支持if,catch目前暫不支持if)。
設置一個條件斷點
b test.c:8 if intValue == 5
condition
與break if
類似,只是condition
只能用在已存在的斷點上
修改斷點號為bnum
的停止條件為expression
condition bnum expression
清楚斷點號為bnum
的停止條件
condition bnum
ignore
忽略停止條件幾次
表示忽略斷點號為bnum的停止條件count次
Ignore bnum count
8 維護停止點
clear
清除所有的已定義的停止點。clear function
清除所有設置在函數上的停止點。clear linenum
清除所有設置在指定行上的停止點。clear filename:linenum
清除所有設置在指定文件:指定行上的停止點。delete [breakpoints] [range...]
刪除指定的斷點,breakpoints為斷點號。如果不指定斷點號,則表示刪除所有的斷點。range
表示斷點號的范圍(如:3-7)。其簡寫命令為d。- 比刪除更好的一種方法是disable停止點,disable了的停止點,GDB不會刪除,當你還需要時,enable即可,就好像回收站一樣。
disable [breakpoints] [range...]
disable所指定的停止點,breakpoints為停止點號。如果什么都不指定,表示disable所有的停止點。簡寫命令是dis.enable [breakpoints] [range...]
enable所指定的停止點,breakpoints為停止點號。enable [breakpoints] once range…
enable所指定的停止點一次,當程序停止后,該停止點馬上被GDB自動disable。enable [breakpoints] delete range…
enable所指定的停止點一次,當程序停止后,該停止點馬上被GDB自動刪除。
9 為停止點設定運行命令
我們可以使用GDB提供的command命令來設置停止點的運行命令。也就是說,當運行的程序在被停止住時,我們可以讓其自動運行一些別的命令,這很有利行自動化調試。對基於GDB的自動化調試是一個強大的支持。
1 commands [bnum] 2 … command-list … 3 end
為斷點號bnum指寫一個命令列表。當程序被該斷點停住時,gdb會依次運行命令列表中的命令。
例如:
1 break foo if x>0 2 commands 3 printf “x is %d “,x 4 continue 5 end
斷點設置在函數foo中,斷點條件是x>0,如果程序被斷住后,也就是,一旦x的值在foo函數中大於0,GDB會自動打印出x的值,並繼續運行程序。
如果你要清除斷點上的命令序列,那么只要簡單的執行一下commands命令,並直接在打個end就行了。
10 調試代碼
run
運行程序,可簡寫為rnext
單步跟蹤,函數調用當作一條簡單語句執行,可簡寫為nstep
單步跟蹤,函數調進入被調用函數體內,可簡寫為sfinish
退出函數until
在一個循環體內單步跟蹤時,這個命令可以運行程序直到退出循環體,可簡寫為u。continue
繼續運行程序,可簡寫為cstepi
或si
,nexti
或ni
單步跟蹤一條機器指令,一條程序代碼有可能由數條機器指令完成,stepi和nexti可以單步執行機器指令。info program
來查看程序的是否在運行,進程號,被暫停的原因。
11 查看運行時數據
print
打印變量、字符串、表達式等的值,可簡寫為pp count
打印count的值p cou1+cou2+cou3
打印表達式值print
接受一個表達式,GDB會根據當前的程序運行的數據來計算這個表達式,表達式可以是當前程序運行中的const常量、變量、函數等內容。但是GDB不能使用程序中定義的宏。
12 程序變量
在GDB中,你可以隨時查看以下三種變量的值:
1. 全局變量(所有文件可見的)
2. 靜態全局變量(當前文件可見的)
3. 局部變量(當前Scope可見的)
如果你的局部變量和全局變量發生沖突(也就是重名),一般情況下是局部變量會隱藏全局變量,也就是說,如果一個全局變量和一個函數中的局部變量同名時,如果當前停止點在函數中,用print顯示出的變量的值會是函數中的局部變量的值。如果此時你想查看全局變量的值時,你可以使用“::”操作符:
file::variable
function::variable
可以通過這種形式指定你所想查看的變量,是哪個文件中的或是哪個函數中的。例如,查看文件f2.c中的全局變量x的值:
1 p ‘f2.c’::x
當然,“::”操作符會和C++中的發生沖突,GDB能自動識別“::”是否C++的操作符,所以你不必擔心在調試C++程序時會出現異常。
4. 數組變量
有時候,你需要查看一段連續的內存空間的值。比如數組的一段,或是動態分配的數據的大小。你可以使用GDB的“@”操作符,“@”的左邊是第一個內存的地址的值,“@”的右邊則你你想查看內存的長度。例如,你的程序中有這樣的語句:
1 int *array = (int *) malloc (len * sizeof (int));
於是,在GDB調試過程中,你可以以如下命令顯示出這個動態數組的取值:
1 p *array@len
@的左邊是數組的首地址的值,也就是變量array所指向的內容,右邊則是數據的長度,其保存在變量len中。
13 自動顯示
你可以設置一些自動顯示的變量,當程序停住時,或是在你單步跟蹤時,這些變量會自動顯示。相關的GDB命令是display。
1 display expr 2 display/fmt expr 3 display/fmt addr
expr是一個表達式,fmt表示顯示的格式,addr表示內存地址,當你用display設定好了一個或多個表達式后,只要你的程序被停下來,GDB會自動顯示你所設置的這些表達式的值。
1 info display
查看display設置的自動顯示的信息。
1 undisplay dnums… 2 delete display dnums…
刪除自動顯示,dnums意為所設置好了的自動顯式的編號。如果要同時刪除幾個,編號可以用空格分隔,如果要刪除一個范圍內的編號,可以用減號表示(如:2-5)
1 disable display dnums… 2 enable display dnums…
disable和enalbe不刪除自動顯示的設置,而只是讓其失效和恢復。
14 歷史記錄
當你用GDB的print查看程序運行時的數據時,你每一個print都會被GDB記錄下來。GDB會以2, 1。這個功能所帶來的好處是,如果你先前輸入了一個比較長的表達式,如果你還想查看這個表達式的值,你可以使用歷史記錄來訪問,省去了重復輸入。
1 (gdb)show values 2 Print the last ten values in the value history, with their item numbers. This is 3 like ‘p $$9’ repeated ten times, except that show values does not change the 4 history. 5 6 (gdb)show values n 7 Print ten history values centered on history item number n. 8 9 (gdb)show values + 10 Print ten history values just after the values last printed. If no more values are 11 available, show values + produces no display.
15 改變程序的執行
一旦使用GDB掛上被調試程序,當程序運行起來后,你可以根據自己的調試思路來動態地在GDB中更改當前被調試程序的運行線路或是其變量的值,這個強大的功能能夠讓你更好的調試你的程序,比如,你可以在程序的一次運行中走遍程序的所有分支。
15.1 修改變量值
修改被調試程序運行時的變量值,在GDB中很容易實現,使用GDB的print命令即可完成。如:
1 (gdb) print x=4
x=4這個表達式是C/C++的語法,意為把變量x的值修改為4,如果你當前調試的語言是Pascal,那么你可以使用Pascal的語法:x:=4。
在某些時候,很有可能你的變量和GDB中的參數沖突,如:
1 (gdb) whatis width 2 type = double 3 (gdb) p width 4 $4 = 13 5 (gdb) set width=47 6 Invalid syntax in expression.
因為,set width是GDB的命令,所以,出現了“Invalid syntax in expression”的設置錯誤,此時,你可以使用set var命令來告訴GDB,width不是你GDB的參數,而是程序的變量名,如:
1 (gdb) set var width=47
另外,還可能有些情況,GDB並不報告這種錯誤,所以保險起見,在你改變程序變量取值時,最好都使用set var格式的GDB命令。
15.2 跳轉執行
一般來說,被調試程序會按照程序代碼的運行順序依次執行。GDB提供了亂序執行的功能,也就是說,GDB可以修改程序的執行順序,可以讓程序執行隨意跳躍。這個功能可以由GDB的jump命令來完:
1 jump linespec
指定下一條語句的運行點。可以是文件的行號,可以是file:line格式,可以是+num這種偏移量格式。表示下一條運行語句從哪里開始。
1 jump *address
這里的是代碼行的內存地址。
注意,jump命令不會改變當前的程序棧中的內容,所以,當你從一個函數跳到另一個函數時,當函數運行完返回時進行彈棧操作時必然會發生錯誤,可能結果還是非常奇怪的,甚至於產生程序Core Dump。所以最好是同一個函數中進行跳轉。
熟悉匯編的人都知道,程序運行時,eip寄存器用於保存當前代碼所在的內存地址。所以,jump命令也就是改變了這個寄存器中的值。於是,你可以使用“set $pc”來更改跳轉執行的地址。如:
1 set $pc = 0×485
15.3 產生信號量
使用singal命令,可以產生一個信號量給被調試的程序。如:中斷信號Ctrl+C。這非常方便於程序的調試,可以在程序運行的任意位置設置斷點,並在該斷點用GDB產生一個信號量,這種精確地在某處產生信號非常有利程序的調試。
語法是:
1 signal signal
UNIX的系統信號量通常從1到15。所以取值也在這個范圍。
single命令和shell的kill命令不同,系統的kill命令發信號給被調試程序時,是由GDB截獲的,而single命令所發出一信號則是直接發給被調試程序的。
15.4 強制函數返回
如果你的調試斷點在某個函數中,並還有語句沒有執行完。你可以使用return命令強制函數忽略還沒有執行的語句並返回。
1 return 2 return expression
使用return命令取消當前函數的執行,並立即返回,如果指定了,那么該表達式的值會被認作函數的返回值。
15.5 強制調用函數
1 call expr
表達式中可以一是函數,以此達到強制調用函數的目的。並顯示函數的返回值,如果函數返回值是void,那么就不顯示。
1 print expr
另一個相似的命令也可以完成這一功能——print,print后面可以跟表達式,所以也可以用他來調用函數,print和call的不同是,如果函數返回void,call則不顯示,print則顯示函數返回值,並把該值存入歷史數據中。
16 顯示源代碼
GDB 可以打印出所調試程序的源代碼,當然,在程序編譯時一定要加上 –g 的參數,把源程序信息編譯到執行文件中。不然就看不到源程序了。當程序停下來以后, GDB會報告程序停在了那個文件的第幾行上。你可以用list命令來打印程序的源代碼。默認打印10行,還是來看一看查看源代碼的GDB命令吧。
1 (gdb)list linenum 2 Print lines centered around line number linenum in the current source file. 3 (gdb)list function
顯示函數名為function的函數的源程序。
1 list
顯示當前行后面的源程序。
1 list -
顯示當前行前面的源程序。
一般是打印當前行的上5行和下5行,如果顯示函數是是上2行下8行,默認是10行,當然,你也可以定制顯示的范圍,使用下面命令可以設置一次顯示源程序的行數。
1 set listsize count
設置一次顯示源代碼的行數。(unless the list argument explicitly specifies some other number)
1 show listsize
17 調試已運行的進程
兩種方法:
1、在UNIX下用ps查看正在運行的程序的PID(進程ID),然后用gdb PID process-id 格式掛接正在運行的程序。
2、先用gdb 關聯上源代碼,並進行gdb,在gdb中用attach process-id 命令來掛接進程的PID。並用detach來取消掛接的進程。
18 線程
如果你程序是多線程的話,你可以定義你的斷點是否在所有的線程上,或是在某個特定的線程。GDB很容易幫你完成這一工作。
1 break linespec thread threadno 2 break linespec thread threadno if …
linespec指定了斷點設置在的源程序的行號。threadno指定了線程的ID,注意,這個ID是GDB分配的,你可以通過“info threads”命令來查看正在運行程序中的線程信息。如果你不指定‘thread threadno ’則表示你的斷點設在所有線程上面。你還可以為某線程指定斷點條件。如:
1 (gdb) break frik.c:13 thread 28 if bartab > lim
當你的程序被GDB停住時,所有的運行線程都會被停住。這方便你你查看運行程序的總體情況。而在你恢復程序運行時,所有的線程也會被恢復運行。那怕是主進程在被單步調試時。
19 查看棧信息
當程序被停住了,你需要做的第一件事就是查看程序是在哪里停住的。當你的程序調用了一個函數,函數的地址,函數參數,函數內的局部變量都會被壓入“棧”(Stack)中。你可以用GDB命令來查看當前的棧中的信息。
下面是一些查看函數調用棧信息的GDB命令:
breacktrace,簡稱bt
打印當前的函數調用棧的所有信息。如:
1 (gdb) bt 2 #0 func (n=250) at tst.c:6 3 #1 0x08048524 in main (argc=1, argv=0xbffff674) at tst.c:30 4 #2 0x400409ed in __libc_start_main () from /lib/libc.so.6
從上可以看出函數的調用棧信息:__libc_start_main –> main() –> func()
1 backtrace n 2 bt n
n是一個正整數,表示只打印棧頂上n層的棧信息。
1 backtrace -n 2 bt -n
-n表一個負整數,表示只打印棧底下n層的棧信息。
如果你要查看某一層的信息,你需要在切換當前的棧,一般來說,程序停止時,最頂層的棧就是當前棧,如果你要查看棧下面層的詳細信息,首先要做的是切換當前棧。
1 frame n
n是一個從0開始的整數,是棧中的層編號。比如:frame 0,表示棧頂,frame 1,表示棧的第二層。
1 (gdb)frame addr 2 f addr Select the frame at address addr. This is useful mainly if the chaining of stack frames has been damaged by a bug, making it impossible for gdb to assign 3 4 numbers properly to all frames. In addition, this can be useful when your program has multiple stacks and switches between them. 5 6 (gdb)up n
表示向棧的上面移動n層,可以不打n,表示向上移動一層。
1 down n
表示向棧的下面移動n層,可以不打n,表示向下移動一層。
上面的命令,都會打印出移動到的棧層的信息。如果你不想讓其打出信息。你可以使用這三個命令:
select-frame
對應於 frame 命令。
up-silently n
對應於 up 命令。
down-silently n
對應於 down 命令。
查看當前棧層的信息,你可以用以下GDB命令:
1 frame 或 f
會打印出這些信息:棧的層編號,當前的函數名,函數參數值,函數所在文件及行號,函數執行到的語句。
1 info frame 2 info f
20 信號
信號是一種軟中斷,是一種處理異步事件的方法。一般來說,操作系統都支持許多信號。尤其是UNIX,比較重要應用程序一般都會處理信號。UNIX定義了許多信號,比如SIGINT表示中斷字符信號,也就是Ctrl+C的信號,SIGBUS表示硬件故障的信號;SIGCHLD表示子進程狀態改變信號; SIGKILL表示終止程序運行的信號,等等。
調試程序的時候處理信號:
1 handle signal [keywords...]
signal可以以SIG開頭或不以SIG開頭,可以用定義一個要處理信號的范圍(如:SIGIO-SIGKILL,表示處理從 SIGIO信號到SIGKILL的信號,其中包括SIGIO,SIGIOT,SIGKILL三個信號),也可以使用關鍵字all來標明要處理所有的信號。一旦被調試的程序接收到信號,運行程序馬上會被GDB停住,以供調試。
keywords列表如下:
1 nostop
當被調試的程序收到信號時,GDB不會停住程序的運行,但會打出消息告訴你收到這種信號。
1 stop
當被調試的程序收到信號時,GDB會停住你的程序。This implies the print keyword as well.
1 print
當被調試的程序收到信號時,GDB會顯示出一條信息。
1 noprint
當被調試的程序收到信號時,GDB不會告訴你收到信號的信息。This implies the nostop keyword as well.
1 pass 2 noignore
當被調試的程序收到信號時,GDB不處理信號。這表示,GDB會把這個信號交給被調試程序處理 or else it may terminate if the signal is fatal and not handled.
1 nopass 2 ignore
當被調試的程序收到信號時,GDB不會讓被調試程序來處理這個信號。
1 info signals 2 info handle
查看有哪些信號在被GDB檢測中。
21catch
當event發生時,停住程序。event可以是下面的內容:
1、throw 一個C++拋出的異常。(throw為關鍵字)
2、catch 一個C++捕捉到的異常。(catch為關鍵字)
22 指定源文件的路徑
某些時候,用-g編譯過后的執行程序中只是包括了源文件的名字,沒有路徑名。GDB提供了可以讓你指定源文件的路徑的命令,以便GDB進行搜索。
1 Directory dirname … 2 dir dirname …
加一個源文件路徑到當前路徑的前面。如果你要指定多個路徑,UNIX下你可以使用“:”,Windows下你可以使用“;”。
1 directory
清除所有的自定義的源文件搜索路徑信息。
show directories
顯示定義了的源文件搜索路徑。
gdb高級用法
一:列文件清單
1.list(l)
1 (gdb) list line1,line2
二:執行程序
要想運行准備調試的程序,可使用run(r)命令,在它后面可以跟隨發給該程序的任何參數,包括標准輸入和標准輸出說明符(<和>)和外殼通配符(*、?、[、])在內。
如果你使用不帶參數的run命令,gdb就再次使用你給予前一條run命令的參數,這是很有用的。
利用set args
命令就可以修改發送給程序的參數,而使用show args 命令就可以查看其缺省參數的列表。
1 (gdb)set args –b –x 2 (gdb)show args 3 (gdb)backtrace(bt) //命令為堆棧提供向后跟蹤功能。 4 (gdb)Backtrace //命令產生一張列表,包含着從最近的過程開始的所以有效過程和調用這些過程的參數。
三:顯示數據
1. print(p) 命令可以檢查各個變量的值。
1 (gdb) print p //(p為變量名)
2. whatis 命令可以顯示某個變量的類型
1 (gdb) whatis p 2 type = int *
print 是gdb的一個功能很強的命令,利用它可以顯示被調試的語言中任何有效的表達式。表達式除了包含你程序中的變量外,還可以包含以下內容:
2.1 對程序中函數的調用
1 (gdb)print find_entry(1,0)
2.2 數據結構和其他復雜對象
(gdb)print *table_start $8={e=reference=’\000’,location=0x0,next=0x0}
- 1
- 2
- 1
- 2
- 1
- 2
2.3 值的歷史成分
(gdb)print $1</span> //(<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$1為歷史記錄變量,在以后可以直接引用 $1 的值)
- 1
- 1
- 1
2.4 人為數組
人為數組提供了一種去顯示存儲器塊(數組節或動態分配的存儲區)內容的方法。早期的調試程序沒有很好的方法將任意的指針換成一個數組。就像對待參數一樣,讓我們查看內存中在變量h后面的10個整數,一個動態數組的語法如下所示:
base@length
- 1
- 1
- 1
因此,要想顯示在h后面的10個元素,可以使用h@10:
(gdb)print h@10 $13=(-1,345,23,-234,0,0,0,98,345,10)
- 1
- 2
- 1
- 2
- 1
- 2
四:斷點(breakpoint)
1. break命令(可以簡寫為b)
可以用來在調試的程序中設置斷點,該命令有如下四種形式:
1. break line-number 使程序恰好在執行給定行之前停止。 2. break function-name 使程序恰好在進入指定的函數之前停止。 3. break line-or-function if condition 如果condition(條件)是真,程序到達指定行或函數時停止。 4. break routine-name 在指定例程的入口處設置斷點
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
如果該程序是由很多原文件構成的,你可以在各個原文件中設置斷點,而不是在當前的原文件中設置斷點,其方法如下:
(gdb) break filename:line-number (gdb) break filename:function-name
- 1
- 2
- 1
- 2
- 1
- 2
要想設置一個條件斷點,可以利用break if命令,如下所示:
(gdb) break line-or-function if expr
- 1
- 1
- 1
例:
(gdb) break 46 if testsize==100
- 1
- 1
- 1
從斷點繼續運行:countinue(c) 命令
五.斷點的管理
1.顯示當前gdb的斷點信息:
(gdb) info break
- 1
- 1
- 1
他會以如下的形式顯示所有的斷點信息:
Num Type Disp Enb Address What
1 breakpoint keep y 0x000028bc in init_random at qsort2.c:155 2 breakpoint keep y 0x0000291c in init_organ at qsort2.c:168 (gdb)
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
2.刪除指定的某個斷點:
(gdb) delete breakpoint 1
- 1
- 1
- 1
該命令將會刪除編號為1的斷點,如果不帶編號參數,將刪除所有的斷點
(gdb) delete breakpoint
- 1
- 1
- 1
3.禁止使用某個斷點
(gdb) disable breakpoint 1
- 1
- 1
- 1
該命令將禁止斷點 1,同時斷點信息的 (Enb)域將變為 n
4.允許使用某個斷點
(gdb) enable breakpoint 1
- 1
- 1
- 1
該命令將允許斷點 1,同時斷點信息的 (Enb)域將變為 y
5.清除原文件中某一代碼行上的所有斷點
(gdb)clean number
- 1
- 1
- 1
注:number 為原文件的某個代碼行的行號
Clear
清除所有的已定義的停止點。
clear <function>
或clear <filename:function>
清除所有設置在函數上的停止點。
clear <linenum>
或clear <filename:linenum>
清除所有設置在指定行上的停止點。
六.變量的檢查和賦值
- whatis:識別數組或變量的類型
- ptype:比whatis的功能更強,他可以提供一個結構的定義
- set variable:將值賦予變量
- print 除了顯示一個變量的值外,還可以用來賦值
七.單步執行
- next(n) 不進入的單步執行
- step(s) 進入的單步執行
- finish 退出該函數返回到它的調用函數中
八.函數的調用
- call name 調用和執行一個函數
(gdb) call gen_and_sork( 1234,1,0 ) (gdb) call printf(“abcd”) $1=4
- 1
- 2
- 3
- 1
- 2
- 3
- 1
- 2
- 3
九.機器語言工具
有一組專用的gdb變量可以用來檢查和修改計算機的通用寄存器,gdb提供了目前每一台計算機中實際使用的4個寄存器的標准名字:
1. $pc: 程序計數器
2. $fp: 幀指針(當前堆棧幀)
3. $sp: 棧指針
4. $ps: 處理器狀態
十.信號
gdb通常可以捕捉到發送給它的大多數信號,通過捕捉信號,它就可決定對於正在運行的進程要做些什么工作。例如,按CTRL-C將中斷信號發送給gdb,通常就會終止gdb。但是你或許不想中斷gdb,真正的目的是要中斷gdb正在運行的程序,因此,gdb要抓住該信號並停止它正在運行的程序,這樣就可以執行某些調試操作。
Handle命令可控制信號的處理,他有兩個參數,一個是信號名,另一個是接受到信號時該作什么。幾種可能的參數是:
1. nostop 接收到信號時,不要將它發送給程序,也不要停止程序。
2. stop 接受到信號時停止程序的執行,從而允許程序調試;顯示一條表示已接受到信號的消息(禁止使用消息除外)
3. print 接受到信號時顯示一條消息
4. noprint 接受到信號時不要顯示消息(而且隱含着不停止程序運行)
5. pass 將信號發送給程序,從而允許你的程序去處理它、停止運行或采取別的動作。
6. nopass 停止程序運行,但不要將信號發送給程序。
例如,假定你截獲SIGPIPE信號,以防止正在調試的程序接受到該信號,而且只要該信號一到達,就要求該序停止,並通知你。要完成這一任務,可利用如下命令:
(gdb) handle SIGPIPE stop print
- 1
- 1
- 1
請注意,UNIX的信號名總是采用大寫字母!你可以用信號編號替代信號名
如果你的程序要執行任何信號處理操作,就需要能夠測試其信號處理程序,為此,就需要一種能將信號發送給程序的簡便方法,這就是signal命令的任務。該 命令的參數是一個數字或者一個名字,如SIGINT。假定你的程序已將一個專用的SIGINT(鍵盤輸入,或CTRL-C;信號2)信號處理程序設置成采 取某個清理動作,要想測試該信號處理程序,你可以設置一個斷點並使用如下命令:
(gdb) signal 2 continuing with signal SIGINT(2)
- 1
- 2
- 1
- 2
- 1
- 2
該程序繼續執行,但是立即傳輸該信號,而且處理程序開始運行.
十一. 原文件的搜索
- search text:該命令可顯示在當前文件中包含text串的下一行。
- Reverse-search text:該命令可以顯示包含text 的前一行。
十二.UNIX接口
shell 命令可啟動UNIX外殼,CTRL-D退出外殼,返回到 gdb.
十三.命令的歷史
為了允許使用歷史命令,可使用 set history expansion on 命令
(gdb) set history expansion on
- 1
- 1
- 1
小結:常用的gdb命令
backtrace //顯示程序中的當前位置和表示如何到達當前位置的棧跟蹤(同義詞:where) breakpoint //在程序中設置一個斷點 cd //改變當前工作目錄 clear //刪除剛才停止處的斷點 commands //命中斷點時,列出將要執行的命令 (#add相當於vs的when hit) continue //從斷點開始繼續執行 delete //刪除一個斷點或監測點;也可與其他命令一起使用 display //程序停止時顯示變量和表達時 down //下移棧幀,使得另一個函數成為當前函數 frame //選擇下一條continue命令的幀 info //顯示與該程序有關的各種信息 jump //在源程序中的另一點開始運行 kill //異常終止在gdb 控制下運行的程序 list //列出相應於正在執行的程序的原文件內容 next //執行下一個源程序行,從而執行其整體中的一個函數 print //顯示變量或表達式的值 pwd //顯示當前工作目錄 ptype //顯示一個數據結構(如一個結構或C++類)的內容 quit //退出gdb reverse-search //在源文件中反向搜索正規表達式 run //執行該程序 search //在源文件中搜索正規表達式 set variable //給變量賦值 signal //將一個信號發送到正在運行的進程 step //執行下一個源程序行,必要時進入下一個函數 undisplay //display命令的反命令,不要顯示表達式 until //結束當前循環 up //上移棧幀,使另一函數成為當前函數 watch //在程序中設置一個監測點(即數據斷點) whatis //顯示變量或函數類型
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
gdb - GNU 調試器
提要
gdb [-help] [-nx] [-q] [-batch] [-cd=dir] [-f] [-b bps]
[-tty=dev] [-s symfile] [-e prog] [-se prog] [-c
core] [-x cmds] [-d dir] [prog[core|procID]]
描述
調試器(如GDB)的目的是允許你在程序運行時進入到某個程序內部去看看該程序在做什么,或者在該程序崩潰時它在做什么。
GDB主要可以做4大類事(加上一些其他的輔助工作),以幫助用戶在程序運行過程中發現bug。
o 啟動您的程序,並列出可能會影響它運行的一些信息
o 使您的程序在特定條件下停止下來
o 當程序停下來的時候,檢查發生了什么
o 對程序做出相應的調整,這樣您就能嘗試糾正一個錯誤並繼續發現其它錯誤
您能使用GDB調試用C、C++、Modula-2寫的程序。等GNU Fortran編譯器准備好過后,GDB將提供對Fortran的支持
GDB通過在命令行方式下輸入gdb來執行。啟動過后,GDB會從終端讀取命令,直到您輸入GDB命令quit使GDB退出。您能通過GDB命令help獲取在線幫助。
您能以無參數無選項的形式運行GDB,不過通常的情況是以一到兩個參數運行GDB,以待調試的可執行程序名為參數
gdb 程序名
您能用兩個參數來運行GDB,可執行程序名與core文件(譯注:不知道怎么翻譯好,就不翻譯了)。
gdb 程序名 core
您可以以進程ID作為第二個參數,以調式一個正在運行的進程
gdb 程序名 1234
將會把gdb附在進程1234之上(除非您正好有個文件叫1234,gdb總是先查找core文件)
下面是一些最常用的GDB命令:
file [filename]
裝入想要調試的可執行文件
kill [filename]
終止正在調試的程序
break [file:]function
在(file文件的)function函數中設置一個斷點
clear
刪除一個斷點,這個命令需要指定代碼行或者函數名作為參數
run [arglist]
運行您的程序 (如果指定了arglist,則將arglist作為參數運行程序)
bt Backtrace: 顯示程序堆棧信息
print expr
打印表達式的值
continue
繼續運行您的程序 (在停止之后,比如在一個斷點之后)
list
列出產生執行文件的源代碼的一部分
next
單步執行 (在停止之后); 跳過函數調用
nexti
執行下一行的源代碼中的一條匯編指令
set
設置變量的值。例如:set nval=54 將把54保存到nval變量中
step
單步執行 (在停止之后); 進入函數調用
stepi
繼續執行程序下一行源代碼中的匯編指令。如果是函數調用,這個命令將進入函數的內部,單步執行函數中的匯編代碼
watch
使你能監視一個變量的值而不管它何時被改變
rwatch
指定一個變量,如果這個變量被讀,則暫停程序運行,在調試器中顯示信息,並等待下一個調試命令。參考rwatch和watch命令
awatch
指定一個變量,如果這個變量被讀或者被寫,則暫停程序運行,在調試器中顯示信息,並等待下一個調試命令。參考rwatch和watch命令
Ctrl-C
在當前位置停止執行正在執行的程序,斷點在當前行
disable
禁止斷點功能,這個命令需要禁止的斷點在斷點列表索引值作為參數
display
在斷點的停止的地方,顯示指定的表達式的值。(顯示變量)
undisplay
刪除一個display設置的變量顯示。這個命令需要將display list中的索引做參數
enable
允許斷點功能,這個命令需要允許的斷點在斷點列表索引值作為參數
finish
繼續執行,直到當前函數返回
ignore
忽略某個斷點制定的次數。例:ignore 4 23 忽略斷點4的23次運行,在第24次的時候中斷
info [name]
查看name信息
load
動態載入一個可執行文件到調試器
xbreak
在當前函數的退出的點上設置一個斷點
whatis
顯示變量的值和類型
ptype
顯示變量的類型
return
強制從當前函數返回
txbreak
在當前函數的退出的點上設置一個臨時的斷點(只可使用一次)
make
使你能不退出 gdb 就可以重新產生可執行文件
shell
使你能不離開 gdb 就執行 UNIX shell 命令
help [name]
顯示GDB命令的信息,或者顯示如何使用GDB的總體信息
quit
退出gdb.
要得到所有使用GDB的資料,請參考Using GDB: A Guide to the GNU
Source-Level Debugger, by Richard M. Stallman and Roland
H. Pesch. 當用info查看的時候,也能看到相同的文章
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
選項
任何參數而非選項指明了一個可執行文件及core 文件(或者進程ID);所
遇到的第一個未關聯選項標志的參數與 ‘-se’ 選項等價,第二個,如果存
在,且是一個文件的名字,則等價與 ‘-c’ 選項。許多選項都有一個長格式
與短格式;都會在這里表示出來。如果你把一個長格式截短,只要不引起歧
義,那么它還是可以被識別。(如果你願意,你可以使用 ‘+’ 而非 ‘-’ 標
記選項參數,不過我們在例子中仍然遵從通常的慣例)
-help
-h 列出所有選項,並附簡要說明。
-symbols=file
-s file
讀出文件(file)中的符號表。
-write
開通(enable)往可執行文件和核心文件寫的權限。
-exec=file
-e file
在適當時候把File作為可執行的文件執行,來檢測與core dump結合的數據。
-se File
從File讀取符號表並把它作為可執行文件。
-core File
-c File
把File作為core dump來執行。
-command=File
-x File
從File中執行GDB命令。
-directory=Directory
-d Directory
把Dicrctory加入源文件搜索的路徑中。
-nx
-n
不從任何.gdbinit初始化文件中執行命令。通常情況下,這些文件中的命令是在所有命令選項和參數處理完后才執行。
-quiet
-q
"Quiet".不輸入介紹和版權信息。這些信息輸出在batch模式下也被關閉。
-batch
運行batch模式。在處理完所有用'-x'選項指定的命令文件(還有'.gdbi-nit',如果沒禁用)后退出,並返回狀態碼0.如果在命令文件中的命令被
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
執行時發生錯誤,則退出,並返回狀態碼非0.batch模式對於運行GDB作為過濾器也許很有用,比如要從另一台電腦上下載並運行一個程序;為了讓這些更有用,當
在batch模式下運行時,消息:Program exited normally.(不論什么時候,一個程序在GDB控制下終止運行,這條消息都會正常發出.),將不會發出.
-cd=Directory
運行GDB,使用Directory作為它的工作目錄,取代當前工作目錄.
-fullname
-f
當Emacs讓GDB作為一個子進程運行時,設置這個選項.它告訴GDB每當一個堆棧結構(棧幀)顯示出來(包括每次程序停止)就用標准的,認同的方式
輸出文件全名和行號.這里,認同的格式看起來像兩個’ 32’字符,緊跟文件名,行號和字符位置(由冒號,換行符分隔).Emacs同GDB的接口程序使用這兩個’ 32’字
符作為一個符號為框架來顯示源代碼.
-b Bps
設置行速(波特率或bits/s).在遠程調試中GDB在任何串行接口中使用的行速.
-tty=Device
使用Device作為你程序運行的標准輸入輸出.
gdb主要調試的是C/C++的程序。要調試C/C++的程序,首先在編譯時,必須要把調試信息加到可執行文件中。使用編譯器(cc/gcc/g++)的 -g 參數即可。如:
[david@DAVID david]$ gcc -g hello.c -o hello
[david@DAVID david]$ g++ -g hello.cpp -o hello
如果沒有-g,將看不見程序的函數名和變量名,代替它們的全是運行時的內存地址。當用-g把調試信息加入,並成功編譯目標代碼以后,看看如何用gdb來調試。
啟動gdb的方法有以下幾種:
-
gdb
program也就是執行文件,一般在當前目錄下。 -
gdb core
用gdb同時調試一個運行程序和core文件,core是程序非法執行后,core dump后產生的文件。 -
gdb
如果程序是一個服務程序,那么可以指定這個服務程序運行時的進程ID。gdb會自動attach上去,並調試它。program應該在PATH環境變量中搜索得到。
●在Linux下用ps(第一章已經對ps作了介紹)查看正在運行的程序的PID(進程ID),然后用gdb PID格式掛接正在運行的程序。
●先用gdb 關聯上源代碼,並進行gdb,在gdb中用attach命令來掛接進程的PID,並用detach來取消掛接的進程。
gdb啟動時,可以加上一些gdb的啟動開關,詳細的開關可以用gdb -help查看。下面只列舉一些比較常用的參數:
-symbols
-s
從指定文件中讀取符號表。
-se file
從指定文件中讀取符號表信息,並把它用在可執行文件中。
-core
-c
調試時core dump的core文件。
-directory
-d
加入一個源文件的搜索路徑。默認搜索路徑是環境變量中PATH所定義的路徑。
4.1.1 gdb的命令概貌
gdb的命令很多,gdb將之分成許多種類。help命令只是列出gdb的命令種類,如果要看其中的命令,可以使用help 命令。如:
(gdb) help data
也可以直接用help [command]來查看命令的幫助。
gdb中,輸入命令時,可以不用輸入全部命令,只用輸入命令的前幾個字符就可以了。當然,命令的前幾個字符應該標志着一個惟一的命令,在linux下,可以按兩次TAB鍵來補齊命令的全稱,如果有重復的,那么gdb會把它全部列出來。
示例一:在進入函數func時,設置一個斷點。可以輸入break func,或是直接輸入b func。
(gdb) b func
Breakpoint 1 at 0x804832e: file test.c, line 5.
(gdb)
示例二:輸入b按兩次TAB鍵,你會看到所有b開頭的命令。
(gdb) b
backtrace break bt
要退出gdb時,只用輸入quit或其簡稱q就行了。
4.1.2 gdb中運行Linux的shell程序
在gdb環境中,可以執行Linux的shell命令:
shell
調用Linux的shell來執行,環境變量SHELL中定義的Linux的shell將會用來執行。如果SHELL沒有定義,那就使用Linux的標准shell:/bin/sh(在Windows中使用Command.com或cmd.exe)。
還有一個gdb命令是make:
make
可以在gdb中執行make命令來重新build自己的程序。這個命令等價於shell make 。
4.1.3 在gdb中運行程序
當以gdb 方式啟動gdb后,gdb會在PATH路徑和當前目錄中搜索的源文件。如要確認gdb是否讀到源文件,可使用l或list命令,看看gdb是否能列出源代碼。
在gdb中,運行程序使用r或是run命令。程序的運行,有可能需要設置下面四方面的事。
- 程序運行參數
set args 可指定運行時參數。如:
set args 10 20 30 40 50
show args 命令可以查看設置好的運行參數。
- 運行環境
path可設定程序的運行路徑。
show paths 查看程序的運行路徑。
set environment varname [=value] 設置環境變量。如:
set env USER=hchen
show environment [varname] 查看環境變量。
- 工作目錄
cd相當於shell的cd命令。
pwd 顯示當前的所在目錄。
- 程序的輸入輸出
info terminal 顯示程序用到的終端的模式。
使用重定向控制程序輸出。如:
run > outfile
tty命令可以指寫輸入輸出的終端設備。如:
tty /dev/ttyb
4.1.4 調試已運行的程序
調試已經運行的程序有兩種方法:
● 在Linux下用ps(第一章已經對ps作了介紹)查看正在運行的程序的PID(進程ID),然后用gdb PID格式掛接正在運行的程序。
● 先用gdb 關聯上源代碼,並進行gdb,在gdb中用attach命令來掛接進程的PID,並用detach來取消掛接的進程。
4.1.5 暫停/恢復程序運行
調試程序中,暫停程序運行是必需的,gdb可以方便地暫停程序的運行。可以設置程序在哪行停住,在什么條件下停住,在收到什么信號時停往等,以便於用戶查看運行時的變量,以及運行時的流程。
當進程被gdb停住時,可以使用info program 來查看程序是否在運行、進程號、被暫停的原因。
在gdb中,有以下幾種暫停方式:斷點(BreakPoint)、觀察點(WatchPoint)、捕捉點(CatchPoint)、信號(Signals)及線程停止(Thread Stops)。
如果要恢復程序運行,可以使用c或是continue命令。
- 設置斷點(BreakPoint)
用break命令來設置斷點。有下面幾種設置斷點的方法:
break
在進入指定函數時停住。C++中可以使用class::function或function(type,type)格式來指定函數名。
break
在指定行號停住。
break +offset
break -offset
在當前行號的前面或后面的offset行停住。offiset為自然數。
break filename:linenum
在源文件filename的linenum行處停住。
break filename:function
在源文件filename的function函數的入口處停住。
break *address
在程序運行的內存地址處停住。
break
該命令沒有參數時,表示在下一條指令處停住。
break … if
condition表示條件,在條件成立時停住。比如在循環體中,可以設置break if i=100,表示當i為100時停住程序。
查看斷點時,可使用info命令,如下所示(注:n表示斷點號):
info breakpoints [n]
info break [n]
- 設置觀察點(WatchPoint)
觀察點一般用來觀察某個表達式(變量也是一種表達式)的值是否變化了。如果有變化,馬上停住程序。有下面的幾種方法來設置觀察點:
watch
為表達式(變量)expr設置一個觀察點。一旦表達式值有變化時,馬上停住程序。
rwatch
當表達式(變量)expr被讀時,停住程序。
awatch
當表達式(變量)的值被讀或被寫時,停住程序。
info watchpoints
列出當前設置的所有觀察點。
- 設置捕捉點(CatchPoint)
可設置捕捉點來補捉程序運行時的一些事件。如載入共享庫(動態鏈接庫)或是C++的異常。設置捕捉點的格式為:
catch
當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 載入共享庫(動態鏈接庫)時 (load為關鍵字,目前此功能只在HP-UX下有用)。
● unload 或 unload 卸載共享庫(動態鏈接庫)時 (unload為關鍵字,目前此功能只在HP-UX下有用)。
tcatch
只設置一次捕捉點,當程序停住以后,應點被自動刪除。
- 維護停止點
上面說了如何設置程序的停止點,gdb中的停止點也就是上述的三類。在gdb中,如果覺得已定義好的停止點沒有用了,可以使用delete、clear、disable、enable這幾個命令來進行維護。
Clear
清除所有的已定義的停止點。
clear
clear
清除所有設置在函數上的停止點。
clear
clear
清除所有設置在指定行上的停止點。
delete [breakpoints] [range…]
刪除指定的斷點,breakpoints為斷點號。如果不指定斷點號,則表示刪除所有的斷點。range 表示斷點號的范圍(如:3-7)。其簡寫命令為d。
比刪除更好的一種方法是disable停止點。disable了的停止點,gdb不會刪除,當還需要時,enable即可,就好像回收站一樣。
disable [breakpoints] [range…]
disable所指定的停止點,breakpoints為停止點號。如果什么都不指定,表示disable所有的停止點。簡寫命令是dis.
enable [breakpoints] [range…]
enable所指定的停止點,breakpoints為停止點號。
enable [breakpoints] once range…
enable所指定的停止點一次,當程序停止后,該停止點馬上被gdb自動disable。
enable [breakpoints] delete range…
enable所指定的停止點一次,當程序停止后,該停止點馬上被gdb自動刪除。
- 停止條件維護
前面在介紹設置斷點時,提到過可以設置一個條件,當條件成立時,程序自動停止。這是一個非常強大的功能,這里,專門介紹這個條件的相關維護命令。
一般來說,為斷點設置一個條件,可使用if關鍵詞,后面跟其斷點條件。並且,條件設置好后,可以用condition命令來修改斷點的條件(只有break和watch命令支持if,catch目前暫不支持if)。
condition
修改斷點號為bnum的停止條件為expression。
condition
清除斷點號為bnum的停止條件。
還有一個比較特殊的維護命令ignore,可以指定程序運行時,忽略停止條件幾次。
ignore
表示忽略斷點號為bnum的停止條件count次。
- 為停止點設定運行命令
可以使用gdb提供的command命令來設置停止點的運行命令。也就是說,當運行的程序在被停住時,我們可以讓其自動運行一些別的命令,這很有利行自動化調試。
commands [bnum]
… command-list …
end
為斷點號bnum指定一個命令列表。當程序被該斷點停住時,gdb會依次運行命令列表中的命令。
例如:
break foo if x>0
commands
printf “x is %d\n”,x
continue
end
斷點設置在函數foo中,斷點條件是x>0,如果程序被斷住后,也就是一旦x的值在foo函數中大於0,gdb會自動打印出x的值,並繼續運行程序。
如果要清除斷點上的命令序列,那么只要簡單地執行一下commands命令,並直接在輸入end就行了。
- 斷點菜單
在C++中,可能會重復出現同一個名字的函數若干次(函數重載)。在這種情況下,break 不能告訴gdb要停在哪個函數的入口。當然,可以使用break