GDB堆棧跟蹤與匯編調試


GDB堆棧跟蹤與匯編調試

堆棧跟蹤

  • 源代碼:

  • 對預先編寫的 stack.c 文件進行編譯,並且使用 CGDB 進行調試,對堆棧進行跟蹤,了解該代碼堆棧是如何變化的。

  • CGDB 中,先設置 main 斷點,接着運行(run),使用 frame info frame 分別查看當前棧幀的簡要信息,以及該棧幀的詳細信息。其中:

    • frame 打印出的信息:棧的層編號,當前的函數名,函數參數值,函數所在文件及行號,函數執行到的語句。
    • info frame 打印出的信息:函數地址,調用函數的地址,被調用函數的地址,目前的函數是由什么樣的程序語言寫成的、函數參數地址及值、局部變量的地址等等。
  • 輸入命令 disassemble ,顯示出該代碼(main())的匯編形式

  • info registers ,顯示當前(main()處)寄存器值

  • 使用 s 單步運行程序:

    • 運行到 f1 函數內,觀察此時堆棧情況

    • 運行到 g1 函數內,觀察此時堆棧情況

    • 使用 up down ,跳轉不同堆棧,查詢其中的堆棧簡要信息

  • 該代碼中,共存在過3個堆棧,對每個堆棧查詢其詳細信息,觀察堆棧變化:

    • main() 函數形成的堆棧(#2):

    • f1 函數形成的堆棧(#1):

    • g1 函數形成的堆棧(#0):

  • 根據3個堆棧的詳細信息,畫出大致的堆棧示圖(此時,程序運行在 g1 ,還沒有返回):

匯編調試

  • GDB 指令加上i就顯示匯編代碼,例如:n(ext)i、s(tep)i,其中:

    • (gdb)p/x i:打印變量名為 i 的十六進制值
    • (gdb) display /3i $pc:這是一種設置,設置好了調試過程中每一步都回顯一次,這里是一次顯示 3 行,3 在這里是指一次顯示幾行,不輸入,缺省為1
    • (e)xamine:功能和display差不太多,區別就是display是一種設置,每次跳命令顯示一次,x是主動顯示:x/<n/f/u> <addr>
      • n選擇從當前地址向后顯示幾個
      • f是顯示格式,還有s字符串和i整型
      • u表示從當前地址往后請求的字節數,如果不指定的話,GDB默認是4個bytes。u參數可以用下面的字符來代替,b表示單字節,h表示雙字節,w表示四字節,g表示八字節。當我們指定了字節長度后,GDB會從指內存定的內存地址開始,讀寫指定字節,並把其當作一個值取出來。
      • 例:x/3uh 0x54320表示,從地址0x54320讀取,h表示以雙字節為單位,3表示三個單位,u表示十六進制
  • mainf1g13個函數所對應的匯編代碼

  • 設置display ,每一步顯示一行代碼,查看當前 main() 斷點處初始的寄存器值(主要觀察%eax,%ebx,%esp,%eip)

  • printf("%d\n,f1(1)+6);轉到fi函數地址處:

  • int f1(int x){建立f1函數的堆棧,保存數據,更新信息:

  • return g1(x);保存f1函數的數據,之后跳轉到g1函數的地址:

  • int g1(int x)建立g1函數的堆棧,保存數據,更新信息:

  • return x+5;,進行計算:

  • },銷毀g1函數的堆棧,並且回到從f1函數跳出來的下一條指令:

  • },銷毀f1函數的堆棧,並且回到從main函數跳出來的下一條指令:

  • printf("%d\n,f1(1)+6);進行運算,並且轉到執行 printf
    的代碼處,使之打印出最終結果:

棧幀變化

  • 其中,每條代碼指令為正在執行的代碼,所有后面的%esp、%ebp、%eax以及棧幀情況都是上一條指令的結果,在等待正在執行的指令完成后再更改

參考資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM