godbg 介绍
Start a new project, the debugger on linux platform for go.
This project is inspired by dlv
github地址
背景
没想到这个项目最终还是沦为为一个玩具。初次有这个想法是因为发现 gdb
调试golang
代码是可以进入runtime的指令,而dlv
却不可以。例如像map
这种的初始化
s := make(map[int]string, 20)
主要是dlv
将runtime
的代码都skip
掉了,表示对golanger
无需关心底层的逻辑,只需要关心自己编写的代码即可。
先看一下效果
实现
代码本身分为5个步骤,代码是在main.go
- 获取生成含.debug可执行文件的路径
- 编译创建可执行文件
- 分析可执行文件里面的_zdebug的字段,以便后续调试使用
- 执行可执行文件,并且ptrace
- 处理用户所有的输入
注意两点:
1.本身
linux
里面并没有多线程的概念,都是task
;没有做上下文切换,所以暂时不支持多协程,全局唯一的pid
;2.为了
ptrace
生效,需要将协程和task
一一绑定,runtime.LockOSThread()
;
前两个步骤没什么好讲的,主要从分析二进制文件开始
分析
分为两个部分,第一个部分是line
和info
两个节区的结合,记录出行信息的表,对应每一行汇编是源码中哪一行生成的,主要是为后续list
和breakpoint
服务的 ;第二部分是FrameSection
,主要是为打印变量时候,算调用栈帧用的 ;
line
和info
识别dwarf
里面compileunit
的tag
,每个编译单元都是记录当前单元的所有行信息,一个编译单元可以理解为一个package
line
和info
识别dwarf
里面SubProgram
的tag
,这个可以理解是每一个函数包含哪些指令范围,这样在程序运行时候拿到pc
寄存器值进行反查就能知道当前运行到哪一个函数了line
和info
识别dwarf
里面的Variable
的tag,是为了找到局部变量的定义、名称、结构以及数据内存地址等等frame
识别里面的CIE
(全称:CommonInfomationEntry
)和FDE
(全称FrameDescriptionEntry
,FDE
对应一定指向一个公用的CIE
),在程序运行时可以按照CIE
和FDE
的规则拿到CFA
的计算规则
处理
断点:
设置断点其实没有什么很深的东西,主要是利用行信息表查出对应的内存块,ptrace
将需要下断点的地方内存指令换成软断点0xcc
;当进程执行到0xcc
会触发一个trap
停止执行后续指令;
这个会出现一个问题,就是当期望恢复断点继续执行的时候,由于破坏了原来的指令则无法继续continue
,需要将指令暂时(注意是暂时,如果不是暂时那么断点就失效了)恢复,并且pc
寄存器数值减少一个指令重新执行;
还有就是golang
是具有gc
高级特效的语言,许多地方增加了checkpoint
,例如每次函数调用的时候,都会去check
当前栈是否需要扩容,如果你的断点下在了checkpoint
的地方,那么很有可能会在同一行代码(checkpoint
也对应用户代码的行表)多次触发,看起来就像是continue
一直在同一行卡住,解决这个问题需要主要一下PrologueEnd
(编译器生成debug信息提供的)
断点列表、显示源码的原理都需要记载在内存里面对应关系就可以做到了;
继续:
continue
上面讲过了,需要将断点暂时恢复一下;而next
和stepin
,正常来讲应该是内部断点的实现方式,这里只用到了一个简单逻辑(暴露玩具的本质);next
就是在当前pc
值(如果当前是断点,应该是pc
-1)过后不停地PtraceSingleStep
直到发现 1.文件名或者行数变了 2.碰到别的断点 3.如果当前是函数调用记录一个calling
状态继续PtraceSingleStep
直到stepout
;
列举:
list
原理跟breakpoint
类似
重启:
原理就是将程序原来的kill
掉,重新执行一个
反汇编:
就是上面根据SubProgram
讲到的pc
找到对应的指令范围,然后反汇编就可以了,注意断点的部分需要特殊处理(因为已经被替换掉了,否则反汇编会报错)
变量:
核心是要计算出来cfa
(callframeaddress
),http://dwarfstd.org/doc/Dwarf3.pdf大概在122页左右;
计算过程相当繁琐,例如这样能发现delve
某些地方解析也是不对的,https://github.com/go-delve/delve/pull/1679;
参考
https://www.cnblogs.com/tsecer/p/10485670.html 其实没有完全看懂
http://ucla.jamesyxu.com/?p=231 也是完全没有看懂
https://www.corsix.org/content/cfa-rsp-x86-64 又是完全看不懂
http://www.cs.uwm.edu/classes/cs315/Bacon/Lecture/HTML/ch10s07.html 好像看懂了
http://dwarfstd.org/doc/Dwarf3.pdf 这本书很重要,结合dlv才能看得懂