欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Linux gdb多進程、多線程調(diào)試過程

 更新時間:2025年07月14日 09:15:06   作者:Tyler_Zx  
本文總結(jié)GDB在Linux下的調(diào)試方法,涵蓋基本命令、堆棧分析、多進程與多線程調(diào)試設(shè)置,如斷點、跟蹤、切換進程線程,以及調(diào)試步驟與參數(shù)配置

前言

gdb 是 linux 平臺下進行程序調(diào)試的最常用的工具。簡單的程序調(diào)試就是加斷點,然后一步一步讓程序運行,直到找到 bug 。

一般的程序調(diào)試起來比較簡單,但是在多進程或多線程情況下調(diào)試起來就比較麻煩。

若 test.c 是你想要調(diào)試的程序,那么在編譯時需要加 -g,即 gcc test.c -g -o test。完成編譯后使用命令:gdb test。

常用命令

命令

命令縮寫及例子

說明

list + n

l + n

顯示源碼第n行前后的代碼,顯示范圍有限。

break + n

b + n

在第n行設(shè)置斷點

info

i

描述程序狀態(tài)

run

r

開始運行程序

display

disp

跟蹤查看某個變量的值

info display

用于顯示當(dāng)前所有要顯示值的表達式的情況

undisplay

undisplay + 編號

用于結(jié)束某個表達式值的顯示

step

s

執(zhí)行下一條語句,如果該語句為函數(shù)調(diào)用,則進入函數(shù)執(zhí)行其中的第一條語句

next

n

執(zhí)行下一條語句,如果該語句為函數(shù)調(diào)用,不會進入函數(shù)內(nèi)部執(zhí)行

print

p

打印內(nèi)部變量的值

continue

c

繼續(xù)運行,直到遇到下一個斷點

start

st

開始執(zhí)行程序,在main函數(shù)的第一條語句前面停下來

kill

k

終止正在調(diào)試的程序

quit

q

退出gdb

set args

set args arg1 arg2

設(shè)置運行參數(shù)

show args

show args

查看運行參數(shù)

finish

finish

一直運行到函數(shù)返回并打印函數(shù)返回時的堆棧地址和返回值及參數(shù)值等信息

堆棧相關(guān)命令

命令

例子

說明

backtrace

bt

查看堆棧信息

frame

f 1

查看棧幀

info reg

info reg/ i r

查看寄存器使用情況

info stack

info stack

查看堆棧使用情況

up/down

up/down

跳到上一層/下一層函數(shù)

這里以一個簡單的程序為例,進行調(diào)試。

#include <bits/stdc++.h>
using namespace std;
#define M 5

int fact(int n)             //線性遞歸
{
    if (n < 0)
        return 0;
    else if(n == 0 || n == 1)
        return 1;
    else
        return n * fact(n - 1);
}
 
int facttail(int n, int a)   //尾遞歸
{
    if (n < 0)
        return 0;
    else if (n == 0)
        return 1;
    else if (n == 1)
        return a;
    else
        return facttail(n - 1, n * a);
}

int facttail1(int n, int a)  
{
    while(n > 0)
    {
        a = n * a;
        n--;
	}
	return a;
}
 
int main()
{
    //printf("%p", facttail);
    int a = fact(M);
    int b = facttail(M, 1);
    cout << "A:" << a <<endl;
    cout << "B:" << b <<endl;
}

(1)開始 gdb 調(diào)試

(2)設(shè)置斷點

(3)查看棧的使用情況

更為詳細的斷點調(diào)試

命令

例子

說明

break + 設(shè)置斷點的行號

break n

在n行處設(shè)置斷點

tbreak + 行號或函數(shù)名

tbreak n/func

設(shè)置臨時斷點,到達后被自動刪除

break + filename + 行號

break main.c:10

用于在指定文件對應(yīng)行設(shè)置斷點

break + <0x...>

break 0x3400a

用于在內(nèi)存某一位置處暫停

break + 行號 + if + 條件

break 10 if i==3

用于設(shè)置條件斷點,在循環(huán)中使用非常方便

info breakpoints/watchpoints [n]

info break

n表示斷點編號,查看斷點/觀察點的情況

clear + 要清除的斷點行號

clear 10

用于清除對應(yīng)行的斷點,要給出斷點的行號,清除時GDB會給出提示

delete + 要清除的斷點編號

delete 3

用于清除斷點和自動顯示的表達式的命令,要給出斷點的編號,清除時GDB不會給出任何提示

disable/enable + 斷點編號

disable 3

讓所設(shè)斷點暫時失效/使能,如果要讓多個編號處的斷點失效/使能,可將編號之間用空格隔開

awatch/watch + 變量

awatch/watch i

設(shè)置一個觀察點,當(dāng)變量被讀出或?qū)懭霑r程序被暫停

rwatch + 變量

rwatch i

設(shè)置一個觀察點,當(dāng)變量被讀出時,程序被暫停

catch

設(shè)置捕捉點來補捉程序運行時的一些事件。如:載入共享庫(動態(tài)鏈接庫)或是C++的異常

tcatch

只設(shè)置一次捕捉點,當(dāng)程序停住以后,應(yīng)點被自動刪除

gdb多進程調(diào)試

命令

例子

說明

set follow-fork-mode [parent|child]

set follow-fork-mode parent or child

設(shè)置調(diào)試器的模式,mode參數(shù)可以是

parent fork之后調(diào)試原進程,子進程不受影響,這是缺省的方式

child fork之后調(diào)試新的進程,父進程不受影響。

show follow-fork-mode

show follow-fork-mode

顯示當(dāng)前調(diào)試器的模式

set detach-on-fork [on|off]

set detach-on-fork on or off

設(shè)置gdb在fork之后是否detach進程中的其中一個,或者繼續(xù)保留控制這兩個進程 。

on子進程(或者父進程,依賴于follow-fork-mode的值)會detach然后獨立運行,這是缺省的mode

off兩個進程都受gdb控制,一個進程(子進程或父進程,依賴于follow-fork-mode)被調(diào)試,另外一個進程被掛起

info inferiors

info inferiors

顯示所有進程

inferiors processid

inferiors 2

切換進程

detach inferiors processid

detach inferiors processid

detach 一個由指定的進程,然后從fork 列表里刪除。這個進程會被允許繼續(xù)獨立運行。

kill inferiors  processid

kill inferiors  processid

殺死一個由指定的進程,然后從fork 列表里刪除。

catch fork

catch fork

讓程序在fork,vfork或者exec調(diào)用的時候中斷

調(diào)試多進程時,需要設(shè)置 detach-on-fork 的值,默認值為 on設(shè)置為 off 的含義:一個進程被調(diào)試,另外一個進程被掛起,這樣就可以交替的調(diào)試進程。follow-fork-mode 默認值為 parent,即默認調(diào)試父進程。調(diào)試代碼:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
	int num = 0;
	pid_t pid = fork();
	if(pid == 0) //子進程
	{
		while(1)
		{
			num++;
			printf("child:pid:[%d] num:[%d]\n", getpid(), num);
			sleep(2);
		}
	}
	else
	{
		while(1){
			num = num + 2;
			printf("parent:pid:[%d] num:[%d]\n", getpid(), num);
			sleep(2);
		}
	}
	return 0;
}

(1) 查看系統(tǒng)默認的 follow-fork-mode 和 detach-on-fork 設(shè)置follow-fork-mode 和 detach-on-fork

show follow-fork-mode
show detach-on-fork
set follow-fork-mode [parent|child]   
set detach-on-fork [on|off]

(2) 設(shè)置斷點并查看斷點信息

(3) 運行程序并使用 info inferiors 命令 (顯示GDB調(diào)試的所有進程,其中帶有*的進程是正在調(diào)試的進程)

(4) 使用 inferior + [編號] 切換進程,對子進程進行調(diào)試

(5) 繼續(xù)運行程序,觀察子進程的輸出

(6) 中斷子進程運行后,開始逐步調(diào)試

(7) 再次切換回父進程完成調(diào)試

gdb多線程調(diào)試

命令

例子

說明

info threads

info threads

查詢線程信息

thread + 線程號

thread 2

切換線程

thread apply [threadno] [all] + 命令

thread apply [threadno] [all] bt

線程根據(jù)相應(yīng)的命令完成操作

set print thread-events

set print thread-events

控制線程開始和結(jié)束時的打印信息

show print thread-events

show print thread-events

顯示線程打印信息的開關(guān)狀態(tài)

調(diào)試代碼:

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
 
/*全局變量*/
int sum = 0;
/*互斥量 */
pthread_mutex_t mutex;
/*聲明線程運行服務(wù)程序*/
void* pthread_function1 (void*);
void* pthread_function2 (void*);
 
int main (void)
{
    /*線程的標(biāo)識符*/
    pthread_t pt_1 = 0;
    pthread_t pt_2 = 0;
    int ret = 0;
    /*互斥初始化*/
    pthread_mutex_init (&mutex, NULL);
    /*分別創(chuàng)建線程1、2*/
    ret = pthread_create( &pt_1,                  //線程標(biāo)識符指針
                           NULL,                  //默認屬性
                           pthread_function1,     //運行函數(shù)
                           NULL);                 //無參數(shù)
    if (ret != 0)
    {
        perror ("pthread_1_create");
    }
	
    ret = pthread_create( &pt_2,                  //線程標(biāo)識符指針
                          NULL,                   //默認屬性
                          pthread_function2,      //運行函數(shù)
                          NULL);                  //無參數(shù)
    if (ret != 0)
    {
        perror ("pthread_2_create");
    }
    
    /*等待線程1、2的結(jié)束*/
    pthread_join (pt_1, NULL);
    pthread_join (pt_2, NULL);
 
    printf ("main programme exit!\n");
    return 0;
}
 
/*線程1的服務(wù)程序*/
void* pthread_function1 (void*a)
{
    int i = 0;
    printf ("This is pthread_1!\n");
    for( i=0; i<3; i++ )
    {
        pthread_mutex_lock(&mutex); /*獲取互斥鎖*/
        /*臨界資源*/
        sum++;
        printf ("Thread_1 add one to num:%d\n",sum);
        pthread_mutex_unlock(&mutex); /*釋放互斥鎖*/
        /*注意,這里以防線程的搶占,以造成一個線程在另一個線程sleep時多次訪問互斥資源,所以sleep要在得到互斥鎖后調(diào)用*/
        sleep (1);
    }
    pthread_exit ( NULL );
}
 
/*線程2的服務(wù)程序*/
void* pthread_function2 (void*a)
{
    int i = 0;
    printf ("This is pthread_2!\n");
    for( i=0; i<5; i++ )
    {
        pthread_mutex_lock(&mutex); /*獲取互斥鎖*/
        /*臨界資源*/
        sum++;
        printf ("Thread_2 add one to num:%d\n",sum);
        pthread_mutex_unlock(&mutex); /*釋放互斥鎖*/
        /*注意,這里以防線程的搶占,以造成一個線程在另一個線程sleep時多次訪問互斥資源,所以sleep要在得到互斥鎖后調(diào)用*/
        sleep (1);
    }
    pthread_exit ( NULL );
}

(1) 設(shè)置斷點并查看信息

(2) 運行程序,這里可以不設(shè)第一個斷點

(3) 兩個線程交替運行,觀察不同線程的輸出結(jié)果

(4) 使用 info threads 查看線程信息,使用 thread + [編號] 切換線程

(5) 使用 thread apply + [編號] + 命令 

鎖定其他線程,只讓當(dāng)前線程運行

(1) 設(shè)置 set scheduler-locking on

(2)  觀察線程 1 運行的情況并完成調(diào)試

其他命令

(1) thread apply ID1 ID2 IDN command: 讓線程編號是ID1,ID2…等等的線程都執(zhí)行command命令。

(2) thread apply all command:所有線程都執(zhí)行command命令。

(3) set scheduler-locking off|on|step: 在調(diào)試某一個線程時,其他線程是否執(zhí)行。在使用step或continue命令調(diào)試當(dāng)前被調(diào)試線程的時候,其他線程也是同時執(zhí)行的,如果我們只想要被調(diào)試的線程執(zhí)行,而其他線程停止等待,那就要鎖定要調(diào)試的線程,只讓他運行。

  • off:不鎖定任何線程,默認值。
  • on:鎖定其他線程,只有當(dāng)前線程執(zhí)行。
  • step:在step(單步)時,只有被調(diào)試線程運行。

(4) set non-stop on/off當(dāng)調(diào)試一個線程時,其他線程是否運行。

(5) set pagination on/off: 在使用backtrace時,在分頁時是否停止。

(6) set target-async on/ff: 同步和異步。同步,gdb在輸出提示符之前等待程序報告一些線程已經(jīng)終止的信息。而異步的則是直接返回。

(7) show scheduler-locking: 查看當(dāng)前鎖定線程的模式

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Linux xargs命令的使用

    Linux xargs命令的使用

    這篇文章主要介紹了Linux xargs命令的使用,幫助大家更好的掌握Linux系統(tǒng)的使用,感興趣的朋友可以了解下
    2020-08-08
  • apache,nginx上傳目錄無執(zhí)行權(quán)限的設(shè)置方法

    apache,nginx上傳目錄無執(zhí)行權(quán)限的設(shè)置方法

    至于為什么設(shè)置上傳目錄無權(quán)限這個我就不累贅了,現(xiàn)在比較流行的web服務(wù)有iis,apache,nginx,使用操作系統(tǒng)無非是windows or *nux
    2010-12-12
  • Linux 常用文本處理命令和vim文本編輯器

    Linux 常用文本處理命令和vim文本編輯器

    這篇文章主要介紹了Linux 常用文本處理命令和vim文本編輯器,本文給大家介紹的非常詳細,具有一定的參考借鑒價值 ,需要的朋友可以參考下
    2019-08-08
  • Linux下強制殺死進程的方法詳解

    Linux下強制殺死進程的方法詳解

    這篇文章中我們給大家分享了關(guān)于Linux下強制殺死進程的方法技巧相關(guān)內(nèi)容,有興趣的朋友們可以參考了下。
    2018-09-09
  • linux系統(tǒng)安裝iso文件方法

    linux系統(tǒng)安裝iso文件方法

    在本篇文章中小編給大家整理了關(guān)于linux系統(tǒng)下怎么安裝iso文件的解決方法和步驟,有需要的朋友們學(xué)習(xí)下。
    2019-05-05
  • 一道題理解Linux中sort命令的多個參數(shù)

    一道題理解Linux中sort命令的多個參數(shù)

    今天小編就為大家分享一篇關(guān)于一道題理解Linux中sort命令的多個參數(shù),小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • Apache?APISIX?Dashboard?未授權(quán)訪問漏洞分析(CVE-2021-45232)

    Apache?APISIX?Dashboard?未授權(quán)訪問漏洞分析(CVE-2021-45232)

    Apache?APISIX?是一個動態(tài)、實時、高性能的?API?網(wǎng)關(guān),?提供負載均衡、動態(tài)上游、灰度發(fā)布、服務(wù)熔斷、身份認證、可觀測性等豐富的流量管理功能,這篇文章主要介紹了Apache?APISIX?Dashboard?未授權(quán)訪問漏洞(CVE-2021-45232),需要的朋友可以參考下
    2023-03-03
  • win10+Ubuntu 20.04 LTS雙系統(tǒng)安裝(UEFI + GPT)(圖文,多圖預(yù)警)

    win10+Ubuntu 20.04 LTS雙系統(tǒng)安裝(UEFI + GPT)(圖文,多圖預(yù)警)

    這篇文章主要介紹了win10+Ubuntu 20.04 LTS雙系統(tǒng)安裝(UEFI + GPT)(圖文,多圖預(yù)警),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • linux云服務(wù)搭建七日殺服務(wù)器的詳細流程

    linux云服務(wù)搭建七日殺服務(wù)器的詳細流程

    這篇文章主要介紹了linux云服務(wù)搭建七日殺服務(wù)器的詳細流程,本文通過實例相結(jié)合給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-08-08
  • Ubuntu系統(tǒng)下擴展LVM根目錄的方法

    Ubuntu系統(tǒng)下擴展LVM根目錄的方法

    這篇文章主要給大家介紹了關(guān)于Ubuntu系統(tǒng)下擴展LVM根目錄的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-05-05

最新評論