我目前正在为脚本虚拟机编写调试器。脚本的编译器生成调试信息,例如函数入口点、变量范围、名称、指令到行的映射等。
但是,并且遇到了跨步问题。
现在,我有以下内容: 1. 查找当前 IP 2. 从中获取源代码行 3. 获取下一个(有效的)源代码行 4. 获取下一个有效源代码行开始的 IP 5. 设置一个临时该指令处的断点
或者:如果下一个源代码行不再属于同一个函数,则在返回地址之后的下一个有效源代码行设置临时断点。
到目前为止,这运作良好。但是,我似乎在跳跃方面遇到了问题。
例如,采用以下代码:
n = 5; // Line A
if(n == 5) // Line B
{
foo(); // Line C
}
else
{
bar(); // Line D
--n;
}
鉴于此代码,如果我在 B 行并选择跳过,则为断点确定的 IP 将在 C 行。但是,如果条件跳转的计算结果为假,则应将其放在 D 行。因为其中,跨步不会在预期位置停止(或者更确切地说,它根本不会停止)。
关于这个特定问题的调试器实现的信息似乎很少。但是,我发现了这个。虽然这是针对 Windows 上的本机调试器,但该理论仍然适用。
尽管作者似乎也没有考虑过这个问题,在“实施跨步”一节中,他说:
1. The UI-threads calls CDebuggerCore::ResumeDebugging with EResumeFlag set to StepOver. This tells the debugger thread (having the debugger-loop) to put IBP on next line. 2. The debugger-thread locates next executable line and address (0x41141e), it places an IBP on that location. 3. It calls then ContinueDebugEvent, which tells the OS to continue running debuggee. 4. The BP is now hit, it passes through EXCEPTION_BREAKPOINT and reaches at EXCEPTION_SINGLE_STEP. Both these steps are same, including instruction reversal, EIP reduction etc. 5. It again calls HaltDebugging, which in turn, awaits user input.
再次:
调试器线程定位下一个可执行行和地址(0x41141e),它在该位置放置一个 IBP。
不过,在涉及跳跃的情况下,这种说法似乎并不成立。
有没有人遇到过这个问题?如果是这样,您对如何解决这个问题有任何提示吗?