Go 语言源码级调试器 Delve

开发
本文我们简单介绍 Go 语言调试器 Delve 的基本使用方式,读者朋友们可以在程序调试时将 Delve 使用起来,替换使用 print 打印的形式调试代码。

01介绍

Delve 是一个简单、强大和易用的 Go 语言源代码层级的调试器,也是 Go 官方推荐使用的调试器。

02安装

Delve 安装非常简单,如果读者朋友使用的是 Go 1.16 或更高版本,可以直接使用 go install 安装:

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

如果读者朋友们使用的是低于 Go 1.16 的版本,可是先下载 Delve 源码,然后使用 go install 安装:

git clone https://github.com/go-delve/delve
cd delve
go install github.com/go-delve/delve/cmd/dlv
  • 1.
  • 2.
  • 3.

安装完成之后,可以使用 go help install 查看 dlv 可执行文件的详细位置。我建议读者朋友们将 dlv可执行文件,配置到 PATH 环境变量。

需要注意的是,如果读者朋友们使用的是 macOS,还需要安装命令行开发工具:

xcode-select --install
  • 1.

为了避免每次使用 dlv 都需要授权允许使用 debugger,建议读者朋友们开启开发者模式:

sudo /usr/sbin/DevToolsSecurity -enable
  • 1.

03实践

在完成 Part 02 中的所有操作之后,我们使用 dlv version 检查 dlv 可执行程序是否已可以使用。

我们可以使用 dlv 的任意可用命令启动一个调式会话,比较常用的命令是 dlv debug, dlv exec 和 dlv test。限于篇幅,本文我们介绍 dlv debug 的使用方法。

示例代码:

package main

import (
    "fmt"
)

func main() {
    a := 1
    b := 2
    c := sum(a, b)
    fmt.Println(c)
}

func sum(a, b int) int {
    res :=  a + b
    return res
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

阅读上面这段我们将用于调试会话的代码示例,它包含一个 main 函数和一个 sum 函数,main 函数中定义变量 a 和变量 b,调用 sub 函数,并将返回结果赋值给变量 c,最后打印变量 c 的值。

启动一个调试会话:

[root@VM-8-14-centos work]# dlv debug
Type 'help' for list of commands.
(dlv)
  • 1.
  • 2.
  • 3.

阅读上面这段代码,我们使用 dlv debug 启动一个调试会话,在没有任何参数的情况下,Delve 编译并开始调试当前目录中的 main 包。

我们也可以指定一个文件名,Delve 将会编译该指定文件的 main 包,并启动一个调试会话。

[root@VM-8-14-centos work]# dlv debug main.go
Type 'help' for list of commands.
(dlv)
  • 1.
  • 2.
  • 3.

调试会话启动后,我们可以使用调试命令进行调试程序。

list 命令:

dlv debug
Type 'help' for list of commands.
(dlv) list main.main
Showing /work/main.go:7 (PC: 0x49670a)
     2:
     3: import (
     4:  "fmt"
     5: )
     6:
     7: func main() {
     8:  a := 1
     9:  b := 2
    10:  c := sum(a, b)
    11:  fmt.Println(c)
    12: }
(dlv) list ./main.go:7
Showing /work/main.go:7 (PC: 0x49670a)
     2:
     3: import (
     4:  "fmt"
     5: )
     6:
     7: func main() {
     8:  a := 1
     9:  b := 2
    10:  c := sum(a, b)
    11:  fmt.Println(c)
    12: }
(dlv)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.

调试会话启动后,我们可以使用 list 命令列出指定位置的源码,包含两种方式,第一种方式是 .,第二种方式是 :。

break 命令:

dlv debug
Type 'help' for list of commands.
(dlv) break main.main
Breakpoint 1 set at 0x49670a for main.main() ./main.go:7
(dlv)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

我们可以使用 break 命令添加断点,和 list 命令一样,添加断点的位置,也可以使用上述两种方式。

我们可以使用 breakpoints 命令,列出所有断点,可以使用 clear 命令删除指定断点,可以使用 clearall 删除所有断定。

continue、next、step、stepout 和 print 命令:

 dlv debug
Type 'help' for list of commands.
(dlv) break main.main
Breakpoint 1 set at 0x49670a for main.main() ./main.go:7
(dlv) continue
> main.main() ./main.go:7 (hits goroutine(1):1 total:1) (PC: 0x49670a)
     2:
     3: import (
     4:  "fmt"
     5: )
     6:
=>   7: func main() {
     8:  a := 1
     9:  b := 2
    10:  c := sum(a, b)
    11:  fmt.Println(c)
    12: }
(dlv) next
> main.main() ./main.go:8 (PC: 0x496718)
     3: import (
     4:  "fmt"
     5: )
     6:
     7: func main() {
=>   8:  a := 1
     9:  b := 2
    10:  c := sum(a, b)
    11:  fmt.Println(c)
    12: }
    13:
(dlv) next
> main.main() ./main.go:9 (PC: 0x496721)
     4:  "fmt"
     5: )
     6:
     7: func main() {
     8:  a := 1
=>   9:  b := 2
    10:  c := sum(a, b)
    11:  fmt.Println(c)
    12: }
    13:
    14: func sum(a, b int) int {
(dlv) next
> main.main() ./main.go:10 (PC: 0x49672a)
     5: )
     6:
     7: func main() {
     8:  a := 1
     9:  b := 2
=>  10:  c := sum(a, b)
    11:  fmt.Println(c)
    12: }
    13:
    14: func sum(a, b int) int {
    15:  res :=  a + b
(dlv) print a
1
(dlv) print b
2
(dlv) step
> main.sum() ./main.go:14 (PC: 0x4967e0)
     9:  b := 2
    10:  c := sum(a, b)
    11:  fmt.Println(c)
    12: }
    13:
=>  14: func sum(a, b int) int {
    15:  res :=  a + b
    16:  return res
    17: }
(dlv) next
> main.sum() ./main.go:15 (PC: 0x496800)
    10:  c := sum(a, b)
    11:  fmt.Println(c)
    12: }
    13:
    14: func sum(a, b int) int {
=>  15:  res :=  a + b
    16:  return res
    17: }
(dlv) next
> main.sum() ./main.go:16 (PC: 0x49680f)
    11:  fmt.Println(c)
    12: }
    13:
    14: func sum(a, b int) int {
    15:  res :=  a + b
=>  16:  return res
    17: }
(dlv) next
> main.main() ./main.go:10 (PC: 0x496739)
Values returned:
 ~r0: 3

     5: )
     6:
     7: func main() {
     8:  a := 1
     9:  b := 2
=>  10:  c := sum(a, b)
    11:  fmt.Println(c)
    12: }
    13:
    14: func sum(a, b int) int {
    15:  res :=  a + b
(dlv) next
> main.main() ./main.go:11 (PC: 0x49673e)
     6:
     7: func main() {
     8:  a := 1
     9:  b := 2
    10:  c := sum(a, b)
=>  11:  fmt.Println(c)
    12: }
    13:
    14: func sum(a, b int) int {
    15:  res :=  a + b
    16:  return res
(dlv) print c
3
(dlv)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.

阅读上面这段代码,我们使用 Delve 添加断点后,执行 continue 命令,程序将执行到断点位置;执行 next 命令,程序继续执行下一行代码;执行 step 命令,程序步入到调用函数内部;执行 stepout 命令,程序步出到调用函数的调用位置;执行 print 命令,打印指定参数的值。

读者朋友们使用以上命令,可以满足大部分调试场景。为了方便理解,以上示例中使用的命令都没有使用简写形式,在实际使用时,使用简写形式会更加便捷。

简写形式:

  • break(b)
  • continue(c)
  • next(n)
  • step(s)
  • stepout(so)
  • print(p)

04总结

本文我们简单介绍 Go 语言调试器 Delve 的基本使用方式,读者朋友们可以在程序调试时将 Delve 使用起来,替换使用 print 打印的形式调试代码。

责任编辑:未丽燕 来源: Golang语言开发栈
相关推荐

2023-03-29 08:18:16

Go调试工具

2017-09-25 08:04:31

Linux调试器源码级断点

2020-07-10 16:52:43

DelveGo程序开源

2017-08-28 15:29:19

Linux调试器源码级逐步执行

2021-07-26 10:14:38

Go语言工具

2010-03-01 11:06:52

Python 调试器

2020-03-16 10:05:13

EmacsGUDLinux

2009-12-14 10:57:34

Ruby调试器

2017-08-28 14:40:57

Linux调试器源码和信号

2011-08-31 16:51:12

Lua调试器

2023-02-28 11:39:55

CMake脚本项目

2009-06-23 11:05:05

Mircosoft C

2011-08-31 16:47:07

Lua调试器

2010-02-24 09:32:24

Python 调试器

2011-08-24 11:08:09

Lua

2011-08-24 16:41:38

lua调试器

2011-08-31 16:39:06

Lua调试器

2021-10-17 19:52:40

Python:源码编译器

2023-03-13 00:21:21

调试器断点开发者

2011-08-25 16:34:27

Lua调试器
点赞
收藏

51CTO技术栈公众号