Golang debug 推薦使用 Delve 工具,項目地址:https://github.com/derekparker/delve
一、安裝
照着 github 上 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)
原因是 Golang 官網被牆了,這里手動修改go.mod
文件,把項目地址替換為 github 上的地址,如:
替換:
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
然后重新編譯安裝,沒有報錯則成功。
2. 添加$GOPATH/bin
到環境變量,執行dlv
命令,查看:
$ 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 調試程序
1. 查看 Delve 支持命令:dlv
或 dlv --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)
2. 查詢單個命令詳情,dlv [command] --help
,如:dlv 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. 調試程序
手動創建一個defer
項目,defer.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)
單步執行進入 main 函數內部,斷點走到第 11 行 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")
args
和 locals
命令查看函數的參數和局部變量:
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 信息:
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