GO delve(dlv)调试工具笔记及实操

这个文档总结了,我自己在linux通过delve上调试go代码的一些操作,比较常用的。无论是在调试应用,还是自己trace源码都挺好用。

GO version: 1.16.8

dlv versoin:1.7.2

dlv安装

 $ go install github.com/go-delve/delve/cmd/dlv@latest

go版本小于1.16的用下面方式安装

 $ git clone https://github.com/go-delve/delve
 $ cd delve
 $ go install github.com/go-delve/delve/cmd/dlv

dlv指令

仅列出常用或者会用到的

指令 用处 实操
attach 这个命令将使Delve控制一个已经运行的进程,并开始一个新的调试会话。 当退出调试会话时,你可以选择让该进程继续运行或杀死它。 case1
exec 这个命令将使Delve执行二进制文件,并立即附加到它,开始一个新的调试会话。请注意,如果二进制文件在编译时没有关闭优化功能,可能很难正确地调试它。请考虑在Go 1.10或更高版本上用-gcflags="all=-N -l "编译调试二进制文件,在Go的早期版本上用-gcflags="-N -l"。 case2
help 使用手册 case3
debug 默认情况下,没有参数,Delve将编译当前目录下的 "main "包,并开始调试。或者,你可以指定一个包的名字,Delve将编译该包,并开始一个新的调试会话。 case4
test test命令允许你在单元测试的背景下开始一个新的调试会话。默认情况下,Delve将调试当前目录下的测试。另外,你可以指定一个包的名称,Delve将在该包中调试测试。双破折号`--`可以用来传递参数给测试程序。 case5
version 查看dlv版本 case6

dlv调试指令

仅记录个人觉得会用到的指令

断点管理

指令 缩写 用法 案例
break b 设置断点 case7
breakpoints bp 查看当前所有断点 case8
clear / 删除断点 case9
clearall / 删除多个断点 case10
toggle / 启用或关闭断点 case11

程序执行中的调试指令

指令 缩写 用法 案例
continue c 继续执行到一个断点或者程序结束吗 case12
next n 执行下一行代码 case13
restart r 重新执行程序 case14
step s 执行代码的下一步 case15
step-instruction si 执行下一行机器码 case16
stepout so 跳出当前执行函数 case17

参数管理

指令 缩写 用法 案例
args / 打印函数input case18
display / 打印加入到display的变量的值,每次执行下一行代码或下一个断点时 case19
locals / 打印局部变量 case20
print p 打印表达式的结果 case21
set / 设置某个变量的值 case22
vars / 查看全局变量 case23
whatis / 查看变量类型 case24

其他

指令 缩写 用法 案例
disassemble disass 查看反编译后的代码,机器码 case25
exit quit / q 退出 case26
funcs / 打印程序用到的所有函数 case27
help h 帮助信息 case28
list ls / l 打印代码 case29

dlv实操案例

测试代码

 package main
 import (
     "fmt"
     "log"
     "math/rand"
     "net/http"
     "time"
 func count(i, j int) int {
     yz := 5
     result := (i + j) * yz
     return result
 func randHandler(w http.ResponseWriter, r *http.Request) {
     rand.Seed(time.Now().Unix())
     var (
         i = rand.Intn(20)
         j = rand.Intn(20)
     result := count(i, j)
     _, _ = w.Write([]byte(fmt.Sprintf("%d", result)))
 func main() {
     http.HandleFunc("/rand", randHandler)
     err := http.ListenAndServe(":8080", nil)
     if err != nil {
         log.Fatalf("start server fail: %v", err)

case1 attach

我理解的就是对一个阻塞的程序进行debug,比如http server。


  1. 背景启动http server
  2. dlv attach 176 ,attach刚才背景执行的程序的pid。同时,给请求的方法打一个断点。
  3. 发送一个请求给这个http server,应该是会阻塞住
  4. c,继续执行,会执行到打断点的地方,这样就可以对http server的方法进行debug

case2 exec

对一个可执行文件进行调试,是针对编译后的。

注意,如果直接 go build -v ,那有些代码会被优化掉,比如内联函数,在调试的时候会被忽略掉。比如如下代码:

 package main
 import "fmt"
 func main(){
     a := count(1,2)
     fmt.Println(a)