在多线程代码中实现安全恢复的断点

Implementing breakpoints that resume safely in multithreaded code

我正在编写一个调试器,目前正在尝试让断点在多个线程同时命中它们时可靠地工作。据我所知,大多数调试器通过将指令的第一个字节替换为 0xCC 来实现断点,我目前也是这样做的。但是,我看不到有任何方法可以恢复原始字节,同时仍然能够停止即将到达该断点的其他线程,而无需停止所有 运行 线程。有没有人知道通常是如何实现的?停止所有线程真的是唯一的解决方案吗?

在所有线程停止的情况下,恢复该字节,步骤 一个线程只 一条指令,重新创建断点,然后恢复所有线程的执行。如果您使用的是有限的硬件调试寄存器之一,您可以使用 RF 暂时忽略一条指令的断点(见下文)。

在调试期间只停止一个线程,而其他线程保持 运行,这只是自找麻烦。考虑一下您在第一次停止时如何处理遇到相同或不同的断点?或者如果发生异常?

在 Intel CPU 上,可以在 EFLAGS 寄存器中设置一个标志(恢复标志,第 16 位)。设置后,这将允许执行第一条指令而不触发断点,并且在使用硬件断点(而不是断点指令)时将起作用。

第 3 卷第 17 章(系统编程指南,可用于 download from Intel)包含有关 Intel IA-32 CPU 调试功能的大量详细信息。

I'm aware that temporarily pausing all threads is the common way to solve that. I'm asking if there's any way to avoid doing that.

第一个到达您的 int3 软件断点的线程是您想要 停止的线程。

如果其他线程在您将其修补回正确内容之前遇到它,请在删除软件断点后恢复这些线程。 (x86 具有一致的指令缓存,因此您可以安全地修改单个代码字节,而无需其他内核需要 运行 栅栏/isync 指令来重新同步它们指令缓存与数据缓存。这在其他 ISA 上是一个更难的问题。)

其他线程可以看到一个小中断。


当然,如果用户在临界区内放置断点(持有锁),或单步进入临界区,其他线程将阻塞。这对于不是 lock-free (in the computer science sense).

的无锁代码也是可能的

在其他线程正在 运行 时检查和修改内存存在潜在风险。另一个线程可能会在您尝试读取或修改内存之前取消映射内存。不过,只要您的调试器本身不崩溃,用户想要制造多少混乱就取决于他们。