调试器中的断点如何工作?

Sha*_*han 33 compiler-construction debugging gdb breakpoints

断点是大多数流行调试器(如GDB)支持的最酷功能之一.但断点如何运作?编译器为实现断点做了哪些代码修改?是否有用于支持断点的特殊硬件功能?

dbr*_*nk0 24

编译器不需要以任何方式"修改"二进制文件以支持断点.但重要的是:

  • 编译器在可执行文件中包含足够的信息(不在代码本身中,而是在同一文件的特殊部分中),因此调试器可以将用户想要调试的源与机器代码相关联.调试器需要知道的一个典型的事情就是能够设置断点(除非你直接指定地址),是程序函数和源代码行开始的位置(在机器代码中).
  • 编译器没有以任何方式优化代码,这使得无法关联源代码和机器代码.通常,您需要未经优化的调试代码或仅执行精心选择的优化的代码.

然后,其余的工作由调试器本身执行.

  1. 软件断点不一定需要特殊的硬件功能.这里的调试器依赖于修改原始二进制文件(它的副本加载到内存中).设置断点时,调试器会在断点位置放置特殊指令.这个特殊指令需要以某种方式让调试器检测它(此特殊指令)何时执行.这可能是一些导致某种中断/异常的指令,调试器可以挂钩,或者是一些处理调试单元控制的指令.如果这在某些操作系统下运行,那么操作系统需要支持修改正在运行的程序(类似于ptrace poke/peek).SW断点的缺点是调试器需要能够修改正在运行的程序,如果程序是从某种只读存储器运行的话(在嵌入式世界中很常见),这是不可能的.
  2. 硬件断点(需要CPU支持)在不修改程序二进制的情况下实现类似的行为.这是特定于CPU的,但通常它允许您至少定义执行应该到达断点的程序地址.CPU不断地将当前PC与这些断点地址进行比较,一旦条件匹配,它就会中断执行.这些断点的数量总是有限的.