作家
登录

开发一个Linux调试器(八):堆栈展开

作者: 来源: 2017-10-09 12:12:56 阅读 我要评论


开辟一个 Linux 调试器(八):客栈展开

有时你须要知道的最重要的信息是什么,你当前的法度榜样状况是若何达到那边的。有一个 backtrace 敕令,它给你供给了法度榜样当前的函数调用链。这篇文┞仿将向你展示如安在 x86_64 上实现客栈展开以生成如许的回溯。

系列索引

这些链接将会跟着其他帖子的宣布而上线。

  1. 预备情况
  2. 断点
  3. 存放器和内存
  4. ELF 和 DWARF
  5. 源码和旌旗灯号
  6. 源码级慢慢履行
  7. 源码级断点
  8. 客栈展开
  9. 攫取变量
  10. 之后步调

用下面的法度榜样作为例子:

  1. void a() { 
  2.     //stopped here 
  3. void b() { 
  4.      a(); 
  5. void c() { 
  6.      a(); 
  7. int main() { 
  8.     b(); 
  9.     c(); 

如不雅调试器停在 //stopped here' 这行,那么竽暌剐两种办法可以达到:main->b->a或main->c->a`。如不雅我们用 LLDB 设置一个断点,持续履行并请求一个回溯,那么我们将获得以下内容:

  1. * frame #0: 0x00000000004004da a.out`a() + 4 at bt.cpp:3 
  2.   frame #1: 0x00000000004004e6 a.out`b() + 9 at bt.cpp:6 
  3.   frame #2: 0x00000000004004fe a.out`main + 9 at bt.cpp:14 
  4.   frame #3: 0x00007ffff7a2e830 libc.so.6`__libc_start_main + 240 at libc-start.c:291 
  5.   frame #4: 0x0000000000400409 a.out`_start + 41 

这解释我们今朝在函数 a 中,a 大年夜函数 b 中跳转,b 大年夜 main 中跳转等等。最后两个帧是编译器若何引导 main 函数的。

如今的问题是我们如安在 x86_64 上实现。最稳健的办法是解析 ELF 文件的 .eh_frame 部分,并解决若何大年夜那边展开客栈,但这会很苦楚。你可以应用 libunwind 或类似的来做,但这很无聊。相反,我们假设编译器以某种方法设置了客栈,我们将手动遍历它。为了做到这一点,我们起首须要懂得客栈的构造。

  1.     High 
  2. |   ...   | 
  3. +---------+ 
  4. |  Arg 1  | 
  5. +---------+ 
  6. |  Arg 2  | 
  7. +---------+ 
  8. Return  | 
  9. +---------+ 
  10. |Saved EBP| 
  11. +---------+ 
  12. |  Var 1  | 
  13. +---------+ 
  14. |  Var 2  | 
  15. +---------+ 
  16. |   ...   | 
  17.     Low 

如你所见,最后一个客栈帧的帧指针存储在当前客栈帧的开端处,创建一个链接的指针列表。客栈根据这个链表解开。我们可以经由过程查找 DWARF 信息中的返回地址来找出列表中下一帧的函数。一些编译器将忽视跟踪 EBP 的帧基址,因为这可以表示为 ESP 的偏移量,并可以释放一个额外的存放器。即使启用了优化,传递 -fno-omit-frame-pointer 到 GCC 或 Clang 会强迫它遵守我们依附的商定。


  推荐阅读

  盘点快递电商们的“绿色计划”

 近日,人平易近日报评论快递业“虚胖的快递担保需瘦身”,让快递担保一向存在且愈演愈烈的“过度包装”,收受接收处理方法被提上日程受到广泛存眷。相干数据显示,2016年,我国快>>>详细阅读


本文标题:开发一个Linux调试器(八):堆栈展开

地址:http://www.17bianji.com/lsqh/37719.html

关键词: 探索发现

乐购科技部分新闻及文章转载自互联网,供读者交流和学习,若有涉及作者版权等问题请及时与我们联系,以便更正、删除或按规定办理。感谢所有提供资讯的网站,欢迎各类媒体与乐购科技进行文章共享合作。

网友点评
自媒体专栏

评论

热度

精彩导读
栏目ID=71的表不存在(操作类型=0)