linux下GDB使用簡單教程

1、什麼是GDB?

GDB 是 GNU 開源組織發佈的一個強大的 UNIX 下調試程序工具。大家知道命令行的強大就是在於,其可以形成執行序列,形成腳本。UNIX 下的軟件全是命令行的,這給程序開發提供了極大的便利,命令行軟件的優勢在於,他們可以非常容易的集成在一起,使用幾個簡單的已有工具的命令,就可以做出一個非常強大的功能。

2、GDB主要功能是什麼?

(1)啓動你的程序,可以按照你自定義的要求隨心所欲的運行程序。
(2)可以讓調試程序在你所指定的位置的斷點處停止。
(3)當程序停止時,可以檢查此時你的程序中所發生的事情。
(4)動態的改變你程序的執行環境。

3、一個簡單代碼示例

源程序:test_gdb.c
1 #include <stdio.h>
2
3 int func(int n)
4 {
5         int sum=0,i;
6         for(i=0; i<=n; i++)
7         {
8             sum+=i;
9         }
10         return sum;
11 }
12
13
14 int main(void)
15 {
16         int i;
17         long result = 0;
18         for(i=1; i<=100; i++)
19         {
20             result += i;
21         }
22
23        printf("result[1-100] = %d \n", result);
24        printf("result[1-250] = %d \n", func(250));
25        return 0;
26 }

(1)編譯代碼,得到可執行文件

gcc -g test_gdb.c -o test_gdb

(2)啓動gdb 調試

gdb test_gdb

(3)查看代碼的命令

list

(4)設置斷點

break  斷點所處行號/具體函數名

如:break 15 ---在第十五行設置斷點        break func  ---在func()處設置斷點

(5)查看設置的斷點信息

info  break

(6)運行調試

run

(7)繼續執行下一行

next ---單條語句執行

(8)程序跳過斷點繼續執行

continue

(9)查看函數棧使用情況

bt

(10)退出gdb調試

quit

4、進一步認識GDB

4.1、關於 -g命令參數

一般來說 GDB 主要調試的是 C/C++程序。要調試 C/C++程序,首先在編譯時,我們必須要把調試信息加到可執行文件中。使用編譯器(cc/gcc/g++)的-g 參數可以做到這一點,如:
$ cc –g hello.c –o hello
$ g++ -g hello.cpp –o hello
如果沒有加入-g,你將看不見程序的函數名,變量名,所代替的全是運行的內存地址。當你用-g 把調試信息加入之後,併成功編譯目標代碼以後,就可以在調試時看到具體的調試信息。

4.2、啓動GDB的幾種方式

(1)gdb programer

programer爲編譯生成的可執行文件,且位於當前可執行目錄;此方式較爲常用。

(2) gdb <program> core
用 gdb 同時調試一個運行程序和 core 文件,core 是程序非法執行後 core dump 後產生的文件。

(3) gdb <program> <PID>
如果你的程序是一個服務程序,那麼你可以指定這個服務程序運行時的進程 ID。gdb會自動 attach 上去,並調試它。program 應該在 PATH 環境變量中搜索到。

4.3、GDB啓動開關

GDB 啓動時,可以加上一些 GDB 的啓動開關,詳細的開關可以用 gdb –help 來查看。

gdb 的命令很多,gdb 把之分成很多種類。help 命令只是列出了 gdb 的命令種類,如果要看種類中的命令,使用 help <class>命令,如:help breakpoints,查看設置斷點的所有命令。也可以直接 help <command>來查看命令的幫助。

4.4、GDB命令自動補全功能

gdb 中,輸入命令時,可以不用打全命令,只用打命令的前幾個字符就可以了,當然,命令的前幾個字符要標誌着一個唯一的命令,在 linux 下,可以敲擊兩次 TAB 鍵來補齊命令的全稱,如果有重複的,gdb 會把其列出來。

4.5、調試已運行程序的兩種方式

方式1:在 UNIX 下用 ps 查看正在運行的程序的 PID(進程 ID),然後用 gdb<program> PID 格式掛接正在運行的程序。
方式2:先用 gdb<program>關聯上源代碼,並進行 gdb,在 gdb 中用 attach 命令來掛接進程的PID,並用 detach 來取消掛接的程序。

4.6、藉助GDB暫停程序運行的幾種方式

斷點(breakpoint)、觀察點(watchpoint)、 捕捉點(catchpoint)、信號(signals)、線程停止(thread stops)。

(1)斷點

break<function>  在進入指定函數時停住。C++中可以使用 class::function 或 function(type,type)格式來指定函數名。

break<linenum>  在指定行號停住。

break  +offset  當前行號的 前面offset行停止。

break  -offset  當前行號的後面的offset行停止。

break filename:linenum    在源文件 filename 的 linenum 行處停住。
break filename:function     在源文件 filename 的 function 函數的入口處停住。

break *address   在程序運行的內存地址處停住。   

break    break 命令沒有參數時,表示在下一條指令處停住。

查看斷點時,可使用命令 info 命令,如下所示:(注:n 表示斷點號)
info breakpoints[n]
info break[n]

(2)捕捉點

我們可以設置捕捉點來捕捉程序運行時的一些事件。如:載入共享庫(動態鏈接庫)或是 C++的異常,設置捕捉點的格式爲:
catch <event>
當 event 發生時,停住程序。Event 可以是下面的內容:
1、throw 一個 C++拋出的異常(throw 爲關鍵字),
2、catch 一個 C++捕捉到的異常(catch 爲關鍵字),
3、exec 調用系統調用 exec 時( exec 爲關鍵字,目前此功能只在 HP-UX 下有用 )
4、fork  調用系統調用 fork 時 。( fork 爲關鍵字,目前此功能只在 HP-UX 下有用 )
5、vfork  調用系統調用 vfork 時 。( vfork 爲關鍵字,目前此功能只在 HP-UX 下
有用)
6、load  或  load <libname> 載入共享庫(動態鏈接庫)時。(load 爲關鍵字,
目前此功能只在 HP-UX 下有用)
7、 unload 或  unload <libname> 卸載共享庫(動態鏈接庫)時。(unload 爲關
鍵字,目前此功能只在 HP-UX 下有用)
tcatch<event>
只設置一次捕捉,當程序停住後,斷點被自動刪除。

4.7、維護停止點
上面說了如何設置程序的停止點,GDB 中的停止點也就是上述的三類。在 GDB 中,如果你覺得已定義好的停止點沒有用了,你可以使用 delete、clear、disable、enable 這幾個命令來進程維護。
clear
清楚所有已定義的停止點。

4.8、 恢復程序運行和單步調試

(1)當程序被停住後,你可以用 continue 命令恢復程序的運行直到程序結束,或下一個斷點的到來。也可以使用 step 或 next 命令單步跟蹤程序。

continue [ignore-count]
c [ignore-count]
fg [ignore-count]
恢復程序運行,直到程序結束,或是下一個斷點到來。Ignore-count 表示忽略其後的斷點次數。continue,c,fg 三個命令都是一樣的意思。

(2)step<count>  和 next<count>
單步跟蹤,如果有函數調用,他會進入該函數。進入函數的前提是,此函數被編譯有 debug 信息。像 VC 等工具中的 step in後面可以加 count,也可以不加,不加表示一條一條地執行,加表示執行後面的 count 條指令,然後再停住 。
next<count>     同樣單步跟蹤,如果有函數調用,他不會進入函數。

4.9、多線程中使用GDB(難點)

如果你的程序時多線程的話,你可以定義你的斷點是否在所有的線程上,或是在某個特定的線程。GDB 很容易幫你完成這一工作。
break<linespec>thread<threadno>
break<linespec>thread<threadno>if…
註明:linespec 指定了斷點是這在源程序的行號。Threadno 指定了線程 ID,注意,這個ID 是 GDB 分配的,你可以通過“info threads”命令來查看正在運行程序中的線程信息。如果你不指定 thread<threadno>則表示你的斷點設在所有的線程上面。還可
以爲某個線程指定斷點條件。
當程序被 GDB 停住時,所有的運行線程都會被停住。這方便你查看運行程序的總體情況。而在你恢復程序運行時,所有的線程也會被恢復運行。哪怕是主進程在被單步調試時。

4.10 查看棧信息

當程序調用了一個函數,函數的地址,函數的參數,函數內的局部變量都會被壓入“棧(stack)”中。我,我們可以使用 GDB 命令來查看當前的棧中的信息。下面是一些查看函數調用棧信息的 GDB 命令:
(1)backtrace
(2)bt

如果你要查看某一層的信息,你需要切換當前的棧,一般來說,程序停止時,最頂層的棧就是當前的棧,如果你要查看棧下面層的詳細信息,首先要做的是切換當前棧。
frame<n>
f<n>
n 是一個從 0 開始的整數,是棧中的層編號。比如:frame 0,表示棧頂,frame 1,表示棧的第二層。

up<n>
表示向棧的上面移動 n 層,可以不打 n,表示向上移動一層。
down<n>
表示向棧的下面移動 n 層,可以不打 n,表示向下移動一層。

info frame
info f
這個命令會打印出更爲詳細的當前棧層的信息,只不過,大多數都是運行時的內存地址 。比如函數的地址,調用函數的地址,被調用函數的地址,目前的函數是由什麼樣的程序語言寫成的、函數參數地址及值,局部變量的地址等等。

4.11 GDB中查看源碼

GDB 可以打印出所調試程序的源代碼,當然,在程序編譯時一定要加上-g 參數,把源程序信息編譯到執行文件中。不然就看不到源程序了。當程序停下來以後,GDB 會報告程序停在了那個文件的第幾行上,你可以用 list 命令來打印程序的源代碼。還是來看一看查看源代碼的 GDB 命令吧。
(1)list<linenum>
顯示程序第 linenum 行周圍的源程序。
(2)list<function>
顯示函數名爲 function 的函數的源程序。
(3)list
顯示當前行後面的源程序

(4)list -
顯示當前行前面的源程序。

(5)show listsize
查看當前 listsize 的設置。

(6)調整 listsize的默認值

set listsize <count>

4.12、查看運行時的數據

在你調試程序時,當程序被停住時,可以使用 print 命令(簡寫命令爲 p),或是同義命令inspect 來查看當前程序的運行數據。print 命令的格式是:
print<expr>
print/<f><expr>
<expr>是表達式,是你所調試的程序的語言的表達式(GDB 可以調試多種編程語言),<f>是輸出的格式,比如,如果要把表達式按 16 進制的格式輸出,那麼就是/x。

4.13、環境變量

你可以在 GDB 的調試環境中定義自己的變量,用來保存一些調試程序中的運行數據。要定義一個 GDB 的變量很簡單。使用 GDB 的 set 命令。GDB 的環境變量和 UNIX 一樣,也是以$起頭。如:set $foo = *object_ptr
使用環境變量時,GDB 會在你第一次使用時創建這個變量,而在以後的使用中,則直接對其賦值。環境變量沒有類型,你可以給環境變量定義任一的類型。包括結構體和數組。
show convenience
該命令查看當前所設置的所有的環境變量。

4.14、CDB中查看寄存器的值

要查看寄存器的值,很簡單,可以使用如下命令:
info registers
查看寄存器的情況(除了浮點寄存器)。
info all-registers
查看所有寄存器的情況(包括浮點寄存器)。
info registers<regname…>
查看所有指定的寄存器的情況。
寄存器中放置了程序運行時的數據,比如程序當前運行的指令地址(ip),程序的當前堆棧地址(sp)等等。你同樣可以使用 print 命令來訪問寄存器的情況,只需要在寄存器名字前加一個$符號就可以來看。如:p $eip。

4.15、強制函數返回

如果你的調試斷點在某個函數中,並還有語句沒有執行完。你可以使用 return 命令強制函數忽略還沒有執行的語句並返回。
return
return <expression>
使用 return 命令取消當前函數的執行,並立即返回,如果指定了<expression>,那麼該表達式的值會作爲函數的返回值。

4.16、強制調用函數

call<expr>
表達式中可以是函數,以此達到強制調用函數的目的。並顯示函數的返回值,如果函數返回值是 void,那麼就不顯示。
另一個相似的命令也可以完成這一功能——print,print 後面可以跟表達式,所以也可以用他來調用函數,print 和 call 不同的是,如果函數返回 void,call 則不顯示,而 print 顯示函數返回值,並把該值存入歷史數據中。

5、GDB支持的編程語言

GDB 支持下列語言:C,C++,Fortran,PASCAL,Java,Chill,assembly 和 Modula-2。一般說來,GDB 會根據你所調用的程序來確定當時的調試語言,比如:發現文件後綴名爲“.c”的,GDB 會認爲是 C 程序。文件後綴名爲“.c,.cc,.cp,.cpp,.cxx,.c++”的 ,GDB 會認爲是 C++程序。而後綴是“.f,.F”的,GDB 會認爲是 Fortran 程序,還有,後綴
名如果是“.s,.S”,GDB 會認爲是彙編語言。
也就是說,GDB 會根據你所調試的程序的語言,來設置自己的語言環境,並讓 GDB 的命令跟着語言環境的改變而改變。比如一些 GDB 命令需要用到表達式或變量時,這些表達式或變量的語法,完全是根據當前的語言環境而改變。如果你當前的程序是由幾種不同語言一同編譯成的,在調試過程中,GDB 也能根據不同的語言自動的切換語言環境。這種跟着語言環境而改變的功
能,真是體貼開發人員的一種設計。
下面是幾個相關於 GDB 語言環境的命令:
(1)show language

(2)info frame
查看當前函數的程序語言。
(3)info source
查看當前文件的程序語言。

如果 GDB 沒有檢測出當前的程序語言,那麼我們也可以手動設置當前的程序語言,使用set language 命令即可做到。

6、後記

GDB本身功能比較強大,本文只是簡明扼要的描述了一些基本的或常用的功能及參數,其他功能需要在實際使用過程中不斷學習。

發佈了29 篇原創文章 · 獲贊 52 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章