GDB多線程調(diào)試的基本命令。
info threads
顯示當(dāng)前可調(diào)試的所有線程,每個(gè)線程會(huì)有一個(gè)GDB為其分配的ID,后面操作線程的時(shí)候會(huì)用到這個(gè)ID。
前面有*的是當(dāng)前調(diào)試的線程。
thread ID
切換當(dāng)前調(diào)試的線程為指定ID的線程。
break thread_test.c:123 thread all
在所有線程中相應(yīng)的行上設(shè)置斷點(diǎn)
thread apply ID1 ID2 command
讓一個(gè)或者多個(gè)線程執(zhí)行GDB命令command。
thread apply all command
讓所有被調(diào)試線程執(zhí)行GDB命令command。
set scheduler-locking off|on|step
估計(jì)是實(shí)際使用過(guò)多線程調(diào)試的人都可以發(fā)現(xiàn),在使用step或者continue命令調(diào)試當(dāng)前被調(diào)試線程的時(shí)候,其他線程也是同時(shí)執(zhí)行的,怎么只讓被調(diào)試程序執(zhí)行呢?通過(guò)這個(gè)命令就可以實(shí)現(xiàn)這個(gè)需求。
off 不鎖定任何線程,也就是所有線程都執(zhí)行,這是默認(rèn)值。
on 只有當(dāng)前被調(diào)試程序會(huì)執(zhí)行。
step 在單步的時(shí)候,除了next過(guò)一個(gè)函數(shù)的情況(熟悉情況的人可能知道,這其實(shí)是一個(gè)設(shè)置斷點(diǎn)然后continue的行為)以外,只有當(dāng)前線程會(huì)執(zhí)行。
在介紹完基本的多線程調(diào)試命令后,大概介紹一下GDB多線程調(diào)試的實(shí)現(xiàn)思路。
比較主要的代碼是thread.c,前面介紹的幾個(gè)命令等都是在其中實(shí)現(xiàn)。
thread_list這個(gè)表存儲(chǔ)了當(dāng)前可調(diào)試的所有線程的信息。
函數(shù)add_thread_silent或者add_thread(不同版本GDB不同)用來(lái)向thread_list列表增加一個(gè)線程的信息。
函數(shù)delete_thread用來(lái)向thread_list列表刪除一個(gè)線程的信息。
上面提到的這2個(gè)函數(shù)會(huì)被有線程支持的target調(diào)用,用來(lái)增加和刪除線程,不同的OS對(duì)線程的實(shí)現(xiàn)差異很大,這么實(shí)現(xiàn)比較好的保證了GDB多線程調(diào)試支持的擴(kuò)展性。
函數(shù)info_threads_command是被命令info threads調(diào)用的,就是顯示thread_list列表的信息。
函數(shù)thread_command是被命令thread調(diào)用,切換當(dāng)前線程最終調(diào)用的函數(shù)是switch_to_thread,這個(gè)函數(shù)會(huì)先將當(dāng)前調(diào)試線程變量inferior_ptid,然后對(duì)寄存器和frame緩沖進(jìn)行刷新。
函數(shù)thread_apply_command被命令thread apply調(diào)用,這個(gè)函數(shù)的實(shí)際實(shí)現(xiàn)其實(shí)很簡(jiǎn)單,就是先切換當(dāng)前線為指定線程,然后調(diào)用函數(shù)execute_command調(diào)用指定函數(shù)。
比較特別的是set scheduler-locking沒(méi)有實(shí)現(xiàn)在thread.c中,而是實(shí)現(xiàn)在控制被調(diào)試程序執(zhí)行的文件infrun.c中。
對(duì)
其的設(shè)置會(huì)保存到變量scheduler_mode中,而實(shí)際使用這個(gè)變量的函數(shù)只有用來(lái)令被調(diào)試程序執(zhí)行的函數(shù)resume。在默認(rèn)情況下,
傳遞給target_resume的變量是resume_ptid,默認(rèn)情況下其的值為RESUME_ALL,也就是告訴target程序執(zhí)行的時(shí)候所有
被調(diào)試線程都要被執(zhí)行。而當(dāng)scheduler_mode設(shè)置為只讓當(dāng)前線程執(zhí)行的時(shí)候,resume_ptid將被設(shè)置為inferior_ptid,
這就告訴target只有inferior_ptid的線程會(huì)被執(zhí)行。
最后特別介紹一下Linux下多線程的支持,基本的調(diào)試功能在linux-nat.c中,這里有對(duì)Linux輕量級(jí)別進(jìn)程本地調(diào)試的支持。但是其
在調(diào)試多線程程序的時(shí)候,還需要對(duì)pthread調(diào)試的支持,這個(gè)功能實(shí)現(xiàn)在linux-thread-db.c中。對(duì)pthread的調(diào)試要通過(guò)調(diào)用
libthread_db庫(kù)來(lái)支持。
這里有一個(gè)單獨(dú)的target"multi-thread",這個(gè)target有2點(diǎn)很特別:
第
一,一般target的裝載是在調(diào)用相關(guān)to_open函數(shù)的時(shí)候調(diào)用push_target進(jìn)行裝載。而這個(gè)target則不同,在其初始化
的時(shí)候,就注冊(cè)了函數(shù)thread_db_new_objfile到庫(kù)文件attach事件中。這樣當(dāng)GDB為調(diào)試程序的動(dòng)態(tài)加載庫(kù)時(shí)候attach庫(kù)文
件的時(shí)候,就會(huì)調(diào)用這個(gè)函數(shù)thread_db_new_objfile。這樣當(dāng)GDB裝載libpthread庫(kù)的時(shí)候,最終會(huì)裝載
target"multi-thread"。
第二,這個(gè)target并沒(méi)有像大部分target那樣自己實(shí)現(xiàn)了全部調(diào)試功能,其配合linux-nat.c的代碼的功能,這里有一個(gè)target多層結(jié)構(gòu)的設(shè)計(jì),要介紹的比較多,就不詳細(xì)介紹了。
最后介紹一下我最近遇見(jiàn)的一個(gè)多線程調(diào)試和解決。
基本問(wèn)題是在一個(gè)Linux環(huán)境中,調(diào)試多線程程序不正常,info threads看不到多線程的信息。
我先用命令
maintenance print
target-stack看了一下target的裝載情況,發(fā)現(xiàn)target"multi-thread"沒(méi)有被裝載,用GDB對(duì)GDB進(jìn)行調(diào)試,發(fā)現(xiàn)在
函數(shù)check_for_thread_db在調(diào)用libthread_db中的函數(shù)td_ta_new的時(shí)候,返回了TD_NOLIBTHREAD,所
以沒(méi)有裝載target"multi-thread"。
在時(shí)候我就懷疑是不是libpthread有問(wèn)題,于是檢查了一下發(fā)現(xiàn)了問(wèn)題,這個(gè)環(huán)
境中的libpthread是被strip過(guò)的,我想可能
就是以為這個(gè)影響了td_ta_new對(duì)libpthread符號(hào)信息的獲取。當(dāng)我換了一個(gè)沒(méi)有strip過(guò)的libpthread的時(shí)候,問(wèn)題果然解決
了。
最終我的解決辦法是拷貝了一個(gè).debug版本的libpthread到lib目錄中,問(wèn)題解決了。 多線程如果dump,多為段錯(cuò)誤,一般都涉及內(nèi)存非法讀寫(xiě)。可以這樣處理,使用下面的命令打開(kāi)系統(tǒng)開(kāi)關(guān),讓其可以在死掉的時(shí)候生成core文件。
ulimit -c unlimited
這樣的話死掉的時(shí)候就可以在當(dāng)前目錄看到core.pid(pid為進(jìn)程號(hào))的文件。接著使用gdb:
gdb ./bin ./core.pid
進(jìn)去后,使用bt查看死掉時(shí)棧的情況,在使用frame命令。
還有就是里面某個(gè)線程停住,也沒(méi)死,這種情況一般就是死鎖或者涉及消息接受的超時(shí)問(wèn)題(聽(tīng)人說(shuō)的,沒(méi)有遇到過(guò))。遇到這種情況,可以使用:
gcore pid (調(diào)試進(jìn)程的pid號(hào))
手動(dòng)生成core文件,在使用pstack(linux下好像不好使)查看堆棧的情況。如果都看不出來(lái),就仔細(xì)查看代碼,看看是不是在if,return,break,continue這種語(yǔ)句操作是忘記解鎖,還有嵌套鎖的問(wèn)題,都需要分析清楚了。
from:
http://blog.chinaunix.net/u3/91335/showart.php?id=2249238
posted on 2010-08-20 17:16
chatler 閱讀(591)
評(píng)論(0) 編輯 收藏 引用 所屬分類(lèi):
Linux_Coding