Go 语言调试工具 —dlv

本文记录下dlv 安装和使用记录。

安装


下载 和编译delve 分支

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

Go versin 1.16版本和之后的版本 可以直接使用

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

dlv 安装到$GOPATH/bin目录下,可以执行执行dlv命令查看是否安装成功.

  1. [lituanjie@localhost src]$ dlv help
  2. Delve is a source level debugger for Go programs.
  3. Delve enables you to interact with your program by controlling the execution of the process,
  4. evaluating variables, and providing information of thread / goroutine state, CPU register state and more.
  5. ......

如何调试的程序


dlv attach

dlv 使用attach 命令调试运行的程序,先使用ps -aux | grep pid-name 找到程序的pid号,在执行dlv attach pid-num

  1. [lituanjie@localhost ~]$ ps -aux | grep dlv_test
  2. lituanj+ 30992 0.0 0.0 702960 6956 pts/3 Sl+ 16:17 0:00 ./dlv_test
  3. lituanj+ 31282 0.0 0.0 112812 976 pts/1 S+ 16:19 0:00 grep --color=auto dlv_test
  4. [lituanjie@localhost ~]$
  5. [lituanjie@localhost ~]$ dlv attach 30992
  6. Type 'help' for list of commands.
  7. (dlv)
  8. (dlv)

dlv debug

使用dlv debug 会编译并调试当前目录下的程序,也可以指定package的位置

  1. [lituanjie@localhost dlv_test]$ dlv debug
  2. Type 'help' for list of commands.
  3. (dlv) break main.main
  4. Breakpoint 1 (enabled) set at 0x4b8918 for main.main() ./main.go:8
  5. (dlv) c
  6. > main.main() ./main.go:8 (hits goroutine(1):1 total:1) (PC: 0x4b8918)
  7. 3: import (
  8. 4: "fmt"
  9. 5: "time"
  10. 6: )
  11. 7:
  12. => 8: func main() {
  13. 9: fmt.Println("dlv test")
  14. 10: for {
  15. 11: time.Sleep(2 * time.Second)
  16. 12: fmt.Println("dlv test")
  17. 13: }
  18. (dlv) n

也可制定package

  1. [lituanjie@localhost src]$ dlv debug github.com/dlv_test/

dlv exec

dlv exec 是调试已经编译好的程序

  1. [lituanjie@localhost dlv_test]$ go build main.go
  2. [lituanjie@localhost dlv_test]$ ls
  3. main main.go
  4. [lituanjie@localhost dlv_test]$ dlv exec ./main
  5. Type 'help' for list of commands.
  6. (dlv) b main.main
  7. Breakpoint 1 (enabled) set at 0x4992f3 for main.main() ./main.go:8
  8. (dlv) n
  9. > main.main() ./main.go:8 (hits goroutine(1):1 total:1) (PC: 0x4992f3)
  10. Warning: debugging optimized function
  11. 3: import (
  12. 4: "fmt"
  13. 5: "time"
  14. 6: )
  15. 7:
  16. => 8: func main() {
  17. 9: fmt.Println("dlv test")
  18. 10: for {
  19. 11: time.Sleep(2 * time.Second)
  20. 12: fmt.Println("dlv test")
  21. 13: }
  22. (dlv)

dlv core

使用dlv core 可以core文件

远程调试


go 语言支持远程调试,在程序运行的机器上开启dlv server, 在代码编译机上开启dlv client,可以方便调试。

  1. --headless Run debug server only, in headless mode.

这个命令适合 attach, debug, test …等调试,在调试的时候加上—headless选项就可以。

  1. dlv [exec | attach | debug | test ...] --headless --listen ip:portnum 进程

dlv server

  1. ubuntu@ubuntu:~$ dlv exec --headless --listen :3000 ./main
  2. API server listening at: [::]:3000

dlv client

  1. #172.16.0.22 是server的IP地址
  2. [lituanjie@localhost ~]$ dlv connect 172.16.0.22:3000
  3. Type 'help' for list of commands.
  4. (dlv) b main.main
  5. Breakpoint 1 (enabled) set at 0x4992f3 for main.main() ./workspace/newgitlab/gowork/src/github.com/dlv_test/main.go:8
  6. (dlv) c
  7. > main.main() ./workspace/newgitlab/gowork/src/github.com/dlv_test/main.go:8 (hits goroutine(1):1 total:1) (PC: 0x4992f3)
  8. Warning: debugging optimized function
  9. 3: import (
  10. 4: "fmt"
  11. 5: "time"
  12. 6: )
  13. 7:
  14. => 8: func main() {
  15. 9: fmt.Println("dlv test")
  16. 10: for {
  17. 11: time.Sleep(2 * time.Second)
  18. 12: fmt.Println("dlv test")
  19. 13: }
  20. (dlv)

go 编译的程序是优化之后的程序,在调试中会出现信息不全的情况,最好在编译时加上gcflags='all=-N -l'

  1. go build -gcflags='all=-N -l' main.go

常用的命令

Command Descripton usage
call 调用函数 call [-unsafe]
continue 继续执行直到指定断点或程序结束 continue []
next 执行下一步 next [count]
step 进入函数
stepout 退出当前函数
break 设置断点 break [name]
breakpoints (bp) 打印所有断点
condition 设置有条件的断点 condition .
clear 清除断点 clear
clearall 清除所有断点 clearall []
display 程序每次停止时打印变量 display -a [%format]
display -d
-a选项是添加一个表达式
-b删除一个表达式
print 打印变量 [goroutine ] [frame ] print [%format]
regs 打印CPU registers的内容
goroutine 显示或这个改变当前的goroutine goroutine
goroutine
goroutine
goroutines 列出所有的goroutine goroutines [-u (default: user location)|-r (runtime location)|-g (go statement location)|-s (start location)] [-t (stack trace)] [-l (labels)]
-u displays location of topmost stackframe in user code
-r displays location of topmost stackframe (including frames inside private runtime functions)
-g displays location of go instruction that created the goroutine
-s displays location of the start function
-t displays goroutine’s stacktrace
-l displays goroutine’s labels
thread 切换指定的thread
threads 打印所有的thread
stack 打印堆栈的信息
frame 设置当前的frame, 或者在不同的frame执行命令 frame
frame
list 显示代码 [goroutine ] [frame ] list []
frame 1 list 69
list testvariables.go:10000
list main.main:30
list 40
set 改变变量的值 [goroutine ] [frame ] set =
whatis 打印变量的类型 whatis

常用指定断点方式

  • *<address> Specifies the location of memory address address. address can be specified as a decimal, hexadecimal or octal number
  • <filename>:<line> Specifies the line line in filename. filename can be the partial path to a file or even just the base name as long as the expression remains unambiguous.
  • <line> Specifies the line line in the current file
  • +<offset> Specifies the line offset lines after the current one
  • -<offset> Specifies the line offset lines before the current one
  • <function>[:<line>] Specifies the line line inside function. The full syntax for function is <package>.(*<receiver type>).<function name> however the only required element is the function name, everything else can be omitted as long as the expression remains unambiguous. For setting a breakpoint on an init function (ex: main.init), the <filename>:<line> syntax should be used to break in the correct init function at the correct location.
  • /<regex>/ Specifies the location of all the functions matching regex