GDB多執行緒除錯

2022-12-20 11:27:02 字數 3044 閱讀 1292

一直對gdb多執行緒除錯接觸不多,最近因為工作有了一些接觸,簡單作點記錄吧。先介紹一下gdb多執行緒除錯的基本命令。

info threads

顯示當前可除錯的所有執行緒,每個執行緒會有乙個gdb為其分配的id,後面操作執行緒的時候會用到這個id。

前面有*的是當前除錯的執行緒。

thread id

切換當前除錯的執行緒為指定id的執行緒。

break thread_ thread all在所有執行緒中相應的行上設定斷點

thread apply id1 id2 command

讓乙個或者多個執行緒執行gdb命令command。

thread apply all command

讓所有被除錯執行緒執行gdb命令command。

set scheduler-locking off|on|step

估計是實際使用過多執行緒除錯的人都可以發現,在使用step或者continue命令除錯當前被除錯執行緒的時候,其他執行緒也是同時執行的,怎麼只讓被除錯程式執行呢?通過這個命令就可以實現這個需求。

off不鎖定任何執行緒,也就是所有執行緒都執行,這是預設值。on只有當前被除錯程式會執行。

step在單步的時候,除了next過乙個函式的情況(熟悉情況的人可能知道,這其實是乙個設定斷點然後continue的行為)以外,只有當前執行緒會執行。

在介紹完基本的多執行緒除錯命令後,大概介紹一下gdb多執行緒除錯的實現思路。

比較主要的**是前面介紹的幾個命令等都是在其中實現。thread_list這個表儲存了當前可除錯的所有執行緒的資訊。

函式add_thread_silent或者add_thread(不同版本gdb不同)用來向thread_list列表增加乙個執行緒的資訊。

函式delete_thread用來向thread_list列表刪除乙個執行緒的資訊。

上面提到的這2個函式會被有執行緒支援的target呼叫,用來增加和刪除執行緒,不同的os對執行緒的實現差異很大,這麼實現比較好的保證了gdb多執行緒除錯支援的擴充套件性。

函式info_threads_command是被命令infothreads呼叫的,就是顯示thread_list列表的資訊。

函式thread_command是被命令thread呼叫,切換當前執行緒最終呼叫的函式是

switch_to_thread,這個函式會先將當前除錯執行緒變數inferior_ptid,然後對暫存器和

frame緩衝進行重新整理。

函式thread_apply_command被命令thread apply呼叫,這個函式的實際實現其實很簡單,就是先切換當前線為指定執行緒,然後呼叫函式execute_command呼叫指定函式。

比較特別的是set scheduler-locking沒有實現在中,而是實現在控制被除錯程式執行的檔案中。

對其的設定會儲存到變數scheduler_mode中,而實際使用這個變數的函式只有用來令被除錯程式執行的函式resume。在預設情況下,傳遞給target_resume的變數是

resume_ptid,預設情況下其的值為resume_all,也就是告訴target程式執行的時候所有被除錯執行緒都要被執行。而當scheduler_mode設定為只讓當前執行緒執行的時候,

resume_ptid將被設定為inferior_ptid,這就告訴target只有inferior_ptid的執行緒會被執行。

最後特別介紹一下linux下多執行緒的支援,基本的除錯功能在中,這裡有對linux輕量級別程序本地除錯的支援。但是其在除錯多執行緒程式的時候,還需要對pthread除錯的支援,這個功能實現在中。對pthread的除錯要通過呼叫libthread_db庫來支援。

這裡有乙個單獨的target"multi-thread",這個target有2點很特別:

第一,一般target的裝載是在呼叫相關to_open函式的時候呼叫push_target進行裝載。而這個target則不同,在其初始化的時候,就註冊了函式thread_db_new_objfile到庫檔案attach事件中。這樣當gdb為除錯程式的動態載入庫時候attach庫檔案的時候,就會呼叫這個函式thread_db_new_objfile。

這樣當gdb裝載libpthread庫的時候,最終會裝載target"multi-thread"。第二,這個target並沒有像大部分target那樣自己實現了全部除錯功能,其配合的**的功能,這裡有乙個target多層結構的設計,要介紹的比較多,就不詳細介紹了。

最後介紹一下我最近遇見的乙個多執行緒除錯和解決。

基本問題是在乙個linux環境中,除錯多執行緒程式不正常,info threads看不到多執行緒的資訊。

我先用命令maintenance print target-stack看了一下target的裝載情況,發現target"multi-thread"沒有被裝載,用gdb對gdb進行除錯,發現在函式

check_for_thread_db在呼叫libthread_db中的函式td_ta_new的時候,返回了td_nolibthread,所以沒有裝載target"multi-thread"。

在時候我就懷疑是不是libpthread有問題,於是檢查了一下發現了問題,這個環境中的libpthread是被strip過的,我想可能就是以為這個影響了td_ta_new對libpthread符號資訊的獲取。當我換了乙個沒有strip過的libpthread的時候,問題果然解決了。

最終我的解決辦法是拷貝了乙個.debug版本的libpthread到lib目錄中,問題解決了。

多執行緒如果dump,多為段錯誤,一般都涉及記憶體非法讀寫。可以這樣處理,使用下面的命令開啟系統開關,讓其可以在死掉的時候生成core檔案。ulimit -c unlimited

這樣的話死掉的時候就可以在當前目錄看到為程序號)的檔案。接著使用gdb:

gdb ./bin ./

進去後,使用bt檢視死掉時棧的情況,在使用frame命令。

還有就是裡面某個執行緒停住,也沒死,這種情況一般就是死鎖或者涉及訊息接受的超時問題(聽人說的,沒有遇到過)。遇到這種情況,可以使用:gcore pid(除錯程序的pid號)

手動生成core檔案,在使用pstack(linux下好像不好使)檢視堆疊的情況。如果都看不出來,就仔細檢視**,看看是不是在if,return,break,continue這種語句操作是忘記解鎖,還有巢狀鎖的問題,都需要分析清楚了。

實驗6多執行緒

一 實驗名稱和性質 二 實驗目的 1.理解執行緒概念 了解執行緒的狀態和生命週期 2.學習繼承thread類來建立執行緒 3.理解執行緒互斥與同步的含義 掌握synchrnized同步方法。三 實驗內容 1 設計乙個包含多執行緒執行的程式,在主程式中依次建立3個執行緒,然後按順序啟動這3個執行緒,每...

多執行緒程式設計練習

實驗五 多執行緒程式設計練習 一 課堂範例的驗證 二 打字遊戲 三 實現書本上128頁上的練習6,7,8 至少3者選1 6.實現多執行緒互斥的方法 lock monit mutex和semaphores 1 lock關鍵字 將某語句塊標記為臨界區,確保該執行緒位於臨界區時,另乙個執行緒不得進入該臨界...

C多執行緒學習 二 如何操縱執行緒

下面我們就動手來建立乙個執行緒,使用thread類建立執行緒時,只需提供執行緒入口即可。執行緒入口使程式知道該讓這個執行緒幹什麼事 在c 中,執行緒入口是通過threadstart delegate 來提供的,你可以把threadstart理解為乙個函式指標,指向執行緒要執行的函式,當呼叫threa...