写过 C/C++ 的都是到,调试程序的时候通常使用 gdb 工具来进行调试,用起来可爽了,那么 gdb 是否也适合 golang 程序的调试呢?

我个人到是通常使用 dlv 来进行 golang 程序的调试,分享一波。

dlv全称 Delve,Delve 可以让你通过控制程序的执行来与程序进行交互,他可以计算变量,并提供线程 / goroutine 状态、CPU 寄存器状态等信息。

Delve 的目标是为调试 Go 程序提供一个简单强大的调试功能。

尝试看一下 dlv 的 help 信息

你是使用什么工具调试 golang 程序的?  第1张

Usage:
  dlv [command]

Available Commands:
  attach      Attach to running process and begin debugging.
  connect     Connect to a headless debug server.
  core        Examine a core dump.
  dap         [EXPERIMENTAL] Starts a headless TCP server communicating via Debug Adaptor Protocol (DAP).
  debug       Compile and begin debugging main package in current directory, or the package specified.
  exec        Execute a precompiled binary, and begin a debug session.
  help        Help about any command
  run         Deprecated command. Use 'debug' instead.
  test        Compile test binary and begin debugging program.
  trace       Compile and begin tracing program.
  version     Prints version.

通过 help 我们可以看到可以使用这些命令来调试我们的程序,根据不同的应用场景

dlv debug
dlv attach
dlv exec

其他的使用方式也类似,看上述的英文大概就知道啥意思了

开始调试小程序

简单写一个小程序来应用一下这个调试工具

const NUM = 10

func main() {
    arr := make([]int, NUM)

    for i := 1; i < NUM; i++ {
        arr[i] = i + i
        fmt.Printf("arr[%d] == %d\n", i, arr[i])
    }
    fmt.Println("program over")
}

1、使用 dlv debug main.go 开始调试

>dlv debug main.go
Type 'help' for list of commands.
(dlv)

2、dlv 里面使用 help 查看一下可以使用哪些命令

你是使用什么工具调试 golang 程序的?  第2张

你是使用什么工具调试 golang 程序的?  第3张

这些命令对应的解释相对还是比较清楚的,我们可以来用一下

breakb
(dlv) b main.main
Breakpoint 1 set at 0xef84ea for main.main() d:/mycode/my_new_first/dlvtest/main.go:7

给 main 函数打 1 断点,断点号是 1

continue
(dlv) c
> main.main() d:/mycode/my_new_first/dlvtest/main.go:7 (hits goroutine(1):1 total:1) (PC: 0xef84ea)
     2: 
     3: import "fmt"
     4: 
     5: const NUM = 10
     6: 
=>   7: func main() {
     8:         arr := make([]int, NUM)
     9: 
    10:         for i := 1; i < NUM; i++ {
    11:                 arr[i] = i + i
    12:                 fmt.Printf("arr[%d] == %d\n", i, arr[i])

5、再 打一个断点,加上具体的条件

bcondition
(dlv) b main.go:12
Breakpoint 2 set at 0xef85a4 for main.main() d:/mycode/my_new_first/dlvtest/main.go:12
(dlv) condition 2 i==7
continue
(dlv) c
arr[1] == 2
arr[2] == 4
arr[3] == 6
arr[4] == 8
arr[5] == 10
arr[6] == 12
> main.main() d:/mycode/my_new_first/dlvtest/main.go:12 (hits goroutine(1):1 total:1) (PC: 0xef85a4)
     7: func main() {
     8:         arr := make([]int, NUM)
     9: 
    10:         for i := 1; i < NUM; i++ {
    11:                 arr[i] = i + i
=>  12:                 fmt.Printf("arr[%d] == %d\n", i, arr[i])
    13:         }
    14:         fmt.Println("program over")
    15: }
localsp/print
(dlv) locals
arr = []int len: 10, cap: 10, [...]
i = 7
(dlv) args
(no args)
(dlv) p i
7
(dlv) p arr
[]int len: 10, cap: 10, [0,2,4,6,8,10,12,14,0,0]
p
bp/breakpointsclear
  • 查看中断列表

  • 清空其中一个中断

  • 再查看中断列表看看效果

(dlv) bp
Breakpoint runtime-fatal-throw (enabled) at 0xe6ca00 for runtime.throw() c:/program files/go/src/runtime/panic.go:1107 (0)
Breakpoint unrecovered-panic (enabled) at 0xe6cc80 for runtime.fatalpanic() c:/program files/go/src/runtime/panic.go:1190 (0)
        print runtime.curg._panic.arg
Breakpoint 1 (enabled) at 0xef84ea for main.main() d:/mycode/my_new_first/dlvtest/main.go:7 (1)
Breakpoint 2 (enabled) at 0xef85a4 for main.main() d:/mycode/my_new_first/dlvtest/main.go:12 (1)
        cond i == 7
(dlv) clear 2
Breakpoint 2 cleared at 0xef85a4 for main.main() d:/mycode/my_new_first/dlvtest/main.go:12
(dlv) bp
Breakpoint runtime-fatal-throw (enabled) at 0xe6ca00 for runtime.throw() c:/program files/go/src/runtime/panic.go:1107 (0)
Breakpoint unrecovered-panic (enabled) at 0xe6cc80 for runtime.fatalpanic() c:/program files/go/src/runtime/panic.go:1190 (0)
        print runtime.curg._panic.arg
Breakpoint 1 (enabled) at 0xef84ea for main.main() d:/mycode/my_new_first/dlvtest/main.go:7 (1)
lsnext
(dlv) ls
> main.main() d:/mycode/my_new_first/dlvtest/main.go:12 (hits total:0) (PC: 0xef85a4)
     7: func main() {
     8:         arr := make([]int, NUM)
     9: 
    10:         for i := 1; i < NUM; i++ {
    11:                 arr[i] = i + i
=>  12:                 fmt.Printf("arr[%d] == %d\n", i, arr[i])
    13:         }
    14:         fmt.Println("program over")
    15: }
const NUM = 10

func main() {
    arr := make([]int, NUM)

    for i := 1; i < NUM; i++ {
        arr[i] = i + i
        fmt.Printf("arr[%d] == %d\n", i, arr[i])
    }
    fmt.Println("program over")
}0

通过箭头我们就可以看出来 ,没有毛病

bt/stack
const NUM = 10

func main() {
    arr := make([]int, NUM)

    for i := 1; i < NUM; i++ {
        arr[i] = i + i
        fmt.Printf("arr[%d] == %d\n", i, arr[i])
    }
    fmt.Println("program over")
}1

查看堆栈信息,可以直接看到汇编里面的具体信息

goroutines
const NUM = 10

func main() {
    arr := make([]int, NUM)

    for i := 1; i < NUM; i++ {
        arr[i] = i + i
        fmt.Printf("arr[%d] == %d\n", i, arr[i])
    }
    fmt.Println("program over")
}2

goroutine 执行的时候默认是查看当前协程的信息,上面打印可以知道,总共有  5 个协程,当前打印的协程信息是第 1 个

goroutine

主动切换到 第 2 个协程,并查看当前协程的信息

const NUM = 10

func main() {
    arr := make([]int, NUM)

    for i := 1; i < NUM; i++ {
        arr[i] = i + i
        fmt.Printf("arr[%d] == %d\n", i, arr[i])
    }
    fmt.Println("program over")
}3

工具需要用起来才有意义。

好了,本次就到这里。

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

我是小魔童哪吒,欢迎点赞关注收藏,下次见~