1. 程式人生 > >一起talk GDB吧(第四回:GDB呼叫棧除錯)

一起talk GDB吧(第四回:GDB呼叫棧除錯)

各位看官們,大家好,上一回中我們說的是GDB的斷點除錯功能,並且說了如何使用GDB進行斷點除錯。

這一回中,我們繼續介紹GDB的除錯功能:呼叫棧除錯。當然了,我們也會介紹如何使用GDB進行呼叫棧

除錯。閒話休提,言歸正轉。讓我們一起talk GDB吧!

看官們,我們先說一下什麼是呼叫棧。大家都知道,程式中經常使用各種各樣的函式,有的是語言提供的

庫函式,比如printf(),有的是我們自己定義的函式。各種函式之間會相互呼叫,有時候函式多了,我們很難

找出函式之間的呼叫關係,函式棧就是用來顯示函式之間呼叫關係的。這們說大家可能覺得有點抽象,不

容易理解,我們舉個例子來說明,例如程式中有以下程式碼。

void funA()

{

        printf("A function is called \n");

}

void funB()

{

        printf("B function is called \n");

        funA();

}

void funC()

{

        printf("C function is called \n");

        funB();

}

void funD()

{

        printf("D function is called \n");

        funC();

}


int main()

{


        printf("show the call stack of functions \n");

        funD();

        return 0;

}

這些函式的功能比較簡單,只有一個輸出語句,顯示函式被呼叫。大家可以看到,程式中自己定義了四個

函式,它們分別是:funA,funB,funC,funD。(以後不用全名,簡稱ABCD)各個函式之間的呼叫關

係為:D->C->B->A。編譯並且執行該函式時,可以得到以下結果:

show the call stack of functions

D function is called

C function is called

B function is called

A function is called

從程式的執行結果中也可以看到,各個函式之間的呼叫關係。如果把D比作棧底,那麼每次呼叫函式就是

在進行入棧操作,D呼叫C就是把C入棧,依此類推,直到最後一個函式A。這種函式呼叫關係符合棧”先進

後出“的特點,因此我們形象地叫它為呼叫棧。此外,從程式的執行結果中也可以看出來ABCD函式的呼叫

關係從棧頂到棧底依次排列。

看官們在實際的程式中,函式的功能不會這麼簡單,函式的呼叫關係也不會這麼簡單。如果我們想了解函

數之間的呼叫關係,怎麼辦?不用擔心,GDB提供了顯示函式呼叫棧的功能。和單步呼叫一樣,呼叫棧調

試也有專門的命令:backtrace(縮寫為bt)。使用該命令,可以通過GDB打印出函式呼叫棧,我們還是舉個

例子來說明,為了方便,還使用上面提到過的程式碼。

1.首先編譯程式,並且加入除錯資訊:gcc -g file.c -o file

2.啟動GDB進行除錯:gdb file

3.在函式D處打一個斷點:b funD。執行結果如下:Breakpoint 3, funA () at file.c:5

4.執行程式,遇到斷點停止執行:run

5.檢視函式呼叫棧:bt.這時顯示的結果如下:

(gdb) bt                     //檢視函式呼叫棧

#0  funA () at file.c:5

#1  0x08048448 in funB () at file.c:10

#2  0x08048461 in funC () at file.c:15

#3  0x0804847a in funD () at file.c:20

#4  0x08048496 in main () at file.c:27

通過執行的結果,我們可以看到,函式A位於棧底,MAIN函式位於棧頂。而且在每行最前面有編號。當然

了,編號從0開始,有點類似陣列中元素的位置。

看官們,關於GDB的內容,今天咱們就說到這裡。欲知後事如何,且聽下回分解!