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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值