GO语言调试利器dlv快速上手
GO语言调试利器dlv快速上手
golang 安装
tar -xvf go1.15.2.linux-arm64.tar.gz -C /usr/local/go
[root@centos7 ~]# ls /usr/local/go go [root@centos7 ~]# ls /usr/local/go/go/ api AUTHORS bin CONTRIBUTING.md CONTRIBUTORS doc favicon.ico lib LICENSE misc PATENTS pkg README.md robots.txt SECURITY.md src test VERSION [root@centos7 ~]#
[root@centos7 ~]# go version go version go1.15.2 linux/arm64 [root@centos7 ~]# cat go.source export GOPATH=/opt/gopath export GOROOT=/usr/local/go/go export GOARCH=arm64 export GOOS=linux export GOTOOLS=/pkg/tool #export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/bin:/bin:/bin export PATH=$PATH:$GOROOT/bin [root@centos7 ~]#
export PATH=$PATH:$GOPATH/bin
[root@centos7 ~]# cat go.source export GOPATH=/opt/gopath export GOROOT=/usr/local/go15.2/go export GOARCH=arm64 export GOOS=linux export GOTOOLS=/pkg/tool #export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/bin:/bin:/bin export PATH=$PATH:$GOPATH/bin export PATH=$PATH:$GOROOT/bin [root@centos7 ~]# ls /opt/gopath/bin/dlv /opt/gopath/bin/dlv [root@centos7 ~]#
一、dlv的安装
1)下载dlv
git clone https://github.com/go-delve/delve.git $GOPATH/src/github.com/go-delve/delve
或者 go get github.com/derekparker/delve/cmd/dlv
root@cloud:~# go version go version go1.14.10 linux/arm64
2)安装
cd $GOPATH/src/github.com/go-delve/delve
make install
root@cloud:~/delve# make install -j $(nproc) go install "-ldflags=-X main.Build=1b2357092c8fee7406988d8191f71059700c5399" github.com/go-delve/delve/cmd/dlv root@cloud:~/delve# dlv -h 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`
(dlv) bp Breakpoint runtime-fatal-throw at 0x429a0 for runtime.fatalthrow() GOROOT/src/runtime/panic.go:1162 (0) Breakpoint unrecovered-panic at 0x42a00 for runtime.fatalpanic() GOROOT/src/runtime/panic.go:1189 (0) print runtime.curg._panic.arg Breakpoint 1 at 0x3edc70 for gvisor.dev/gvisor/pkg/sentry/mm.(*MemoryManager).MMap() pkg/sentry/mm/syscalls.go:75 (1) (dlv) clear 1 Breakpoint 1 cleared at 0x3edc70 for gvisor.dev/gvisor/pkg/sentry/mm.(*MemoryManager).MMap() pkg/sentry/mm/syscalls.go:75 (dlv) bp Breakpoint runtime-fatal-throw at 0x429a0 for runtime.fatalthrow() GOROOT/src/runtime/panic.go:1162 (0) Breakpoint unrecovered-panic at 0x42a00 for runtime.fatalpanic() GOROOT/src/runtime/panic.go:1189 (0) print runtime.curg._panic.arg (dlv) quit Would you like to kill the process? [Y/n] n root@cloud:~/delve#
dlv和golang
root@cloud:~/delve# dlv -h Command 'dlv' not found, did you mean: command 'ddv' from deb ncbi-tools-x11 command 'delv' from deb dnsutils command 'dav' from deb dav-text command 'lv' from deb lv command 'dlg' from deb pccts command 'dll' from deb brickos Try: apt install <deb name> root@cloud:~/delve# source ~/hyper/go_source root@cloud:~/delve# dlv -h 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`
查看协程
(dlv) goroutines Goroutine 1 - User: GOROOT/src/runtime/sema.go:56 sync.runtime_Semacquire (0x73ac8) [semacquire] Goroutine 2 - User: GOROOT/src/runtime/proc.go:307 runtime.gopark (0x450c0) [force gc (idle)] Goroutine 3 - User: GOROOT/src/runtime/proc.go:307 runtime.gopark (0x450c0) [GC sweep wait] Goroutine 4 - User: GOROOT/src/runtime/proc.go:307 runtime.gopark (0x450c0) [GC scavenge wait] Goroutine 5 - User: GOROOT/src/runtime/proc.go:307 runtime.gopark (0x450c0) [GC worker (idle)] Goroutine 6 - User: GOROOT/src/runtime/proc.go:307 runtime.gopark (0x450c0) [GC worker (idle)] Goroutine 7 - User: GOROOT/src/runtime/proc.go:307 runtime.gopark (0x450c0) [GC worker (idle)] Goroutine 8 - User: GOROOT/src/runtime/proc.go:307 runtime.gopark (0x450c0) [GC worker (idle)] Goroutine 9 - User: GOROOT/src/runtime/proc.go:307 runtime.gopark (0x450c0) [GC worker (idle)] Goroutine 10 - User: GOROOT/src/runtime/proc.go:307 runtime.gopark (0x450c0) [GC worker (idle)] Goroutine 11 - User: GOROOT/src/runtime/proc.go:307 runtime.gopark (0x450c0) [GC worker (idle)] Goroutine 12 - User: GOROOT/src/runtime/proc.go:307 runtime.gopark (0x450c0) [GC worker (idle)] Goroutine 13 - User: GOROOT/src/runtime/proc.go:307 runtime.gopark (0x450c0) [GC worker (idle)] Goroutine 14 - User: GOROOT/src/runtime/proc.go:307 runtime.gopark (0x450c0) [GC worker (idle)]
could not open debug info
[root@centos7 ~]# cat go.source export GOPATH=/opt/gopath export GOROOT=/usr/local/go15.2/go export GOARCH=arm64 export GOOS=linux export GOTOOLS=/pkg/tool #export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/bin:/bin:/bin export PATH=$PATH:$GOPATH/bin export PATH=$PATH:$GOROOT/bin [root@centos7 ~]# ls /opt/gopath/bin/dlv /opt/gopath/bin/dlv [root@centos7 ~]# ps -elf | grep nginx | grep ingress 4 S 101 64638 64619 0 80 0 - 7 SyS_rt 03:05 ? 00:00:00 /usr/bin/dumb-init -- /nginx-ingress-controller --publish-service=ingress-nginx/ingress-nginx-controller --election-id=ingress-controller-leader --ingress-class=nginx --configmap=ingress-nginx/ingress-nginx-controller --validating-webhook=:8443 --validating-webhook-certificate=/usr/local/certificates/cert --validating-webhook-key=/usr/local/certificates/key 4 S 101 64679 64638 0 80 0 - 11673 SyS_ep 03:05 ? 00:00:13 /nginx-ingress-controller --publish-service=ingress-nginx/ingress-nginx-controller --election-id=ingress-controller-leader --ingress-class=nginx --configmap=ingress-nginx/ingress-nginx-controller --validating-webhook=:8443 --validating-webhook-certificate=/usr/local/certificates/cert --validating-webhook-key=/usr/local/certificates/key [root@centos7 ~]# dlv attach 64679 could not attach to pid 64679: could not open debug info [root@centos7 ~]#
一、dlv的安装
1)下载dlv
git clone https://github.com/go-delve/delve.git $GOPATH/src/github.com/go-delve/delve
或者 go get github.com/derekparker/delve/cmd/dlv
2)安装
cd $GOPATH/src/github.com/go-delve/delve
make install
二、dlv简要使用说明
2.1、获取帮助信息
安装后执行dlv -h将会看到帮助信息:
上面的信息只是列出了命令列表,具体使用方法没有给出,我们可以执行dlv help + 具体命令来查看详细说明,
比如我们执行dlv help attach:
2.2、进入调试模式
1)dlv attach pid:类似与gdb attach pid,可以对正在运行的进程直接进行调试(pid为进程号)。
2)dlv debug:运行dlv debug test.go会先编译go源文件,同时执行attach命令进入调试模式,该命令会在当前目录下生成一个名为debug的可执行二进制文件,退出调试模式会自动被删除。
3)dlv exec executable_file :直接从二进制文件启动调试模式。如果要带参数执行需要添加--,如dlv exec executable_file -- -f xxx.conf
4)dlv core executable_file core_file:以core文件启动调试,通常进行dlv的目的就是为了找出可执行文件core的原因,通过core文件可直接找出具体进程异常的信息。
3、常用调试方法
3.1 dlv trace追踪调用轨迹
该命令最直接的用途是可以追踪代码里函数的调用轨迹,
如下源代码,现用trace命令跟踪其调轨迹。
package main import ( "fmt" "time" ) func Test() { fmt.Println("hello") time.Sleep(1000 * 1000 * 100) } func Test2() { fmt.Println("world") time.Sleep(1000 * 1000 * 100) } func main() { for i := 0; i < 2; i++ { go Test() go Test2() } time.Sleep(1000 * 1000 * 2000) fmt.Println("end") }
运行结果,这里看除了Test,test2也被追踪:
$ dlv trace hello.go Test
> goroutine(19): main.Test2()
> goroutine(21): main.Test2()
> goroutine(18): main.Test()
world
hello
world
> goroutine(20): main.Test()
hello
=> ()
=> ()
=> ()
=> ()
end
3.2 调试模式基本命令
这里用上节的源码作为示例进行调试。开始调试:dlv debug hello.go
1)b(break):打断点
设置断点,当需要设置多个断点时,为了断点可识别可进行自定义命名。进入调试模式后先打断点。
例:b Test
b test.go:13
2)r(restart):重启当前进程
类似gdb里的run,如果刚执行dlv debug hello.go,进程已经起来,不用执行。如果进程已结算或需要重新开始则需要执行r
3)c(continue):继续执行到断点处
4)bp:查看所有断点
5)on :当运行到某断点时执行相应命令
断点可以是名称(在设置断点时可命名断点)或者编号,例如on 3 p i表示运行到断点3时打印变量i。
6)cond(condition) :有条件的断点
针对某个断点,只有表达式成立才会被中断。例:
condition 3 i==1
7)n(next):逐行执行代码,不进入函数内
8)s(step):逐行执行代码,遇到函数会跳进内部
9)stepout:当使用s命令进入某个函数后,执行它可跳出函数
10)si(step-instruction):单步单核执行代码
如果不希望多协程并发执行可以使用该命令,这在多协程调试时极为方便。
11)args:查看被调用函数所传入的参数值
12)locals:查看所有局部变量
locals var_name:查看具体某个变量,var_name可以是正则表达式。
13)clear:清除单个断点
14)clearall:清除所有断点
15)list:打印当前断点位置的源代码
list后面加行号可以展示该行附近的源代码,要注意该行必须是代码行而不能是空行。
16)bt:打印当前栈信息。
3.3 多协程调试
1)goroutines:显示所有协程
2)goroutine:协程切换
先执行goroutine 7表示切换到7号协程上
3.4 其他命令
1)frame:切换栈。
2)regs:打印寄存器内容。
3)sources:打印所有源代码文件路径
4)source:执行一个含有dlv命令的文件
source命令允许将dlv命令放在一个文件中,然后逐行执行文件内的命令。
5)trace:类似于打断点,但不会中断,同时会输出一行提示信息