抱歉回晚了 这个文章挺好 不过我建议是否可以在开头简单介绍一下inferior call的作用 举几个小例子什么的 是否会更清晰一些 让读者明白这是一个什么功能? 2011/6/25 Yao Qi <qiyaoltc@xxxxxxxxx>: > 决定写一系列文章,关于调试器内部机理的,名字叫做Debugger Not In Depth。为了以后方便保存,我都是用latex写的,tex > -> html -> txt > > 今天这篇是关于inferior call,欢迎意见。 > > > 1 inferior call > > inferior call 可以被简单地理解为"调试器在当前的堆栈上,主动调用被调试程序的函数 > ,并且正确的得到函数的返回值(这一句好像有点多余)"。inferior call理解起来,远 > 比我们想象的简单,这个功能在我们的调试过程经常会被用到。比如在调试GCC rtl的时候 > ,我们经常在GDB中用 p print_rtx (rtx),来打印rtx 的内容。这就是一个inferior > call。我们来仔细想一下,第一,函数print_rtx (rtx)是在被调试程序那里执行的,而不 > 是在GDB这里;第二,参数rtx是GDB传给被调试程序的函数;第三,GDB能够正确得到 > print_rtx (rtx)这个函数的返回值;最后,被调试程序在执行完成print_rtx (rtx)后, > 仍然停在原来的位置,程序的状态没有任何变化。上边这几点,就是调试器为了实现 > inferior call所需要做到的,或者,需要保证的。 > 下来我们想想,调试器应该怎样保证上边四条, > > 1. 第一,函数是在被调试程序那里实行的。这个容易实现,调试器需要找到函数的入口 > 地址,把寄存器pc设置为函数的入口地址,然后用ptrace让被调试程序继续执行( > PTRACE_CONT)就可以了。 > 2. 第二,调试器传递参数给调用的函数。这个相对麻烦一些,因为调试器需要知道当前 > 被调试程序所在系统的函数调用规则(function call convention),也就是规定, > 每一个函数的参数,应该如何传递给被调用函数。这个也是系统ABI的一部分。简单点 > 说,如果函数有四个参数,这个四个参数在函数调用的时候,应该在什么位置,是在 > 寄存器里边还是在堆栈上?调试器在知道这些规范以后,必须按照规范把被调用函数 > 需要的参数,放在规定的地方。 > 3. 第三, 调试器需要得到函数调用的返回值。函数调用的返回值所在的位置同样规范在 > 系统的ABI中。函数的返回值是在寄存器里边,还是堆栈上?调试器根据这个规范,从 > 规定的位置,得到函数的返回值。 > 4. 第四,调试器需要函数调用完成后,程序依然停在之前的位置,没有任何变化。被调 > 用的函数是不知道它被调用是一般的正常调用,还是调试器用inferior call。所以, > 调试器在程序返回地址上,做了一些手脚。一般来说,程序的返回地址应该是调用这 > 个函数的指令的下一条指令。在inferior call,调试器会把函数调用的返回地址设置 > 为一个特殊的地址,并且在这个地址上设置一个断点。这样,当程序返回的时候,调 > 试器就能够保证程序执行完成后,程序就停下来。 > > 这样看来,只要能够对系统的ABI有个全面的了解,实现inferior call应该没有什么困难 > 。下来我们看看GDB里边,是怎么实现 inferior call的, > > [这里还有一个表格,帖进来就乱了,参见附件。] > > -- > Yao Qi <qiyaoltc AT gmail DOT com> > http://sites.google.com/site/duewayqi/ >