我有一个遗留的GDB命令脚本,用于根据
Python 2.6源代码附带的GDB脚本获取Python堆栈跟踪(SO不允许超链接,但这里是URL:http:// #http://svn.python.组织/视图/ *结帐* /蟒/支链/ release26-MAINT /杂项/)
该脚本有一个while循环,根据要退出的程序计数器进行相当脆弱的检查,(如注释中的原始代码中所述)可能仅适用于直接运行Python,而不是解释器是从C/C++应用程序开始.
现有的while循环如下所示:
while $pc < Py_Main || $pc > Py_GetArgcArgv
# ...
# code for extracting Python stack from local vars in relevant frames
# of C stack
# ...
up-silently 1
对于我想要调试的程序,对Py_Main和Py_GetArgcArgv的检查不会很好地工作,所以我正在寻找一个循环条件,当它到达main时将评估为false.
所以我一直在考虑使用程序计数器,帧指针和堆栈指针的想法,因为如果无声地失败,它们将具有与之前相同的值,这意味着我是在堆栈的顶部,像这样:
set $oldpc = -1
set $oldfp = -1
set $oldsp = -1
while !($oldpc == $pc && $oldfp == $fp && $oldsp == $sp)
# ...
# code for extracting Python stack from local vars in relevant frames
# of C stack
# ...
set $oldpc = $pc
set $oldsp = $sp
set $oldfp = $fp
up-silently 1
我认为这应该是诀窍,初步检查表明它工作正常.但是,我并不过分熟悉编译器可以做的各种优化,而且我担心可能存在一些极端情况,它们可能在堆栈中间的某处有效地相同.
看起来$fp对于已经优化了帧指针的调用(例如,通过使用GCC使用-g -O3进行编译)可以为零.我也不确定是否可以依赖$pc,特别是如果发生递归调用.我希望$sp会有所不同,同时还有待处理的有效堆栈,但我有一种模糊的怀疑,即与tail recursion相关的优化可能会导致$sp相同.
任何建议将不胜感激.
具体问题:
问题1:在遗留(非Python)GDB脚本中是否有更好的方法来确定您是否处于堆栈顶部?
问题2:对于大多数或所有优化方案,我对$sp,$pc和$fp的假设是否成立?
最佳答案 所以我对问题1没有答案,但我想我可以部分回答问题2.
Tail recursion确实会重用现有的堆栈指针和帧指针.这对堆栈跟踪意味着对同一优化尾递归函数的多次调用只会在GDB中出现一次,因为(显然)堆栈指针正被重用(并且没有新的堆栈或帧指针被推送).
这似乎暗示您可以检查停止条件的$sp的先前值和当前值.不幸的是,$sp值在堆栈中间可以是相同的.当一些函数调用被优化掉时,似乎会发生这种情况.
因此,我在我的问题中提出的停止条件可能相当脆弱,即使它适用于几个真实世界的例子.