参考: Go调试工具—— Delve - 慢行厚积 - 博客园
1. 查看版本,帮助信息
[root@etcd2 encryption]# dlv versionDelve DebuggerVersion: 1.3.2Build: $Id: 569ccbd514fc47c8b4c521b142556867ec5e6917 $[root@etcd2 encryption]# dlv --helpDelve 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 commandrun 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 --helpCompiles your program with optimizations disabled, starts and attaches to it.By default, with no arguments, Delve will compile the 'main' package in thecurrent directory, and begin to debug it. Alternatively you can specify apackage name and Delve will compile that package instead, and begin a new debugsession.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.goType 'help' for list of commands.(dlv) helpThe 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 $EDITORexit (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 goroutinegoroutines (alias: grs) ----- List program goroutines.help (alias: h) ------------- Prints the help message.libraries ------------------- List loaded dynamic librarieslist (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 commandssources --------------------- 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 typesup -------------------------- 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) cStarting maincount : 0count : 1count : 2count : 3count : 4count : 5count : 6count : 7count : 8count : 9Process 33806 has exited with status 0(dlv) rProcess restarted with PID 34040(dlv) b main.mainBreakpoint 1 set at 0x4aa708 for main.main() ./test.go:16(dlv) b main.countingBreakpoint 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 <- i12: }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) bpBreakpoint 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.argBreakpoint 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 <- i12: }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 msgmsg = "\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) localsmsg = "Starting main"(dlv) p countCommand 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) nStarting main> main.main() ./test.go:19 (PC: 0x4aa7c8)Values returned:n: 14err: error nil14: }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 msgstring(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 <- i12: }13: close(c)(dlv) help goroutineShows or changes current goroutinegoroutinegoroutine <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) goroutineThread 34040 at ./test.go:8Goroutine 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 1Command failed: command not available(dlv) goroutine 1Switched from 6 to 1 (thread 34040)(dlv) goroutineThread 34040 at ./test.go:8Goroutine 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 6Switched from 1 to 6 (thread 34040)(dlv) help goroutinesList 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 goroutineIf no flag is specified the default is -u.(dlv) goroutinesGoroutine 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) argsc = chan<- int 0/0(dlv) ccount : 0count : 1count : 2count : 3count : 4count : 5count : 6count : 7count : 8count : 9Process 34040 has exited with status 0(dlv) rProcess restarted with PID 35004(dlv) b main.mainCommand failed: Breakpoint exists at /home/gowork/src/github.com/user/dlvtest/test.go:16 at 4aa708(dlv) cStarting 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 <- i12: }13: close(c)(dlv) stepoutcount : 0count : 1count : 2count : 3count : 4count : 5count : 6count : 7count : 8> runtime.goexit() /usr/local/go/src/runtime/asm_amd64.s:1358 (PC: 0x45ae81)Warning: debugging optimized functionValues returned:1353:1354: // The top-most function running on a goroutine1355: // returns to goexit+PCQuantum.1356: TEXT runtime·goexit(SB),NOSPLIT,$0-01357: BYTE $0x90 // NOP=>1358: CALL runtime·goexit1(SB) // does not return1359: // traceback from goexit1 must hit code range of goexit1360: BYTE $0x90 // NOP1361:1362: // This is called from .init_array and follows the platform, not Go, ABI.1363: TEXT runtime·addmoduledata(SB),NOSPLIT,$0-0(dlv) rProcess restarted with PID 35179(dlv) breakpointsBreakpoint 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.argBreakpoint 1 at 0x4aa65f for main.counting() ./test.go:8 (0)(dlv) help onExecutes 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:21Breakpoint 2 set at 0x4aa803 for main.main() ./test.go:21(dlv) breakpointsBreakpoint 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.argBreakpoint 1 at 0x4aa65f for main.counting() ./test.go:8 (0)Breakpoint 2 at 0x4aa803 for main.main() ./test.go:21 (0)(dlv) cStarting 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 setChanges 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-shared199: // has a main, but it is not executed.200: return201: }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.goStarting maincount : 0count : 1count : 2count : 3count : 4count : 5count : 6count : 7count : 8count : 9attach 测试:root 59253 3.6 1.0 308592 10032 pts/1 Sl+ 14:21 0:00 go run test.goroot 59276 0.0 0.0 102724 956 pts/1 Sl+ 14:21 0:00 /tmp/go-build582338132/b001/exe/testroot 59282 0.0 0.0 112708 972 pts/0 S+ 14:21 0:00 grep --color=auto test[root@etcd2 dlvtest]# dlv attach 59253Type 'help' for list of commands.(dlv) cProcess 59253 has exited with status 0(dlv)
3. 测试代码
package mainimport ("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)}}