On 2011-6-25 22:00, Yao Qi wrote:
决定写一系列文章,关于调试器内部机理的,名字叫做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的, [这里还有一个表格,帖进来就乱了,参见附件。]
牛,全部概念我都理解了,厉害! 嘿嘿,你为什么latex变成html之后,再变成txt???奇怪。