调试器开发:具体的实现方案选择
确定方案
对于业界主流的调试器实现,一般都会将其分为frontend、backend,二者通过service层进行通信,gdb、delve等等,无一例外。
本书提供的调试器实现,是从普及调试器设计实现角度出发,我们实际上提供了两个版本的调试器实现。
指令级调试器实现:它是一个基于UI层、符号层、目标层3层架构的简易调试器实现,实现思路已体现在了本节各部分描述中。本书提供的配套的完整版指令级调试器实现的源码地址为: hitzhangjie/golang-debugger-lessons/0-godbg or hitzhangjie/godbg。为了方便大家按照章节循序渐进地学习,本书也提供了按照章节组织、循序渐进地开发调试器的代码示例,其源码地址为: hitzhangjie/golang-debugger-lessons。
符号级调试器实现:最初希望从头编写或者讲指令级调试器版本演变成一个符号级调试器版本作为教学示例,但是开发工作量较大,要想达到一个可用标准的版本工作量就更大。所以最后倾向于裁剪go-delve/delve以用更少的代码、更少的时间来完成符号级调试部分,把最核心的设计实现要点呈现给大家。对应的源码地址为 hitzhangjie/tinydbg。
ps:也许我们提供的两个版本的调试器,中间可能有点“跳跃”,是的,但是这样也并不是没有好处。一个是指令级调试器,非常精简,适合读者了解底层原理;一个是裁剪后的go-delve/delve,功能相对完整,适合读者了解现代调试器应具备的方方面面。作者最终选择裁剪go-delve/delve,工作量是一方面原因,再一个就是有go-delve/delve背书读者学完后也可以真正建立起调试器开发这个领域的“信心”。
工作量评估
读者可能以为裁剪 go-delve/delve 会变得很简单,也对也不对:
如果要达到对go语言程序调试完全可用,方便大家系统性学习、测试,从0到1开发工作量本身就会很大。我们搞个极度简化版的,作为教学目的作用也不大,大家学完之后还是会认为自己是个250,只知道点皮毛,而不会建立起那种“我能行”“我可以”的信心。所以要从0到1开发一个符合作者意愿的版本,开发工作量是非常大的。从这点来说,从已经发布的版本中筛选一个版本进行裁剪,和从头开发一个相比,工作量会一点;
但是,要知道 go-delve/delve 是一个10多年来不断进行更新的项目,go语言在演进、DWARF调试信息也在演进、delve也在演进,这里的工作量“基数”摆在这,即便是像作者这样先裁剪、再重构优化也是个工作量非常大的工作。在此基础上,还要将过去几十年来调试领域的探索在delve中的实践进行系统性总结,比如 DWARF调试信息如何描述不同程序构造、状态,Mozilla RR 如何实现确定性重放,等等。
简而言之,即便是裁剪go-delve/delve,工作量也非常大。
欢迎读者朋友们下载体验,如您发现有问题,或者有更好的建议,欢迎请在本书项目issues中留言 :) 。
ps: shit! 这flag都不知立了多少次了,今天2025.2.18,过去1年《三角洲行动》上线攻坚,实在没有时间续更,今年上半年能完成吧! ps:本电子书的更新断断停停,这几年中发生了很多事情,2023.8.6开始恢复更新。今年必须完成,:muscle: 我准备用AI帮我翻译成英文版,也许可以吸引到一些同样感兴趣的贡献者。
本节小结
本节我们对调试器实现方案进行了梳理和分析,介绍了指令级调试器和符号级调试器两种实现路径,并结合实际项目(如 godbg 和裁剪版 delve)讨论了各自的设计思路、适用场景及开发工作量。通过对比可以看出,指令级调试器适合入门和理解底层原理,而符号级调试器则更贴近实际应用需求,能够帮助读者建立起开发现代调试器的信心。
在明确了实现方案和工作量评估后,接下来我们将深入探讨调试器各个核心模块的设计与实现细节,帮助读者逐步掌握调试器开发的关键技术点。