我正在编写调试器,当前正在尝试使多个线程同时命中断点时可靠地工作。据我所知,大多数调试器通过将指令的第一个字节替换为0xCC来实现断点,这也是我目前的做法。但是,我看不到任何恢复原始字节的方法,同时仍然能够停止即将达到该断点的其他线程,而不会暂停所有正在运行的线程。是否有人知道通常如何实现?停止所有线程真的是唯一的解决方案吗?
答案 0 :(得分:6)
在所有线程停止的情况下,您恢复该字节,对一条指令执行仅一个线程的操作,重新创建断点,然后恢复所有线程的执行。如果使用有限的硬件调试寄存器之一,则可以使用RF暂时忽略一条指令的断点(请参见下文)。
在调试过程中仅停止一个线程,而其他线程保持运行,这只是自找麻烦。考虑一下在第一次停止时如何处理相同或不同的断点?还是发生异常?
在Intel CPU上,可以在EFLAGS寄存器中设置一个标志(恢复标志,位16)。设置此选项后,将允许在不触发断点的情况下执行第一条指令,并且在使用硬件断点(而非断点指令)时将起作用。
第3卷第17章(《系统编程指南》,可用于download from Intel)包含有关Intel IA-32 CPU调试功能的许多详细信息。
答案 1 :(得分:2)
我知道暂时暂停所有线程是解决该问题的常用方法。我在问是否有避免这种情况的方法。
第一个达到您的int3
软件断点的线程是您想要要停止的线程。
如果在您将其修补回正确的内容之前遇到了其他线程,请在删除软件断点后恢复这些线程。 ( x86具有一致的指令缓存,因此您可以安全地修改单个代码字节,而其他内核无需运行fence / isync
指令以将其指令缓存与数据缓存重新同步。这是其他ISA上更难解决的问题。)
其他线程可能会遇到小的中断。
当然,如果用户在关键部分(持有锁)中放置一个断点,或者单步进入关键部分,则其他线程将阻塞该断点。对于不是lock-free (in the computer science sense)的无锁代码,这也是可能的。
在其他线程正在运行时检查和修改内存可能存在风险。在尝试读取或修改内存之前,另一个线程可能会取消映射内存。只要调试器本身不会崩溃,就由用户决定他们要制造多少混乱。