從 0 開始學習 Linux 系列之「08.15 個 gdb 調試基礎命令」

代碼鍵盤

版權聲明:本文為 cdeveloper 原創文章,可以隨意轉載,但必須在明確位置注明出處!

gdb 簡介

gdbUNIXUNIX-like 下的調試工具,在 Linux 下一般都直接在命令行中用 gdb 來調試程序,相比 Windows 上的集成開發環境 IDE 提供的圖形界面調試,一開始使用 gdb 調試可能會讓你感到生無可戀,但是只要熟悉了 gdb 調試的常用命令,調試出程序會很有成就感,一方面因為這些命令就類似圖形界面調試按鈕背后的邏輯,另一方面用命令行來調試程序,逼格瞬間就上了一個檔次,這次就跟大家分享 gdb 調試的基本技術和 15 個常用調試命令。

在此之前,我們先來回顧下在 Windows 上使用 IDE 的圖形界面調試過程。

IDE 的調試步驟

在 Windows 的 IDE 下調試程序,例如使用 VS,一般都有下面這幾個操作:

  1. Debug 模式編譯并啟動程序
  2. 程序運行出錯,打斷點分析出錯的地方
  3. 單步運行程序,包括:step over 單步執行;step into 跳入函數;step return 跳出函數
  4. 還有全速運行,打印或者監視變量,凍結或解凍線程等調試技術

在 IDE 中上面的這些步驟一般都有固定的按鈕提供給我們使用,非常的簡單方便,我們只要多練習練習,在圖形界面調試程序不會很難,但是在 Linux 下用命令來調試程序就比圖形界面要復雜很多了。

其實,你知道真正的調試高手是什么樣的嗎?就是 Ta 對計算機原理和程序本身的邏輯理解非常深刻在 Ta 的腦海中已經可以模擬程序的運行過程,并且知道可能出錯的地方,這樣連斷點都不用打了,而且 Bug 的命中率也不低,或許這就是真正的大佬吧 :)

我們回到正題,來介紹在 Linux 使用命令行的調試過程。

gdb 的調試步驟

在 Linux 下既然是使用命令行來調試,顧名思義就是手敲命令來調試程序,大體分為下面幾個步驟,后面會詳細介紹:

  1. 編譯可以調試的程序
  2. 運行程序,打斷點
  3. 單步調試,監控變量
  4. 可視化調試
  5. 其他調試技術

可以看出,與 IDE 調試過程差不多,但是實際操作起來可是千差萬別,可不是點按鈕了,而是自己敲調試程序的命令,就相當于你正在學習那些調試按鈕背后的原理,把這種方法學會,不用學就會使用 IDE 來調試程序,不管你信不信,我反正是信了 :)

下面開始正式的調試技術介紹。

15 個 gdb 調試基礎命令

下面來正式介紹 gdb 常用的調試技術,都是調試命令,只看不做比較乏味,還是建議你跟我一起動手調試下面的程序,這樣才能真正的學會,這是本次要調試的 hello.c 程序,非常簡單:

#include <stdio.h>

int add(int x, int y) {
    return x + y;
}

int main() {
    int a = 1;
    int b = 2;
    printf("a = %d\n", a);
    printf("b = %d\n", b);

    int c = add(a, b);
    printf("%d + %d = %d\n", a, b, c);
    return 0;
}

1. 編譯可以調試的程序

我們平常使用 gcc 編譯的程序如果不加 [-g] 選項:

gcc hello.c -o hello

gdb 會提示該可執行文件沒有調試符號,不能調試:

gdb hello
# gdb 提示信息
Reading symbols from a.out...(no debugging symbols found)...done.

如果需要讓程序可以調試,就必須在編譯的時候加上 [-g] 參數

gcc -g hello.c -o hello

2. 載入要調試的程序

我們在命令行下需要手動載入待調試的程序,有 2 種方法:

方法一 - gdb 可執行文件

使用如下的命令來載入可執行文件 hello 到 gdb 中:

gdb hello

載入成功,gdb 會打印一段提示信息,并且命令行前綴變為 (gdb),下面是我的 Ubuntu 打印的信息:

GNU gdb (Ubuntu 7.11.90.20161005-0ubuntu1) 7.11.90.20161005-git
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from hello...done.
(gdb) q

注:q 退出 gdb

方法二 - 使用 gdb 提供的 file 命令

第二種方法是在 gdb 環境中使用 file 命令,我們需要先進入 gdb 環境下:

gdb

使用 file hello 載入待調試程序:

...
(gdb) file hello
Reading symbols from hello...done.
(gdb) q

3. 查看調試程序

在 gdb 下查看調試程序使用命令 list 或簡寫 l,「回車」列出后面程序:

(gdb) list
1   #include <stdio.h>
2   
3   int add(int x, int y) {
4       return x + y;
5   }
6   
7   
8   int main() {
9       int a = 1;
10      int b = 2;
(gdb) 
11      printf("a = %d\n", a);
12      printf("b = %d\n", b);
13      
14      int c = add(a, b);
15      printf("%d + %d = %d\n", a, b, c);
16      return 0;
17  }

4. 添加斷點

在 gdb 下添加斷點使用命令 break 或簡寫 b,有下面幾個常見用法(這里統一用 b):

  1. b function_name
  2. b row_num
  3. b file_name:row_num
  4. b row_num if condition

比如我們以第一個為例,在 main 函數上添加斷點:

(gdb) b main
Breakpoint 1 at 0x6e8: file hello.c, line 4.

打印的信息告訴我們在 hello.c 文件的第 4 行,地址 0x6e8 處添加了一個斷點,那如何查看斷點呢?

5. 查看斷點

在 gdb 下查看斷點使用命令 info break 或簡寫 i b,比如查看剛才打的斷點:

(gdb) i b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000000006e8 in main at hello.c:4

可以看到打印出剛才添加的 main 函數的斷點信息:編號,類型,顯示狀態,是否啟用,地址,其他信息,那又如何刪除這個斷點呢?

6. 禁用斷點

在 gdb 下禁用斷點使用命令 disable Num,比如禁用剛才打的斷點:

(gdb) disable 1
(gdb) i b
Num     Type           Disp Enb Address            What
1       breakpoint     keep n   0x00000000000006e8 in main at hello.c:4

可以看到字段「Enb」已經變為 n,表示這個斷點已經被禁用了。

7. 刪除斷點

在 gdb 下刪除斷點使用命令 delete 斷點 Num 或簡寫 d Num,比如刪除剛才的 Num = 1 的斷點:

(gdb) d 1
(gdb) i b
No breakpoints or watchpoints.

刪除后再次查看斷點,提示當前沒有斷點,說明刪除成功啦,下面來運行程序試試。

8. 運行程序

在 gdb 下使用命令 run 或簡寫 r 來運行當前載入的程序:

(gdb) r
Starting program: /home/orange/Desktop/gdb/hello 
a = 1
b = 2
1 + 2 = 3
[Inferior 1 (process 10415) exited normally]

我這次沒有添加斷點,程序全速運行,然后正常退出了。

9. 單步執行下一步

在 gdb 下使用命令 next 或簡寫 n 來單步執行下一步,假設我們在 main 打了斷點:

(gdb) b main
Breakpoint 1 at 0x6e8: file hello.c, line 4.
(gdb) r
Starting program: /home/orange/Desktop/gdb/hello 

Breakpoint 1, main () at hello.c:4
4       int a = 1;
(gdb) n
5       printf("a = %d\n", a);

可以看到當前停在 int a = 1; 這一行,按 n 執行了下一句代碼 printf("a = %d\n", a);

10. 跳入,跳出函數

在 gdb 下使用命令 step 或簡寫 s 來跳入一個函數,使用 finish 來跳出一個函數,我們在第 14 行 int c = add(a, b); 添加一個斷點:

(gdb) b 14
Breakpoint 1 at 0x6f6: file hello.c, line 14.
(gdb) r
Starting program: /home/orange/Desktop/gdb/hello 
a = 1
b = 2

Breakpoint 1, main () at hello.c:14
14      int c = add(a, b);
(gdb) s
add (x=1, y=2) at hello.c:4
4       return x + y;
(gdb) finish
Run till exit from #0  add (x=1, y=2) at hello.c:4
0x0000555555554705 in main () at hello.c:14
14      int c = add(a, b);
Value returned is $1 = 3
(gdb) n
15      printf("%d + %d = %d\n", a, b, c);

這個過程是這樣的:

  1. 在 14 行 int c = add(a, b); 添加斷點
  2. 程序運行并停到 int c = add(a, b); 這一行
  3. s 跳入 add 函數
  4. finish 跳出 add 函數,并輸出一些函數返回的信息

11. 打印變量

在 gdb 中使用命令 print var 或簡寫 p var 來打印一個變量或者函數的返回值,我們在第 10 行 int b = 2; 添加一個斷點:

(gdb) b 10
Breakpoint 1 at 0x6c3: file hello.c, line 10.
(gdb) r
Starting program: /home/orange/Desktop/gdb/hello 

Breakpoint 1, main () at hello.c:10
10      int b = 2;
(gdb) p a
$1 = 1

我們打印出變量 a 的值為 1,在調試中比較頻繁的操作是「監視變量」,在 gdb 中如何做呢?

12. 監控變量

在 gdb 中使用命令 watch var 來監控一個變量,使用 info watch 來查看監控的變量,我們這里來監控變量 c

(gdb) b 14
Breakpoint 1 at 0x6f6: file hello.c, line 14.
(gdb) r
Starting program: /home/orange/Desktop/gdb/hello 
a = 1
b = 2

Breakpoint 1, main () at hello.c:14
14      int c = add(a, b);
(gdb) watch c
Hardware watchpoint 2: c
(gdb) info watch
Num     Type           Disp Enb Address            What
2       hw watchpoint  keep y                      c

注意:程序必須要先運行才能監控。

13. 查看變量類型

在 gdb 下使用命令 whatis 查看一個變量的類型:

(gdb) b 10
Breakpoint 1 at 0x6c3: file hello.c, line 10.
(gdb) r
Starting program: /home/orange/Desktop/gdb/hello 

Breakpoint 1, main () at hello.c:10
10      int b = 2;
(gdb) whatis b
type = int

這里變量 bint 類型。

14. 在 gdb 中進入 shell

在 gdb 下使用命令 shell 啟動 shell :

(gdb) shell
orange@ubuntu:~/Desktop/gdb$ exit
exit
(gdb) 

使用 exit 會再次退回到 gdb 中。

15. 在 gdb 中實現可視化調試

誰說 gdb 只能在命令行調試呢?gdb 也支持「圖形界面」,不過這里的圖形界面都是用字符顯示的,當然不如 VS 那種好看,不過使用可視化相比直接看命令行更加直觀了。

在 gdb 下使用 wi 啟動可視化調試:

(gdb) wi

效果如下圖所示,上面是代碼效果,下面是命令界面:

gdb 圖形界面

有了圖形界面,就再對照著圖形界面將前面的命令再練習練習,看看自己手敲的命令背后到底做了些什么,加深下影響。

結語

這篇博客主要介紹了 gdb 基本的調試技術,一篇文章不可能面面俱到,還有很多命令沒有介紹,如果你有興趣的話,這里還有一份比較好的 gdb 快速學習指南 送給愛學習的你,不用客氣,叫我雷鋒就好。

最后,感謝你的閱讀,我們下次再見 :)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,362評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,013評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,346評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,421評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,146評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,534評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,585評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,767評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,318評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,074評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,258評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,828評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,486評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,916評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,156評論 1 290
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,993評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,234評論 2 375

推薦閱讀更多精彩內容

  • 程序調試的基本思想是“分析現象->假設錯誤原因->產生新的現象去驗證假設”這樣一個循環過程,根據現象如何假設錯誤原...
    Manfred_Zone閱讀 16,561評論 0 26
  • 通常軟件開發中,很難有工程師能夠一次性寫出正確無誤的程序代碼。而程序調試以及測試步驟將會在整個軟件開發過程中占據相...
    團團BB閱讀 1,159評論 0 5
  • 概述 GDB是一個由GNU開源組織發布的、UNIX/Linux操作系統下的、基于命令行的、功能強大的程序調試工具。...
    咕咕鷄閱讀 20,889評論 0 8
  • 作者: liigo原文鏈接: http://blog.csdn.net/liigo/archive/2006/01...
    wuqingyi閱讀 1,826評論 0 4
  • 選擇回家實習是我對人生的妥協,也是一個讓我既高興又有點憂傷的決定。 和大學里的好朋友們分開,不能幾...
    小辣狗閱讀 217評論 0 0