使用delve调试go程序
Table of Contents
1. 什么是delve?
调试是开发过程中非常常见的流程,目前go语言支持的调试工具除了最常见的GDB和LLVM系列的LLDB以外,还有专为go语言设计的delve。与另外两个通用调试器相比,delve可以更好地感知go routine和go的栈。
1.1. 安装
$ git clone https://github.com/go-delve/delve $ cd delve $ go install github.com/go-delve/delve/cmd/dlv
注意,如果你的go版本在1.21以下,最新版本的delve可能会无法安装,可以使用delve1.22.1及之前的版本。
安装之后,尝试下dlv命令是否已经存在,存在就是安装成功了。
2. 调试go程序
2.1. 进入调试
2.1.1. 调试源代码文件
这应该是最常用的调试方式,进入项目所在文件夹,执行 dlv debug
。delve默认会寻找main package开始调试,当然可以使用 dlv debug packageA
这种方式来指定要调试的package,还可以用 dlv debug main.go
这种方式指定入口文件。
这种方式调试时,delve会在当前目录下生成一个名为__debug_binXXXX的二进制文件用于调试。
2.1.2. 调试二进制产物
也可以调试构建好的可执行程序,通过 dlv exec
指令,比如正常启动程序的指令为 ./application --env=dev
,那么使用 dlv ./application -- --env=dev
指令,可以调试这个二进制的可执行文件。
但要注意,为了避免编译器内联优化导致的debug定位错误,构建需要增加参数:
$ go build -gcflags=all="-N -l"
2.1.3. 调试正在运行的go进程
使用 dlv attach
指令,可以对已经在运行的go进程进行调试。delve会获取到这个进程的控制权,并开启一个调试会话。结束调试会话的时候,可以选择是否终止这个被调试的进程。
2.2. 调试中的指令
本节用一个实例实验delve的调试过程。
被调试的代码:
启动调试:
2.2.1. 设置断点
断点是调试排障过程中非常有用的工具,在进入调试会话后,使用 break
指令设置断点。
例如,把断点设置到main.go文件的第9行:
break main.go:9
把断点设置到test函数:
break main.test
还可以给断点起名字:
break functest main.test
使用 breakpoints
指令查看已设置的断点:
使用 clear
可以删除指定断点, clearall
删除所有断点。
还可以使用 condition
指令来设置条件断点,比如,我首先在24行设置断点:
然后设置该断点的条件
condition 5 x!=""
这样只有在执行到第24行时x不为空字符串,才会停住。
2.2.2. 单步调试
控制
设置好断点后,首先执行 continue
,运行到断点暂停,如果没有遇到断点,则一直运行到程序结束。
执行 step
步进(如果有函数则stepin),执行 next
执行到下一行,执行 stepout
跳出当前函数。
查看上下文
在执行过程中,可以使用 stack
查看当前执行栈,通过 goroutine
查看当前的go routine,通过 goroutines
查看所有go routine,通过 thread
和 threads
查看线程:
也可以使用 goroutine
和 thread
将调试会话在多个线程和协程之间切换。
查看变量和计算表达式
运行时可以通过 vars
查看package下所有的变量的值,这个太多了,可以使用 vars 正则
来过滤一部分。
但更方便的是直接使用 print 变量名
打印出指定变量的值,还可以使用print计算表达式的结果:
使用whatis,可以查看变量的类型。
其它的可用功能,可以在delve会话中使用 help
,介绍很详尽。