用dlv调试golang程序

139 阅读3分钟

image.png


import (
    "fmt"
)

func main() {
    nums := make([]int, 5)
    for i := 0; i <len(nums); i++ {
        nums[i] = i * i
    }
    fmt.Println(nums)
}

命令行进入包所在目录,然后输入 dlv debug 命令进入调试:

Type 'help' for list of commands.
(dlv)

每个 Go 程序的入口是 main.main 函数,我们可以用 break 在此设置一个断点:

Breakpoint 1 set at 0x10ae9b8 for main.main() ./main.go:7

然后通过 breakpoints 查看已经设置的所有断点:

main.initdone· = 2
runtime.main_init_done = chan bool 0/0
runtime.mainStarted = true
(dlv)

然后就可以通过 continue 命令让程序运行到下一个断点处:

> main.main() ./main.go:7 (hits goroutine(1):1 total:1) (PC: 0x10ae9b8)
     2:
     3: import (
     4:         "fmt"
     5: )
     6:
=>   7: func main() {
     8:         nums := make([]int, 5)
     9:         for i := 0; i <len(nums); i++ {
    10:                 nums[i] = i * i
    11:         }
    12:         fmt.Println(nums)
(dlv)

输入 next 命令单步执行进入 main 函数内部:

> main.main() ./main.go:8 (PC: 0x10ae9cf)
     3: import (
     4:         "fmt"
     5: )
     6:
     7: func main() {
=>   8:         nums := make([]int, 5)
     9:         for i := 0; i <len(nums); i++ {
    10:                 nums[i] = i * i
    11:         }
    12:         fmt.Println(nums)
    13: }
(dlv)

进入函数之后可以通过 args 和 locals 命令查看函数的参数和局部变量:

(no args)
(dlv) locals
nums = []int len: 842350763880, cap: 17491881, nil

因为 main 函数没有参数,因此 args 命令没有任何输出。而 locals 命令则输出了局部变量 nums 切片的值:此时切片还未完成初始化,切片的底层指针为 nil,长度和容量都是一个随机数值。

再次输入 next 命令单步执行后就可以查看到 nums 切片初始化之后的结果了:

(dlv) next
> main.main() ./main.go:9 (PC: 0x10aea12)
     4:         "fmt"
     5: )
     6:
     7: func main() {
     8:         nums := make([]int, 5)
=>   9:         for i := 0; i <len(nums); i++ {
    10:                 nums[i] = i * i
    11:         }
    12:         fmt.Println(nums)
    13: }
(dlv) locals
nums = []int len: 5, cap: 5, [...]
i = 17601536
(dlv)

我们还可以通过 stack 查看当前执行函数的栈帧信息:

0  0x00000000010aea33 in main.main
   at ./main.go:10
1  0x000000000102bd60 in runtime.main
   at /usr/local/go/src/runtime/proc.go:198
2  0x0000000001053bd1 in runtime.goexit
   at /usr/local/go/src/runtime/asm_amd64.s:2361
(dlv)

或者通过 goroutine 和 goroutines 命令查看当前 Goroutine 相关的信息:

Thread 101686 at ./main.go:10
Goroutine 1:
  Runtime: ./main.go:10 main.main (0x10aea33)
  User: ./main.go:10 main.main (0x10aea33)
  Go: /usr/local/go/src/runtime/asm_amd64.s:258 runtime.rt0_go (0x1051643)
  Start: /usr/local/go/src/runtime/proc.go:109 runtime.main (0x102bb90)
(dlv) goroutines
[4 goroutines]
* Goroutine 1 - User: ./main.go:10 main.main (0x10aea33) (thread 101686)
  Goroutine 2 - User: /usr/local/go/src/runtime/proc.go:292 \
                runtime.gopark (0x102c189)
  Goroutine 3 - User: /usr/local/go/src/runtime/proc.go:292 \
                runtime.gopark (0x102c189)
  Goroutine 4 - User: /usr/local/go/src/runtime/proc.go:292 \
                runtime.gopark (0x102c189)
(dlv)

最后完成调试工作后输入 quit 命令退出调试器。至此我们已经掌握了 Delve 调试器器的简单用法。