当前位置: 首页 > 科技观察

一个Demo学习使用GoDelve调试

时间:2023-03-12 00:10:06 科技观察

本文转载自微信公众号《我脑子炸了》,作者陈建宇。转载本文请联系脑筋急转弯公众号。大家好,我是炸鱼。在Go语言中,除了go工具链中的pprof、trace等profiling工具的大神。经常有小伙伴问有没有更好用更精致的。大家总是不喜欢pprof、trace这些工具。它们不够详细,无法一次性看到根本原因或特定变数。赶上代码级调试的,看具体变量的值是多少,想看就看。为此,今天我将介绍Go语言强大的Delve(dlv)调试工具,更深入地分析问题。要安装,我们需要先安装Godelve。对于Go1.16及以后的版本,可以直接执行以下命令安装:$goinstallgithub.com/go-delve/delve/cmd/dlv@latest也可以通过gitclone安装:$gitclonehttps://github。com/go-delve/delve$cddelve$goinstallgithub.com/go-delve/delve/cmd/dlv安装完成后,我们执行dlv版本命令查看安装状态:$dlvversionDelveDebuggerVersion:1.7。0Build:$Id:e353a65161e6ed74952b96bbb62ebfc56090832b$可以清楚的看到我们安装的版本是v1.7.0。演示程序我们计划用一个反转字符串的演示程序来调试Go程序。第一部分从完成stringer包的Reverse方法开始。代码如下:packagestringerfuncReverse(sstring)string{r:=[]rune(s)fori,j:=0,len(r)-1;imain.main()./main.go:9(hitsgoroutine(1):1total:1)(PC:0x10cbab3)4:"fmt"5:6:"github.com/eddycjy/awesome-project/stringer"7:)8:=>9:funcmain(){10:fmt.Println(stringer.Reverse("大脑炸了fish!"))11:}(dlv)在断点处可以看到具体的代码块、goroutine、CPU寄存器地址等运行时信息。紧接着执行关键字n(next的缩写)进入程序的下一步:(dlv)n>main.main()./main.go:10(PC:0x10cbac1)5:6:"github.com/eddycjy/awesome-project/stringer"7:)8:9:funcmain(){=>10:fmt.Println(stringer.Reverse("大脑是炸鱼!"))11:}我们可以看到程序go到了main.go文件的第10行,调用了stringer.Reverse方法进行处理。此时我们可以执行关键字s(step的关键字)进入这个函数继续调试:(dlv)s>github.com/eddycjy/awesome-project/stringer.Reverse()./stringer/string.go:3(PC:0x10cb87b)1:packagestringer2:=>3:funcReverse(sstring)string{4:r:=[]rune(s)5:fori,j:=0,len(r)-1;igithub.com/eddycjy/awesome-project/stringer.Reverse()./stringer/string.go:6(hitsgoroutine(1):1total:1)(PC:0x10cb92c)1:packagestringer2:3:funcReverse(sstring)string{4:r:=[]rune(s)5:fori,j:=0,len(r)-1;i6:r[i],r[j]=r[j],r[i]7:}8:returnstring(r)9:}走到对应的代码段后,执行关键字locals:(dlv)localsr=[]int32len:7,cap:32,[...]j=6i=0,我们可以看到对应的变量r,i,j的取值是多少,我们可以以此来分析程序流程是否符合我们的预期。另外,也可以调用关键字set为特定变量设置想要的值:(dlv)seti=1(dlv)localsr=[]int32len:7,cap:32,[...]j=6i=1设置完后,如果还需要继续查看,可以继续调用关键字c定位这种常用于特定变量的特定值的异常,这样设置后基本就可以查出来了和调试。排查完成后,我们可以执行关键字r(reset缩写):(dlv)rProcessrestartedwithPID56614执行完成后,整个调试会被reset,比如断点前设置的变量值会恢复。查看设置的断点,也可以执行关键字bp查看:(dlv)bpBreakpointruntime-fatal-throw(enabled)at0x1038fc0forruntime.fatalthrow()/usr/local/Cellar/go/1.16.2/libexec/src/runtime/panic.go:1163(0)Breakpointunrecovered-panic(enabled)at0x1039040forruntime.fatalpanic()/usr/local/Cellar/go/1.16.2/libexec/src/runtime/panic.go:1190(0)printruntime。curg._panic.argBreakpoint1(enabled)at0x10cbab3formain.main()./main.go:9(0)Breakpoint2(enabled)at0x10cb92cforgithub.com/eddycjy/awesome-project/stringer.Reverse()./stringer/string.go:6(0)查看断点后,如果有的已经消除,可以调用关键字clearall清除部分断点:(dlv)clearallmain.mainBreakpoint1(enabled)clearedat0x10cbab3formmain.main()./main.go:9if如果没有断点指定,默认清除所有断点。在日常的Go项目中,从main方法进入太麻烦了。我们可以直接使用函数名来调试定位:)./stringer/string.go:3(dlv)c>github.com/eddycjy/awesome-project/stringer.Reverse()./stringer/string.go:3(hitsgoroutine(1):1total:1)(PC:0x10cb87b)1:packagestringer2:=>3:funcReverse(sstring)string{4:r:=[]rune(s)5:fori,j:=0,len(r)-1;i