Golang debug 推荐使用 Delve 工具,项目地址:https://github.com/derekparker/delve

一、安装

go mod

1. 拉取最新 delve 项目代码到本地,编译安装。

# cd $GOPATH/src/
# git clone https://github.com/derekparker/delve.git
# cd delve/cmd/dlv/
# go build
# go install
go build
go: golang.org/x/crypto@v0.0.0-20180614174826-fd5f17ee7299: unrecognized import path "golang.org/x/crypto" (https fetch: Get https://golang.org/x/crypto?go-get=1: dial tcp 216.239.37.1:443: i/o timeout)
go: golang.org/x/sys@v0.0.0-20180614134839-8883426083c0: unrecognized import path "golang.org/x/sys" (https fetch: Get https://golang.org/x/sys?go-get=1: dial tcp 216.239.37.1:443: i/o timeout)
go: golang.org/x/arch@v0.0.0-20171004143515-077ac972c2e4: unrecognized import path "golang.org/x/arch" (https fetch: Get https://golang.org/x/arch?go-get=1: dial tcp 216.239.37.1:443: i/o timeout)
go.mod

替换:

golang.org/x/arch v0.0.0-20171004143515-077ac972c2e4 => github.com/golang/arch v0.0.0-20171004143515-077ac972c2e4
        golang.org/x/crypto v0.0.0-20180614174826-fd5f17ee7299 => github.com/golang/crypto v0.0.0-20180614174826-fd5f17ee7299
        golang.org/x/sys v0.0.0-20180614134839-8883426083c0 => github.com/golang/sys v0.0.0-20180614134839-8883426083c0

然后重新编译安装,没有报错则成功。

$GOPATH/bindlv
$ dlv
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.
  dap         [EXPERIMENTAL] Starts a TCP server communicating via Debug Adaptor Protocol (DAP).
  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')
      --only-same-user       Only connections from the same user that started this instance of Delve are allowed to connect. (default true)
      --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.

二、使用 Delve 调试程序

dlvdlv --help
(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.
    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.
    disassemble (alias: disass) - Disassembler.
    down ------------------------ Move the current frame down.
    exit (alias: quit | q) ------ Exit the debugger.
    frame ----------------------- Set the current frame, or execute command...
    funcs ----------------------- Print list of functions.
    goroutine ------------------- Shows or changes current goroutine
    goroutines ------------------ List program goroutines.
    help (alias: h) ------------- Prints the help message.
    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...
    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 --------------------- 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)
dlv [command] --helpdlv debug --help
$ 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")
      --tty string      TTY to use for the target program

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')
      --only-same-user       Only connections from the same user that started this instance of Delve are allowed to connect. (default true)
      --wd string            Working directory for running the program. (default ".")

3. 调试程序

deferdefer.go 
package main

import (
	"log"
)

var first = "panic in defer"
var second = "panic in main"

func main() {
	 defer func() {
		 for {
			 if err := recover(); err != nil {
				 log.Println(err)
			 }else{
				 log.Fatalln("fatal")
			 }
		 }
	 }()
	 defer func() {
	 	panic(first)
	 }()
	 panic(second)
}
dlv debug defer.go
$ dlv debug defer.go
Type 'help' for list of commands.
(dlv)
命令为break(简:b)b main.go:10
(dlv) b main.main
Breakpoint 1 set at 0x10ae9b8 for main.main() ./main.go:10
breakpoints(简:bp)
(dlv) bp
Breakpoint runtime-fatal-throw at 0x437ef0 for runtime.fatalthrow() c:/go/src/runtime/panic.go:1162 (0)
Breakpoint unrecovered-panic at 0x437f70 for runtime.fatalpanic() c:/go/src/runtime/panic.go:1189 (0)
        print runtime.curg._panic.arg
Breakpoint 1 at 0x4cdaff for main.main() C:/Users/y30002195/Desktop/已完成/0.总结文档/go/ch1/4_delve/defer.go:10 (0)

可以看到除了我们手动打的断点,Go 还自动帮我们打了 fatal 异常的两个断点

vars 命令可以查看全部包级的变量:

(dlv) vars main
runtime.main_init_done = chan bool nil
runtime.mainStarted = false
main.second = "panic in main"
main.first = "panic in defer"
命令为continue(简:c)
> main.main() C:/Users/y30002195/Desktop/已完成/0.总结文档/go/ch1/4_delve/defer.go:10 (hits goroutine(1):1 total:1) (PC: 0x4cdaff)
     5: )
     6:
     7: var first = "panic in defer"
     8: var second = "panic in main"
     9:
=>  10: func main() {
    11:          defer func() {
    12:                  for {
    13:                          if err := recover(); err != nil {
    14:                                  log.Println(err)
    15:                          }else{
received SIGINT, stopping process (will not forward signal)
next(简:n)
     6:
     7: var first = "panic in defer"
     8: var second = "panic in main"
     9:
    10: func main() {
=>  11:          defer func() {
    12:                  for {
    13:                          if err := recover(); err != nil {
    14:                                  log.Println(err)
    15:                          }else{
    16:                                  log.Fatalln("fatal")

argslocals
args
(no args)
locals
(no locals)

该程序没有局部变量,所以没有相关参数信息

stack
stack
0  0x00000000004cdb16 in main.main
   at C:/Users/y30002195/Desktop/已完成/0.总结文档/go/ch1/4_delve/defer.go:11
1  0x000000000043a40a in runtime.main
   at c:/go/src/runtime/proc.go:203
2  0x0000000000464b21 in runtime.goexit
   at c:/go/src/runtime/asm_amd64.s:1373
goroutine/goroutines
goroutine
Thread 14264 at C:/Users/y30002195/Desktop/已完成/0.总结文档/go/ch1/4_delve/defer.go:11
Goroutine 1:
        Runtime: C:/Users/y30002195/Desktop/已完成/0.总结文档/go/ch1/4_delve/defer.go:11 main.main (0x4cdb16)
        User: C:/Users/y30002195/Desktop/已完成/0.总结文档/go/ch1/4_delve/defer.go:11 main.main (0x4cdb16)
        Go: c:/go/src/runtime/asm_amd64.s:220 runtime.rt0_go (0x46289c)
        Start: c:/go/src/runtime/proc.go:113 runtime.main (0x43a250)
quit/exit
q

y30002195@DESKTOP-GT8J20C MINGW64 ~/Desktop/已完成/0.总结文档/go/ch1/4_delve