go调试工具
1 概念
Delve是一个用于Go程序的源码级调试器,通过控制程序的执行与你的程序互动,评估变量,并提供线程/goroutine状态、CPU寄存器状态等信息,目标是为调试Go程序提供一个简单而强大的接口。
使用方法:
dlv [command]
可用的命令:
attach 连接到正在运行的进程并开始调试。
connect 连接到一个无头调试服务器。
core 检查一个核心转储。
dap [EXPERIMENTAL] 启动一个通过Debug Adaptor Protocol (DAP)通信的TCP服务器。
debug 编译并开始调试当前目录下的主包,或指定的包。
exec 执行一个预编译的二进制文件,并开始调试会话。
help 关于任何命令的帮助
run 已废弃的命令。使用'debug'代替。
test 编译测试二进制文件并开始调试程序。
trace 编译并开始追踪程序。
version 打印版本。
可用标志:
--accept-multiclient 允许无头服务器接受多个客户端连接。
--api-version int 选择无头时的API版本。(默认为1)
--backend string 后台选择(见'dlv help backend')。(默认为 "default")
--build-flags string 构建标志,将被传递给编译器。
--check-go-version 检查正在使用的Go的版本是否与Delve兼容。(默认为true)
--headless 只运行调试服务器,在无头模式下。
--init string 启动文件,由终端客户端执行。
-l, --listen string 调试服务器监听地址。(默认为 "127.0.0.1:0")
--log 启用调试服务器的日志记录。
--log-dest string 将日志写到指定的文件或文件描述符(见'dlv help log')。
--log-output string 逗号分隔的应该产生调试输出的组件列表(见'dlv help log')
--only-same-user 只允许启动这个Delve实例的同一个用户的连接。(默认为true)
--wd string 运行程序的工作目录。(默认为".")
2 debug和exec命令
使用debug命令是从源码编译成二进制后进入调试会话,在本地目录下编译出来的__debug_bin
临时文件,结束调试会话会自动删除临时文件__debug_bin
,debug命令进入调试会话:
dlv debug –check-go-version=false
使用exec命令指定编译后的二进制文件进入调试会话,也就是比debug少了编译过程,exec 命令进入调试交互会话:
dlv exec <binary file> –check-go-version=false
调试会话命令说明:
运行程序命令:
call ------------------------ 恢复进程,注入一个函数调用(实验性的!!)。
continue (alias: c) --------- 运行到断点或程序终止。
next (alias: n) ------------- 跨越到下一个源代码行。
restart (alias: r) ---------- 重新启动程序。
step (alias: s) ------------- 单个程序的步骤。
step-instruction (alias: si) 单步执行一条cpu指令。
stepout (alias: so) --------- 走出当前函数。
操纵断点命令:
break (alias: b) ------- 设置一个断点。
breakpoints (alias: bp) 打印出活动断点的信息。
clear ------------------ 删除断点。
clearall --------------- 删除多个断点。
condition (alias: cond) 设置断点条件。
on --------------------- 当断点被击中时,执行一条命令。
trace (alias: t) ------- 设置跟踪点。
查看程序变量和内存命令:
args ----------------- 打印函数参数。
display -------------- 每次程序停止时打印表达式的值。
examinemem (alias: x) 检查内存。
locals --------------- 打印本地变量。
print (alias: p) ----- 评估一个表达式。
regs ----------------- 打印CPU寄存器的内容。
set ------------------ 改变一个变量的值。
vars ----------------- 打印软件包变量。
whatis --------------- 打印一个表达式的类型。
列出并在线程和goroutine之间切换命令:
goroutine (alias: gr) -- 显示或改变当前的goroutine
goroutines (alias: grs) 列出程序的goroutine。
thread (alias: tr) ----- 切换到指定的线程。
threads ---------------- 打印出每个被追踪的线程的信息。
查看调用栈和选择帧命令:
deferred --------- 在一个延迟调用的背景下执行命令。
down ------------- 将当前帧向下移动。
frame ------------ 设置当前帧,或在不同的帧上执行命令。
stack (alias: bt) 打印堆栈跟踪。
up --------------- 将当前帧向上移动。
其他命令:
config --------------------- 更改配置参数。
disassemble (alias: disass) 反汇编程序。
edit (alias: ed) ----------- 打开你在$DELVE_EDITOR或$EDITOR中的位置
exit (alias: quit | q) ----- 退出调试器。
funcs ---------------------- 打印函数的列表。
help (alias: h) ------------ 打印帮助信息。
libraries ------------------ 列出加载的动态库
list (alias: ls | l) ------- 显示源代码。
source --------------------- 执行一个包含delve命令列表的文件
sources -------------------- 打印源文件的列表。
types ---------------------- 打印类型列表
3 简单调试示例
文件列表
.
├── cal
│ └── cal.go
└── main.go
main.go代码
package main
import (
"demo/calculators/cal"
"fmt"
"time"
)
func main() {
v := cal.Cal{12, 3}
go func() {
time.Sleep(time.Minute)
}()
fmt.Println(v.Add())
fmt.Println(v.Sub())
fmt.Println(v.Mul())
fmt.Println(v.Div())
time.Sleep(time.Second * 5)
}
cal.go代码
package cal
type Cal struct {
X1 int
X2 int
}
func (c *Cal)Add() int {
return c.X1 +c.X2
}
func (c *Cal)Sub() int {
return c.X1 -c.X2
}
func (c *Cal)Mul() int {
return c.X1 *c.X2
}
func (c *Cal)Div() int {
return c.X1 / c.X2
}
进入调试会话
dlv debug main.go
(1) 打断点
Type 'help' for list of commands.
(dlv) b main.main
Breakpoint 1 set at 0x494b2f for main.main() ./main.go:9
(dlv) b main.go:16
Breakpoint 2 set at 0x494b6c for main.main() ./main.go:16
(dlv) b main.go:17
Breakpoint 3 set at 0x494bff for main.main() ./main.go:17
(dlv) b main.go:18
Breakpoint 4 set at 0x494c90 for main.main() ./main.go:18
(dlv) b main.go:19
Breakpoint 5 set at 0x494d25 for main.main() ./main.go:19
查看断点列表
(dlv) bp
Breakpoint runtime-fatal-throw at 0x432f00 for runtime.fatalthrow() /usr/local/go/src/runtime/panic.go:1244 (0)
Breakpoint unrecovered-panic at 0x433000 for runtime.fatalpanic() /usr/local/go/src/runtime/panic.go:1271 (0)
print runtime.curg._panic.arg
Breakpoint 1 at 0x494b2f for main.main() ./main.go:9 (0)
Breakpoint 2 at 0x494b6c for main.main() ./main.go:16 (0)
Breakpoint 3 at 0x494bff for main.main() ./main.go:17 (0)
Breakpoint 4 at 0x494c90 for main.main() ./main.go:18 (0)
Breakpoint 5 at 0x494d25 for main.main() ./main.go:19 (0)
清除断点使用 clearall
命令
(2) 执行到断点或结束位置
(dlv) c
> main.main() ./main.go:9 (hits goroutine(1):1 total:1) (PC: 0x494b2f)
4: "demo/calculators/cal"
5: "fmt"
6: "time"
7: )
8:
=> 9: func main() {
10: v := cal.Cal{12, 3}
11:
12: go func() {
13: time.Sleep(time.Minute)
14: }()
(3) 执行下一个代码行
(dlv) n
> main.main() ./main.go:12 (PC: 0x494b5e)
7: )
8:
9: func main() {
10: v := cal.Cal{12, 3}
11:
=> 12: go func() {
13: time.Sleep(time.Minute)
14: }()
15:
16: fmt.Println(v.Add())
17: fmt.Println(v.Sub())
(4) 查看和修改变量
(dlv) locals
v = demo/calculators/cal.Cal {X1: 12, X2: 3}
(dlv) set v.X2=4
(dlv) locals
v = demo/calculators/cal.Cal {X1: 12, X2: 4}
(dlv) print v
demo/calculators/cal.Cal {X1: 12, X2: 4}
(5) 查看调用栈信息
(dlv) bt
0 0x0000000000494bff in main.main
at ./main.go:17
1 0x0000000000435273 in runtime.main
at /usr/local/go/src/runtime/proc.go:255
2 0x000000000045f961 in runtime.goexit
at /usr/local/go/src/runtime/asm_amd64.s:1581
(5) 查看goroutine
# 当前goroutine
(dlv) goroutine
Thread 67537 at ./main.go:16
Goroutine 1:
Runtime: ./main.go:16 main.main (0x494b6c)
User: ./main.go:16 main.main (0x494b6c)
Go: <autogenerated>:1 runtime.newproc (0x461e29)
Start: /usr/local/go/src/runtime/proc.go:145 runtime.main (0x435080)
# 所有goroutine
(dlv) goroutines
* Goroutine 1 - User: ./main.go:16 main.main (0x494b6c) (thread 67537)
Goroutine 2 - User: /usr/local/go/src/runtime/proc.go:367 runtime.gopark (0x435692)
Goroutine 3 - User: /usr/local/go/src/runtime/proc.go:367 runtime.gopark (0x435692)
Goroutine 4 - User: /usr/local/go/src/runtime/proc.go:367 runtime.gopark (0x435692)
Goroutine 5 - User: /usr/local/go/src/runtime/proc.go:367 runtime.gopark (0x435692)
Goroutine 6 - User: ./main.go:12 main.main.func1 (0x494e00)
[6 goroutines]
(6) 打印每个被追踪的线程的信息
(dlv) threads
* Thread 67537 at 0x494b6c ./main.go:16 main.main
Thread 67667 at 0x46119d /usr/local/go/src/runtime/sys_linux_amd64.s:146 runtime.usleep
Thread 67668 at 0x46119d /usr/local/go/src/runtime/sys_linux_amd64.s:146 runtime.usleep
Thread 67669 at 0x461723 /usr/local/go/src/runtime/sys_linux_amd64.s:520 runtime.futex
Thread 67670 at 0x461723 /usr/local/go/src/runtime/sys_linux_amd64.s:520 runtime.futex
(7) 反汇编
(dlv) disassemble
TEXT main.main(SB) /home/vison/work/golang/project/src/demo/calculators/main.go
main.go:9 0x494b20 4c8d642498 lea r12, ptr [rsp-0x68]
main.go:9 0x494b25 4d3b6610 cmp r12, qword ptr [r14+0x10]
main.go:9 0x494b29 0f86a8020000 jbe 0x494dd7
main.go:9 0x494b2f* 4881ece8000000 sub rsp, 0xe8
main.go:9 0x494b36 4889ac24e0000000 mov qword ptr [rsp+0xe0], rbp
main.go:9 0x494b3e 488dac24e0000000 lea rbp, ptr [rsp+0xe0]
main.go:10 0x494b46 440f117c2420 movups xmmword ptr [rsp+0x20], xmm15
main.go:10 0x494b4c 48c74424200c000000 mov qword ptr [rsp+0x20], 0xc
main.go:10 0x494b55 48c744242803000000 mov qword ptr [rsp+0x28], 0x3
main.go:12 0x494b5e 31c0 xor eax, eax
main.go:12 0x494b60 488d1d89dd0100 lea rbx, ptr [rip+0x1dd89]
main.go:12 0x494b67 e81484faff call $runtime.newproc
=> main.go:16 0x494b6c* 488d442420 lea rax, ptr [rsp+0x20]
main.go:16 0x494b71 e80ae5fcff call $demo/calculators/cal.(*Cal).Add
main.go:16 0x494b76 4889442418 mov qword ptr [rsp+0x18], rax
main.go:16 0x494b7b 440f117c2470 movups xmmword ptr [rsp+0x70], xmm15
main.go:16 0x494b81 488d4c2470 lea rcx, ptr [rsp+0x70]
main.go:16 0x494b86 48894c2448 mov qword ptr [rsp+0x48], rcx
main.go:16 0x494b8b 488b442418 mov rax, qword ptr [rsp+0x18]
main.go:16 0x494b90 e80b52f7ff call $runtime.convT64
main.go:16 0x494b95 4889442440 mov qword ptr [rsp+0x40], rax
main.go:16 0x494b9a 488b4c2448 mov rcx, qword ptr [rsp+0x48]
main.go:16 0x494b9f 8401 test byte ptr [rcx], al
main.go:16 0x494ba1 488d15f86d0000 lea rdx, ptr [rip+0x6df8]
main.go:16 0x494ba8 488911 mov qword ptr [rcx], rdx
main.go:16 0x494bab 488d7908 lea rdi, ptr [rcx+0x8]
main.go:16 0x494baf 833deab30c0000 cmp dword ptr [runtime.writeBarrier], 0x0
main.go:16 0x494bb6 7402 jz 0x494bba
main.go:16 0x494bb8 eb08 jmp 0x494bc2
main.go:16 0x494bba 48894108 mov qword ptr [rcx+0x8], rax
main.go:16 0x494bbe 6690 data16 nop
main.go:16 0x494bc0 eb07 jmp 0x494bc9
main.go:16 0x494bc2 e8d9adfcff call $runtime.gcWriteBarrier
main.go:16 0x494bc7 eb00 jmp 0x494bc9
main.go:16 0x494bc9 488b442448 mov rax, qword ptr [rsp+0x48]
main.go:16 0x494bce 8400 test byte ptr [rax], al
main.go:16 0x494bd0 eb00 jmp 0x494bd2
main.go:16 0x494bd2 48898424b0000000 mov qword ptr [rsp+0xb0], rax
main.go:16 0x494bda 48c78424b800000001000000 mov qword ptr [rsp+0xb8], 0x1
main.go:16 0x494be6 48c78424c000000001000000 mov qword ptr [rsp+0xc0], 0x1
main.go:16 0x494bf2 bb01000000 mov ebx, 0x1
main.go:16 0x494bf7 4889d9 mov rcx, rbx
main.go:16 0x494bfa e8c1a8ffff call $fmt.Println
main.go:17 0x494bff* 488d442420 lea rax, ptr [rsp+0x20]
main.go:17 0x494c04 e8b7e4fcff call $demo/calculators/cal.(*Cal).Sub
main.go:17 0x494c09 4889442418 mov qword ptr [rsp+0x18], rax
main.go:17 0x494c0e 440f117c2470 movups xmmword ptr [rsp+0x70], xmm15
main.go:17 0x494c14 488d542470 lea rdx, ptr [rsp+0x70]
main.go:17 0x494c19 4889542438 mov qword ptr [rsp+0x38], rdx
main.go:17 0x494c1e 488b442418 mov rax, qword ptr [rsp+0x18]
main.go:17 0x494c23 e87851f7ff call $runtime.convT64
main.go:17 0x494c28 4889442430 mov qword ptr [rsp+0x30], rax
main.go:17 0x494c2d 488b542438 mov rdx, qword ptr [rsp+0x38]
main.go:17 0x494c32 8402 test byte ptr [rdx], al
main.go:17 0x494c34 488d35656d0000 lea rsi, ptr [rip+0x6d65]
main.go:17 0x494c3b 488932 mov qword ptr [rdx], rsi
main.go:17 0x494c3e 488d7a08 lea rdi, ptr [rdx+0x8]
main.go:17 0x494c42 833d57b30c0000 cmp dword ptr [runtime.writeBarrier], 0x0
main.go:17 0x494c49 7402 jz 0x494c4d
main.go:17 0x494c4b eb06 jmp 0x494c53
main.go:17 0x494c4d 48894208 mov qword ptr [rdx+0x8], rax
main.go:17 0x494c51 eb07 jmp 0x494c5a
main.go:17 0x494c53 e848adfcff call $runtime.gcWriteBarrier
main.go:17 0x494c58 eb00 jmp 0x494c5a
main.go:17 0x494c5a 488b442438 mov rax, qword ptr [rsp+0x38]
main.go:17 0x494c5f 8400 test byte ptr [rax], al
main.go:17 0x494c61 eb00 jmp 0x494c63
main.go:17 0x494c63 4889842498000000 mov qword ptr [rsp+0x98], rax
main.go:17 0x494c6b 48c78424a000000001000000 mov qword ptr [rsp+0xa0], 0x1
main.go:17 0x494c77 48c78424a800000001000000 mov qword ptr [rsp+0xa8], 0x1
main.go:17 0x494c83 bb01000000 mov ebx, 0x1
main.go:17 0x494c88 4889d9 mov rcx, rbx
main.go:17 0x494c8b e830a8ffff call $fmt.Println
main.go:18 0x494c90* 488d442420 lea rax, ptr [rsp+0x20]
main.go:18 0x494c95 e866e4fcff call $demo/calculators/cal.(*Cal).Mul
main.go:18 0x494c9a 4889442418 mov qword ptr [rsp+0x18], rax
main.go:18 0x494c9f 440f117c2470 movups xmmword ptr [rsp+0x70], xmm15
main.go:18 0x494ca5 488d542470 lea rdx, ptr [rsp+0x70]
main.go:18 0x494caa 4889542468 mov qword ptr [rsp+0x68], rdx
main.go:18 0x494caf 488b442418 mov rax, qword ptr [rsp+0x18]
main.go:18 0x494cb4 e8e750f7ff call $runtime.convT64
main.go:18 0x494cb9 4889442460 mov qword ptr [rsp+0x60], rax
main.go:18 0x494cbe 488b542468 mov rdx, qword ptr [rsp+0x68]
main.go:18 0x494cc3 8402 test byte ptr [rdx], al
main.go:18 0x494cc5 488d35d46c0000 lea rsi, ptr [rip+0x6cd4]
main.go:18 0x494ccc 488932 mov qword ptr [rdx], rsi
main.go:18 0x494ccf 488d7a08 lea rdi, ptr [rdx+0x8]
main.go:18 0x494cd3 833dc6b20c0000 cmp dword ptr [runtime.writeBarrier], 0x0
main.go:18 0x494cda 7402 jz 0x494cde
main.go:18 0x494cdc eb06 jmp 0x494ce4
main.go:18 0x494cde 48894208 mov qword ptr [rdx+0x8], rax
main.go:18 0x494ce2 eb07 jmp 0x494ceb
main.go:18 0x494ce4 e8b7acfcff call $runtime.gcWriteBarrier
main.go:18 0x494ce9 eb00 jmp 0x494ceb
main.go:18 0x494ceb 488b442468 mov rax, qword ptr [rsp+0x68]
main.go:18 0x494cf0 8400 test byte ptr [rax], al
main.go:18 0x494cf2 eb00 jmp 0x494cf4
main.go:18 0x494cf4 4889842480000000 mov qword ptr [rsp+0x80], rax
main.go:18 0x494cfc 48c784248800000001000000 mov qword ptr [rsp+0x88], 0x1
main.go:18 0x494d08 48c784249000000001000000 mov qword ptr [rsp+0x90], 0x1
main.go:18 0x494d14 bb01000000 mov ebx, 0x1
main.go:18 0x494d19 4889d9 mov rcx, rbx
main.go:18 0x494d1c 0f1f4000 nop dword ptr [rax], eax
main.go:18 0x494d20 e89ba7ffff call $fmt.Println
main.go:19 0x494d25* 488d442420 lea rax, ptr [rsp+0x20]
main.go:19 0x494d2a e831e4fcff call $demo/calculators/cal.(*Cal).Div
main.go:19 0x494d2f 4889442418 mov qword ptr [rsp+0x18], rax
main.go:19 0x494d34 440f117c2470 movups xmmword ptr [rsp+0x70], xmm15
main.go:19 0x494d3a 488d542470 lea rdx, ptr [rsp+0x70]
main.go:19 0x494d3f 4889542458 mov qword ptr [rsp+0x58], rdx
main.go:19 0x494d44 488b442418 mov rax, qword ptr [rsp+0x18]
main.go:19 0x494d49 e85250f7ff call $runtime.convT64
main.go:19 0x494d4e 4889442450 mov qword ptr [rsp+0x50], rax
main.go:19 0x494d53 488b542458 mov rdx, qword ptr [rsp+0x58]
main.go:19 0x494d58 8402 test byte ptr [rdx], al
main.go:19 0x494d5a 488d353f6c0000 lea rsi, ptr [rip+0x6c3f]
main.go:19 0x494d61 488932 mov qword ptr [rdx], rsi
main.go:19 0x494d64 488d7a08 lea rdi, ptr [rdx+0x8]
main.go:19 0x494d68 833d31b20c0000 cmp dword ptr [runtime.writeBarrier], 0x0
main.go:19 0x494d6f 7402 jz 0x494d73
main.go:19 0x494d71 eb06 jmp 0x494d79
main.go:19 0x494d73 48894208 mov qword ptr [rdx+0x8], rax
main.go:19 0x494d77 eb09 jmp 0x494d82
main.go:19 0x494d79 e822acfcff call $runtime.gcWriteBarrier
main.go:19 0x494d7e 6690 data16 nop
main.go:19 0x494d80 eb00 jmp 0x494d82
main.go:19 0x494d82 488b442458 mov rax, qword ptr [rsp+0x58]
main.go:19 0x494d87 8400 test byte ptr [rax], al
main.go:19 0x494d89 eb00 jmp 0x494d8b
main.go:19 0x494d8b 48898424c8000000 mov qword ptr [rsp+0xc8], rax
main.go:19 0x494d93 48c78424d000000001000000 mov qword ptr [rsp+0xd0], 0x1
main.go:19 0x494d9f 48c78424d800000001000000 mov qword ptr [rsp+0xd8], 0x1
main.go:19 0x494dab bb01000000 mov ebx, 0x1
main.go:19 0x494db0 4889d9 mov rcx, rbx
main.go:19 0x494db3 e808a7ffff call $fmt.Println
main.go:21 0x494db8 48b800f2052a01000000 mov rax, 0x12a05f200
main.go:21 0x494dc2 e8997afcff call $time.Sleep
main.go:22 0x494dc7 488bac24e0000000 mov rbp, qword ptr [rsp+0xe0]
main.go:22 0x494dcf 4881c4e8000000 add rsp, 0xe8
main.go:22 0x494dd6 c3 ret
main.go:9 0x494dd7 e8048cfcff call $runtime.morestack_noctxt
main.go:9 0x494ddc 0f1f4000 nop dword ptr [rax], eax
main.go:9 0x494de0 e93bfdffff jmp $main.main
其他命令使用方法使用help查看。
专题「golang相关」的其它文章 »
- 使用开发框架sponge快速把单体web服务拆分为微服务 (Sep 18, 2023)
- 使用开发框架sponge一天多开发完成一个简单版社区后端服务 (Jul 30, 2023)
- 一个提高开发项目效率的开发框架sponge,支持mysql、mongodb、postgresql、tidb、sqlite (Jan 06, 2023)
- go test命令 (Apr 15, 2022)
- go应用程序性能分析 (Mar 29, 2022)
- channel原理和应用 (Mar 22, 2022)
- go runtime (Mar 14, 2022)
- cobra (Mar 10, 2022)
- grpc使用实践 (Nov 27, 2020)
- 配置文件viper库 (Nov 22, 2020)
- 根据服务名称查看golang程序的profile信息 (Sep 03, 2019)
- go语言开发规范 (Aug 28, 2019)
- goroutine和channel应用——处理队列 (Sep 06, 2018)
- golang中的context包 (Aug 28, 2018)