go-delve 实战

Delve 是go语言的一款调试器

调试方式

  • 命令行调试
  • 配合goland等ide进行remote debug

命令行调试

dlv exec

如果你已经有一个编译好的应用,可以直接通过dlv exec执行一个预编译好的二进制程序并开启debug会话

1
2
3
//path/to/demo
$ go build .
$ dlv exec ./demo

dlv attach

如果程序已经运行,可以直接attach

1
dlv attach pid

dlv attach 会导致程序阻塞,千万要注意

dlv core

如果程序出core,使用dlv core命令来检查core dump,帮助调查core发生时的进程运行状态

1
dlv core 二进制文件 core文件

A core dump file is a file that contains the memory dump of a running process and its process status

dlv debug

在禁用编译优化条件下编译程序,开启并attach

1
2
3
4
dlv debug .
等同于
go build -gcflags="-all=-N -l" .
go exec ./xxxx

输入 help 显示所有可以操作的命令

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
Running the program:
call ------------------------ Resumes process, injecting a function call (EXPERIMENTAL!!!)
continue (alias: c) --------- Run until breakpoint or program termination.
next (alias: n) ------------- Step over to next source line.
restart (alias: r) ---------- Restart process.
step (alias: s) ------------- Single step through program.
step-instruction (alias: si) Single step a single cpu instruction.
stepout (alias: so) --------- Step out of the current function.
Manipulating breakpoints:
break (alias: b) ------- Sets a breakpoint.
breakpoints (alias: bp) Print out info for active breakpoints.
clear ------------------ Deletes breakpoint.
clearall --------------- Deletes multiple breakpoints.
condition (alias: cond) Set breakpoint condition.
on --------------------- Executes a command when a breakpoint is hit.
trace (alias: t) ------- Set tracepoint. tracepoint是一个不会中断程序的点,在该点上可以执行自定义的命令
Viewing program variables and memory:
args ----------------- Print function arguments.
display -------------- Print value of an expression every time the program stops.
examinemem (alias: x) Examine memory:
locals --------------- Print local variables.
print (alias: p) ----- Evaluate an expression.
regs ----------------- Print contents of CPU registers.
set ------------------ Changes the value of a variable.
vars ----------------- Print package variables.
whatis --------------- Prints type of an expression.
Listing and switching between threads and goroutines:
goroutine (alias: gr) -- Shows or changes current goroutine
goroutines (alias: grs) List program goroutines.
thread (alias: tr) ----- Switch to the specified thread.
threads ---------------- Print out info for every traced thread.
Viewing the call stack and selecting frames:
deferred --------- Executes command in the context of a deferred call.
down ------------- Move the current frame down.
frame ------------ Set the current frame, or execute command on a different frame.
stack (alias: bt) Print stack trace.
up --------------- Move the current frame up.
Other commands:
config --------------------- Changes configuration parameters.
disassemble (alias: disass) Disassembler.
edit (alias: ed) ----------- Open where you are in $DELVE_EDITOR or $EDITOR
exit (alias: quit | q) ----- Exit the debugger.
funcs ---------------------- Print list of functions. *
help (alias: h) ------------ Prints the help message.
libraries ------------------ List loaded dynamic libraries
list (alias: ls | l) ------- Show source code.
source --------------------- Executes a file containing a list of delve commands
sources -------------------- Print list of source files.
types ---------------------- Print list of types

按回车键可以重复上次的操作

远程debug(配合goland使用)

第一步: 在远端机器项目下开启dlv API服务端口

1
dlv debug --headless --listen=:8333 --api-version=2 --accept-multiclient

第二步: 本机goland配置远端ip:端口,点击启动程序并开启debug会话

交互模式

delve提供两种交互模式 命令行交互模式headless模式, 其中命令行交互模式是默认模式,这里重点说一下headless模式。

通过--headless开启模式。该模式下delve对外暴露API接口,通过这些接口,其他IDE或编辑器可以与delve进行交互。
举例: dlv debug —headless —log —listen=127.0.0.1:8181 —accept-multiclient

  • —headless表示以headless启动
  • —listen指明要监听的端口
  • —accept-multiclient表明开启多客户端访问支持

你可以通过connect命令直接连接这台headless调试服务器
dlv connect 127.0.0.1:8181

FAQ

线上环境使用须知

无论是debug还是attach都会导致程序的阻塞,对于线上服务谨慎使用(举个例子,在A方法中打断点,来请求暂停至A方法后,整个程序阻塞,对于不会调用A方法的请求同样也会阻塞)

删除断点时通常只需要删除某个方法内的断点,如何操作

clearall
例: clearall main.main

观测程序栈帧信息时如何同时显示源码

使用bt -full

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
(dlv) bt
0 0x00000000014960ed in main.main
at ./demo.go:7
1 0x000000000103dd28 in runtime.main
at /usr/local/Cellar/go/1.14/libexec/src/runtime/proc.go:203
2 0x0000000001070b41 in runtime.goexit
at /usr/local/Cellar/go/1.14/libexec/src/runtime/asm_amd64.s:1373
(dlv) bt -full
0 0x00000000014960ed in main.main
at ./demo.go:7
1 0x000000000103dd28 in runtime.main
at /usr/local/Cellar/go/1.14/libexec/src/runtime/proc.go:203
g = (*runtime.g)(0xc000000180)
needUnlock = false
fn = (unreadable empty OP stack)
2 0x0000000001070b41 in runtime.goexit
at /usr/local/Cellar/go/1.14/libexec/src/runtime/asm_amd64.s:1373

如何在delve中重新加载源文件

Delve目前不支持重新加载正在运行的编译代码并保存断点及跟踪等状态。
暂时可以用source命令来加速重新编译运行后设置断点、跟踪等的时间
例如debug.txt存在以下内容

1
2
break foo.go:171
on 1 print myVar

回到dlv debug

1
2
3
4
5
$ dlv debug
Type 'help' for list of commands.
(dlv) source debug.txt
Breakpoint 1 set at 0x1b0f5e5 for /path/to/foo.MyFunction() ./foo.go:171
(dlv)

相关资料

delve api
使用 Delve 调试 Go 服务的一次经历
Using the Go Delve Debugger from the command line


注释1. all=-N -l表示关闭编译优化及内联。go build 可以用-gcflags向go编译器传入参数,也就是传给go tool compile的参数,可以通过go tool compile —help查看所有可用参数。