從 0 開(kāi)始學(xué)習(xí) Linux 系列之「08.15 個(gè) gdb 調(diào)試基礎(chǔ)命令」

代碼鍵盤

版權(quán)聲明:本文為 cdeveloper 原創(chuàng)文章焙矛,可以隨意轉(zhuǎn)載放闺,但必須在明確位置注明出處凉夯!

gdb 簡(jiǎn)介

gdbUNIXUNIX-like 下的調(diào)試工具鱼辙,在 Linux 下一般都直接在命令行中用 gdb 來(lái)調(diào)試程序峰档,相比 Windows 上的集成開(kāi)發(fā)環(huán)境 IDE 提供的圖形界面調(diào)試间校,一開(kāi)始使用 gdb 調(diào)試可能會(huì)讓你感到生無(wú)可戀肛跌,但是只要熟悉了 gdb 調(diào)試的常用命令刊棕,調(diào)試出程序會(huì)很有成就感个曙,一方面因?yàn)檫@些命令就類似圖形界面調(diào)試按鈕背后的邏輯锈嫩,另一方面用命令行來(lái)調(diào)試程序,逼格瞬間就上了一個(gè)檔次垦搬,這次就跟大家分享 gdb 調(diào)試的基本技術(shù)和 15 個(gè)常用調(diào)試命令祠挫。

在此之前,我們先來(lái)回顧下在 Windows 上使用 IDE 的圖形界面調(diào)試過(guò)程悼沿。

IDE 的調(diào)試步驟

在 Windows 的 IDE 下調(diào)試程序等舔,例如使用 VS,一般都有下面這幾個(gè)操作:

  1. Debug 模式編譯并啟動(dòng)程序
  2. 程序運(yùn)行出錯(cuò)糟趾,打斷點(diǎn)分析出錯(cuò)的地方
  3. 單步運(yùn)行程序慌植,包括:step over 單步執(zhí)行甚牲;step into 跳入函數(shù);step return 跳出函數(shù)
  4. 還有全速運(yùn)行蝶柿,打印或者監(jiān)視變量丈钙,凍結(jié)或解凍線程等調(diào)試技術(shù)

在 IDE 中上面的這些步驟一般都有固定的按鈕提供給我們使用,非常的簡(jiǎn)單方便交汤,我們只要多練習(xí)練習(xí)雏赦,在圖形界面調(diào)試程序不會(huì)很難,但是在 Linux 下用命令來(lái)調(diào)試程序就比圖形界面要復(fù)雜很多了芙扎。

其實(shí)星岗,你知道真正的調(diào)試高手是什么樣的嗎?就是 Ta 對(duì)計(jì)算機(jī)原理和程序本身的邏輯理解非常深刻戒洼,在 Ta 的腦海中已經(jīng)可以模擬程序的運(yùn)行過(guò)程俏橘,并且知道可能出錯(cuò)的地方,這樣連斷點(diǎn)都不用打了圈浇,而且 Bug 的命中率也不低寥掐,或許這就是真正的大佬吧 :)

我們回到正題,來(lái)介紹在 Linux 使用命令行的調(diào)試過(guò)程磷蜀。

gdb 的調(diào)試步驟

在 Linux 下既然是使用命令行來(lái)調(diào)試召耘,顧名思義就是手敲命令來(lái)調(diào)試程序,大體分為下面幾個(gè)步驟褐隆,后面會(huì)詳細(xì)介紹:

  1. 編譯可以調(diào)試的程序
  2. 運(yùn)行程序污它,打斷點(diǎn)
  3. 單步調(diào)試,監(jiān)控變量
  4. 可視化調(diào)試
  5. 其他調(diào)試技術(shù)

可以看出妓灌,與 IDE 調(diào)試過(guò)程差不多,但是實(shí)際操作起來(lái)可是千差萬(wàn)別蜜宪,可不是點(diǎn)按鈕了虫埂,而是自己敲調(diào)試程序的命令,就相當(dāng)于你正在學(xué)習(xí)那些調(diào)試按鈕背后的原理圃验,把這種方法學(xué)會(huì)掉伏,不用學(xué)就會(huì)使用 IDE 來(lái)調(diào)試程序,不管你信不信澳窑,我反正是信了 :)

下面開(kāi)始正式的調(diào)試技術(shù)介紹斧散。

15 個(gè) gdb 調(diào)試基礎(chǔ)命令

下面來(lái)正式介紹 gdb 常用的調(diào)試技術(shù),都是調(diào)試命令摊聋,只看不做比較乏味鸡捐,還是建議你跟我一起動(dòng)手調(diào)試下面的程序,這樣才能真正的學(xué)會(huì)麻裁,這是本次要調(diào)試的 hello.c 程序箍镜,非常簡(jiǎn)單:

#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. 編譯可以調(diào)試的程序

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

gcc hello.c -o hello

gdb 會(huì)提示該可執(zhí)行文件沒(méi)有調(diào)試符號(hào)源祈,不能調(diào)試:

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

如果需要讓程序可以調(diào)試,就必須在編譯的時(shí)候加上 [-g] 參數(shù)

gcc -g hello.c -o hello

2. 載入要調(diào)試的程序

我們?cè)诿钚邢滦枰謩?dòng)載入待調(diào)試的程序色迂,有 2 種方法:

方法一 - gdb 可執(zhí)行文件

使用如下的命令來(lái)載入可執(zhí)行文件 hello 到 gdb 中:

gdb hello

載入成功香缺,gdb 會(huì)打印一段提示信息,并且命令行前綴變?yōu)?(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 環(huán)境中使用 file 命令图张,我們需要先進(jìn)入 gdb 環(huán)境下:

gdb

使用 file hello 載入待調(diào)試程序:

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

3. 查看調(diào)試程序

在 gdb 下查看調(diào)試程序使用命令 list 或簡(jiǎn)寫 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. 添加斷點(diǎn)

在 gdb 下添加斷點(diǎn)使用命令 break 或簡(jiǎn)寫 b诈悍,有下面幾個(gè)常見(jiàn)用法(這里統(tǒng)一用 b):

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

比如我們以第一個(gè)為例祸轮,在 main 函數(shù)上添加斷點(diǎn):

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

打印的信息告訴我們?cè)?hello.c 文件的第 4 行,地址 0x6e8 處添加了一個(gè)斷點(diǎn)写隶,那如何查看斷點(diǎn)呢倔撞?

5. 查看斷點(diǎn)

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

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

可以看到打印出剛才添加的 main 函數(shù)的斷點(diǎn)信息:編號(hào)慕趴,類型痪蝇,顯示狀態(tài),是否啟用冕房,地址躏啰,其他信息,那又如何刪除這個(gè)斷點(diǎn)呢耙册?

6. 禁用斷點(diǎn)

在 gdb 下禁用斷點(diǎn)使用命令 disable Num给僵,比如禁用剛才打的斷點(diǎn):

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

可以看到字段「Enb」已經(jīng)變?yōu)?n,表示這個(gè)斷點(diǎn)已經(jīng)被禁用了详拙。

7. 刪除斷點(diǎn)

在 gdb 下刪除斷點(diǎn)使用命令 delete 斷點(diǎn) Num 或簡(jiǎn)寫 d Num帝际,比如刪除剛才的 Num = 1 的斷點(diǎn):

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

刪除后再次查看斷點(diǎn),提示當(dāng)前沒(méi)有斷點(diǎn)饶辙,說(shuō)明刪除成功啦蹲诀,下面來(lái)運(yùn)行程序試試。

8. 運(yùn)行程序

在 gdb 下使用命令 run 或簡(jiǎn)寫 r 來(lái)運(yùn)行當(dāng)前載入的程序:

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

我這次沒(méi)有添加斷點(diǎn)弃揽,程序全速運(yùn)行脯爪,然后正常退出了。

9. 單步執(zhí)行下一步

在 gdb 下使用命令 next 或簡(jiǎn)寫 n 來(lái)單步執(zhí)行下一步矿微,假設(shè)我們?cè)?main 打了斷點(diǎn):

(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);

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

10. 跳入,跳出函數(shù)

在 gdb 下使用命令 step 或簡(jiǎn)寫 s 來(lái)跳入一個(gè)函數(shù)涌矢,使用 finish 來(lái)跳出一個(gè)函數(shù)掖举,我們?cè)诘?14 行 int c = add(a, b); 添加一個(gè)斷點(diǎn):

(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);

這個(gè)過(guò)程是這樣的:

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

11. 打印變量

在 gdb 中使用命令 print var 或簡(jiǎn)寫 p var 來(lái)打印一個(gè)變量或者函數(shù)的返回值娜庇,我們?cè)诘?10 行 int b = 2; 添加一個(gè)斷點(diǎn):

(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拇泛,在調(diào)試中比較頻繁的操作是「監(jiān)視變量」滨巴,在 gdb 中如何做呢?

12. 監(jiān)控變量

在 gdb 中使用命令 watch var 來(lái)監(jiān)控一個(gè)變量俺叭,使用 info watch 來(lái)查看監(jiān)控的變量恭取,我們這里來(lái)監(jiān)控變量 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

注意:程序必須要先運(yùn)行才能監(jiān)控

13. 查看變量類型

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

(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 中進(jìn)入 shell

在 gdb 下使用命令 shell 啟動(dòng) shell :

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

使用 exit 會(huì)再次退回到 gdb 中蜈垮。

15. 在 gdb 中實(shí)現(xiàn)可視化調(diào)試

誰(shuí)說(shuō) gdb 只能在命令行調(diào)試呢?gdb 也支持「圖形界面」裕照,不過(guò)這里的圖形界面都是用字符顯示的攒发,當(dāng)然不如 VS 那種好看,不過(guò)使用可視化相比直接看命令行更加直觀了晋南。

在 gdb 下使用 wi 啟動(dòng)可視化調(diào)試:

(gdb) wi

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

gdb 圖形界面

有了圖形界面负间,就再對(duì)照著圖形界面將前面的命令再練習(xí)練習(xí)偶妖,看看自己手敲的命令背后到底做了些什么,加深下影響政溃。

結(jié)語(yǔ)

這篇博客主要介紹了 gdb 基本的調(diào)試技術(shù)趾访,一篇文章不可能面面俱到,還有很多命令沒(méi)有介紹董虱,如果你有興趣的話扼鞋,這里還有一份比較好的 gdb 快速學(xué)習(xí)指南 送給愛(ài)學(xué)習(xí)的你,不用客氣愤诱,叫我雷鋒就好云头。

最后,感謝你的閱讀淫半,我們下次再見(jiàn) :)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末溃槐,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子撮慨,更是在濱河造成了極大的恐慌竿痰,老刑警劉巖脆粥,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件砌溺,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡变隔,警方通過(guò)查閱死者的電腦和手機(jī)规伐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)匣缘,“玉大人猖闪,你說(shuō)我怎么就攤上這事鲜棠。” “怎么了培慌?”我有些...
    開(kāi)封第一講書人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵豁陆,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我吵护,道長(zhǎng)盒音,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任馅而,我火速辦了婚禮祥诽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘瓮恭。我一直安慰自己雄坪,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布屯蹦。 她就那樣靜靜地躺著维哈,像睡著了一般。 火紅的嫁衣襯著肌膚如雪颇玷。 梳的紋絲不亂的頭發(fā)上笨农,一...
    開(kāi)封第一講書人閱讀 52,268評(píng)論 1 309
  • 那天,我揣著相機(jī)與錄音帖渠,去河邊找鬼谒亦。 笑死,一個(gè)胖子當(dāng)著我的面吹牛空郊,可吹牛的內(nèi)容都是我干的份招。 我是一名探鬼主播,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼狞甚,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼锁摔!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起哼审,我...
    開(kāi)封第一講書人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤谐腰,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后涩盾,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體十气,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年春霍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了砸西。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖芹枷,靈堂內(nèi)的尸體忽然破棺而出衅疙,到底是詐尸還是另有隱情,我是刑警寧澤鸳慈,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布饱溢,位于F島的核電站,受9級(jí)特大地震影響走芋,放射性物質(zhì)發(fā)生泄漏理朋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一绿聘、第九天 我趴在偏房一處隱蔽的房頂上張望嗽上。 院中可真熱鬧,春花似錦熄攘、人聲如沸兽愤。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)浅萧。三九已至,卻和暖如春哲思,著一層夾襖步出監(jiān)牢的瞬間洼畅,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工棚赔, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留帝簇,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓靠益,卻偏偏與公主長(zhǎng)得像丧肴,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子胧后,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 程序調(diào)試的基本思想是“分析現(xiàn)象->假設(shè)錯(cuò)誤原因->產(chǎn)生新的現(xiàn)象去驗(yàn)證假設(shè)”這樣一個(gè)循環(huán)過(guò)程芋浮,根據(jù)現(xiàn)象如何假設(shè)錯(cuò)誤原...
    Manfred_Zone閱讀 16,551評(píng)論 0 26
  • 通常軟件開(kāi)發(fā)中,很難有工程師能夠一次性寫出正確無(wú)誤的程序代碼壳快。而程序調(diào)試以及測(cè)試步驟將會(huì)在整個(gè)軟件開(kāi)發(fā)過(guò)程中占據(jù)相...
    團(tuán)團(tuán)BB閱讀 1,144評(píng)論 0 5
  • 概述 GDB是一個(gè)由GNU開(kāi)源組織發(fā)布的纸巷、UNIX/Linux操作系統(tǒng)下的、基于命令行的眶痰、功能強(qiáng)大的程序調(diào)試工具瘤旨。...
    咕咕鷄閱讀 20,820評(píng)論 0 8
  • 作者: liigo原文鏈接: http://blog.csdn.net/liigo/archive/2006/01...
    wuqingyi閱讀 1,819評(píng)論 0 4
  • 選擇回家實(shí)習(xí)是我對(duì)人生的妥協(xié),也是一個(gè)讓我既高興又有點(diǎn)憂傷的決定凛驮。 和大學(xué)里的好朋友們分開(kāi)裆站,不能幾...
    小辣狗閱讀 214評(píng)論 0 0