http://hi.baidu.com/hcq11/blog/item/9f5bfc6e696209d680cb4a25.html
http://hi.baidu.com/litto/blog/item/759389dd198111375882dd1e.html
http://blogold.chinaunix.net/u3/94700/showart_2389432.html <推薦閱讀>
先介紹一下GDB多線程調試的基本命令。
info threads 顯示當前可調試的所有線程,每個線程會有一個GDB為其分配的ID,后面操作線程的時候會用到這個ID。 前面有*的是當前調試的線程。
thread ID 切換當前調試的線程為指定ID的線程。
break thread_test.c:123 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對於多線程程序的調試有如下的支持:
- 線程產生通知:在產生新的線程時, gdb會給出提示信息
(gdb) r
Starting program: /root/thread
[New Thread 1073951360 (LWP 12900)]
[New Thread 1082342592 (LWP 12907)]---以下三個為新產生的線程
[New Thread 1090731072 (LWP 12908)]
[New Thread 1099119552 (LWP 12909)]
- 查看線程:使用info threads可以查看運行的線程。
(gdb) info threads
4 Thread 1099119552 (LWP 12940) 0xffffe002 in ?? ()
3 Thread 1090731072 (LWP 12939) 0xffffe002 in ?? ()
2 Thread 1082342592 (LWP 12938) 0xffffe002 in ?? ()
* 1 Thread 1073951360 (LWP 12931) main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb)
注意,行首的藍色文字為gdb分配的線程號,對線程進行切換時,使用該該號碼,而不是上文標出的綠色數字。
另外,行首的紅色星號標識了當前活動的線程
- 切換線程:使用 thread THREADNUMBER 進行切換,THREADNUMBER 為上文提到的線程號。下例顯示將活動線程從 1 切換至 4。
(gdb) info threads
4 Thread 1099119552 (LWP 12940) 0xffffe002 in ?? ()
3 Thread 1090731072 (LWP 12939) 0xffffe002 in ?? ()
2 Thread 1082342592 (LWP 12938) 0xffffe002 in ?? ()
* 1 Thread 1073951360 (LWP 12931) main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb) thread 4
[Switching to thread 4 (Thread 1099119552 (LWP 12940))]#0 0xffffe002 in ?? ()
(gdb) info threads
* 4 Thread 1099119552 (LWP 12940) 0xffffe002 in ?? ()
3 Thread 1090731072 (LWP 12939) 0xffffe002 in ?? ()
2 Thread 1082342592 (LWP 12938) 0xffffe002 in ?? ()
1 Thread 1073951360 (LWP 12931) main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb)
后面就是直接在你的線程函數里面設置斷點,然后continue到那個斷點,一般情況下多線程的時候,由於是同時運行的,最好設置 set scheduler-locking on
這樣的話,只調試當前線程
先介紹一下GDB多線程調試的基本命令。
info threads
顯示當前可調試的所有線程,每個線程會有一個GDB為其分配的ID,后面操作線程的時候會用到這個ID。
前面有*的是當前調試的線程。
thread ID
切換當前調試的線程為指定ID的線程。
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.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緩沖進行刷新。
函數thread_apply_command被命令thread apply調用,這個函數的實際實現其實很簡單,就是先切換當前線為指定線程,然后調用函數execute_command調用指定函數。
比較特別的是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下尤其是嵌入式Linux環境中調試多線程程序的一個常見問題的解決。
基本現象是在一個Linux環境中,調試多線程程序不正常,info threads看不到多線程的信息。有時候基本調試正常,或者會收到很多奇怪的信號。
造成這個問題的原因有:
1. 使用的庫是glibc而libpthread庫被strip過。
2. libthread_db庫和libpthread庫不匹配。
第1種情況一般是嵌入式開發在板子上運行GDB所遇到的情況,為了 節省板子上的空間,有時候會把所有的庫都strip一下,就遇見了這種現象,解決這種問題的辦法是:拷貝一個沒有strip過的libpthread庫到 板子上,或者使用“strip --strip-debug libpthread.so.0”代替直接strip。
第2種情況一般是在板子使用gdbserver,遠程使用GDB進 行調試,這時候往往板子和運行GDB的機器的體系結構不同,造成了庫的不匹配。這時候可以在用remote命令連接gdbserver以前,用“set solib-absolute-prefix”或者“set sysroot”命令設置正確的庫搜索路徑,就可以解決這個問題。
