测试代码片段
package main
import (
"fmt"
)
func main() {
nums := make([]int, 5)
for i := 0; i < len(nums); i++ {
nums[i] = i * i
}
fmt.Println(nums)
}
进入调试模式
corollad@MacBook-Pro go_dlv % dlv debug
Type 'help' for list of commands.
(dlv)
(dlv) help
The following commands are available:
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.
rebuild --------------------- Rebuild the target executable and restarts it. It does not work if the executable was not built by delve.
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.
toggle ----------------- Toggles on or off a breakpoint.
trace (alias: t) ------- Set tracepoint.
watch ------------------ Set watchpoint.
Viewing program variables and memory:
args ----------------- Print function arguments.
display -------------- Print value of an expression every time the program stops.
examinemem (alias: x) Examine raw memory at the given address.
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.
dump ----------------------- Creates a core dump from the current process state
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
Type help followed by a command for full documentation.
每个Go程序的入口是main.main函数,我们可以用break在此设置一个断点:
(dlv) break main.main
Breakpoint 1 set at 0x10cbbd8 for main.main() ./main.go:7
然后通过breakpoints查看已经设置的所有断点:
(dlv) breakpoints
Breakpoint runtime-fatal-throw (enabled) at 0x1038dc0 for runtime.throw() /usr/local/Cellar/go/1.16.6/libexec/src/runtime/panic.go:1107 (0)
Breakpoint unrecovered-panic (enabled) at 0x1039040 for runtime.fatalpanic() /usr/local/Cellar/go/1.16.6/libexec/src/runtime/panic.go:1190 (0)
print runtime.curg._panic.arg
Breakpoint 1 (enabled) at 0x10cbbd8 for main.main() ./main.go:7 (0)
除了我们自己设置的main.main函数断点外,Delve内部已经为panic异常函数设置了一个断点。
通过vars命令可以查看全部包级的变量。因为最终的目标程序可能含有大量的全局变量,我们可以通过一个正则参数选择想查看的全局变量:
(dlv) vars main
runtime.main_init_done = chan bool nil
runtime.mainStarted = false
然后就可以通过continue命令让程序运行到下一个断点处:
(dlv) continue
> main.main() ./main.go:7 (hits goroutine(1):1 total:1) (PC: 0x10cbbd8)
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)
输入next命令单步执行进入main函数内部:
(dlv) next
> main.main() ./main.go:8 (PC: 0x10cbbef)
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: }
进入函数之后可以通过args和locals命令查看函数的参数和局部变量:
(dlv) args
(no args)
(dlv) locals
nums = []int len: 5, cap: 5, [...]
再次输入next命令单步执行后就可以查看到nums切片初始化之后的结果了:
(dlv) next
> main.main() ./main.go:10 (PC: 0x10cbc4b)
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 = 0
下面我们通过组合使用break和condition命令,在循环内部设置一个条件断点,当循环变量i等于3时断点生效:
(dlv) break main.go:10
Breakpoint 2 set at 0x10cbc4b for main.main() ./main.go:10
(dlv) condition 2 i==3
(dlv)
然后通过continue执行到刚设置的条件断点,并且输出局部变量:
(dlv) continue
> main.main() ./main.go:10 (hits goroutine(1):1 total:1) (PC: 0x10cbc4b)
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 = 3
(dlv) print nums
[]int len: 5, cap: 5, [0,1,4,0,0]
我们还可以通过stack查看当前执行函数的栈帧信息:
(dlv) stack
0 0x00000000010cbc4b in main.main
at ./main.go:10
1 0x000000000103b6e3 in runtime.main
at /usr/local/Cellar/go/1.16.6/libexec/src/runtime/proc.go:225
2 0x000000000106eba1 in runtime.goexit
at /usr/local/Cellar/go/1.16.6/libexec/src/runtime/asm_amd64.s:1371
或者通过goroutine和goroutines命令查看当前Goroutine相关的信息:
(dlv) goroutine
Thread 158218 at ./main.go:10
Goroutine 1:
Runtime: ./main.go:10 main.main (0x10cbc4b)
User: ./main.go:10 main.main (0x10cbc4b)
Go: /usr/local/Cellar/go/1.16.6/libexec/src/runtime/asm_amd64.s:226 runtime.rt0_go (0x106cd96)
Start: /usr/local/Cellar/go/1.16.6/libexec/src/runtime/proc.go:115 runtime.main (0x103b4c0)
(dlv) goroutines
* Goroutine 1 - User: ./main.go:10 main.main (0x10cbc4b) (thread 158218)
Goroutine 2 - User: /usr/local/Cellar/go/1.16.6/libexec/src/runtime/proc.go:337 runtime.gopark (0x103baf5) [force gc (idle)]
Goroutine 3 - User: /usr/local/Cellar/go/1.16.6/libexec/src/runtime/proc.go:337 runtime.gopark (0x103baf5) [GC sweep wait]
Goroutine 4 - User: /usr/local/Cellar/go/1.16.6/libexec/src/runtime/proc.go:337 runtime.gopark (0x103baf5) [GC scavenge wait]
Goroutine 17 - User: /usr/local/Cellar/go/1.16.6/libexec/src/runtime/proc.go:337 runtime.gopark (0x103baf5) [finalizer wait]
[5 goroutines]
最后完成调试工作后输入quit命令退出调试器。
(dlv) quit
corollad@MacBook-Pro go_dlv %
用到的命令总结:
1、dlv debug
2、break main.main
3、breakpoints
4、vars main
5、continue
6、next
7、args
8、locals
9、break main.go:10 && condition 2 i==3
10、print nums
11、stack
12、goroutine
13、goroutines
14、step(进入函数)
参考资料:《go 语言高级编程》