Linux學習——Gdb基本調試方法&&多線程調試

1.Gdb的基本調試

示例代碼mysql

//e.c
 #include <stdio.h>
 void debug(char *str)
{
    printf("debug info :%s\n",str );
}

int main(int argc,char *argv[]){
    int i,j;
    j=0;
    for(i=0;i<10;i++){
        j+=5;
        printf("now a=%d\n", j);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

gcc -g -o e e.c
調試gdb e
或者輸入gdb
而後 file esql

1. list 命令用法多線程

list命令顯示多行源代碼,從上次的位置開始顯示,默認狀況下,一次顯示10行,第一次使用時,從代碼其實位置顯示。併發

list n顯示已第n行未中心的10行代碼
list functionname顯示以functionname的函數爲中心的10行代碼
  • 1
  • 2

2. 斷點命令break
break location:在location位置設置斷點,改位置能夠爲某一行,某函數名或者其它結構的地址。gdb會在執行該位置的代碼以前停下來.app

使用delete breakpoints 斷點號 刪除斷點
這裏的斷點號表示的是第幾個斷點,剛纔執行break 10返回 
reakpoint 1 at 0x40050a: file e.c, line 10.
中的1表示該斷點的標號,所以使用 delete breakpoints 1表示刪除第10行所定義的斷點

clear n表示清除第n行的斷點,所以clear 10等同於delete breakpoints 1
disable/enable n表示使得編號爲n的斷點暫時失效或有效
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

可以使用info查看斷點相關的信息
info breakpoints函數

c(continue),繼續程序運行直到下一個斷點ui

3.display命令
查看參數的值spa

4.step及next命令
step可以使得程序逐條執行,即執行完一條語句而後在下一跳語句前停下來,等待用戶的命令。通常使用step命令是,可以使用display或者watch命令查看變量的變化,從而判斷程序行爲是否符合要求。當下一條指令爲函數時,s進入函數內部,在其第一條語句前停下來。next單步執行,但不進入函數內部。
step n,next n 表示連續但不執行n條指令,若是期間遇到斷點,則停下來
5.print打印內部變量值
6.bt 查看堆棧信息
7.watch 監視變量值的變化命令行

watch一般須要和break,run,continue聯合使用。線程

下面舉例說明:

代碼以下:
#include <stdio.h>

int main()
{
int a=0;
for(int i=0; i<10; i++)
a+=i;
}
調試的時候過程以下:

(gdb) l
1 #include <stdio.h>
2
3 int main()
4 {
5 int a=0;
6 for(int i=0; i<10; i++)
7 a+=i;
8 }
(gdb) b 5 -------在第5行設置斷電
Breakpoint 1 at 0x80483ba: file a.cpp, line 5.
(gdb) r -------執行到斷點處中止
Starting program: /a.o

Breakpoint 1, main () at a.cpp:5
5 int a=0;
(gdb) watch a -------觀察a的值,當有變化時,中止
Hardware watchpoint 2: a
(gdb) c -------繼續執行,當a的值變化時中止
Continuing.
Hardware watchpoint 2: a

Old value = 0
New value = 1
main () at a.cpp:6
6 for(int i=0; i<10; i++)
(gdb)
Continuing.
Hardware watchpoint 2: a

Old value = 1
New value = 3
main () at a.cpp:6
6 for(int i=0; i<10; i++)
(gdb)
Continuing.
Hardware watchpoint 2: a

即,在使用watch時步驟以下:

  1. 使用break在要觀察的變量所在處設置斷點;

  2. 使用run執行,直到斷點;

  3. 使用watch設置觀察點;

  4. 使用continue觀察設置的觀察點是否有變化。

8.set variable value=x 動態改變變量值
1,調試中須要修改臨時變量的值時,可使用set命令
語法:

set variable key = value
set var key = value
示例:
(gdb) set variable array[1] = 12

2,另外一種更簡單的方式,使用print命令修改
語法:
print key=value
在這裏插入圖片描述

2.多線程調試

1. 線程的查看
首先建立兩個線程:

#include <stdio.h> #include <unistd.h> #include <pthread.h> #include <stdlib.h> #include <string.h> void* pthread_run1(void* arg) { (void)arg; while(1) { printf("I am thread1,ID: %d\n",pthread_self()); sleep(1); } } void* pthread_run2(void* arg) { (void)arg; while(1) { printf("I am thread2,ID: %d\n",pthread_self()); sleep(1); } } int main() { pthread_t tid1; pthread_t tid2; pthread_create(&tid1,NULL,pthread_run1,NULL); pthread_create(&tid2,NULL,pthread_run2,NULL); printf("I am main thread\n"); pthread_join(tid1,NULL); pthread_join(tid2,NULL); return 0; } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

分析:上面程序中建立了兩個線程,程序執行起來,main函數所在程序爲主線程,在這個主線程中有兩個新線程運行。
命令行查看:

//查看當前運行的進程
ps aux|grep a.out
//查看當前運行的輕量級進程
ps -aL|grep a.out
//查看主線程和新線程的關係
pstree -p 主線程id
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在這裏插入圖片描述
2. 線程棧結構的查看

  1. 獲取線程ID
  2. 經過命令查看棧結構 ps stack 線程ID
    在這裏插入圖片描述
    3. 利用gdb查看線程信息
    將進程附加到gdb調試器當中,查看是否建立了新線程:gdb attach 主線程ID
    在這裏插入圖片描述

查看線程的一些信息

//1.查看進程:info inferiors
//2.查看線程:info threads
//3.查看線程棧結構:bt
//4.切換線程:thread n(n表明第幾個線程)
在這裏插入圖片描述

4. 利用gdb調試多線程
  當程序沒有啓動,線程尚未執行,此時利用gdb調試多線程和調試普通程序同樣,經過設置斷點,運行,查看信息等等,在這裏不在演示,最後會加上調試線程的命令

設置斷點

//1. 設置斷點:break 行號/函數名
//2. 查看斷點:info b
  • 1
  • 2

在這裏插入圖片描述
執行線程2的函數,指行完畢繼續運行到斷點處

1. 繼續使某一線程運行:thread apply 1-n(第幾個線程) n
2. 從新啓動程序運行到斷點處:r
  • 1
  • 2

在這裏插入圖片描述
3.只運行當前線程

. 設置:set scheduler-locking on 2
. 運行:n
  • 1
  • 2

在這裏插入圖片描述
4.全部線程併發執行

1. 設置:set scheduler-locking off
    2. 運行:n
  • 1
  • 2

在這裏插入圖片描述

注意點:
ctrl+c ctrl+d ctrl+z 的區別和使用場景

Ctrl+C :強制中斷程序,程序不管運行哪裏都中止。

Ctrl+D :發送一個 exit 的信號,退出當前的用戶或者是客戶端。

Ctrl+Z :暫停程序,在進程中維持掛起狀態。

引用別人的說法:

一、Ctrl+C比較暴力,就是發送Terminal到當前的程序,好比你正在運行一個查找功能,文件正在查找中,Ctrl+C就會強制結束當前的這個進程。二、Ctrl+Z 是把當前的程序掛起,暫停執行這個程序,好比你正在mysql終端中,須要出來搞點其餘的文件操做,又不想退出mysql終端(由於下次還得輸入用戶名密碼進入,挺麻煩),因而能夠ctrl+z將mysql掛起,而後進行其餘操做,而後輸入 fg 回車後就能夠回來,固然能夠掛起好多進程到後臺,而後 fg 加編號就能把掛起的進程返回到前臺。固然,配合bg(後臺)和fg命令進行先後臺切換會很是方便。三、Ctrl+D 是發送一個exit信號,沒有那麼強烈,相似ctrl+C的操做,好比你從管理員root退回到你的普通用戶就能夠這麼用。

相關文章
相關標籤/搜索