我正在使用GCC 5.4对Ubuntu LTS 16.04.1 X86_64进行简单的实验。
实验是获取正在运行的C程序的完整调用堆栈。
我所做的是:
因为BP是一个链,我应该能够获得一系列返回地址。之后,通过使用列表文件或矮人数据分析地址序列,我终于能够计算出完整的调用堆栈。类似于' main - > funcA - > funcB - >功能......'。
我的问题是,如果调用堆栈完全在我的测试程序的代码中,这可以正常工作。我的意思是每个函数都是由我编写的。但是,如果测试程序在CRT或系统API中停止,例如' scanf'或者“睡觉”,BP链不再有效。
我检查了disassambly并注意到CRT或系统API函数没有通过推送ebp'来建立堆栈帧。和' mov ebp,esp'就像我的功能一样。难怪为什么上述方法不起作用。但我无法解释为什么GDB在这种情况下仍能正常工作?!因此,对于Linux C程序的调用堆栈,必须有许多我不了解的事情。
你能算出我的错误/误会吗?或者你可以简单地建议我阅读一些文章/链接?非常感谢你。
答案 0 :(得分:3)
因为BP是一个链
他们不。过去曾经在i386
上使用了帧指针链,但是几年后,即使在-fomit-frame-pointer
上,GCC也会在优化的编译中默认为i386
。在x86_64
,-fno-omit-frame-pointer
从未是优化代码中的默认值。
如果调用堆栈完全在我的测试程序代码中,这可以正常工作。
如果您在没有优化的情况下进行编译(或者 使用-fno-omit-frame-pointer
进行优化,那么仅可以正常工作。)
我无法解释为什么GDB在这种情况下仍能正常工作
GDB(和libunwind)使用DWARF
展开信息,您可以使用readelf -wf a.out
进行检查。