Debugging 调试器实现-跳过问题

Debugging 调试器实现-跳过问题,debugging,breakpoints,Debugging,Breakpoints,我目前正在为脚本虚拟机编写调试器。 脚本的编译器生成调试信息,如函数入口点、变量范围、名称、指令到行的映射等 然而,和遇到了一个问题与步骤 现在,我有以下几点: 1.查找当前IP地址 2.从中获取源代码行 3.获取下一个(有效)源代码行 4.获取下一个有效源行开始的IP 5.在该指令上设置一个临时断点 或者:如果下一个源代码行不再属于同一个函数,请在返回地址后的下一个有效源代码行设置临时断点 到目前为止,这种方法效果良好。然而,我似乎有跳跃的问题 例如,以以下代码为例: n = 5; // Li

我目前正在为脚本虚拟机编写调试器。 脚本的编译器生成调试信息,如函数入口点、变量范围、名称、指令到行的映射等

然而,和遇到了一个问题与步骤

现在,我有以下几点: 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行。但是,如果条件跳转的计算结果为false,则应将其放置在D行。因此,跳过不会在预期位置停止(或者更确切地说,它根本不会停止)

关于这个特定问题的调试器实现的信息似乎很少。然而,我发现。虽然这适用于Windows上的本机调试器,但该理论仍然适用

作者似乎也没有在“实施步骤”一节中考虑这个问题,正如他所说:

再次:

调试器线程定位下一个可执行行和地址(0x41141e),它在该位置放置一个IBP。

不过,在涉及跳跃的情况下,这种说法似乎并不成立


以前有人遇到过这个问题吗?如果是这样的话,您对如何解决这个问题有什么建议吗?

好的,因为这似乎有点像黑魔法,在这种情况下,最明智的做法是枚举下一行开始的指令(或指令流结束+1),然后在再次停止之前运行那么多指令


唯一的问题是我必须跟踪堆栈帧,以防调用被执行;这些指令应该在没有计数的情况下运行,以防跳转。

因为当搜索“调试器实现跳转”时,这个线程首先出现在Google中。我将分享关于x86体系结构的经验

首先实现步骤:这基本上是单步执行指令并检查与当前EIP对应的行是否更改。(您可以使用DIA SDK或读取dwarf调试数据来查找EIP的当前行)

在单步执行的情况下:在单步执行下一条指令之前,需要检查当前指令是否为调用指令。如果它是一条CALL指令,那么在它后面的指令上放置一个临时断点,并继续执行,直到执行停止(然后删除它)。在这种情况下,您实际上在程序集级别以及源代码中跳过了函数调用

不需要管理堆栈帧(除非需要处理单行递归函数)。这种类比也适用于其他体系结构

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.