断点如何在C ++代码中工作?

时间:2010-10-12 14:01:33

标签: c++ debugging breakpoints

断点如何在C ++代码中运行?在编译代码时,它们是否在某些汇编指令之间插入了特殊指令?或者还有其他的东西吗?此外,如何实现代码逐步执行?与断点相同......?

4 个答案:

答案 0 :(得分:37)

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

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

  • 在所需位置插入一字节INT3指令
  • 等到断点异常命中
  • 将异常地址与断点列表进行比较以确定哪一个
  • 执行断点操作
  • 将INT3替换为原始字节,并将调试过程切换为跟踪模式(逐步执行CPU指令)
  • 继续调试过程
  • 立即捕获跟踪异常 - 指令已执行
  • 放回INT3

观察点可以以类似的方式实现,但是您可以将监视变量所在的内存页面设置为只读,或者进入无访问模式,而不是INT3,等待分段异常。

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

当你只是将地址加载到某个寄存器时,某些CPU也有硬件断点支持。

答案 1 :(得分:8)

根据technochakra.com上的this blog entry,你是对的:

  

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

我不确定如何执行下一条指令的步骤。但是,文章继续补充:

  

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

但是,这只会用于“运行到当前行选项”。

答案 2 :(得分:4)

单步执行是在(汇编程序)代码级而不是在C ++级实现的。调试器知道如何将C ++代码行映射到代码地址。

有不同的实现。有些CPU支持使用断点寄存器进行调试。当执行到达断点寄存器中的地址时,CPU将执行断点异常。

另一种方法是使用特殊指令对执行时的代码进行修补,最好是单字节指令。在x86系统中,通常是int 3。

第一种方法允许ROM中的断点,第二种方法允许同时有更多的断点。

答案 3 :(得分:1)

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

当处理器尝试执行这些特殊值之一时,会引发异常,调试器捕获它并检查异常的地址是否在其断点列表中。 如果是,则调用调试器并为用户提供交互机会。 如果它不是,那么异常是由于程序从一开始就存在的,并且调试器允许异常“传递”到可能存在的任何错误处理程序。

另请注意,调试自修改代码可能会失败,因为调试器会暂时修改代码本身。 (当然,没有人会写自我修改,现在他们会吗?&gt ;; - )

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