3.GDB查看棧信息

棧:是程序存放數據內存區域之一,特點是LIFO(後進先出)。

PUSH:入棧

POP:出戰

使用場景:

1.保存動態分配的自動變量使用棧

2.函數調用時,用棧傳遞函數參數,半寸返回地址,返回值

代碼sum.c

#include <stdio.h>      
#include <ctype.h>      
#include <stdlib.h>      
#define MAX  (1UL << 20)      
typedef unsigned long long u64;      
typedef unsigned int u32;      
u32 max_addend=MAX;      
u64 sum_till_MAX(u32 n)      
{          
    u64 sum;          
    n++;          
    sum=n;          
    if(n<max_addend)              
    sum+=sum_till_MAX(n);          
    return sum;      
}      
int main(int argc,char** argv){          
    u64 sum=0;          
    if((argc==2) && isdigit(*(argv[1])))              
    max_addend=strtoul(argv[1],NULL,0);          
    if(max_addend>MAX||max_addend==0){              
    fprintf(stderr,"Invalid number is specified\n");              
    return 1;          
    }          
    sum=sum_till_MAX(0);          
    printf("sum(0..%lu)=%llu\n",max_addend,sum);          
    return 0;      
}

 

該程序計算0到命令行參數傳遞過來的數字之間所有的正數和。

圖a是函數調用前的棧,圖b是函數調用後的棧,圖c是再次函數調用後的棧。

棧上保存了函數參數,調用返回地址,上層棧幀指針和函數內部使用的自動變量。

有時,還會用棧保存寄存器,每個函數獨有,稱作棧幀。

此時,需要設置表示棧幀起始地址的幀指針(FP)。

棧指針(SP)永遠指向棧頂!

編譯程序

#gcc -g -Wall -o sum sum.c

啓動gdb調試sum

#gdb sum

(gdb) disas main

從圖中可見call指令自動把返回地址0x8048494壓入棧中

再看sum_till_MAX函數

在棧上保存上層幀的幀指針0x8048494,

然後將新的棧幀賦給幀指針%esp,

然後在棧上分配用於保存自動變量的空間,至此完成棧幀。

0x8(%ebp)指向幀指針+8字節的地址,

-0x10(%ebp)爲指針-10字節的地址

leave指令刪除棧幀,釋放當前的棧,

ret指令爲函數返回,將棧中保存的返回地址POP到程序計數寄存器,控制權返回給調用者。

這是第二次進入sum_till_MAX函數時使用backtrace

獲取當前執行位置,可以通過程序計數器PC獲得,在x86上是eip寄存器,FP是ebp寄存器

下面查看棧的內容,從表示棧頂的SP開始。

(gdb) x/40xw $sp

從棧上的返回地址信息可以看到和之前backtrace結果相同的調用跟蹤信息0x080484c1和0x0804858d

用frame命令查看現在選擇的幀,

frame 1選擇幀1

up選擇下一層的幀

用info命令的frame選項可以查看更詳細的棧幀信息

棧的大小限制

注意,如果上述sum程序不帶參數會引發段錯誤。

#./sum

發生棧溢出。

下面用gdb跟蹤,查看程序計數器PC即可看到程序執行位置

#gdb sum

(gdb) r

(gdb) x/i $pc

這正是將sum_till_MAX的參數PUSH到棧頂的命令

查看棧指針SP的位置

(gdb) p $sp

查看該進程的內存映射

(gdb) i proc mapping

最後一行的[stack]表示棧空間,頂端是0xbf401000,之前看到的棧指針是0xbf3ffff0,超出了棧的範圍發生溢出。

分析內核轉儲的時候無法使用上述命令,可以使用

(gdb) info files或者(gdb) info target得到相同信息

 

linux棧大小

顯示本機系統支持的棧大小

# ulimit -s
10240

修改棧大小擴大10倍

#ulimit -Ss 102400

這樣就不會棧溢出了

 

Linux下默認的棧空間大小是10M,可以通過ulimit -s進行查看,不同的Linux發行版本可能不太一樣。下面介紹棧空間大小修改方法。
 
臨時修改方法:
ulimit -s <新的棧空間大小>
 
永久修改方法:
1. 可以修改配置文件/etc/security/limits.conf
2. 可以將ulimit -s命令放到/etc/profile中,在任何用戶啓動的時候調用

參考《Debug.Hacks中文版 深入調試的技術和工具-調試時必須的棧知識》
————————————————
版權聲明:本文爲CSDN博主「unix21」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/unix21/article/details/8450182

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章