这是一个令人惊讶的非平凡工作量,包含许多设计决策和功能权衡。考虑:您正在调试。被调试者被挂起。它在内存中的图像包含源的目标代码,以及对象的二进制布局、堆、堆栈。调试器正在检查其内存映像。它已将有关符号、类型、地址映射、pc (ip) 的调试信息加载到源对应关系。它显示调用堆栈、数据值。
现在,您希望允许对代码和/或数据进行一组特定的可能编辑,而无需停止调试器并重新启动。最简单的可能是将一行代码更改为另一行。也许你重新编译那个文件或者只是那个函数或者只是那个行。现在,您必须修补被调试对象映像,以便在您下次跨过它或以其他方式运行它时执行该新代码行。这在引擎盖下是如何工作的?如果代码大于它替换的代码行会发生什么?它如何与编译器优化交互?也许您只能在专门为 EnC 调试目标编译的上执行此操作。也许您会限制可能的站点,它对 EnC 是合法的。考虑一下:如果您在调用堆栈中暂停的函数中编辑一行代码会发生什么。当代码返回那里时,它是运行函数的原始版本还是运行您的行更改的版本?如果是原始版本,该来源来自哪里?
您可以添加或删除本地人吗?这对挂起帧的调用堆栈有什么影响?目前的功能?
你能改变函数签名吗?向对象添加字段/从对象中删除字段?现有的实例呢?挂起的析构函数或终结器呢?等等。
要使任何类型的可用 EnC 工作,需要注意很多很多功能细节。然后有许多跨工具集成问题需要提供基础设施来为 EnC 供电。特别是,它有助于拥有某种调试信息存储库,可以将编辑前和编辑后的调试信息和目标代码提供给调试器。对于 C++,PDB 中可增量更新的调试信息会有所帮助。增量链接也可能有所帮助。
从 MS 生态系统到 GCC 生态系统,很容易想象 GDB/GCC/binutils 之间的复杂性和集成问题、无数的目标、一些需要的特定于 EnC 的目标抽象,以及“很好但无关紧要”的性质EnC,这就是为什么它还没有出现在 GDB/GCC 中的原因。
快乐黑客!
(ps 看看 Smalltalk-80 交互式编程环境可以做什么是很有启发性和启发性的。在 St80 中没有“重新启动”的概念——如果您编辑了图像的任何方面,图像及其对象内存始终是活动的。类你仍然必须继续运行。在这样的环境中,对象版本控制不是假设的。)