• 堆栈桢的生成原理(调试器是如何生成堆栈的调用过程的)


    一直比较好奇,调试器是如何生成堆栈的调用过程的,比如如下代码:
    int add(int a, int b)
    {
        return a + b;
    }

    int main()
    {
        int c = add(1, 2);
        system("pause");

        return 0;
    }

    调用Add时的堆栈截图如下:


    调试器究竟是如何生成这个堆栈过程的呢?

    我最初的理解调试器是根据EBP来生成该堆栈的,原理如下:

    可以看到按照上面的原理, 每次EBP里存放的都是当前函数的堆栈桢基址,所以我们只要一直递推,就可以得到完整的Call Stack.

    但是我们很快会发现, 并不是每个函数都是以
    push ebp   
    mov ebp, esp
    开头的,我们可以写一些裸(naked)函数, 
    比如int __declspec(naked) add(int x,int y) 来手动控制函数头,
    而且很多编译器优化过的函数代码也是没有该标准函数头的。

    那么调试器在这种情况下又是如何生成完整的call stack的呢?

    和群里的朋友讨论的结果是调试器很可能是在调用call指令时保存了调用现场,
    这样只要在调试器下运行,它就一直可以知道正确而完整的call stack.

    这也解释了为什么我们在分析Crash的Dump文件时很多时候得不到正确的堆栈过程?
    有可能是堆栈本身被我们的异常代码破坏了;
    更有可能是因为我们的代码在直接运行时没有调试器的参与, 所以堆栈过程没有被保存,所以windbg分析dump时只能根据堆栈里内容自己分析和推理堆栈调用过程,所以很多时候得不到正确的堆栈过程。

    那么Windbg分析dump时,会如何倒推堆栈过程呢?

    如果每个函数都是有标准的push ebp, 那么按照ebp递推就可以了;
    否这就只能用其他方法分析,比如看看堆栈里某个地址是不是函数返回地址(该地址属于某个模块的代码段),这样就可以确定该地址是某个函数堆栈桢的起始地址。

    上面关于生成call stack的原理只是一些非专业人士的个人看法,如果有不正确的地方,欢迎指正。

    注: 和开发过调试器的朋友讨论,上面 关于callstack产生原理的推论,实际上是不正确的, 调试器实际上是通过查询PDB文件的方式获取的callstack.
    posted on 2012-07-20 14:00 Richard Wei 阅读(3023) 评论(3)  编辑 收藏 引用 所属分类: 汇编


    FeedBack:
     
    # re: 堆栈桢的生成原理
    2012-07-20 15:31 | Richard Wei
    据写过调试器的朋友指点,调试器会尽量减少代码运行时的干预,所以上面关于函数调用时调试器保存调用现场的猜测,应该是不正确的。
    调试器更多的可能是根据PDB文件信息来计算推理的,如果没有PDB文件,它就只能猜测,很多堆栈信息就会出错了。

    据说<<软件调试>>里有相关介绍,回头看下, 希望这篇博文不要误导他人。  回复  更多评论
      
    # re: 堆栈桢的生成原理[未登录]
    2012-07-20 21:19 | Korall
    “和群里的朋友讨论的结果是调试器很可能是在调用call指令时保存了调用现场,
    这样只要在调试器下运行,它就一直可以知道正确而完整的call stack.”

    猜测确实不太符合实际;我还没有见过哪一款调试器是这样实现的,虚拟机除外。
    就算是在调试器下运行,不设置“堆栈帧”的函数调试器也是无法知道正确而完整的 call stack 的。  回复  更多评论
      
    # re: 堆栈桢的生成原理
    2012-07-21 00:14 | fzy
    call 会push下一条指令的地址到堆栈。
    可能是根据这个来进行堆栈帧的检测。
      回复  更多评论

    http://www.cppblog.com/weiym/archive/2012/07/20/184344.html

  • 相关阅读:
    可视化工具D3.js教程 入门 (第三章)—— 理解 Update Enter Exit
    可视化工具D3.js教程 入门 (第二章)—— 选择元素与数据绑定
    可视化工具D3.js教程 入门 (第一章)—— hello world
    可视化工具D3.js教程 入门 (V5版)
    [译]C语言实现一个简易的Hash table(3)
    [译]C语言实现一个简易的Hash table(2)
    [译]C语言实现一个简易的Hash table(1)
    C/C++中的malloc、calloc和realloc
    数据结构--单向链表
    使用Screen管理远程会话
  • 原文地址:https://www.cnblogs.com/findumars/p/5794096.html
Copyright © 2020-2023  润新知