1.Gdb的基本調試
示例代碼
//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 e
1. list 命令用法
list命令顯示多行源代碼,從上次的位置開始顯示,默認情況下,一次顯示10行,第一次使用時,從代碼其實位置顯示。
list n顯示已第n行未中心的10行代碼
list functionname顯示以functionname的函數為中心的10行代碼
- 1
- 2
2. 斷點命令break
break location:在location位置設置斷點,改位置可以為某一行,某函數名或者其它結構的地址。gdb會在執行該位置的代碼之前停下來.
使用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),繼續程序運行直到下一個斷點
3.display命令
查看參數的值
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時步驟如下:
-
使用break在要觀察的變量所在處設置斷點;
-
使用run執行,直到斷點;
-
使用watch設置觀察點;
-
使用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. 線程棧結構的查看
- 獲取線程ID
- 通過命令查看棧結構 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 :暫停程序,在進程中維持掛起狀態。
引用別人的說法:
1、Ctrl+C比較暴力,就是發送Terminal到當前的程序,比如你正在運行一個查找功能,文件正在查找中,Ctrl+C就會強制結束當前的這個進程。
2、Ctrl+Z 是把當前的程序掛起,暫停執行這個程序,比如你正在mysql終端中,需要出來搞點其他的文件操作,又不想退出mysql終端(因為下次還得輸入用戶名密碼進入,挺麻煩),於是可以ctrl+z將mysql掛起,然后進行其他操作,然后輸入 fg 回車后就可以回來,當然可以掛起好多進程到后台,然后 fg 加編號就能把掛起的進程返回到前台。當然,配合bg(后台)和fg命令進行前后台切換會非常方便。
3、Ctrl+D 是發送一個exit信號,沒有那么強烈,類似ctrl+C的操作,比如你從管理員root退回到你的普通用戶就可以這么用。