你是使用什么工具調(diào)試 golang 程序的?
寫過 C/C++ 的都是到,調(diào)試程序的時候通常使用 gdb 工具來進行調(diào)試,用起來可爽了,那么 gdb 是否也適合 golang 程序的調(diào)試的
我個人到是通常使用 dlv 來進行 golang 程序的調(diào)試,分享一波
dlv 是什么,全稱 Delve
Delve 可以讓你通過控制程序的執(zhí)行來與程序進行交互,他可以計算變量,并提供線程 / goroutine 狀態(tài)、CPU 寄存器狀態(tài)等信息
Delve 的目標是為調(diào)試 Go 程序提供一個簡單強大的調(diào)試功能
嘗試看一下 dlv 的 help 信息

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?headless?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.
通過 help 我們可以看到可以使用這些命令來調(diào)試我們的程序,根據(jù)不同的應(yīng)用場景
例如,
我們直接編譯并調(diào)試的時候就可以使用 dlv debug
調(diào)試一個正在運行的程序,就可以使用 dlv attach
調(diào)試一個編譯好的二進制文件,可以使用 dlv exec
其他的使用方式也類似,看上述的英文大概就知道啥意思了
開始調(diào)試小程序
簡單寫一個小程序來應(yīng)用一下這個調(diào)試工具
const?NUM?=?10
func?main()?{
?arr?:=?make([]int,?NUM)
?for?i?:=?1;?i?<?NUM;?i++?{
??arr[i]?=?i?+?i
??fmt.Printf("arr[%d]?==?%d\n",?i,?arr[i])
?}
?fmt.Println("program?over")
}
1、使用 dlv debug main.go 開始調(diào)試
dlv?debug?main.go
Type?'help'?for?list?of?commands.
(dlv)
2、dlv 里面使用 help 查看一下可以使用哪些命令


這些命令對應(yīng)的解釋相對還是比較清楚的,我們可以來用一下
3、使用 break
打給 main 函數(shù)一個端點,或者是用 b
(dlv)?b?main.main
Breakpoint?1?set?at?0xef84ea?for?main.main()?d:/mycode/my_new_first/dlvtest/main.go:7
給 main 函數(shù)打 1 斷點,斷點號是 1
4、continue
繼續(xù)執(zhí)行代碼,直到運行到 main 的中斷
(dlv)?c
?main.main()?d:/mycode/my_new_first/dlvtest/main.go:7?(hits?goroutine(1):1?total:1)?(PC:?0xef84ea)
?????2:?
?????3:?import?"fmt"
?????4:?
?????5:?const?NUM?=?10
?????6:?
=>???7:?func?main()?{
?????8:?????????arr?:=?make([]int,?NUM)
?????9:?
????10:?????????for?i?:=?1;?i?<?NUM;?i++?{
????11:?????????????????arr[i]?=?i?+?i
????12:?????????????????fmt.Printf("arr[%d]?==?%d\n",?i,?arr[i])
5、再 打一個斷點,加上具體的條件
b
文件:行數(shù)condition
中斷號 具體的條件
(dlv)?b?main.go:12
Breakpoint?2?set?at?0xef85a4?for?main.main()?d:/mycode/my_new_first/dlvtest/main.go:12
(dlv)?condition?2?i==7
6、continue
繼續(xù)執(zhí)行代碼
(dlv)?c
arr[1]?==?2
arr[2]?==?4
arr[3]?==?6
arr[4]?==?8
arr[5]?==?10
arr[6]?==?12
?main.main()?d:/mycode/my_new_first/dlvtest/main.go:12?(hits?goroutine(1):1?total:1)?(PC:?0xef85a4)
?????7:?func?main()?{
?????8:?????????arr?:=?make([]int,?NUM)
?????9:?
????10:?????????for?i?:=?1;?i?<?NUM;?i++?{
????11:?????????????????arr[i]?=?i?+?i
=>??12:?????????????????fmt.Printf("arr[%d]?==?%d\n",?i,?arr[i])
????13:?????????}
????14:?????????fmt.Println("program?over")
????15:?}
7、locals
查看本地變量信息 , p/print
打印變量信息
(dlv)?locals
arr?=?[]int?len:?10,?cap:?10,?[...]
i?=?7
(dlv)?args
(no?args)
(dlv)?p?i
7
(dlv)?p?arr
[]int?len:?10,?cap:?10,?[0,2,4,6,8,10,12,14,0,0]
使用
p
查看多個變量的信息,打印出具體的值
8、bp/breakpoints
?查看中斷列表 , clear
清空中斷
查看中斷列表
清空其中一個中斷
再查看中斷列表看看效果
(dlv)?bp
Breakpoint?runtime-fatal-throw?(enabled)?at?0xe6ca00?for?runtime.throw()?c:/program?files/go/src/runtime/panic.go:1107?(0)
Breakpoint?unrecovered-panic?(enabled)?at?0xe6cc80?for?runtime.fatalpanic()?c:/program?files/go/src/runtime/panic.go:1190?(0)
????????print?runtime.curg._panic.arg
Breakpoint?1?(enabled)?at?0xef84ea?for?main.main()?d:/mycode/my_new_first/dlvtest/main.go:7?(1)
Breakpoint?2?(enabled)?at?0xef85a4?for?main.main()?d:/mycode/my_new_first/dlvtest/main.go:12?(1)
????????cond?i?==?7
(dlv)?clear?2
Breakpoint?2?cleared?at?0xef85a4?for?main.main()?d:/mycode/my_new_first/dlvtest/main.go:12
(dlv)?bp
Breakpoint?runtime-fatal-throw?(enabled)?at?0xe6ca00?for?runtime.throw()?c:/program?files/go/src/runtime/panic.go:1107?(0)
Breakpoint?unrecovered-panic?(enabled)?at?0xe6cc80?for?runtime.fatalpanic()?c:/program?files/go/src/runtime/panic.go:1190?(0)
????????print?runtime.curg._panic.arg
Breakpoint?1?(enabled)?at?0xef84ea?for?main.main()?d:/mycode/my_new_first/dlvtest/main.go:7?(1)
9、ls
查看當前代碼運行的位置 ,next
執(zhí)行源碼的下一行
(dlv)?ls
?main.main()?d:/mycode/my_new_first/dlvtest/main.go:12?(hits?total:0)?(PC:?0xef85a4)
?????7:?func?main()?{
?????8:?????????arr?:=?make([]int,?NUM)
?????9:?
????10:?????????for?i?:=?1;?i?<?NUM;?i++?{
????11:?????????????????arr[i]?=?i?+?i
=>??12:?????????????????fmt.Printf("arr[%d]?==?%d\n",?i,?arr[i])
????13:?????????}
????14:?????????fmt.Println("program?over")
????15:?}(dlv)?next
?main.main()?d:/mycode/my_new_first/dlvtest/main.go:12?(hits?total:0)?(PC:?0xef85a4)
?????7:?func?main()?{
?????8:?????????arr?:=?make([]int,?NUM)
?????9:?
????10:?????????for?i?:=?1;?i?<?NUM;?i++?{
????11:?????????????????arr[i]?=?i?+?i
????12:?????????????????fmt.Printf("arr[%d]?==?%d\n",?i,?arr[i])
=>??13:?????????}
????14:?????????fmt.Println("program?over")
????15:?}
通過箭頭我們就可以看出來 ,沒有毛病
10、bt/stack
打印堆棧信息
(dlv)?bt
0??0x0000000000ef85a4?in?main.main
???at?d:/mycode/my_new_first/dlvtest/main.go:12
1??0x0000000000e6f2f6?in?runtime.main
???at?c:/program?files/go/src/runtime/proc.go:225
2??0x0000000000e9f3a1?in?runtime.goexit
???at?c:/program?files/go/src/runtime/asm_amd64.s:1371
查看堆棧信息,可以直接看到匯編里面的具體信息
11、goroutines
查看程序中的協(xié)程列表,以及其對應(yīng)的代碼行數(shù)
(dlv)?goroutines
*?Goroutine?1?-?User:?d:/mycode/my_new_first/dlvtest/main.go:12?main.main?(0xef85a4)?(thread?26592)
??Goroutine?2?-?User:?c:/program?files/go/src/runtime/proc.go:337?runtime.gopark?(0xe6f6f6)?[force?gc?(idle)]
??Goroutine?3?-?User:?c:/program?files/go/src/runtime/proc.go:337?runtime.gopark?(0xe6f6f6)?[GC?sweep?wait]
??Goroutine?4?-?User:?c:/program?files/go/src/runtime/proc.go:337?runtime.gopark?(0xe6f6f6)?[GC?scavenge?wait]
??Goroutine?5?-?User:?c:/program?files/go/src/runtime/proc.go:337?runtime.gopark?(0xe6f6f6)?[finalizer?wait]
[5?goroutines]
(dlv)?goroutine
Thread?26592?at?d:/mycode/my_new_first/dlvtest/main.go:12
Goroutine?1:
????????Runtime:?d:/mycode/my_new_first/dlvtest/main.go:12?main.main?(0xef85a4)
????????User:?d:/mycode/my_new_first/dlvtest/main.go:12?main.main?(0xef85a4)
????????Go:?c:/program?files/go/src/runtime/asm_amd64.s:226?runtime.rt0_go?(0xe9d3cc)
????????Start:?c:/program?files/go/src/runtime/proc.go:115?runtime.main?(0xe6f0e0)
goroutine 執(zhí)行的時候默認是查看當前協(xié)程的信息,上面打印可以知道,總共有 ?5 個協(xié)程,當前打印的協(xié)程信息是第 1 個
12、goroutine
顯示當前當前協(xié)程的具體信息和切換協(xié)程
主動切換到 第 2 個協(xié)程,并查看當前協(xié)程的信息
(dlv)?goroutine?2
Switched?from?1?to?2?(thread?26592)
(dlv)?goroutine
Thread?26592?at?d:/mycode/my_new_first/dlvtest/main.go:12
Goroutine?2:
????????Runtime:?c:/program?files/go/src/runtime/proc.go:337?runtime.gopark?(0xe6f6f6)
????????User:?c:/program?files/go/src/runtime/proc.go:337?runtime.gopark?(0xe6f6f6)
????????Go:?c:/program?files/go/src/runtime/proc.go:264?runtime.init.6?(0xe6f47c)
????????Start:?c:/program?files/go/src/runtime/proc.go:267?runtime.forcegchelper?(0xe6f4a0)
(dlv)?goroutines
??Goroutine?1?-?User:?d:/mycode/my_new_first/dlvtest/main.go:12?main.main?(0xef85a4)?(thread?26592)
*?Goroutine?2?-?User:?c:/program?files/go/src/runtime/proc.go:337?runtime.gopark?(0xe6f6f6)?[force?gc?(idle)]
??Goroutine?3?-?User:?c:/program?files/go/src/runtime/proc.go:337?runtime.gopark?(0xe6f6f6)?[GC?sweep?wait]
??Goroutine?4?-?User:?c:/program?files/go/src/runtime/proc.go:337?runtime.gopark?(0xe6f6f6)?[GC?scavenge?wait]
??Goroutine?5?-?User:?c:/program?files/go/src/runtime/proc.go:337?runtime.gopark?(0xe6f6f6)?[finalizer?wait]
[5?goroutines]
工具需要用起來才有意義

好了,本次就到這里
技術(shù)是開放的,我們的心態(tài),更應(yīng)是開放的。擁抱變化,向陽而生,努力向前行。
我是阿兵云原生,歡迎點贊關(guān)注收藏,下次見~