【軟體開發底層知識修煉】十七 快速學習GDB除錯四 使用GDB進行函式呼叫棧的檢視
- 上一篇文章學習瞭如何使用GDB資料斷點進行記憶體監測:【軟體開發底層知識修煉】十五 快速學習GDB除錯三 使用GDB的資料斷點監測變數是否改變
- 本篇文章繼續上一篇文章的學習:如何使用GDB進行函式呼叫棧的檢視
文章目錄
1 backtrace和frame
一般來說,檢視函式呼叫棧,主要是為了研究函式的呼叫過程。
一般使用下面的命令進行檢視:
backtrace
- 檢視函式的呼叫順序(函式呼叫棧的資訊)
frame N
- 切換到棧編號為N的上下文中(具體棧編號是什麼在下面的實際案例中會有)
info frame
- 檢視當前函式呼叫棧幀的資訊
至於什麼是棧幀資訊,大概就是下圖的樣子,這裡不再多介紹,後面還會有文章學習函式棧幀的概念,或者推薦大家去閱讀程式設計師的自我修養。
- 上面有一個info frame命令,我們在前幾篇文章已經學習過info的幾個命令。下面再介紹幾個下圖中的info命令:
2 使用GDB進行函式呼叫棧的檢視的實際程式碼案例
我們還是給出以下程式碼,作為這次除錯的程式碼:
frame.c
#include <stdio.h>
int sum(int n)
{
int ret = 0;
if( n > 0 )
{
ret = n + sum(n-1);
}
return ret;
}
int main()
{
int s = 0;
s = sum(10);
printf("sum = %d\n", s);
return 0;
}
上述程式碼很簡單,sum函式是一個遞迴的求解過程,最終求得1+2+3+…+n
- 開始進行除錯:
首先將程式編譯,並開啟gdb除錯,這在前幾篇文章已經做過很多次,大概如下圖所示的步驟:
然後我們再sum函式處打一個斷點,並給出條件,當n==0的時候斷點成立
break sum if n==0
檢視斷點是否打上:info breakpoints
執行程式:continue
執行上述幾個步驟後,程式執行到sum函式,並在sum函式遞迴呼叫到n==0的時候停止:
此時,函式呼叫被中斷,我們現在來使用backtrace命令來檢視之前sum函式的呼叫棧的順序(左側的#0 ,#1…就是棧的編號):
此時程式執行到n==0,本應該繼續執行sum函式,但是卻被我們的斷點中斷了。所以此時停在最後一層的sum函式遞迴呼叫上。且是停在sum函式中的第6行:
我們連續輸入兩次next,並且檢視當前程式的棧資訊:
程式執行到13行停下來了,這一行是本該return的。此時的函式棧中
n==0,ret==0
,這個ret就差返回給上一層函式呼叫了。現在我們來使用info registers檢視當前的函式呼叫過程的各個暫存器的值,並使用info frame檢視當前函式呼叫過程的函式棧幀的詳細資訊:
如上圖,暫存器比較多,這裡我們只關心一個暫存器,ebp,ebp暫存器儲存的是呼叫這個函式的函式(也就是上一個函式,在這裡是#1號棧對應的函式)棧幀基地址(old_ebp)。可以看到,此時的函式棧幀中的ebp地址為
0xbffff088
。注意你自己執行的話地址可能與我的不一樣。這個地址中儲存的是上一個函式,其實就是1號棧的基地址。我們使用以下命令來檢視該地址處的內容:x /1bx 0xbffff088 //顯示結果為:
如上圖,紅框內的內容,就是#1號棧的基地址。當然我們可以驗證:連續輸入兩個next命令,程式就會把返回值返回給#1號棧的函式呼叫。那麼此時再輸入info args,n就等於1,因為此時位於#1號棧中。然後在輸入info registers命令檢視#1號棧的暫存器值資訊,如下:
如上圖,#1號棧中的ebp值為0xbffff0b8,與我們上面在#0號棧中查詢的值是一樣的。這與函式棧幀的理論也是完全相符的。
上面的除錯內容,非常簡單,我們並沒有除錯什麼bug,而是通過上述內容,學習一些除錯的技巧。
3 總結
- 本節內容學習如何使用GDB檢視函式的呼叫棧資訊。
本文章參考狄泰軟體學院相關課程 想學習的可以加狄泰軟體學院群, 群聊號碼:199546072
學習探討加個人(可以免費幫忙下載CSDN資源):
qq:1126137994
微信:liu1126137994
學習交流資源分享qq群:962535112