断点在C++;密码? 如何断点在C++代码中工作?在编译代码时,它们是插入到某些汇编指令之间的特殊指令吗?或者还有其他的东西吗?另外,代码是如何实现的?与断点相同…?

断点在C++;密码? 如何断点在C++代码中工作?在编译代码时,它们是插入到某些汇编指令之间的特殊指令吗?或者还有其他的东西吗?另外,代码是如何实现的?与断点相同…?,c++,debugging,breakpoints,C++,Debugging,Breakpoints,根据technochakra.com上的说法,您是正确的: 软件断点通过在被调试的程序中插入特殊指令来工作。英特尔平台上的这条特殊指令是“int 3”。执行时,它调用调试器的异常处理程序 不过,我不确定如何执行下一条指令。不过,本文接着补充道: 出于实际原因,在添加或删除断点时要求重新编译是不明智的。调试器会在内存中更改加载的可执行文件映像,并在运行时插入“int 3”指令 但是,这只适用于“Runto to RealLayObjyPosivices”。在C++(C++)级(汇编)代码级实现。单

根据technochakra.com上的说法,您是正确的:

软件断点通过在被调试的程序中插入特殊指令来工作。英特尔平台上的这条特殊指令是“int 3”。执行时,它调用调试器的异常处理程序

不过,我不确定如何执行下一条指令。不过,本文接着补充道:

出于实际原因,在添加或删除断点时要求重新编译是不明智的。调试器会在内存中更改加载的可执行文件映像,并在运行时插入“int 3”指令


<>但是,这只适用于“Runto to RealLayObjyPosivices”。

在C++(C++)级(汇编)代码级实现。单步执行器知道如何将C++代码行映射到代码地址。 有不同的实现。有一些CPU支持使用断点寄存器进行调试。当执行到达断点寄存器中的地址时,CPU执行断点异常

另一种方法是在执行时使用一条特殊指令(最多一条单字节指令)修补代码


第一种方法允许在ROM中使用断点,第二种方法允许同时使用更多断点。

这在很大程度上取决于CPU和调试器

例如,x86 CPU上可能的解决方案之一:

  • 在所需位置插入一个字节的INT3指令
  • 等待断点异常出现
  • 将异常地址与断点列表进行比较,以确定是哪个断点
  • 执行断点操作
  • 将INT3替换为原始字节,并将调试后的进程切换到跟踪模式(逐步执行CPU指令)
  • 继续调试进程
  • 立即捕获跟踪异常-指令已执行
  • 把INT3放回去
监视点可以以类似的方式实现,但是您可以将被监视变量所在的内存页设置为只读或无访问模式,并等待分段异常

单步执行程序集也可以使用跟踪模式完成。单步执行源代码行也可以根据调试数据将断点放在下一条指令上完成

另外,当您只需将地址加载到某个寄存器中时,某些CPU还支持硬件断点。

AFAIK允许无限数量断点的所有调试器(对于任何编译语言)都使用一种变体,即用特殊值替换要断点的指令(如上所述)并保留这些值放置位置的列表

当处理器尝试执行其中一个特殊值时,将引发异常,调试器将捕获它并检查异常地址是否在其断点列表中。 如果是,调试器将被调用,用户将有机会进行交互。 如果不是,则异常是由于程序从一开始就存在的某些内容造成的,调试器允许异常“传递”到可能存在的任何错误处理程序

还要注意,调试自修改代码可能会失败,因为调试器会瞬间修改代码本身。(当然,没有人会编写自修改代码,是吗?>;-)


出于这些原因,在终止调试会话之前,让调试器有机会删除它设置的所有断点是很重要的。

在进程的运行时,调试器会动态地注入断点。我希望这也会影响代码的执行。但我不是100%肯定我对此很感兴趣。@gablin,你介意我们把问题编辑成关于“本机”代码而不是“C++”的问题吗?这几乎是同一个问题,更好地反映了你的答案。@StevenFisher:不,请继续。=)“在终止调试会话之前,让调试器有机会删除它设置的所有断点,这一点很重要。"不——调试器只修改内存中的映像,而不是磁盘上的原始文件。事实上,如果您结束调试器并让程序继续运行,它必须先删除内存中的断点,然后再让程序运行。如果您的程序代码大于内存,怎么办?可能gdb使用带有MAP_PRIVATE的mmap来防止断点碰到disk…我不明白“用原始字节替换INT3”部分…为什么我们需要这样做?从断点恢复后,您需要在停止的位置执行CPU指令,但您损坏了它-将第一个字节替换为INT3操作码。因此,您需要恢复它,让CPU处理该指令,然后将INT3放回-所以下次执行此指令时,您会再次中断不,我明白了。这就是调试器在代码中“注入”断点的方式。谢谢!引用操作码
0xCC
,因此如果我们在调试器上使用操作码的当前示例,将采用指令
B0 61
MOV AL,61h
),存储第一个字节(
B0
)并将其替换为
CC
生成操作码
CC 61
。当CPU读取此指令时,程序中断并跳转到调试器中。其余为历史记录。。。↑