一.gdb常用目錄表
操作 | 描述 |
---|---|
l | 命令相當於list,從第一行開始列出源碼 |
回車 | 重複上一次命令 |
break +行號 | 設置斷點 |
break+函數名 | 在函數的入口點設置斷點 |
r | 運行程序running的簡寫 |
into break | 查看斷點信息 |
n | 單語句執行 ,next的簡寫 |
c | 繼續運行程序,continue的簡寫 |
bt | 查看函數的堆棧 |
finish | 退出函數 |
q | 退出gdb |
二.多進程調試
測試代碼:
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
pid_t id = fork();
if(id == 0)//child
{
printf("I am child ,my id is:%d;my father id is:%d \n",getpid(),getppid());
}
else if(id > 0)//parent
{
sleep(2);
printf("I am father:%d \n",getpid());
}
else
{
perror("fork error");
return -1;
}
return 0;
}
默認設置下,在調試多進程程序時GDB只會調試主進程。但是GDB(>V7.0)支持多進程的分別以及同時調試,換句話說,GDB可以同時調試多個程序。只需要設置follow-fork-mode(默認值:parent)和detach-on-fork(默認值:on)即可。
parent | on | 只調試主進程(此程序中系統默認只調試parent) |
---|---|---|
child | on | 只調試子進程 |
parent | off | 同時調試兩個進程,gdb跟主進程。子進程block(阻塞)在fork位置 |
child | off | 同時調試兩個進程,gdb跟子進程,主進程block在fork位置 |
設置方法如下圖:show follow-fork-mode show detach-on-fork
- 查詢正在調試的進程:info inferiors
顯示GDB調試的所有inferior,GDB會爲他們分配ID。其中帶有*的進程是正在調試的inferior.
( GDB將每一個被調試程序的執行狀態記錄在一個名爲inferior的結構中。一般情況下一個inferior對應一個進程,每個不同的inferior有不同的地址空間。inferior有時候會在進程沒有啓動的時候就存在。)
切換調試的進程: inferior < infer number >
切換到ID是num的inferior進行調試。
添加新的調試進程: add-inferior [-copies n] [-exec executable] ,可以用file executable來分配給inferior可執行文件。
增加n個inferior並執行程序爲executable。如果不指定n只增加一個inferior。如果不指定executable,則執行程序留空,增加後可使用file命令重新指定執行程序。這時候創建的inferior其關聯的進程並沒啓動。remove-inferiors infno:
刪除一個infno號的inferior。如果inferior正在運行,則不能刪除,所以刪除前需要先kill或者detach這個inferior。detach inferior:
detach掉編號是infno的inferior。注意這個inferior還存在,可以再次用run命令執行它kill inferior infno:
kill掉infno號inferior。注意這個inferior仍然存在,可以再次用run等命令執行它。
三.多線程調試
多線程代碼
#include<stdio.h>
#include<pthread.h>
void* start_routine1()
{
printf("I am a thread1 ,my tid is:%u\n",pthread_self());
return NULL;
}
void* start_routine2()
{
printf("I am a thread1 ,my tid is:%u\n",pthread_self());
return NULL;
}
int main()
{
pthread_t tid1;
pthread_t tid2;
pthread_create(&tid1,NULL, start_routine1, NULL);
pthread_create(&tid2,NULL, start_routine2, NULL);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
return 0;
}
注意:在創建線程時候,在編譯鏈接的時候一定要加-lpthread!!!一定要加-lpthread!!!一定要加-lpthread!!!! 重要的事情說三遍,慘痛的教訓
運行圖
在多線程編程時,當我們需要調試時,有時需要控制某些線程停在斷點,有些線程繼續執行。有時需要控制線程的運行順序。有時需要中斷某個線程,切換到其他線程。這些都可以通過gdb實現。
GDB默認支持調試多線程,跟主線程,子線程block在create thread。
多線程編程常用目錄表
操作 | 描述 |
---|---|
info threads | 顯示當前可調試的所有線程,每個線程會有一個GDB爲其分配的ID,後面操作線程的時候會用到這個ID。 前面有*的是當前調試的線程。 |
thread ID | 切換當前調試的線程爲指定ID的線程 |
break FileName.cpp:LinuNum thread all | 所有線程都在文件FileName.cpp的第LineNum行有斷點 |
thread apply ID1 ID2 command | 讓一個或者多個線程執行GDB命令command |
thread apply all command | 讓所有被調試線程執行GDB命令command |
set scheduler-locking off/on/step | 在調式某一個線程時,其他線程是否執行。off,不鎖定任何線程,默認值。on,鎖定其他線程,只有當前線程執行。step,在step(單步)時,只有被調試線程運行。 |
set non-stop on/off | 當調式一個線程時,其他線程是否運行 |
set pagination on/off | 在使用backtrace時,在分頁時是否停止 |
set target-async on/ff | 同步和異步。同步,gdb在輸出提示符之前等待程序報告一些線程已經終止的信息。而異步的則是直接返回 |
四.關於core
core的意思是核心,dumped的意思就是拋出,轉儲,core dumped就是核心轉儲的意思。當一個進程異常退出前,該進程會拋出當時該程序進程的內存詳細情況存儲在硬盤上,文件名通常是core,這就叫core dump。
進程異常終止通常是因爲代碼存在BUG,比如非法內存訪問導致段錯誤,事後可以用調試器檢查core文件以查清錯誤原因,這叫做事後調試.
關於core的指令:
指令 | 描述 |
---|---|
uname -a | 查看機器參數 |
ulimit -a | 查看默認參數 |
ulimit -c 1024 | 設置core文件大小爲1024 |
ulimit -c unlimit | 設置core文件大小爲無限 |
修改ulimit的設置,讓它產生。
指令 | 描述 |
---|---|
ulimit -c 1024 | 設置core文件大小爲1024。要是core文件大於1024個塊,就產生不出來了。 |
ulimit -c unlimit | 設置core文件大小爲無限 |