• 使用 dlv 进行 debug


    使用 dlv 可以方便的对 go 生成的二进制文件进行 debug,以下面的代码 main.go 为例讲解 dlv 的使用

    package main
    
    import (
    	"fmt"
    	"net/http"
    	"time"
    )
    
    func Hello(w http.ResponseWriter, r *http.Request) {
    	q := r.URL.Query().Get("q")
    	if q != "" {
    		fmt.Printf("search query: %s\n", q)
    	}
    	fmt.Fprintf(w, "Hello World! %s", time.Now())
    }
    
    func main() {
    	http.HandleFunc("/", Hello)
    	http.ListenAndServe(":8080", nil)
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    1️⃣ 安装 dlv

    直接使用 go install 命令即可将 dlv 安装到 $GOPATH/bin 目录下面

    # 可以下载最新的
    go install github.com/go-delve/delve/cmd/dlv@latest
    
    # 也可以下载指定的版本
    go install github.com/go-delve/delve/cmd/dlv@v1.7.3
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2️⃣ 编译代码,设置编译参数

    直接使用 go build 编译二进制文件的时候,会对代码进行优化和内联,导致使用 dlv 的时候部分命令不能使用,比如函数的调用。

    # 存在优化的编译
    go build -o http_server main.go
    
    # 去掉编译优化
    go build -gcflags="all=-N -l" -o http_server main.go
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3️⃣ dlv exec path/to/bin,进入调试模式

    使用 exec 子命令,直接调试可运行的二进制文件

    ➜ dlv exec ./http_server
    Type 'help' for list of commands.
    (dlv) 
    
    • 1
    • 2
    • 3

    4️⃣ 比对文件路径和行数,设置对应的断点

    比如我想在 main.goHello 函数进行调试,定位这个函数的行数为第 9 行,路径为 main.go,然后可以执行 break main.go:9

    (dlv) break main.go:9
    Breakpoint 1 set at 0x6e1bef for main.Hello() ./main.go:9
    
    • 1
    • 2

    如果提示 location xxx ambiguous,需要对路径进行明确,使用输出的长路径即可,比如 break github.com/xxx/xxx/main.go

    设置好断点之后,可以通过 breakpoints命令查询所有的断点,可以发现 dlv 默认也会将 panic 加入断点。

    (dlv) breakpoints
    Breakpoint runtime-fatal-throw (enabled) at 0x438720 for runtime.throw() /usr/local/go/src/runtime/panic.go:1188 (0)
    Breakpoint unrecovered-panic (enabled) at 0x438a80 for runtime.fatalpanic() /usr/local/go/src/runtime/panic.go:1271 (0)
            print runtime.curg._panic.arg
    Breakpoint 1 (enabled) at 0x6e1bef for main.Hello() ./main.go:9 (1)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5️⃣ 执行程序,直到运行到断点或者程序结束

    这一步不能省略!!! 省略之后无法调试断点,执行 continue 命令

    (dlv) continue
    # or
    (dlv) c
    
    • 1
    • 2
    • 3

    6️⃣ 进行请求,使其能够执行到断点处

    如果请求 ok 了,continue 命令不再阻塞

    (dlv) continue
    > main.Hello() ./main.go:9 (hits goroutine(18):1 total:2) (PC: 0x6e1bef)
         4:         "fmt"
         5:         "net/http"
         6:         "time"
         7: )
         8:
    =>   9: func Hello(w http.ResponseWriter, r *http.Request) { 
        10:         q := r.URL.Query().Get("q")
        11:         if q != "" {
        12:                 fmt.Printf("search query: %s\n", q)  
        13:         }
        14:         fmt.Fprintf(w, "Hello World! %s", time.Now()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    如果出现 warning 是因为二进制文件是经过优化的,编译的时候可以添加 -gcflags="all=-N -l" 参数去掉该提示。

    7️⃣ 愉快的进行调试

    使用 dlv 提供的命令,进行调试

    命令说明
    args当前函数的参数
    step进入函数/方法中
    next跳转到下一行代码
    continue/c运行代码直到下一个断点或者结束
    break/b设置断点
    breakpoints/bp所有的断点
    clear xx清理掉第 xx 个断点
    clearall清理所有的断点
    locals输出所有局部变量
    print输出指定的变量

    print 如果需要输出长字符串,可以先执行 config max-string-len 1000 扩大输出的字符串长度

    编译时需要禁止优化才能使用

    go build xxxx -gcflags="all=-N -l"
    
    • 1
    命令说明
    list输出源代码
    call调用函数

    8️⃣ More

    dlv 不仅使用 attach 对正在运行的程序进行调试,也可以直接对二进制文件进行调试 (dlv exec),甚至是没有编译的代码包 (dlv debug),更多更详细的文档,可以参考下面的两个链接:

    多动手试试,很容易就可以熟悉 dlv 使用~

    From My Blog

  • 相关阅读:
    在推荐系统中,BPRloss、Embloss、CrossEntropyloss是怎么计算的,代表的意义是什么
    湖州OLED透明拼接屏技术应用引领现代化旅游观光方式
    无代码开发卡片视图入门教程
    Linux--信号
    有趣的 TCP 抢带宽行为
    阿里云ACP认证考试易错题集
    (附源码)spring boot建达集团公司平台 毕业设计 141538
    Github上前十大开源Rust项目
    (实用)页面在线QQ咨询html代码
    硬核Go语言学习万字长文之上篇(两篇文章学会Go语言)
  • 原文地址:https://blog.csdn.net/weixin_44676081/article/details/127914384