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

 

posted @ 2020-08-28 20:25  熊鑫xxx1x  阅读(191)  评论(0)    收藏  举报