當前位置:
首頁 > 知識 > gdb常用命令及使用gdb調試多進程多線程程序

gdb常用命令及使用gdb調試多進程多線程程序

一、常用普通調試命令1.簡單介紹GDB

介紹: gdb是Linux環境下的代碼調試?具。

使?:需要在源代碼?成的時候加上 -g 選項。

開始使?: gdb binFile

退出: ctrl + d 或 quit

gdb常用命令及使用gdb調試多進程多線程程序

2.調試過程

(1)list命令

list linenum 顯?binFile第linenum行周圍的源代碼,接著上次的位置往下列,每次列10?。 list function 顯示函數名為function的函數的源程序 list 顯示當前行後面的源程序 list - 顯示當前行前面的源程序

gdb常用命令及使用gdb調試多進程多線程程序

(2)run或r

運行程序。

run args run命令可以直接接命令行參數值,也可以在執行run之前通過 set args + 參數值實現。

gdb常用命令及使用gdb調試多進程多線程程序

(3)break(b)

打斷點,使用方法:

  • b linenum 在某行打斷點
  • b +offset/-offset 在當前行號的前面或後面offset停住
  • b filename:linenum 在某文件的某行打斷點
  • b filename:function 在某文件某個函數入口停住
  • b *address 在程序的運行地址處停住
  • b 沒有參數在下一句停住
  • b where if condition 當某個條件滿足時,在某一行停住(這個很有用,比如b 10 if ret == 5)
  • breaktrace(或bt) 查看各級函數調?及參數
  • delete breakpoints 刪除所有斷點
  • delete breakpoints n 刪除序號為n的斷點
  • disable breakpoints 禁?斷點
  • enable breakpoints 啟?斷點

gdb常用命令及使用gdb調試多進程多線程程序

對於break命令,我們要靈活使用。例如打多個斷點。多線程程序中我們可以主函數中線程創建後立即打斷點,執行線程函數入口打斷點等。

(4)單步命令

普通用法就不說了。

  • step count 一次性執行count步,如果有函數會進入函數
  • next count 一次執行count,不進入函數
  • finish 運行程序,直到當前函數完成返回,並列印函數返回時的堆棧地址和返回值以及參數信息
  • until 退出循環體(尤其是針對for循環這種,很煩的)

(5)continue命令continue(或c):從當前位置開始連續??單步執?程序

當程序被停住之後,可以使用continue(c)命令,恢復程序的運行直到程序結束,或到達下一個斷點。這裡要注意如果沒有斷點程序是會直接結束的。

(6)print(p)命令

這個命令比較常用,用來查看我們想看的內容。比如有關數組可以看全部,也可以看從左到右某一部分:

gdb常用命令及使用gdb調試多進程多線程程序

print命令針對變數查看的輸出格式有:

  • x 按十六進位格式顯示變數
  • d 按十進位格式顯示變數
  • u 按十六進位格式顯示無符號整型
  • o 按八進位格式顯示變數
  • t 按二進位格式顯示變數t 按二進位格式顯示變數
  • a 按十六進位格式顯示變數
  • c 按字元格式顯示變數
  • f 按浮點數格式顯示變數

(7)watch命令

這個命令比較有用。watch一般用來觀察某個表達式(變數也是一種表達式)的值是否有變化,如果有變化,馬上停住程序。我們有一下幾種方法設置觀察點:

watch expr 為表達式expr設置一個觀察點,一旦表達式值有變化,馬上停住程序 rwatch expr 當表達式expr被讀時,停住程序 awatch expr 當表達式的值被讀或被寫時,停住程序。 info watchpoints 列出所有觀察點(info指令通常可以去套 舉例如下,演示觀測*i的值,一旦變化停下來:

gdb常用命令及使用gdb調試多進程多線程程序

在循環中我們也可以使用watch,配合ignore,它是除了until命令之外又一個可以讓我們跳出循環的方法,不過watch+ignore更強大,可以任意跳轉到第i次循環。它們的意思就是觀察一個變數,可以理解為斷點,ignore這個斷點多少次,然後用continue就可以直接跳過了。

gdb常用命令及使用gdb調試多進程多線程程序

(8)examine命令

使用該命令來查看內存地址中的值。語法是:x/u addr

addr表示一個內存地址。「x/」後的n、f、u都是可選的參數,n 是一個正整數,表示顯示內存的長度,也就是說從當前地址向後顯示幾個地址的內容;f 表示顯示的格式,如果地址所指的是字元串,那麼格式可以是s,如果地址是指令地址,那麼格式可以是i;u 表示從當前地址往後請求的位元組數,如果不指定的話,GDB默認是4位元組。u參數可以被一些字元代替:b表示單位元組,h表示雙位元組,w表示四位元組,g表示八位元組。當我們指定了位元組長度後,GDB會從指定的內存地址開始,讀寫指定位元組,並把其當作一個值取出來。n、f、u這3個參數可以一起使用,例如命令「x/3uh 0x54320」表示從內存地址0x54320開始以雙位元組為1個單位(h)、16進位方式(u)顯示3個單位(3)的內存。

gdb常用命令及使用gdb調試多進程多線程程序

(9)jump命令

jump命令不會改變程序棧的內容,一般只在同一函數內跳轉。

  • jump linespec 指定下一條語句的運行點,linespec可以是linenum,filename+linenum,+offset這幾種形式
  • jump address 跳到代碼行的地址

(10)signal命令

使用signal 信號名(如SIGINT)這種方式把信號發送給程序,如果程序註冊了signal_handler函數,還可以進行相應的處理,幫助調試程序。

(11)set命令

  • set args 設置命令行參數
  • set env environmentVarname=value 設置環境變數。如:set env USER=benben

(12)call命令

  • call function 強制調用某函數

強制調用某函數,它會顯示函數返回值(如果函數返回值不是void)。print命令也可以完成該功能。

(13)disassemble命令

反彙編命令,查看執行時源代碼的機器碼。

gdb常用命令及使用gdb調試多進程多線程程序

(14)其他命令

  • info(i) locals: 查看當前棧幀局部變數的值
  • info break : 查看斷點信息
  • info(或i) breakpoints: 參看當前設置了哪些斷點
  • finish: 執?到當前函數返回,然後挺下來等待命令
  • set var: 修改變數的值
  • display 變數名: 跟蹤查看?個變數,每次停下來都顯?它的值
  • undisplay: 取消對先前設置的那些變數的跟蹤
  • until X?號: 跳?X? 直接回
  • n 或 next: 單條執?
  • p 變數: 列印變數值。

二、使用gdb調試多進程多線程程序1.設置

默認設置下,在調試多進程程序時GDB只會調試主進程。但是GDB(>V7.0)支持多進程的分別以及同時調試,換句話說,GDB可以同時調試多個程序。只需要設置follow-fork-mode(默認值:parent)和detach-on-fork(默認值:on)即可。兩者結合起來構成了GDB的調試模式。

follow-fork-mode detach-on-fork 說明

parent on 只調試主進程(GDB默認)

child on 只調試子進程

parent off 同時調試兩個進程,gdb跟主進程,子進程block在fork位置

child off 同時調試兩個進程,gdb跟子進程,主進程block在fork位置

設置方法:set follow-fork-mode [parent|child] set detach-on-fork [on|off]

查詢正在調試的進程:info inferiors

切換調試的進程: inferior

添加新的調試進程: add-inferior [-copies n] [-exec executable] ,可以用file executable來分配給inferior可執行文件。

其他:remove-inferiors infno, detach inferior

查看gdb默認的參數設置:

2.演示代碼

下面這段代碼的主要流程就是在main函數中fork創建一個子進程,然後在父進程中又創建一個線程,接著就使用gdb進行調試(block子進程)。

1 #include
2 #include 3 #include
4 #include
5
6 int main(int argc, const char **argv)
7 {
8 int pid;
9 pid = fork;
10 if (pid != 0) //add the first breakpoint.
11 Parent;
12 else
13 Child;
14 return 0;
15 }
16
17 //Parent process handle.
18 void Parent
19 {
20 pid_t pid = getpid;
21 char cParent = "Parent";
22 char cThread = "Thread";
23 pthread_t pt;
24
25 printf("[%s]: [%d] [%s]
", cParent, pid, "step1");
26
27 if (pthread_create(&pt, NULL, (void *)*ParentDo, cThread))
28 {
29 printf("[%s]: Can not create a thread.
", cParent);
30 }
31
32 ParentDo(cParent);
33 sleep(1);
34 }
35 //Parent process handle after generate a thread.
36 void * ParentDo(char *argv)
37 {
38 pid_t pid = getpid;
39 pthread_t tid = pthread_self; //Get the thread-id selfly.
40 char tprefix = "thread";
41
42 printf("[%s]: [%d] [%s] [%lu] [%s]
", argv, pid, tprefix, tid, "step2"); //add the second breakpoint.
43 printf("[%s]: [%d] [%s] [%lu] [%s]
", argv, pid, tprefix, tid, "step3");
44
45 return NULL;
46 }
47 //Child process handle.
48 void Child
49 {
50 pid_t pid = getpid;
51 char prefix = "Child";
52 printf("[%s]: [%d] [%s]
", prefix, pid, "step1");
53 return;
54 }

如果直接運行程序,那麼輸出的結果如下:

gdb常用命令及使用gdb調試多進程多線程程序

3.gdb調試

3.1設置調試模式和Catchpoint

設置調試父子進程,gdb跟主進程,子進程block在fork位置。

gdb常用命令及使用gdb調試多進程多線程程序

gdb常用命令及使用gdb調試多進程多線程程序

gdb常用命令及使用gdb調試多進程多線程程序

這時可以另開一個終端,使用如下命令查看當前CentOS系統所有進程的狀態:發現父進程PID為10062,通過fork產生的子進程為10065:

gdb常用命令及使用gdb調試多進程多線程程序

同時,可以使用命令cat /proc/10062/status查看當前進程的詳細信息:進程PID為10060,它的父進程(即GDB進程)為10062,同時這也是追蹤進程ID,線程數Threads為1(共享使用該信號描述符的線程數,在POSIX多線程序應用程序中,線程組中的所有線程使用同一個信號描述符)。

gdb常用命令及使用gdb調試多進程多線程程序

3.2 設置第一個斷點

在程序的第46行設置斷點,並運行到斷點處:

gdb常用命令及使用gdb調試多進程多線程程序

gdb常用命令及使用gdb調試多進程多線程程序

這時再次使用命令pstree -pul查看當前系統進程的狀態:發現此時仍然只有父進程13162和子進程13159。

3.3 執行到第一個斷點此時如果切換到子進程13162

gdb常用命令及使用gdb調試多進程多線程程序

重新切換到父進程13159

gdb常用命令及使用gdb調試多進程多線程程序

3.4 設置第二個斷點並調試

在第50行設置斷點繼續調試主進程(使父進程產生線程),其中父進程和線程到底是誰先執行是由內核調度控制的。

gdb常用命令及使用gdb調試多進程多線程程序

這時使用命令pstree -pul查看當前系統進程的狀態:存在父進程13159和子進程13162以及父進程創建的一個線程14208(線程用大括弧{}表示)。同時,使用命令cat /proc/13159/status查看當前進程的詳細信息:進程PID為13159,它的父進程(即GDB進程)為13154,同時這也是追蹤進程ID,線程數Threads為2(當前父進程13159+線程14208)。

gdb常用命令及使用gdb調試多進程多線程程序

3.5 查看第二個斷點處的調試信息

gdb常用命令及使用gdb調試多進程多線程程序

3.6手動切換到線程

gdb常用命令及使用gdb調試多進程多線程程序

3.7 開始執行第二個斷點處的代碼

gdb常用命令及使用gdb調試多進程多線程程序

這時使用命令查看當前系統進程的狀態:存在父進程13159和子進程13162,其中線程14208已經結束了。

本文部分參考:https://typecodes.com/cseries/multilprocessthreadgdb.html

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 達人科技 的精彩文章:

Spring Data JPA與PostgreSQL的jsonb類型集成與支持
細說Nullable類型
Javascript 「繼承」

TAG:達人科技 |

您可能感興趣

Python多進程編程
入門Python多線程/多進程編程
Android 進程和線程
深入Python多進程編程基礎
用 Python 管理系統進程
Python 並發編程之線程池/進程池
Python學習之進程和線程
Python網路編程——進程
一篇文章學會使用 Android IPC 多進程
Python的分散式進程
python 進程實現多任務
走進Node.js之多進程模型
python threading中處理主進程和子線程的關係
深入Python多進程通信原理與實戰——圖文
linux進程信息查詢命令lsof詳解
蘋果iOS 13將限制VolP後台進程 或影響Facebook等應用通話功能
Perl 進程管理
Python學習之多進程詳解
linux中如何用命令結束一個進程
豐田使用HoloLens來加快造車進程