程序员应了解的那些事(27)学会用GDB查看栈帧信息

        当我们阅读代码和查找BUG时,往往有一个烦恼。就是我们不知道函数的调用顺序。而这些函数调用顺序对应我们理解程序结构,程序运行过程是很有帮助的。
        那么问题是:程序的调用过程往往是很复杂的,而且可能是多层嵌套,跨文件调用的。这时候如果靠人工去查找,这将是一件非常大工作量的事情。GDB中有办法帮助我们做到查看函数调用的过程吗?
        首先我们需要知道,函数调用信息存放在哪?只有知道函数调用信息,我们才能进行信息提取这一步。关于函数的信息都存放在栈中。

【GDB查看函数调用栈】
backtrace:查看函数调用的顺序(函数调用栈的信息)
frame N:切换到栈编号为N的上下文中
info frame:查看当前函数调用的栈帧信息
info命令的其他使用方式:

【示例操作:函数调用栈的查看】 

//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;
}
<1.设置断点:设置到递归结束标志的位置>
(gdb) start
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Temporary breakpoint 4 at 0x80483f9: file frame.c, line 19.
Starting program: /home/delphi/workspace/test.out 

Temporary breakpoint 4, main () at frame.c:19
19       int s = 0;
(gdb) break sum if n==0   < --------------设置sum函数中, n==0 时的数据断点。
Breakpoint 5 at 0x80483ca: file frame.c, line 6.
(gdb) info break    < --------------- 查看断点信息
Num     Type           Disp Enb Address    What
5       breakpoint     keep y   0x080483ca in sum at frame.c:6
stop only if n==0

注: (gdb) break sum if n==0   < --------------设置sum函数中, n==0 时的数据断点

<2.查看函数调用过程>

(gdb) continue 
Continuing.

Breakpoint 5, sum (n=0) at frame.c:6
6       int ret = 0;
(gdb) backtrace  < ----------- 查看函数调用的顺序
#0  sum (n=0) at frame.c:6
#1  0x080483e5 in sum (n=1) at frame.c:10
#2  0x080483e5 in sum (n=2) at frame.c:10
#3  0x080483e5 in sum (n=3) at frame.c:10
#4  0x080483e5 in sum (n=4) at frame.c:10
#5  0x080483e5 in sum (n=5) at frame.c:10
#6  0x080483e5 in sum (n=6) at frame.c:10
#7  0x080483e5 in sum (n=7) at frame.c:10
#8  0x080483e5 in sum (n=8) at frame.c:10
#9  0x080483e5 in sum (n=9) at frame.c:10
#10 0x080483e5 in sum (n=10) at frame.c:10
#11 0x0804840d in main () at frame.c:21
<3.分析函数调用过程>

(gdb) next
8       if( n > 0 )
(gdb) next
13      return ret;
(gdb) info args   < ---------- 查看当前函数参数的值
n = 0
(gdb) frame 7    < ---------- 切换栈编号为7的上下文中
#7  0x080483e5 in sum (n=7) at frame.c:10
10          ret = n + sum(n-1);
(gdb) info args   < ---------- 查看栈编号为7时函数参数的值
n = 7
(gdb) info locals  < ---------- 查看当前局部变量ret的值
ret = 0  < ------- 计算结果
(gdb) frame 0
#0  sum (n=0) at frame.c:13
13      return ret;
(gdb) info registers   < ------------ 查看当前寄存器的值
eax            0x0  0
ecx            0x241be83d   605808701
edx            0x1  1
ebx            0x287ff4 2654196
esp            0xbffff070   0xbffff070
ebp            0xbffff098   0xbffff098
esi            0x0  0
edi            0x0  0
eip            0x80483eb    0x80483eb <sum+39>
eflags         0x200246 [ PF ZF IF ID ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0  0
gs             0x33 51
(gdb) info frame  < --------- 查看当前栈帧的详细信息
Stack level 0, frame at 0xbffff0a0:
 eip = 0x80483eb in sum (frame.c:13); saved eip 0x80483e5
 called by frame at 0xbffff0d0
 source language c.
 Arglist at 0xbffff098, args: n=0
 Locals at 0xbffff098, Previous frame's sp is 0xbffff0a0 < -- 上一个栈指针地址
 Saved registers:  < ---- 将下面值保存到寄存器中
  ebp at 0xbffff098, eip at 0xbffff09c
(gdb) x /1wx 0xbffff098 < ----- 查看ebp地址中的值
0xbffff098: 0xbffff0c8
(gdb) next
14  }
(gdb) next
13      return ret;
(gdb) info args
n = 1
(gdb) info registers  < ------ 查看栈帧编号为1的寄存器值
eax            0x1  1
ecx            0x241be83d   605808701
edx            0x1  1
ebx            0x287ff4 2654196
esp            0xbffff0a0   0xbffff0a0
ebp            0xbffff0c8   0xbffff0c8
esi            0x0  0
edi            0x0  0
eip            0x80483eb    0x80483eb <sum+39>
eflags         0x200202 [ IF ID ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0  0
gs             0x33 51
(gdb) info locals
ret = 1  < ------ 计算结果

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值