使用show inferior-tty來(lái)告知GDB顯示程序即將運(yùn)行使用的終端
調(diào)試已經(jīng)運(yùn)行的進(jìn)程
attach process-id
該命令attach到一個(gè)正在運(yùn)行的進(jìn)程,該進(jìn)程在GDB之外啟動(dòng)。當(dāng)按回車(chē)鍵希望重復(fù)執(zhí)行上一個(gè)attach,就會(huì)發(fā)現(xiàn)attach不支持這種方式。
如果希望使用attach,則環(huán)境必須支持進(jìn)程,并且你必須有權(quán)限發(fā)送給該進(jìn)程一個(gè)信號(hào)。
使用attach時(shí),調(diào)試器會(huì)在當(dāng)前工作目錄--->源文件搜索路徑去查找源代碼文件,也可以用file命令加載程序。
GDB attach到指定進(jìn)程后做的第一件事情就是stop it,然后可以用GDB命令來(lái)檢查和修改被attached的進(jìn)程:run、step、continue等等。
detach
調(diào)試完指定進(jìn)程后,可以運(yùn)行detach命令來(lái)讓GDB釋放該進(jìn)程,該進(jìn)程得以繼續(xù)運(yùn)行。當(dāng)回車(chē)時(shí),detach不會(huì)重復(fù)。當(dāng)執(zhí)行完detach后,進(jìn)程和GDB不再相關(guān),GDB可以attach其他進(jìn)程。
當(dāng)有一個(gè)attached進(jìn)程時(shí),離開(kāi)GDB,會(huì)detach該進(jìn)程。如果正在run該程序,則會(huì)kill掉該進(jìn)程。一般情況下,上述情況GDB會(huì)請(qǐng)求你確認(rèn),你可以用
set confirm命令來(lái)決定是否需要給出確定提示。
殺死子進(jìn)程
kill
殺死GDB產(chǎn)生的用于運(yùn)行程序的子進(jìn)程
這個(gè)在調(diào)試core dump時(shí)有用,GDB在你的程序運(yùn)行時(shí)會(huì)忽略掉所有的core dump文件。
在一些OS上,如果你在GDB調(diào)試它時(shí)設(shè)置了斷點(diǎn),則該程序不會(huì)運(yùn)行,可以用kill命令允許其在GDB之外運(yùn)行。
kill命令在希望重新編譯鏈接程序使也比較有用,在大多數(shù)系統(tǒng)上,當(dāng)在進(jìn)程下運(yùn)行程序時(shí)不允許修改可執(zhí)行文件,在這種情況下,當(dāng)你kill掉
進(jìn)程,然后修改,然后run時(shí),GDB會(huì)發(fā)現(xiàn)程序改變,然后重新讀取符號(hào)表(會(huì)試圖保留之前設(shè)置的斷點(diǎn))。
調(diào)試多個(gè)子程序
GDB允許在一個(gè)單獨(dú)的session里面調(diào)試多個(gè)程序。有些系統(tǒng)允許GDB同時(shí)運(yùn)行多個(gè)程序,更一般的情況,在每一個(gè)進(jìn)程中有多個(gè)線(xiàn)程執(zhí)行。
GDB用inferior來(lái)表示每個(gè)程序執(zhí)行,inferior與進(jìn)程對(duì)應(yīng),也可用于沒(méi)有進(jìn)程的target。Inferiors在進(jìn)程運(yùn)行之前創(chuàng)建,在進(jìn)程退出之后
保留。Inferior也有自己的標(biāo)記,這個(gè)標(biāo)記與PID不同。
通常,每個(gè)inferior都有自己的不同地址空間,一些嵌入式targets可以在一個(gè)地址空間的不同部分運(yùn)行不同的inferior。每個(gè)inferior內(nèi)可以有
多個(gè)線(xiàn)程運(yùn)行。
1、info inferiors
打印GDB當(dāng)前管理的inferiors列表,對(duì)每個(gè)inferior,GDB以如下順序打印信息:
1. the inferior number assigned by gdb
2. the target system's inferior identifier
3. the name of the executable the inferior is running.
而數(shù)字前的*表示當(dāng)前inferior
(gdb) info inferiors
Num Description Executable
2 process 2307 hello
* 1 process 3401 goodbye
2、inferior infno
使inferior號(hào)infno成為當(dāng)前inferior,這個(gè)inferior號(hào)就是上面由GDB賦給的那個(gè)(1).
3、add-inferior [-copies n] [-exec executable]
在同一個(gè)session里增加n個(gè)inferiors來(lái)運(yùn)行程序,使用executable來(lái)作為可執(zhí)行文件,n默認(rèn)值為1。如果沒(méi)有指定executable,則inferior是
空的??梢杂胒ile executable來(lái)分配給inferior可執(zhí)行文件。
4、clone-inferior [-copies n] [infno]
增加n個(gè)inferiors來(lái)執(zhí)行inferior號(hào)為infno的可執(zhí)行程序,n默認(rèn)為1,infno默認(rèn)為當(dāng)前inferior。
在一些系統(tǒng)上,GDB會(huì)在執(zhí)行fork或exec調(diào)用時(shí)自動(dòng)將inferiors加進(jìn)debug session。
5、remove-inferiors infno ...
刪除inferior。不過(guò)不會(huì)remove掉執(zhí)行該命令的inferior,如果想,可使用kill或detach。
如果想離開(kāi)當(dāng)前inferior,可以用detach inferior(允許其獨(dú)立運(yùn)行)或使用kill inferiors命令
detach inferior infno...
Detach掉inferior或infno指定的inferiors,注意這些inferiors仍會(huì)顯示在info inferiors條目里面,但是描述會(huì)顯示'<null>'。
kill inferiors infno...
殺死inferior或infno指定的inferiors,注意這些inferiors仍會(huì)顯示在info inferiors條目里面,但是描述會(huì)顯示'<null>'。
在detach、 detach inferiors、kill或kill inferiors或進(jìn)程執(zhí)行完后,該inferior仍然可用,顯示在info inferiors條目里面
6、set print inferior-events
set print inferior-events on
set print inferior-events off
在GDB發(fā)現(xiàn)新的inferiors啟動(dòng)或inferiors退出或被detach后,是否打印消息。默認(rèn)不打印。
7、show print inferior-events
當(dāng)GDB發(fā)現(xiàn)inferiors啟動(dòng)、退出或被detached后,是否打印信息。
8、maint info program-spaces
打印GDB當(dāng)前管理的所有程序空間列表,按如下順序打印每個(gè)程序空間:
1. the program space number assigned by gdb
2. the name of the executable loaded into the program space, with e.g., the
file command.
當(dāng)前程序空間前面加*
(gdb) maint info program-spaces
Id Executable
2 goodbye
Bound inferiors: ID 1 (process 21561)
* 1 hello
這里,沒(méi)有inferior運(yùn)行hello程序,進(jìn)程21561運(yùn)行程序goodbye.一些平臺(tái)上,可能多個(gè)inferiors綁定到一個(gè)程序空間,更加常見(jiàn)的例子是:
調(diào)試vfork產(chǎn)生的父子進(jìn)程:
(gdb) maint info program-spaces
Id Executable
* 1 vfork-test
Bound inferiors: ID 2 (process 18050), ID 1 (process 18045)
這里inferior 2 和inferior 1都運(yùn)行在同一程序空間,因?yàn)閕nferior 1執(zhí)行了一個(gè)vfork調(diào)用
調(diào)試多線(xiàn)程程序
多線(xiàn)程和多進(jìn)程最大的不同在于:多線(xiàn)程共享同一個(gè)地址空間。此外,每個(gè)線(xiàn)程有自己的寄存器、stack,以及可能有私有內(nèi)存。
這里提供的命令在支持線(xiàn)程的系統(tǒng)上才有用。
GDB允許監(jiān)視所有進(jìn)程,但GDB控制時(shí),僅能控制一個(gè),即當(dāng)前線(xiàn)程。GDB能自動(dòng)發(fā)現(xiàn)新的線(xiàn)程,并以[New systag]格式給出提示,例如:GNU/Linux下的顯示:
[New Thread 0x41e02940 (LWP 25582)]
為了調(diào)試目的,GDB會(huì)分配屬于自己定義的線(xiàn)程號(hào)。
1、info threads [id...]
顯示系統(tǒng)中所有線(xiàn)程,或由id列表指定的線(xiàn)程信息,id之間使用空格隔開(kāi):
(gdb) info threads
2 Thread 0x4226f940 (LWP 30603) 0x0000003dd80cced2 in select () from /lib64/libc.so.6
* 1 Thread 0x2b66a424c900 (LWP 30601) 0x0000003dd80d4018 in epoll_wait () from /lib64/libc.so.6
GDB為每個(gè)線(xiàn)程顯示:
1. the thread number assigned by gdb
2. the target system's thread identifier (systag)
3. the thread's name, if one is known. A thread can either be named by theuser (see thread name, below), or, in some cases, by the program itself.
4. the current stack frame summary for that thread
*表示當(dāng)前線(xiàn)程:
(gdb) info threads
Id Target Id Frame
3 process 35 thread 27 0x34e5 in sigpause ()
2 process 35 thread 23 0x34e5 in sigpause ()
* 1 process 35 thread 13 main (argc=1, argv=0x7ffffff8)
at threadtest.c:68
2、maint info sol-threads
Solaris專(zhuān)用,顯示其用戶(hù)線(xiàn)程信息
3、thread threadno
使線(xiàn)程號(hào)為threadno的線(xiàn)程成為當(dāng)前線(xiàn)程。這里的線(xiàn)程號(hào)是GDB線(xiàn)程號(hào),即info threads中的第一列的值。GDB會(huì)顯示線(xiàn)程系統(tǒng)標(biāo)記以及其當(dāng)前
棧幀summary:
(gdb) thread 2
[Switching to thread 2 (Thread 0xb7fdab70 (LWP 12747))]
#0 some_function (ignore=0x0) at example.c:8
8 printf ("hello\n");
GDB變量$_thread包含了當(dāng)前線(xiàn)程的線(xiàn)程號(hào)。
4、thread apply [threadno | all] command
將命令command應(yīng)用到1個(gè)或多個(gè)線(xiàn)程。threadno代表線(xiàn)程號(hào),是info threads的第一列顯示的內(nèi)容,可以是單個(gè)線(xiàn)程,也可以是一個(gè)線(xiàn)程范圍,如2-4.
thread apply all代表將命令應(yīng)用到所有線(xiàn)程。
5、thread name [name]
給當(dāng)前線(xiàn)程分配名字,如果沒(méi)指定[name],則現(xiàn)有的用戶(hù)指定的名字被刪除。線(xiàn)程名出現(xiàn)在info threads顯示里面
在一些系統(tǒng),比如GNU/Linux,GDB能夠決定OS給定的線(xiàn)程名,使用thread name給定的名字可以覆蓋系統(tǒng)給定的名字,刪除用戶(hù)指定名字會(huì)重新顯示系統(tǒng)指定名。
6、thread find [regexp]
尋找名字或標(biāo)記符和正則表達(dá)式regexp的線(xiàn)程,這個(gè)命令同樣允許使用t線(xiàn)程target systag來(lái)標(biāo)記自身,例如GNU/Linux就是用LWP id。
(gdb) thread find 26688
Thread 4 has target id ’Thread 0x41e02940 (LWP 26688)’
(gdb) info thread 4
Id Target Id Frame
4 Thread 0x41e02940 (LWP 26688) 0x00000031ca6cd372 in select ()
7、set print thread-events
set print thread-events on
set print thread-events off
當(dāng)GDB發(fā)現(xiàn)新的線(xiàn)程啟動(dòng)或退出時(shí),使能或禁止打印信息。默認(rèn)打印,但并不是所有平臺(tái)都支持禁止打印該信息
8、show print thread-events
顯示:規(guī)則制定為是打印還是禁止打印信息,當(dāng)GDB發(fā)現(xiàn)新的線(xiàn)程啟動(dòng)或退出時(shí)
9、set libthread-db-search-path [path]
如果設(shè)置了該變量,則path就是以冒號(hào):分割的路徑列表,GDB用于從中搜索libthread_db,如果沒(méi)有設(shè)置,則該變量為空。
在GNU/Linux和Solaris系統(tǒng)中,GDB使用libthread_lib庫(kù)來(lái)獲取在inferior進(jìn)程中的線(xiàn)程信息。首先從該路徑讀取,如果沒(méi)找到,則從默認(rèn)路徑中
查找,最終會(huì)將libpthread加載進(jìn)inferior process。
對(duì)上述路徑查找到的libthread_db,GDB試圖在當(dāng)前inferior進(jìn)程中對(duì)其初始化,如果初始化失敗,則GDB會(huì)卸載這個(gè)目錄下找到的libthread_db,進(jìn)入
下一個(gè)目錄查找,直到成功。如果都不行,則GDB會(huì)發(fā)出警告,并禁止線(xiàn)程調(diào)試。
僅部分平臺(tái)支持。
10、show libthread-db-search-path
顯示當(dāng)前l(fā)ibthread_db搜索路徑
11、set debug libthread-db
show debug libthread-db
顯示或不顯示libthread_db相關(guān)的事件,1=enable,0=disable。
調(diào)試Forks
在大多數(shù)系統(tǒng)上,GDB對(duì)使用fork產(chǎn)生子進(jìn)程的程序調(diào)試沒(méi)有特殊的支持。當(dāng)一個(gè)程序fork時(shí),GDB仍繼續(xù)調(diào)試父進(jìn)程,子進(jìn)程的運(yùn)行沒(méi)有任何影響。
如果在子進(jìn)程將要執(zhí)行的代碼上設(shè)置了斷點(diǎn),則子進(jìn)程會(huì)收到SIGTRAP信號(hào)并停止(除非它能夠catch并處理該信號(hào))。
如果想要調(diào)試子進(jìn)程,則可以在fork子進(jìn)程后,在子進(jìn)程要執(zhí)行的代碼里調(diào)用sleep函數(shù)(可以在某全局變量被設(shè)置或某個(gè)文件存在時(shí)睡眠),然后獲取
該子進(jìn)程的PID,讓GDB使用attach來(lái)調(diào)試子進(jìn)程。
目前只有HP-UX(11.x~)和GNU/Linux(2.5.60~)支持GDB調(diào)試使用fork或vfork產(chǎn)生子進(jìn)程的程序,但默認(rèn)情況下,當(dāng)一個(gè)程序fork時(shí),GDB仍繼續(xù)調(diào)試父進(jìn)程,
子進(jìn)程的運(yùn)行沒(méi)有任何影響。可以用set follow-fork-mode來(lái)跟蹤子進(jìn)程而非父進(jìn)程。
1、set follow-fork-mode mode
在fork或vfork產(chǎn)生子進(jìn)程時(shí),使用如下mode決定跟蹤誰(shuí):
parent :默認(rèn)情況,當(dāng)一個(gè)程序fork時(shí),GDB仍繼續(xù)調(diào)試原進(jìn)程,子進(jìn)程的運(yùn)行沒(méi)有任何影響。
child :GDB調(diào)試新進(jìn)程,父進(jìn)程不受影響的運(yùn)行。
2、show follow-fork-mode
顯示是跟蹤parent還是child
在Linux上,如果你想同時(shí)調(diào)試parent和child進(jìn)程,則使用命令set detach-on-fork。
3、set detach-on-fork mode
告訴GDB:在fork后是否detach掉一個(gè)進(jìn)程,還是繼續(xù)保留調(diào)試父子兩個(gè)進(jìn)程。
on : 默認(rèn)。根據(jù)follow-fork-mode,來(lái)決定detach掉父進(jìn)程還是子進(jìn)程。
off :父子兩個(gè)進(jìn)程都在GDB控制之下,根據(jù)follow-fork-mode,一個(gè)進(jìn)程被正常調(diào)試,一個(gè)被GDB held掛起
4、show detach-on-fork
顯示3中是on還是off
如果detatch-on-fork模式off,則同時(shí)控制所有fork的進(jìn)程,可以用info inferiors來(lái)查看情況,并使用inferior來(lái)切換當(dāng)前被調(diào)試的進(jìn)程。
如果想離開(kāi)調(diào)試的進(jìn)程,可以用detach inferiors或使用kill inferiors命令
If you ask to debug a child process and a vfork is followed by an exec, gdb executes
the new target up to the first breakpoint in the new target. If you have a breakpoint set on
main in your original program, the breakpoint will also be set on the child process’s main.
在一些系統(tǒng)上,如果使用了vfork產(chǎn)生子進(jìn)程,則在exec調(diào)用結(jié)束之前無(wú)法調(diào)試子進(jìn)程和父進(jìn)程。
如果在執(zhí)行了exec函數(shù)之后,對(duì)GDB運(yùn)行了run命令,則目標(biāo)進(jìn)程重啟。
If you issue a run command to gdb after an exec call executes, the new target restarts.
To restart the parent process, use the file command with the parent executable name
as its argument. By default, after an exec call executes, gdb discards the symbols of the
previous executable image. You can change this behaviour with the set follow-exec-mode
command.
5、set follow-exec-mode mode
使GDB響應(yīng)程序?qū)xec()調(diào)用,所有的exec調(diào)用會(huì)替換進(jìn)程的程序映像。mode可以有:
new GDB創(chuàng)建一個(gè)新的inferior,并使進(jìn)程綁定到該新的inferior。在exec之前的本來(lái)進(jìn)程使用的程序,可以在重啟原來(lái)的inferior后重啟運(yùn)行。
(gdb) info inferiors
(gdb) info inferior
Id Description Executable
* 1 <null> prog1
(gdb) run
process 12020 is executing new program: prog2
Program exited normally.
(gdb) info inferiors
Id Description Executable
* 2 <null> prog2
1 <null> prog1
same : GDB使進(jìn)程依然綁定到原來(lái)的同一個(gè)inferior。在該inferior中新執(zhí)行映像替代了原來(lái)的程序映像。在exec調(diào)用后重啟inferior,如run,會(huì)重啟
在exec調(diào)用后進(jìn)程運(yùn)行的映像。
(gdb) info inferiors
Id Description Executable
* 1 <null> prog1
(gdb) run
process 12020 is executing new program: prog2
Program exited normally.
(gdb) info inferiors
Id Description Executable
* 1 <null> prog2
可以使用catch命令來(lái)使GDB停止,在無(wú)論fork、vfork還是exec調(diào)用后都停止
Setting a Bookmark to Return to Later
在一些系統(tǒng)上(當(dāng)前只有GNU/Linux),GDB可以設(shè)置程序狀態(tài)快照,即checkpoint,然后在以后可以回到這個(gè)點(diǎn)。
返回checkpoint意味著undo所有的檢查點(diǎn)之后的事情,包括內(nèi)存、寄存器的改變,甚至一些系統(tǒng)狀態(tài)。
在需要很長(zhǎng)時(shí)間或很多步才能到猜想的bug可能發(fā)生的點(diǎn)時(shí),這個(gè)非常有用。
1、checkpoint
為調(diào)試的當(dāng)前程序執(zhí)行狀態(tài)保存快照。該命令沒(méi)參數(shù),但會(huì)自動(dòng)分配一個(gè)小的數(shù)字編號(hào)。
2、info checkpoints
列出當(dāng)前debugging session中設(shè)置的checkpoints列表,對(duì)每一個(gè)checkpoint,會(huì)列出下列信息:
Checkpoint ID
Process ID
Code Address
Source line, or label
3、restart checkpoint-id
Restore程序狀態(tài)到檢查點(diǎn)checkpoint-id保存的狀態(tài)。所有的程序變量、寄存器、棧幀都會(huì)恢復(fù)到檢查點(diǎn)時(shí)的值。
但是斷點(diǎn)、GDB變量、命令行歷史不會(huì)改變,因?yàn)闄z查點(diǎn)保存的僅僅是被調(diào)試程序的信息,而是GDB調(diào)試器的信息。
4、delete checkpoint checkpoint-id
刪除checkpoint-id標(biāo)記的檢查點(diǎn)。
返回到某個(gè)檢查點(diǎn)意味著恢復(fù)被調(diào)試程序的用戶(hù)狀態(tài),加上OS狀態(tài)的子集(包括文件指針)。它不會(huì)恢復(fù)檢查點(diǎn)時(shí)的
文件數(shù)據(jù),但是會(huì)將文件指針指回檢查點(diǎn)時(shí)的位置,這樣先前寫(xiě)入的數(shù)據(jù)就會(huì)被覆蓋了。讀模式打開(kāi)的文件,文件指針
也會(huì)恢復(fù),這樣就可以讀之前的數(shù)據(jù)了。
Of course, characters that have been sent to a printer (or other external device) cannot
be “snatched back”, and characters received from eg. a serial device can be removed from
internal program buffers, but they cannot be “pushed back” into the serial pipeline, ready
to be received again. Similarly, the actual contents of files that have been changed cannot
be restored (at this time).
當(dāng)返回到檢查點(diǎn)時(shí),進(jìn)程id會(huì)變化。
使用檢查點(diǎn)的好處:由于安全性原因,很多系統(tǒng),如GNU/Linux采用隨機(jī)性地址空間,所以需要重啟程序時(shí),
很難對(duì)一個(gè)絕對(duì)地址設(shè)置斷點(diǎn)和watchpoint,因?yàn)榻^對(duì)地址在重啟后變了。而checkpoint,是一個(gè)進(jìn)程獨(dú)一
無(wú)二的拷貝,如果創(chuàng)建了一個(gè)checkpoint,這樣就可以簡(jiǎn)單的回到檢查點(diǎn)而不是重啟程序,這樣就免去了地址
空間隨機(jī)性的的影響。
聯(lián)系客服