1>介紹: gdb是Linux環(huán)境下的代碼調(diào)試工具。
2>使用:需要在源代碼生成的時候加上 -g 選項.
3>開始使用: gdb binFile
4>退出:ctrl + d 或 quit
5>調(diào)試過程中的常用命令:
list/l 行號:顯示binFile源代碼,接著上次的位置往下列,每次列10行。 list/l 函數(shù)名:列出某個函數(shù)的源代碼。 r或run:運行程序。 s或step:進入函數(shù)調(diào)用 breaktrace(bt):查看各級函數(shù)調(diào)用及參數(shù) info(i) locals:查看當前棧幀局部變量的值 info break :查看斷點信息。 finish:執(zhí)行到當前函數(shù)返回,然后挺下來等待命令 print(p):打印表達式的值,通過表達式可以修改變量的值或者調(diào)用函數(shù) set var:修改變量的值 quit:退出gdb break(b) 行號:在某一行設置斷點 break 函數(shù)名:在某個函數(shù)開頭設置斷點 continue(或c):從當前位置開始連續(xù)而非單步執(zhí)行程序 run(或r):從開始連續(xù)而非單步執(zhí)行程序 delete breakpoints:刪除所有斷點 delete breakpoints n:刪除序號為n的斷點 disable breakpoints:禁用斷點 enable breakpoints:啟用斷點 info(或i) breakpoints:參看當前設置了哪些斷點 display 變量名:跟蹤查看一個變量,每次停下來都顯示它的值 undisplay:取消對先前設置的那些變量的跟蹤 until X行號:跳至X行 p 變量:打印變量值 n 或 next:單條執(zhí)行
1 ,調(diào)試代碼
1 /************************************** 2 *文件說明:process.c 3 *作者:段曉雪 4 *創(chuàng)建時間:2017年06月10日 星期六 10時59分14秒 5 *開發(fā)環(huán)境:Kali Linux/g++ v6.3.0 6 ****************************************/ 7 8 #include<stdio.h> 8 #include<stdio.h> 9 #include<unistd.h> 10 #include<sys/types.h> 11 #include<sys/wait.h> 12 13 int main() 14 { 15 pid_t pid = fork();//創(chuàng)建子進程 16 17 if(pid == -1) 18 { 19 perror("fork error"); 20 return -1; 21 } 22 else if(pid == 0)//child 23 { 24 printf("i am a child:my pid is %d,my father is %d\n",getpid(),getppid()); 25 } 26 else//father 27 { 28 printf("i am a father:my pid is %d\n",getpid()); 29 wait(NULL);//等待子進程 30 } 31 32 return 0; 33 34 }
2,默認設置下,在調(diào)試多進程程序時GDB只會調(diào)試主進程。但是GDB(>V7.0)支持多進程的分別以及同時調(diào)試,換句話說,GDB可以同時調(diào)試多個程序。只需要設置follow-fork-mode(默認值:parent)和detach-on-fork(默認值:on)即可。
follow-fork-mode detach-on-fork 說明:
parent on 只調(diào)試主進程(GDB默認)child on 只調(diào)試子進程parent off 同時調(diào)試兩個進程,gdb跟主進程,子進程block在fork位置child off 同時調(diào)試兩個進程,gdb跟子進程,主進程block在fork位置
1>進入gdb調(diào)試模式:
2>查看系統(tǒng)默認的follow-fork-mode 和 detach-on-fork:
show follow-fork-modeshow detach-on-fork
3>設置follow-fork-mode 和 detach-on-fork:
set follow-fork-mode [parent|child] set detach-on-fork [on|off]
4>用l/list命令查看源代碼(按enter翻頁),分別在子進程和父進程相應位置下斷點:
5>運行程序,查詢正在調(diào)試的進程:
顯示GDB調(diào)試的所有inferior,GDB會為他們分配ID。其中帶有*的進程是正在調(diào)試的inferior。( GDB將每一個被調(diào)試程序的執(zhí)行狀態(tài)記錄在一個名為inferior的結構中。一般情況下一個inferior對應一個進程,每個不同的inferior有不同的地址空間。inferior有時候會在進程沒有啟動的時候就存在。)
runinfo inferiors
6> 切換調(diào)試的進程:
inferior <infer number>
7>其他
(1)add-inferior [-copies n] [-exec executable]
添加新的調(diào)試進程,可以用file executable來分配給inferior可執(zhí)行文件。增加n個inferior并執(zhí)行程序為executable。如果不指定n只增加一個inferior。如果不指定executable,則執(zhí)行程序留空,增加后可使用file命令重新指定執(zhí)行程序。這時候創(chuàng)建的inferior其關聯(lián)的進程并沒啟動。
(2)remove-inferiors infno
刪除一個infno號的inferior。如果inferior正在運行,則不能刪除,所以刪除前需要先kill或者detach這個inferior。
(3)clone-inferior [-copies n] [infno]
復制n個編號是infno的inferior。如果不指定n的話,就只復制一個inferior。如果不指定infno,則就復制正在調(diào)試的inferior。
(4)detach inferior
detach掉編號是infno的inferior。注意這個inferior還存在,可以再次用run命令執(zhí)行它。
(5)kill inferior infno:
kill掉infno號inferior。注意這個inferior仍然存在,可以再次用run等命令執(zhí)行它。
(6)set schedule-multiple on|off
設為off:只有當前inferior會執(zhí)行。
設為on:全部是執(zhí)行狀態(tài)的inferior都會執(zhí)行。
這個選項類似于多線程調(diào)試里的set .
(7)scheduler-locking
注意:如果scheduler-locking是指為on,即使schedule-multiple設置為on,也只有當前進程的當前線程會執(zhí)行。
show schedule-multiple: 查看schedule-multiple的狀態(tài)。
(8)set follow-exec-mode new|same
設置same:當發(fā)生exec的時候,在執(zhí)行exec的inferior上控制子進程。
設置為new:新建一個inferior給執(zhí)行起來的子進程。而父進程的inferior仍然保留,當前保留的inferior的程序狀態(tài)是沒有執(zhí)行。
show follow-exec-mode
查看follow-exec-mode設置的模式。
(9)set print inferior-events on|off
用來打開和關閉inferior狀態(tài)的提示信息。
show print inferior-events
查看print inferior-events設置的狀態(tài)。
(10)maint info program-spaces
用來顯示當前GDB一共管理了多少地址空間。
1,多線程程序舉例
1 /************************************** 2 *文件說明:thread.c 3 *作者:段曉雪 4 *創(chuàng)建時間:2017年06月10日 星期六 15時24分05秒 5 *開發(fā)環(huán)境:Kali Linux/g++ v6.3.0 6 ****************************************/ 7 8 #include<stdio.h> 9 #include<pthread.h> 10 11 void* thread1(void* arg) 12 { 13 printf("i am thread1,my tid is %u\n",pthread_self()); 14 return NULL; 15 } 16 17 void* thread2(void* arg) 18 { 19 printf("i am thread2,my tid is %u\n",pthread_self()); 20 return NULL; 21 } 22 23 int main() 24 { 25 pthread_t tid1,tid2; 26 pthread_create(&tid1,NULL,thread1,NULL);//創(chuàng)建線程1 27 pthread_create(&tid2,NULL,thread2,NULL);//創(chuàng)建線程2 28 29 pthread_join(tid1,NULL);//等待線程1 30 pthread_join(tid2,NULL);//等待線程2 31 32 return 0; 33 }
以上代碼中,主線程main創(chuàng)建了兩個子線程分別是thread1和thread2,所以線程的總數(shù)為3個。
2,使用gdb對多線程程序進行調(diào)試
在多線程編程時,當我們需要調(diào)試時,有時需要控制某些線程停在斷點,有些線程繼續(xù)執(zhí)行。有時需要控制線程的運行順序。有時需要中斷某個線程,切換到其他線程。這些都可以通過gdb實現(xiàn)。
GDB默認支持調(diào)試多線程,跟主線程,子線程block在create thread。
gdb調(diào)試多線程常用命令:
(1)info threads
顯示可以調(diào)試的所有線程。gdb會為每個線程分配一個ID(和tid不同),編號一般從1開始。后面的ID是指這個ID。
1>在主線程處打斷點
2>在線程1中打斷點
3>在線程2中打斷點
(2)thread ID
切換當前調(diào)試的線程為指定ID的線程。
(3)其他 break FileName.cpp:LinuNum thread all
:
所有線程都在文件FileName.cpp的第LineNum行有斷點。
thread apply ID1 ID2 IDN command
:
讓線程編號是ID1,ID2…等等的線程都執(zhí)行command命令。
thread apply all command
:所有線程都執(zhí)行command命令。
set scheduler-locking off|on|step
:
在調(diào)式某一個線程時,其他線程是否執(zhí)行。在使用step或continue命令調(diào)試當前被調(diào)試線程的時候,其他線程也是同時執(zhí)行的,如果我們只想要被調(diào)試的線程執(zhí)行,而其他線程停止等待,那就要鎖定要調(diào)試的線程,只讓他運行。
off
:不鎖定任何線程,默認值。 on
:鎖定其他線程,只有當前線程執(zhí)行。
step
:在step(單步)時,只有被調(diào)試線程運行。
set non-stop on/off
:
當調(diào)式一個線程時,其他線程是否運行。
set pagination on/off
:
在使用backtrace時,在分頁時是否停止。
set target-async on/ff
:
同步和異步。同步,gdb在輸出提示符之前等待程序報告一些線程已經(jīng)終止的信息。而異步的則是直接返回。
show scheduler-locking
:
查看當前鎖定線程的模式