热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Linux环境下的堆栈调试C程序

完整的调试过程,跟踪堆栈变化,32位下。注意64位和此不同。a.c代码:#includeintmain(){AF

完整的调试过程,跟踪堆栈变化,32位下。

注意64位和此不同。

 

a.c代码:

#include
int main()
{ AFunc(5,6);return 0;
} int BFunc(int i,int j)
{int m = 1;int n = 2;m = i;n = j; return m;
}int AFunc(int i,int j)
{int m = 3;int n = 4; m = i;n = j;BFunc(m,n);return 8;
}


编译加上调试信息

#gcc  -g  -o  a a.c

 

要调试C程序,在编译时,必须要把调试信息加到可执行文件中。使用编译器(cc/gcc/g++)的 -g 参数可以做到这一点。如:

    > cc -g hello.c -o hello
    > g++ -g hello.cpp -o hello

如果没有-g,你将看不见程序的函数名、变量名,所代替的全是运行时的内存地址。

启动gdb

#gdb a

 

增加断点

#break *main

运行

#run

步入

#s     进入的单步执行

如果已经进入了某函数,而想退出该函数返回到它的调用函数中,可使用命令finish
#finsh

#n    不进入的单步执行

查看数组的值
有时候,你需要查看一段连续的内存空间的值。比如数组的一段,或是动态分配的数据的大小。你可以使用GDB的“@”操作符,“@”的左边是第一个内存的地址的值,“@”的右边则你你想查看内存的长度。例如,你的程序中有这样的语句:
int *array = (int *) malloc (len * sizeof (int));
于是,在GDB调试过程中,你可以以如下命令显示出这个动态数组的取值:
#p *array@len
如果是静态数组的话,可以直接用print数组名,就可以显示数组中所有数据的内容了。

 

whatis 命令可以显示某个变量的类型
(gdb) whatis p
type = int *

 

查看汇编

#disas

#bt 查看栈帧

#f 0查看第0帧

#f 1查看第1帧

#f N查看第N帧

之后查看寄存器也会查看对应的寄存器

#i r

之后也会查看对应寄存器内容

#x/40xw $esp

查看堆栈底

#x/40xw $ebp

ebp的内容为0

 

2.main函数中第2个s,开始调用A函数

很明显esp和ebp变化了,上一步的ebp地址被pusp到新的ebp的内容。

 

3.进入A函数

显示ebp入栈;

然后esp指向新的ebp

sub $0x18,%esp即esp减少24个地址;0xbffff618-18=0xbffff600

第1帧:

第0帧:

ebp依次保存了:

“上一个ebp的地址  0xbffff638;

“main函数中调用完A函数后的执行地址 0x080483b1”;

“上级函数传递的参数5保存在ebp的正向地址”;

“上级函数传递的参数6保存在ebp的正向地址”

将进入AFunc函数之前的EBP的值入栈保存,这时候的EBP相当于是AFunc上级函数; 的一个现场信息,所以需要保存起来,以便于AFunc返回后上级函数可以恢复EBP使其指向其调用; AFunc之前的堆栈位置(当然,这还需要靠恢复ESP来协助达到这一目的)

 

4.A函数中int n=4前

0x8(%ebp)的-8个位置存放3;

0x4(%ebp)的-4个位置存放4。

注意:这里如果调用f 0则后面的i r和x/40xw $ebp都是查看该栈帧

 

5.A函数m=j前

函数的局部变量放置在EBP的负偏移处(Negative; Offset)也就是向低地址方向。

esp在0xbffff618,3和4分别在0xbffff610和0xbffff614。

 

6.A函数n=j之前

 

0x8(ebp)获取ebp正向地址的值稍后mov到eax寄存器;

然后将eax寄存器中的5移到-0x8(ebp)即ebp的负地址8

0xbffff610处的3已经被替换为5

 

7.进入B函数之前

0xc(%ebp)从ebp高地址获取6并存储在ebp的低地址-4位置,然后放到eax寄存器

 0xbffff614处的4已经被替换为6

 

8.进入B函数

按之前的第7步在进入B函数之前先把参数5和6从ebp的-4和-8地址上取出存在eax寄存器,然后存储到esp的正向地址上

esp和ebp存储新的内存地址位置

参数5和6依次保存在esp的正向地址中

 

8.B函数n=2之前

第2帧:

第1帧:

第一帧的ebp保存着:

main函数的ebp地址0xbffff638;

以及main函数需要继续执行的地址0x080483b1

 

第0帧:

这是当前B函数的帧以及对应的寄存器内容,其中1被存储在ebp的-8位置,和之前的A函数中的过程一样,没有新的差异。

 

9.B函数的m=i之前

 

10.B函数的n=j之前

 

11.B函数return之前

 

12.B函数返回值

leave 将ebp值赋给esp,

pop先前栈内的上级函数栈的基地址给ebp,

恢复原栈基址相当于:

movl %ebp,%esp  

popl %ebp

返回值放在eax寄存器中

 

13.回到A函数

8赋给eax寄存器

 

14.A返回值,pop出main函数的ebp

 

15.回到main函数

 

16.退出main函数

 

17.进入__libc_start_main ()系统调用

18.结束

 

关于win32环境下的堆栈参考:Win32 环境下的堆栈

关于gdb查看栈参考: GDB查看栈信息

关于gdb调试可以参考:GDB调试--以汇编语言为例

 GDB 进行调试 使用心得   

 


推荐阅读
  • linux 字符串数组初始化,C++字符数组初始化方法的分析
    发现了一个字符数组初始化的误区,而这个往往能导致比较严重的性能问题,分析介绍如下:往往我们在初始化一个字符数组,大概有如下几 ... [详细]
  • linux进阶50——无锁CAS
    1.概念比较并交换(compareandswap,CAS),是原⼦操作的⼀种,可⽤于在多线程编程中实现不被打断的数据交换操作࿰ ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Webpack5内置处理图片资源的配置方法
    本文介绍了在Webpack5中处理图片资源的配置方法。在Webpack4中,我们需要使用file-loader和url-loader来处理图片资源,但是在Webpack5中,这两个Loader的功能已经被内置到Webpack中,我们只需要简单配置即可实现图片资源的处理。本文还介绍了一些常用的配置方法,如匹配不同类型的图片文件、设置输出路径等。通过本文的学习,读者可以快速掌握Webpack5处理图片资源的方法。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • ShiftLeft:将静态防护与运行时防护结合的持续性安全防护解决方案
    ShiftLeft公司是一家致力于将应用的静态防护和运行时防护与应用开发自动化工作流相结合以提升软件开发生命周期中的安全性的公司。传统的安全防护方式存在误报率高、人工成本高、耗时长等问题,而ShiftLeft提供的持续性安全防护解决方案能够解决这些问题。通过将下一代静态代码分析与应用开发自动化工作流中涉及的安全工具相结合,ShiftLeft帮助企业实现DevSecOps的安全部分,提供高效、准确的安全能力。 ... [详细]
  • 第四讲ApacheLAMP服务器基本配置Apache的编译安装从Apache的官方网站下载源码包:http:httpd.apache.orgdownload.cgi今 ... [详细]
  • 原文地址http://balau82.wordpress.com/2010/02/28/hello-world-for-bare-metal-arm-using-qemu/最开始时 ... [详细]
  • TPL实现Task.WhileAll扩展方法
    文章翻译整理自NikolaMalovic两篇博文:Task.WhileAllAwaitabletaskprogressreporting当Task.WhenAll遇见 ... [详细]
  • 【技术分享】一个 ELF 蠕虫分析
    【技术分享】一个 ELF 蠕虫分析 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文介绍了C++中省略号类型和参数个数不确定函数参数的使用方法,并提供了一个范例。通过宏定义的方式,可以方便地处理不定参数的情况。文章中给出了具体的代码实现,并对代码进行了解释和说明。这对于需要处理不定参数的情况的程序员来说,是一个很有用的参考资料。 ... [详细]
  • C语言注释工具及快捷键,删除C语言注释工具的实现思路
    本文介绍了C语言中注释的两种方式以及注释的作用,提供了删除C语言注释的工具实现思路,并分享了C语言中注释的快捷键操作方法。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
author-avatar
1500799277_a9483d_353
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有