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)  

主要是dlvruntime的代码都skip掉了,表示对golanger无需关心底层的逻辑,只需要关心自己编写的代码即可。

先看一下效果

display.gif

实现

代码本身分为5个步骤,代码是在main.go

  1. 获取生成含.debug可执行文件的路径
  2. 编译创建可执行文件
  3. 分析可执行文件里面的_zdebug的字段,以便后续调试使用
  4. 执行可执行文件,并且ptrace
  5. 处理用户所有的输入

注意两点:

1.本身linux里面并没有多线程的概念,都是task;没有做上下文切换,所以暂时不支持多协程,全局唯一的pid

2.为了ptrace生效,需要将协程和task一一绑定,runtime.LockOSThread()

前两个步骤没什么好讲的,主要从分析二进制文件开始

分析

分为两个部分,第一个部分是lineinfo两个节区的结合,记录出行信息的表,对应每一行汇编是源码中哪一行生成的,主要是为后续listbreakpoint服务的 ;第二部分是FrameSection,主要是为打印变量时候,算调用栈帧用的 ;

  1. lineinfo识别dwarf里面compileunittag,每个编译单元都是记录当前单元的所有行信息,一个编译单元可以理解为一个package
  2. lineinfo识别dwarf里面SubProgramtag,这个可以理解是每一个函数包含哪些指令范围,这样在程序运行时候拿到pc寄存器值进行反查就能知道当前运行到哪一个函数了
  3. lineinfo识别dwarf里面的Variable的tag,是为了找到局部变量的定义、名称、结构以及数据内存地址等等
  4. frame识别里面的CIE(全称:CommonInfomationEntry)和FDE(全称FrameDescriptionEntryFDE对应一定指向一个公用的CIE),在程序运行时可以按照CIEFDE的规则拿到CFA的计算规则

处理

断点

设置断点其实没有什么很深的东西,主要是利用行信息表查出对应的内存块,ptrace将需要下断点的地方内存指令换成软断点0xcc;当进程执行到0xcc会触发一个trap停止执行后续指令;

这个会出现一个问题,就是当期望恢复断点继续执行的时候,由于破坏了原来的指令则无法继续continue,需要将指令暂时(注意是暂时,如果不是暂时那么断点就失效了)恢复,并且pc寄存器数值减少一个指令重新执行;

还有就是golang是具有gc高级特效的语言,许多地方增加了checkpoint,例如每次函数调用的时候,都会去check当前栈是否需要扩容,如果你的断点下在了checkpoint的地方,那么很有可能会在同一行代码(checkpoint也对应用户代码的行表)多次触发,看起来就像是continue一直在同一行卡住,解决这个问题需要主要一下PrologueEnd(编译器生成debug信息提供的)

断点列表、显示源码的原理都需要记载在内存里面对应关系就可以做到了;

继续:

continue上面讲过了,需要将断点暂时恢复一下;而nextstepin,正常来讲应该是内部断点的实现方式,这里只用到了一个简单逻辑(暴露玩具的本质);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才能看得懂