1 简介
本文汇总 Go调试工具dlv
常用命令概览
dlv attach
: 连接并调试运行中的进程dlv connect
: 终端连接无头调试服务器dlv core
: 分析核心转储文件dlv dap
: 启动DAP服务器dlv debug
: 编译并调试主包dlv exec
: 从二进制文件启动调试dlv test
: 编译调试测试二进制dlv trace
: 开始跟踪程序dlv version
: 显示版本信息
调试技巧:
break
设置断点,如break main.main
condition
设定断点条件,如condition 2 i = 3
continue
执行到下一个断点next
单步执行args
,locals
检查变量stack
查看栈帧goroutine
和goroutines
检查goroutine状态disassemble
反汇编代码step-instruction
单步执行汇编regs
查看寄存器状态print
检查内存地址数据quit
退出调试
dlv
提供深入调试支持,包括汇编和goroutine分析,助于复杂问题定位。
2 golang调试 常用指令
附加到正在运行的进程并开始调试。
dlv attach
使用终端客户端连接到无头调试服务器。
dlv connect
检查核心转储
dlv core
启动通过调试适配器协议 (DAP) 进行通信的无头 TCP 服务器。
dlv dap
编译并开始调试当前目录或指定包中的主包。
dlv debug
执行预编译的二进制文件,并开始调试会话。
dlv exec
重播 rr 跟踪。
dlv replay
已弃用的命令。请改用“调试”。
dlv run
编译测试二进制文件并开始调试程序。
dlv test
编译并开始跟踪程序。
dlv trace
打印版本。
dlv version
关于日志记录标志的帮助
dlv log
关于--backend标志的帮助
dlv backend
查看全部包级别的变量。 因为最终目标程序可能含有大量全局变量。
vars main
在main函数入口设置一个 断点
break main.main
程序继续运行到下一个断点。
continue
指令单步执行进入 main() 函数
next
进入函数后
args // 查看局部变量
locals //查看全局变量
3 调试的组合指令:调试循环条件,和例程 状态
break 和 condition 组合命令 用于在函数循环 内部设置条件断点
比如 在 main.go 10 行设置断点
break main.go 10
Breakpoint 2 set at main.main
为断点2 设置条件 当 i = 3 生效
condition 2 i = 3
然后 continue 运行到 该条件,查看输出。
如果发现循环变量i为3时,切片的前3个元素已经正确初始化,那么可以通过 stack 查看当前函数执行的栈帧信息
stack
0 0x000000000084d1e7 in main.main
at /main.go:49
1 0x00000000001b1428 in runtime.main
at /go/src/runtime/proc.go:250
2 0x00000000001ddac1 in runtime.goexit
at /go/src/runtime/asm_amd64.s:1594
或者通过 goroutine 和 goroutines 查看当前 goroutine 相关信息
goroutine
Thread 8244 at d:/gospace/strtech/main.go:49
Goroutine 1:
Runtime: /main.go:49 main.main (0x84d1e7)
User: /main.go:49 main.main (0x84d1e7)
Go: <autogenerated>:1 runtime.newproc (0x1dfeec)
Start: /go/src/runtime/proc.go:145 runtime.main (0x1b1260)
(dlv) goroutines
* Goroutine 1 - User: /main.go:49 main.main (0x84d1e7) (thread 8244)
Goroutine 2 - User: /go/src/runtime/proc.go:364 runtime.gopark (0x1b181d) [force gc (idle)]
Goroutine 3 - User: /go/src/runtime/proc.go:364 runtime.gopark (0x1b181d) [GC sweep wait]
...
查看当前代码 ,命令(在命令行界面中)将具有以下结果:
list main.main
(dlv) list main.main
Showing ./goid_stored/main.go:116 (PC: 0xb2b76a)
111: }(i)
112: }
113: wg.Wait()
114: }
115:
116: func main() {
117: fmt.Printf("gls:%#v \n", gls)
118: UsageGls()
119: }
4 调试时反汇编单步
disassemble 反汇编计数查看 main函数对应的汇编代码。
Sending output to pager...
TEXT main.main(SB) /main.go
main.go:41 0x84d100 4c8d6424e8
lea r12, ptr [rsp-0x18]
main.go:41 0x84d105 4d3b6610
cmp r12, qword ptr [r14+0x10]
main.go:41 0x84d109 0f86ed000000
jbe 0x84d1fc
step-instruction 单步执行汇编指令的命令。
使用break 设置断开,continue到断点停下,或继续
查看全部寄存器状态
(div) regs
Rip = 0x000000000084d1e7
Rsp = 0x000000c0004c3ee0
Rax = 0x0000000000c93100
Rbx = 0x0000000000000006
Rcx = 0x0000000000000000
Rdx = 0x000000c000536230
Rsi = 0x0000000000000000
Rdi = 0x000000c00033cb00
Rbp = 0x000000c0004c3f70
R8 = 0x0000000000000000
R9 = 0x000000000000034e
R10 = 0x0000000000000000
R11 = 0x0000000000000246
R12 = 0x000000c0004c3ac8
R13 = 0x0000000000000000
R14 = 0x000000c000056000
R15 = 0x0000000000000020
Rflags = 0x0000000000000204 [PF IF IOPL=0]
Cs = 0x0000000000000033
Fs = 0x0000000000000053
Gs = 0x000000000000002b
由此推断程序内部定义的 数据地址,然后使用print 可以查看 该地址的数据
print *(*[5]byte)
退出调试
quit
5 小结
本文简单介绍go程序调试的方式,相比c程序 gcc工具 和 python的pdb工具,go提供了更多层级的工具,比如内置的cgo汇编程序,伪汇编代码,应用级的dlv工具等等,对于在某些场景的深度问题定位和功能开发有帮助。