我知道可执行文件中的software breakpoints可以通过用另一个替换所需位置的汇编器指令来工作,这会导致中断。因此,调试器可以在此处完全停止执行,并将此指令替换为原始指令,并询问用户下一步操作或调用某些命令等。
但是这样的可执行文件的代码不被其他程序使用,并且在内存中只有一个副本。 软件断点如何与共享库一起工作?例如,如果我在C库的某个内部函数中设置了一个软件断点,它是如何工作的(据我所知它只有一个副本用于所有应用程序,所以我们不能只替换它中的一些指令)?是否有为此目的的“软件断点”技术?
答案 0 :(得分:8)
Linux的答案是Linux内核实现了COW(Copy-on-Write):如果写入共享库的代码,内核首先会创建共享页面的私有副本,重新映射内部虚拟内存仅用于该过程到副本,并允许应用程序继续。这对用户态应用程序完全不可见,完全在内核中完成。
因此,在第一次将软件断点放入共享库之前,其代码确实是 shared ;但之后,不是。此后,该过程使用脏的私人副本进行操作。
这个内核魔术允许调试器不会导致其他所有应用程序突然停止。
然而,在诸如VxWorks之类的操作系统上,这是不可能的。根据个人经验,当我为VxWorks实现GDB远程调试服务器时,我不得不禁止我的用户在semTake()
和semGive()
(操作系统信号量函数)中单步执行,因为a)GDB在其源级单步实现中使用软件断点; b)VxWorks使用信号量来保护其断点列表......
令人不快的结果是一个中断风暴,其中一个断点会导致一个中断,并且在这个中断中会有另一个中断,另一个和另一个在一个不可避免的链中甚至阻止Ctrl-Z。唯一的出路就是关掉电机。