gdb初用
背景介绍:
Linux下面写代码的调试工具,可以实现传统的代码单步执行 core dump 文件分析等。
core dump
介绍core dump文件的生成及基本的应用 https://www.cnblogs.com/Anker/p/6079580.html
1. ➜ ~ ulimit -c unlimited 将系统的core dump的大小限制设置为无穷大
2. 生成core dump 的过程
gcc 添加 -c选项 生成调试信息
源码:
#include <stdio.h>
int sum(int n)
{
int ret = 0;
if(n > 0)
{
int tt = sum(n-1);
ret = tt + n;
}
return ret;
}
int main()
{
int s = 0;
s = sum(10);
printf("sum = %d\n", s);
return 0;
}
info frame 的信息解析:
(gdb) info frame Stack level 0, frame at 0x7fffffffdc70: rip = 0x555555554678 in sum (main.cc:10); saved rip = 0x55555555466f called by frame at 0x7fffffffdca0 source language c++. Arglist at 0x7fffffffdc60, args: n=0 Locals at 0x7fffffffdc60, Previous frame's sp is 0x7fffffffdc70 Saved registers: rbp at 0x7fffffffdc60, rip at 0x7fffffffdc68
ESP: 栈指针寄存器 ,其内存放着一个指针 ,指向最上面的一个栈帧的栈顶。
EBP: 基址指针寄存器 ,其内存放着一个指针, 指向最上面一个栈帧的底部。
EAX: 一般用来保存函数的返回值。
Stack level 0, frame at 0x7fffffffdc70:
这个0x7fffffffdc70:当前程序所分配使用的栈地址。这里就有二义性,到底是指的整个进场的栈的基址,还是当前栈帧的基址。
应该是当前栈帧的基址,也就是EBP的值。
Stack level 0 :表示栈帧的层数,0表示顶层。
frame n: 可以去到第n层
backtrace:可以查看所有的层的编号
rip = 0x555555554678 in sum (main.cc:10); saved rip = 0x55555555466f
rip = 0x555555554678 : 表示当前的rip寄存器中保存的值是0x555555554678
saved rip = 0x55555555466f :表示调用本函数的指令的地址,用于本函数执行完返回时用。 表示被保存的及被压栈的rip的值。
简单理解上一句是将要执行的下一句指令的地址
下一句是 本函数结束后返回调用函数要执行的地址。
(gdb) info frame Stack level 0, frame at 0x7fffffffde20: rip = 0x555555554662 in sum (main.cc:8); saved rip = 0x55555555466f called by frame at 0x7fffffffde50 source language c++. Arglist at 0x7fffffffde10, args: n=9 Locals at 0x7fffffffde10, Previous frame's sp is 0x7fffffffde20 Saved registers: rbp at 0x7fffffffde10, rip at 0x7fffffffde18 (gdb) info args n = 9 (gdb) disas Dump of assembler code for function sum(int): 0x000055555555464a <+0>: push %rbp 0x000055555555464b <+1>: mov %rsp,%rbp 0x000055555555464e <+4>: sub $0x20,%rsp 0x0000555555554652 <+8>: mov %edi,-0x14(%rbp) 0x0000555555554655 <+11>: movl $0x0,-0x8(%rbp) 0x000055555555465c <+18>: cmpl $0x0,-0x14(%rbp) 0x0000555555554660 <+22>: jle 0x55555555467d <sum(int)+51> => 0x0000555555554662 <+24>: mov -0x14(%rbp),%eax 0x0000555555554665 <+27>: sub $0x1,%eax 0x0000555555554668 <+30>: mov %eax,%edi 0x000055555555466a <+32>: callq 0x55555555464a <sum(int)> 0x000055555555466f <+37>: mov %eax,-0x4(%rbp) 0x0000555555554672 <+40>: mov -0x4(%rbp),%edx 0x0000555555554675 <+43>: mov -0x14(%rbp),%eax 0x0000555555554678 <+46>: add %edx,%eax 0x000055555555467a <+48>: mov %eax,-0x8(%rbp) 0x000055555555467d <+51>: mov -0x8(%rbp),%eax 0x0000555555554680 <+54>: leaveq 0x0000555555554681 <+55>: retq End of assembler dump.
以上在int tt = sum(n-1);处打下断点 对应的代码起始地址就是 0x0000555555554662 这也是下一个要执行的代码的地址
而返回后的跳转地址 0x000055555555466f 是调用sum后的第一句指令的地址。
called by frame at 0x7fffffffdca0
这句表示调用函数的帧基。EBP 调用函数--->本函数--->被调函数
Arglist at 0x7fffffffdc60, args: n=0
参数列表的起始地址
Locals at 0x7fffffffdc60, Previous frame's sp is 0x7fffffffdc70
这里是因为参数只有一个的原因吗,参数的起始地址和局部变量的起始地址一样。 上一栈帧的ESP 0x7fffffffdc70 就是这一栈帧的栈基EBP
经查证 Arglist at 和 Locals at 总是相等的原因并不是参数列表不占据空间而是一个bug 这里的两个参数的输出值是没有意义的。
参考:
https://stackoverflow.com/questions/22876072/gdb-info-frame-output-wrong-value-for-arglist-at
Saved registers: rbp at 0x7fffffffdc60, rip at 0x7fffffffdc68
就是保存上一栈帧的EBP 和 EIP

浙公网安备 33010602011771号