日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Linux环境下的堆栈--调试C程序

發布時間:2023/11/27 生活经验 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux环境下的堆栈--调试C程序 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

完整的調試過程,跟蹤堆棧變化,32位下。

注意64位和此不同。

?

a.c代碼:

#include <stdio.h>   
int main()  
{  AFunc(5,6);return 0;
}  int BFunc(int i,int j)
{int m = 1;int n = 2;m = i;n = j; return m;
}int AFunc(int i,int j)
{int m = 3;int n = 4;     m = i;n = j;BFunc(m,n);return 8;
}


編譯加上調試信息

#gcc? -g? -o? a a.c

?

要調試C程序,在編譯時,必須要把調試信息加到可執行文件中。使用編譯器(cc/gcc/g++)的 -g 參數可以做到這一點。如:

??? > cc -g hello.c -o hello
??? > g++ -g hello.cpp -o hello

如果沒有-g,你將看不見程序的函數名、變量名,所代替的全是運行時的內存地址。

啟動gdb

#gdb a

?

增加斷點

#break *main

運行

#run

步入

#s???? 進入的單步執行

如果已經進入了某函數,而想退出該函數返回到它的調用函數中,可使用命令finish
#finsh

#n??? 不進入的單步執行

查看數組的值
有時候,你需要查看一段連續的內存空間的值。比如數組的一段,或是動態分配的數據的大小。你可以使用GDB的“@”操作符,“@”的左邊是第一個內存的地址的值,“@”的右邊則你你想查看內存的長度。例如,你的程序中有這樣的語句:
int *array = (int *) malloc (len * sizeof (int));
于是,在GDB調試過程中,你可以以如下命令顯示出這個動態數組的取值:
#p *array@len
如果是靜態數組的話,可以直接用print數組名,就可以顯示數組中所有數據的內容了。

?

whatis 命令可以顯示某個變量的類型
(gdb) whatis p
type = int *

?

查看匯編

#disas

#bt 查看棧幀

#f 0查看第0幀

#f 1查看第1幀

#f N查看第N幀

之后查看寄存器也會查看對應的寄存器

#i r

之后也會查看對應寄存器內容

#x/40xw $esp

查看堆棧底

#x/40xw $ebp

--《深入理解計算機系統(原書第2版)》

開始

1.main函數中第1個s

ebp的內容為0

?

2.main函數中第2個s,開始調用A函數

很明顯esp和ebp變化了,上一步的ebp地址被pusp到新的ebp的內容。

?

3.進入A函數

顯示ebp入棧;

然后esp指向新的ebp

sub $0x18,%esp即esp減少24個地址;0xbffff618-18=0xbffff600

第1幀:

第0幀:

ebp依次保存了:

“上一個ebp的地址? 0xbffff638

“main函數中調用完A函數后的執行地址 0x080483b1”;

“上級函數傳遞的參數5保存在ebp的正向地址”;

“上級函數傳遞的參數6保存在ebp的正向地址”

將進入AFunc函數之前的EBP的值入棧保存,這時候的EBP相當于是AFunc上級函數; 的一個現場信息,所以需要保存起來,以便于AFunc返回后上級函數可以恢復EBP使其指向其調用; AFunc之前的堆棧位置(當然,這還需要靠恢復ESP來協助達到這一目的)

?

4.A函數中int n=4前

0x8(%ebp)的-8個位置存放3;

0x4(%ebp)的-4個位置存放4。

注意:這里如果調用f 0則后面的i r和x/40xw $ebp都是查看該棧幀

?

5.A函數m=j前

函數的局部變量放置在EBP的負偏移處(Negative; Offset)也就是向低地址方向。

esp在0xbffff618,3和4分別在0xbffff610和0xbffff614。

?

6.A函數n=j之前

?

0x8(ebp)獲取ebp正向地址的值稍后mov到eax寄存器;

然后將eax寄存器中的5移到-0x8(ebp)即ebp的負地址8

0xbffff610處的3已經被替換為5

?

7.進入B函數之前

0xc(%ebp)從ebp高地址獲取6并存儲在ebp的低地址-4位置,然后放到eax寄存器

?0xbffff614處的4已經被替換為6

?

8.進入B函數

按之前的第7步在進入B函數之前先把參數5和6從ebp的-4和-8地址上取出存在eax寄存器,然后存儲到esp的正向地址上

esp和ebp存儲新的內存地址位置

參數5和6依次保存在esp的正向地址中

?

8.B函數n=2之前

第2幀:

第1幀:

第一幀的ebp保存著:

main函數的ebp地址0xbffff638;

以及main函數需要繼續執行的地址0x080483b1

?

第0幀:

這是當前B函數的幀以及對應的寄存器內容,其中1被存儲在ebp的-8位置,和之前的A函數中的過程一樣,沒有新的差異。

?

9.B函數的m=i之前

?

10.B函數的n=j之前

?

11.B函數return之前

?

12.B函數返回值

leave 將ebp值賦給esp,

pop先前棧內的上級函數棧的基地址給ebp,

恢復原棧基址相當于:

movl %ebp,%esp??

popl %ebp

返回值放在eax寄存器中

?

13.回到A函數

8賦給eax寄存器

?

14.A返回值,pop出main函數的ebp

?

15.回到main函數

?

16.退出main函數

?

17.進入__libc_start_main ()系統調用

18.結束

?

關于win32環境下的堆棧參考:Win32 環境下的堆棧

關于gdb查看棧參考:?GDB查看棧信息

關于gdb調試可以參考:GDB調試--以匯編語言為例

?GDB 進行調試 使用心得???

?

總結

以上是生活随笔為你收集整理的Linux环境下的堆栈--调试C程序的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。