gdb pid 執行緒 gdb除錯多執行緒

2021-10-17 05:52:39 字數 3185 閱讀 9444

gdb 多執行緒除錯基本命令 實現簡介 以及乙個問題的解決

[email protected]

一直對gdb多執行緒除錯接觸不多,最近因為工作有了一些接觸,簡單作點記錄吧。

如果程式是多程序在跑,先將其設定成單程序模式(kamailio)

檢視程序中所有執行緒的棧呼叫:pstack 程序pid (pstack不是系統預設工具,需要yum安裝)

gdb attach 程序id

先介紹一下gdb多執行緒除錯的基本命令。

info threads

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

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

thread id

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

break thread_test.c:123 thread all

在所有執行緒中相應的行上設定斷點

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

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

set scheduler-locking off|on|step

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

off 不鎖定任何執行緒,也就是所有執行緒都執行,這是預設值。

on 只有當前被除錯程式會執行。

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

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

比較主要的**是thread.c,前面介紹的幾個命令等都是在其中實現。

thread_list這個表儲存了當前可除錯的所有執行緒的資訊。

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

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

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

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

函式thread_command是被命令thread呼叫,切換當前執行緒最終呼叫的函式是switch_to_thread,這個函式會先將當前除錯執行緒變數inferior_ptid,然後對暫存器和frame緩衝進行重新整理。

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

對其的設定會儲存到變數scheduler_mode中,而實際使用這個變數的函式只有用來令被除錯程式執行的函式resume。在預設情況下, 傳遞給target_resume的變數是resume_ptid,預設情況下其的值為resume_all,也就是告訴target程式執行的時候所有 被除錯執行緒都要被執行。而當scheduler_mode設定為只讓當前執行緒執行的時候,resume_ptid將被設定為inferior_ptid, 這就告訴target只有inferior_ptid的執行緒會被執行。

最後特別介紹一下linux下多執行緒的支援,基本的除錯功能在linux-nat.c中,這裡有對linux輕量級別程序本地除錯的支援。但是其 在除錯多執行緒程式的時候,還需要對pthread除錯的支援,這個功能實現在linux-thread-db.c中。對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那樣自己實現了全部除錯功能,其配合linux-nat.c的**的功能,這裡有乙個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

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

gdb ./bin ./core.pid

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

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

gcore pid (除錯程序的pid號)

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

**:

gdb pid 執行緒 gdb多執行緒除錯

死鎖除錯 1 g引數 2 attach 3 info threads void workthread void arg pthread mutex t mutex pthread mutex init mutex,0 usleep 1000 1000 fprintf stderr,timeout w...

gdb pid 執行緒 gdb除錯多程序多執行緒程式

一 除錯的指令 1.list命令 list linenum 顯示程式第linenum行的周圍的程式 list function 顯示程式名為function的函式的源程式 list 顯示當前行後面的源程式 list 顯示當前行前面的源程式 2.run r 執行命令 run args run命令可以直...

gdb除錯執行緒

推薦閱讀 先介紹一下gdb多執行緒除錯的基本命令。info threads顯示當前可除錯的所有執行緒,每個執行緒會有乙個gdb為其分配的id,後面操作執行緒的時候會用到這個id。前面有 的是當前除錯的執行緒。thread id切換當前除錯的執行緒為指定id的執行緒。break thread test...