Go调试工具—— Delve
参考: Go调试工具—— Delve - 慢行厚积 - 博客园
1. 查看版本,帮助信息
[root@etcd2 encryption]# dlv version
Delve Debugger
Version: 1.3.2
Build: $Id: 569ccbd514fc47c8b4c521b142556867ec5e6917 $
[root@etcd2 encryption]# dlv --help
Delve is a source level debugger for Go programs.
Delve enables you to interact with your program by controlling the execution of the process,
evaluating variables, and providing information of thread / goroutine state, CPU register state and more.
The goal of this tool is to provide a simple yet powerful interface for debugging Go programs.
Pass flags to the program you are debugging using `--`, for example:
`dlv exec ./hello -- server --config conf/config.toml`
Usage:
dlv [command]
Available Commands:
attach Attach to running process and begin debugging.
connect Connect to a headless debug server.
core Examine a core dump.
debug Compile and begin debugging main package in current directory, or the package specified.
exec Execute a precompiled binary, and begin a debug session.
help Help about any command
run Deprecated command. Use 'debug' instead.
test Compile test binary and begin debugging program.
trace Compile and begin tracing program.
version Prints version.
Flags:
--accept-multiclient Allows a headless server to accept multiple client connections.
--api-version int Selects API version when headless. (default 1)
--backend string Backend selection (see 'dlv help backend'). (default "default")
--build-flags string Build flags, to be passed to the compiler.
--check-go-version Checks that the version of Go in use is compatible with Delve. (default true)
--headless Run debug server only, in headless mode.
--init string Init file, executed by the terminal client.
-l, --listen string Debugging server listen address. (default "127.0.0.1:0")
--log Enable debugging server logging.
--log-dest string Writes logs to the specified file or file descriptor (see 'dlv help log').
--log-output string Comma separated list of components that should produce debug output (see 'dlv help log')
--wd string Working directory for running the program. (default ".")
Additional help topics:
dlv backend Help about the --backend flag.
dlv log Help about logging flags.
Use "dlv [command] --help" for more information about a command.
[root@etcd2 encryption]# dlv debug --help
Compiles your program with optimizations disabled, starts and attaches to it.
By default, with no arguments, Delve will compile the 'main' package in the
current directory, and begin to debug it. Alternatively you can specify a
package name and Delve will compile that package instead, and begin a new debug
session.
Usage:
dlv debug [package] [flags]
Flags:
--continue Continue the debugged process on start.
--output string Output path for the binary. (default "./__debug_bin")
Global Flags:
--accept-multiclient Allows a headless server to accept multiple client connections.
--api-version int Selects API version when headless. (default 1)
--backend string Backend selection (see 'dlv help backend'). (default "default")
--build-flags string Build flags, to be passed to the compiler.
--check-go-version Checks that the version of Go in use is compatible with Delve. (default true)
--headless Run debug server only, in headless mode.
--init string Init file, executed by the terminal client.
-l, --listen string Debugging server listen address. (default "127.0.0.1:0")
--log Enable debugging server logging.
--log-dest string Writes logs to the specified file or file descriptor (see 'dlv help log').
--log-output string Comma separated list of components that should produce debug output (see 'dlv help log')
--wd string Working directory for running the program. (default ".")
2. 调试
[root@etcd2 dlvtest]# dlv debug test.go
Type 'help' for list of commands.
(dlv) help
The following commands are available:
args ------------------------ Print function arguments.
break (alias: b) ------------ Sets a breakpoint.
breakpoints (alias: bp) ----- Print out info for active breakpoints.
call ------------------------ Resumes process, injecting a function call (EXPERIMENTAL!!!)
clear ----------------------- Deletes breakpoint.
clearall -------------------- Deletes multiple breakpoints.
condition (alias: cond) ----- Set breakpoint condition.
config ---------------------- Changes configuration parameters.
continue (alias: c) --------- Run until breakpoint or program termination.
deferred -------------------- Executes command in the context of a deferred call.
disassemble (alias: disass) - Disassembler.
down ------------------------ Move the current frame down.
edit (alias: ed) ------------ Open where you are in $DELVE_EDITOR or $EDITOR
exit (alias: quit | q) ------ Exit the debugger.
frame ----------------------- Set the current frame, or execute command on a different frame.
funcs ----------------------- Print list of functions.
goroutine (alias: gr) ------- Shows or changes current goroutine
goroutines (alias: grs) ----- List program goroutines.
help (alias: h) ------------- Prints the help message.
libraries ------------------- List loaded dynamic libraries
list (alias: ls | l) -------- Show source code.
locals ---------------------- Print local variables.
next (alias: n) ------------- Step over to next source line.
on -------------------------- Executes a command when a breakpoint is hit.
print (alias: p) ------------ Evaluate an expression.
regs ------------------------ Print contents of CPU registers.
restart (alias: r) ---------- Restart process.
set ------------------------- Changes the value of a variable.
source ---------------------- Executes a file containing a list of delve commands
sources --------------------- Print list of source files.
stack (alias: bt) ----------- Print stack trace.
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.
thread (alias: tr) ---------- Switch to the specified thread.
threads --------------------- Print out info for every traced thread.
trace (alias: t) ------------ Set tracepoint.
types ----------------------- Print list of types
up -------------------------- Move the current frame up.
vars ------------------------ Print package variables.
whatis ---------------------- Prints type of an expression.
Type help followed by a command for full documentation.
(dlv) c
Starting main
count : 0
count : 1
count : 2
count : 3
count : 4
count : 5
count : 6
count : 7
count : 8
count : 9
Process 33806 has exited with status 0
(dlv) r
Process restarted with PID 34040
(dlv) b main.main
Breakpoint 1 set at 0x4aa708 for main.main() ./test.go:16
(dlv) b main.counting
Breakpoint 2 set at 0x4aa65f for main.counting() ./test.go:8
(dlv) c
> main.main() ./test.go:16 (hits goroutine(1):1 total:1) (PC: 0x4aa708)
11: c <- i
12: }
13: close(c)
14: }
15:
=> 16: func main() {
17: msg := "Starting main"
18: fmt.Println(msg)
19: bus := make(chan int)
20: msg = "starting a gofunc"
21: go counting(bus)
(dlv) bp
Breakpoint runtime-fatal-throw at 0x42e020 for runtime.fatalthrow() /usr/local/go/src/runtime/panic.go:820 (0)
Breakpoint unrecovered-panic at 0x42e090 for runtime.fatalpanic() /usr/local/go/src/runtime/panic.go:847 (0)
print runtime.curg._panic.arg
Breakpoint 1 at 0x4aa708 for main.main() ./test.go:16 (1)
Breakpoint 2 at 0x4aa65f for main.counting() ./test.go:8 (0)
(dlv) list
> main.main() ./test.go:16 (hits goroutine(1):1 total:1) (PC: 0x4aa708)
11: c <- i
12: }
13: close(c)
14: }
15:
=> 16: func main() {
17: msg := "Starting main"
18: fmt.Println(msg)
19: bus := make(chan int)
20: msg = "starting a gofunc"
21: go counting(bus)
(dlv) n
> main.main() ./test.go:17 (PC: 0x4aa71f)
12: }
13: close(c)
14: }
15:
16: func main() {
=> 17: msg := "Starting main"
18: fmt.Println(msg)
19: bus := make(chan int)
20: msg = "starting a gofunc"
21: go counting(bus)
22: for count := range bus{
(dlv) p msg
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00...+4439097 more"
(dlv) locals bus
(no locals)
(dlv) locals msg
msg = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00...+4439097 more"
(dlv) s
> main.main() ./test.go:18 (PC: 0x4aa737)
13: close(c)
14: }
15:
16: func main() {
17: msg := "Starting main"
=> 18: fmt.Println(msg)
19: bus := make(chan int)
20: msg = "starting a gofunc"
21: go counting(bus)
22: for count := range bus{
23: fmt.Println("count : ", count)
(dlv) locals
msg = "Starting main"
(dlv) p count
Command failed: could not find symbol value for count
(dlv) s
> fmt.Println() /usr/local/go/src/fmt/print.go:273 (PC: 0x4a4733)
268: }
269:
270: // Println formats using the default formats for its operands and writes to standard output.
271: // Spaces are always added between operands and a newline is appended.
272: // It returns the number of bytes written and any write error encountered.
=> 273: func Println(a ...interface{}) (n int, err error) {
274: return Fprintln(os.Stdout, a...)
275: }
276:
277: // Sprintln formats using the default formats for its operands and returns the resulting string.
278: // Spaces are always added between operands and a newline is appended.
(dlv) s
> fmt.Println() /usr/local/go/src/fmt/print.go:274 (PC: 0x4a4758)
269:
270: // Println formats using the default formats for its operands and writes to standard output.
271: // Spaces are always added between operands and a newline is appended.
272: // It returns the number of bytes written and any write error encountered.
273: func Println(a ...interface{}) (n int, err error) {
=> 274: return Fprintln(os.Stdout, a...)
275: }
276:
277: // Sprintln formats using the default formats for its operands and returns the resulting string.
278: // Spaces are always added between operands and a newline is appended.
279: func Sprintln(a ...interface{}) string {
(dlv) n
Starting main
> main.main() ./test.go:19 (PC: 0x4aa7c8)
Values returned:
n: 14
err: error nil
14: }
15:
16: func main() {
17: msg := "Starting main"
18: fmt.Println(msg)
=> 19: bus := make(chan int)
20: msg = "starting a gofunc"
21: go counting(bus)
22: for count := range bus{
23: fmt.Println("count : ", count)
24: }
(dlv) n
> main.main() ./test.go:20 (PC: 0x4aa7eb)
15:
16: func main() {
17: msg := "Starting main"
18: fmt.Println(msg)
19: bus := make(chan int)
=> 20: msg = "starting a gofunc"
21: go counting(bus)
22: for count := range bus{
23: fmt.Println("count : ", count)
24: }
25: }
(dlv) n
> main.main() ./test.go:21 (PC: 0x4aa803)
16: func main() {
17: msg := "Starting main"
18: fmt.Println(msg)
19: bus := make(chan int)
20: msg = "starting a gofunc"
=> 21: go counting(bus)
22: for count := range bus{
23: fmt.Println("count : ", count)
24: }
25: }
(dlv) p msg == "Starting main"
false
(dlv) p msg == "Starting a gofunc"
false
(dlv) p msg == "starting a gofunc"
true
(dlv) whatis msg
string
(dlv) c
> main.counting() ./test.go:8 (hits goroutine(6):1 total:1) (PC: 0x4aa65f)
3: import (
4: "fmt"
5: "time"
6: )
7:
=> 8: func counting(c chan<- int){
9: for i := 0; i < 10; i++{
10: time.Sleep(2 * time.Second)
11: c <- i
12: }
13: close(c)
(dlv) help goroutine
Shows or changes current goroutine
goroutine
goroutine <id>
goroutine <id> <command>
Called without arguments it will show information about the current goroutine.
Called with a single argument it will switch to the specified goroutine.
Called with more arguments it will execute a command on the specified goroutine.
(dlv) goroutine
Thread 34040 at ./test.go:8
Goroutine 6:
Runtime: ./test.go:8 main.counting (0x4aa65f)
User: ./test.go:8 main.counting (0x4aa65f)
Go: ./test.go:21 main.main (0x4aa825)
Start: ./test.go:8 main.counting (0x4aa650)
(dlv) groutine 1
Command failed: command not available
(dlv) goroutine 1
Switched from 6 to 1 (thread 34040)
(dlv) goroutine
Thread 34040 at ./test.go:8
Goroutine 1:
Runtime: /usr/local/go/src/runtime/chan.go:421 runtime.chanrecv (0x405b34)
User: ./test.go:22 main.main (0x4aa849)
Go: /usr/local/go/src/runtime/asm_amd64.s:220 runtime.rt0_go (0x458e34)
Start: /usr/local/go/src/runtime/proc.go:113 runtime.main (0x42f790)
(dlv) locals
(no locals)
(dlv) goroutine 6
Switched from 1 to 6 (thread 34040)
(dlv) help goroutines
List program goroutines.
goroutines [-u (default: user location)|-r (runtime location)|-g (go statement location)|-s (start location)] [ -t (stack trace)]
Print out info for every goroutine. The flag controls what information is shown along with each goroutine:
-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 stack trace of goroutine
If no flag is specified the default is -u.
(dlv) goroutines
Goroutine 1 - User: ./test.go:22 main.main (0x4aa849)
Goroutine 2 - User: /usr/local/go/src/runtime/proc.go:305 runtime.gopark (0x42fd0b)
Goroutine 3 - User: /usr/local/go/src/runtime/proc.go:305 runtime.gopark (0x42fd0b)
Goroutine 4 - User: /usr/local/go/src/runtime/proc.go:305 runtime.gopark (0x42fd0b)
Goroutine 5 - User: /usr/local/go/src/runtime/proc.go:305 runtime.gopark (0x42fd0b)
* Goroutine 6 - User: ./test.go:8 main.counting (0x4aa65f) (thread 34040)
[6 goroutines]
(dlv) args
c = chan<- int 0/0
(dlv) c
count : 0
count : 1
count : 2
count : 3
count : 4
count : 5
count : 6
count : 7
count : 8
count : 9
Process 34040 has exited with status 0
(dlv) r
Process restarted with PID 35004
(dlv) b main.main
Command failed: Breakpoint exists at /home/gowork/src/github.com/user/dlvtest/test.go:16 at 4aa708
(dlv) c
Starting main
> main.counting() ./test.go:8 (hits goroutine(6):1 total:1) (PC: 0x4aa65f)
3: import (
4: "fmt"
5: "time"
6: )
7:
=> 8: func counting(c chan<- int){
9: for i := 0; i < 10; i++{
10: time.Sleep(2 * time.Second)
11: c <- i
12: }
13: close(c)
(dlv) stepout
count : 0
count : 1
count : 2
count : 3
count : 4
count : 5
count : 6
count : 7
count : 8
> runtime.goexit() /usr/local/go/src/runtime/asm_amd64.s:1358 (PC: 0x45ae81)
Warning: debugging optimized function
Values returned:
1353:
1354: // The top-most function running on a goroutine
1355: // returns to goexit+PCQuantum.
1356: TEXT runtime·goexit(SB),NOSPLIT,$0-0
1357: BYTE $0x90 // NOP
=>1358: CALL runtime·goexit1(SB) // does not return
1359: // traceback from goexit1 must hit code range of goexit
1360: BYTE $0x90 // NOP
1361:
1362: // This is called from .init_array and follows the platform, not Go, ABI.
1363: TEXT runtime·addmoduledata(SB),NOSPLIT,$0-0
(dlv) r
Process restarted with PID 35179
(dlv) breakpoints
Breakpoint runtime-fatal-throw at 0x42e020 for runtime.fatalthrow() /usr/local/go/src/runtime/panic.go:820 (0)
Breakpoint unrecovered-panic at 0x42e090 for runtime.fatalpanic() /usr/local/go/src/runtime/panic.go:847 (0)
print runtime.curg._panic.arg
Breakpoint 1 at 0x4aa65f for main.counting() ./test.go:8 (0)
(dlv) help on
Executes a command when a breakpoint is hit.
on <breakpoint name or id> <command>.
Supported commands: print, stack and goroutine)
(dlv) b /home/gowork/src/github.com/user/dlvtest/test.go:21
Breakpoint 2 set at 0x4aa803 for main.main() ./test.go:21
(dlv) breakpoints
Breakpoint runtime-fatal-throw at 0x42e020 for runtime.fatalthrow() /usr/local/go/src/runtime/panic.go:820 (0)
Breakpoint unrecovered-panic at 0x42e090 for runtime.fatalpanic() /usr/local/go/src/runtime/panic.go:847 (0)
print runtime.curg._panic.arg
Breakpoint 1 at 0x4aa65f for main.counting() ./test.go:8 (0)
Breakpoint 2 at 0x4aa803 for main.main() ./test.go:21 (0)
(dlv) c
Starting main
> main.main() ./test.go:21 (hits goroutine(1):1 total:1) (PC: 0x4aa803)
16: func main() {
17: msg := "Starting main"
18: fmt.Println(msg)
19: bus := make(chan int)
20: msg = "starting a gofunc"
=> 21: go counting(bus)
22: for count := range bus{
23: fmt.Println("count : ", count)
24: }
25: }
(dlv) help set
Changes the value of a variable.
[goroutine <n>] [frame <m>] set <variable> = <value>
See $GOPATH/src/github.com/go-delve/delve/Documentation/cli/expr.md for a description of supported expressions. Only numerical variables and pointers can be changed.
(dlv) set msg = "change msg"
Command failed: literal string can not be allocated because function calls are not allowed without using 'call'
(dlv) up
> main.main() ./test.go:21 (hits goroutine(1):1 total:1) (PC: 0x4aa803)
Frame 1: /usr/local/go/src/runtime/proc.go:203 (PC: 42f964)
198: // A program compiled with -buildmode=c-archive or c-shared
199: // has a main, but it is not executed.
200: return
201: }
202: fn := main_main // make an indirect call, as the linker doesn't know the address of the main package when laying down the runtime
=> 203: fn()
204: if raceenabled {
205: racefini()
206: }
207:
208: // Make racy client program work: if panicking on
(dlv) down
> main.main() ./test.go:21 (hits goroutine(1):1 total:1) (PC: 0x4aa803)
Frame 0: ./test.go:21 (PC: 4aa803)
16: func main() {
17: msg := "Starting main"
18: fmt.Println(msg)
19: bus := make(chan int)
20: msg = "starting a gofunc"
=> 21: go counting(bus)
22: for count := range bus{
23: fmt.Println("count : ", count)
24: }
25: }
(dlv) exit
[root@etcd2 dlvtest]# go run test.go
Starting main
count : 0
count : 1
count : 2
count : 3
count : 4
count : 5
count : 6
count : 7
count : 8
count : 9
attach 测试:
root 59253 3.6 1.0 308592 10032 pts/1 Sl+ 14:21 0:00 go run test.go
root 59276 0.0 0.0 102724 956 pts/1 Sl+ 14:21 0:00 /tmp/go-build582338132/b001/exe/test
root 59282 0.0 0.0 112708 972 pts/0 S+ 14:21 0:00 grep --color=auto test
[root@etcd2 dlvtest]# dlv attach 59253
Type 'help' for list of commands.
(dlv) c
Process 59253 has exited with status 0
(dlv)
3. 测试代码
package main
import (
"fmt"
"time"
)
func counting(c chan<- int){
for i := 0; i < 10; i++{
time.Sleep(2 * time.Second)
c <- i
}
close(c)
}
func main() {
msg := "Starting main"
fmt.Println(msg)
bus := make(chan int)
msg = "starting a gofunc"
go counting(bus)
for count := range bus{
fmt.Println("count : ", count)
}
}