目录

【Go】Go语言的调试利器 dlv debug

简述

之前介绍了Go如何产生coredump,也发现了gdb无法分析Go生成的coredump文件,今天来一起学习一下,Go语言的调试利器 dlv 如何分析coredump。

开始

环境安装

Linux环境安装

方法一:

go get github.com/go-delve/delve/cmd/dlv

注意:如果在go mod的模式下使用 Go,则必须在模块目录之外执行此命令,否则 Delve 将作为依赖项添加到项目中。

方法二:

确保$GOPATH设置:

1
2
3
$ git clone https://github.com/go-delve/delve.git $GOPATH/src/github.com/go-delve/delve
$ cd $GOPATH/src/github.com/go-delve/delve
$ make install
  • 推荐使用第一种的方法。

分析coredump

  • Demo
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
package main

import "fmt"

func main() {
  a := 10
  for i := 1; i <= 10; i++ {
    fmt.Println(a/(10-i))
  }
}
  • gdb查看,发现查不出什么问题来。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    
    $ gdb main core.main.4744
    GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-120.el7
    Copyright (C) 2013 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
    and "show warranty" for details.
    This GDB was configured as "x86_64-redhat-linux-gnu".
    For bug reporting instructions, please see:
    <http://www.gnu.org/software/gdb/bugs/>...
    Reading symbols from /root/main/main...done.
    [New LWP 4744]
    [New LWP 4748]
    [New LWP 4746]
    [New LWP 4745]
    [New LWP 4747]
    Core was generated by `./main'.
    Program terminated with signal 6, Aborted.
    #0  runtime.raise () at /usr/local/go/src/runtime/sys_linux_amd64.s:165
    165		RET
    warning: File "/usr/local/go/src/runtime/runtime-gdb.py" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load:/usr/bin/mono-gdb.py".
    To enable execution of this file add
    	add-auto-load-safe-path /usr/local/go/src/runtime/runtime-gdb.py
    line to your configuration file "/root/.gdbinit".
    To completely disable this security protection add
    	set auto-load safe-path /
    line to your configuration file "/root/.gdbinit".
    For more information about this security protection see the
    "Auto-loading safe path" section in the GDB manual.  E.g., run from the shell:
    	info "(gdb)Auto-loading safe path"
    (gdb) bt full
    #0  runtime.raise () at /usr/local/go/src/runtime/sys_linux_amd64.s:165
    No locals.
    #1  0x000000000044637d in runtime.dieFromSignal (sig=6)
        at /usr/local/go/src/runtime/signal_unix.go:776
    No locals.
    #2  0x0000000000446891 in runtime.sigfwdgo (sig=6, info=0xc000009bf0,
        ctx=0xc000009ac0, ~r3=<optimized out>)
        at /usr/local/go/src/runtime/signal_unix.go:990
            fwdFn = <optimized out>
            flags = <optimized out>
            g = <optimized out>
    #3  0x0000000000445034 in runtime.sigtrampgo (sig=6, info=0xc000009bf0,
        ctx=0xc000009ac0) at /usr/local/go/src/runtime/signal_unix.go:428
            setStack = <optimized out>
            gsignalStack = <optimized out>
            g = <optimized out>
    #4  0x0000000000464da3 in runtime.sigtramp ()
        at /usr/local/go/src/runtime/sys_linux_amd64.s:409
    No locals.
    #5  0x0000000000464ea0 in ?? ()
    No locals.
    #6  0x0000000000000007 in ?? ()
    No symbol table info available.
    #7  0x0000000000000000 in ?? ()
    ---Type <return> to continue, or q <return> to quit---
    No symbol table info available.
    
  • 使用dlv分析

    1
    2
    3
    4
    
    // dlv core {运行文件} {coredump文件}
    $ dlv core main core.main.4744
    Type 'help' for list of commands.
    (dlv)
    
  • 查看所有的goroutines

    1
    2
    3
    4
    5
    6
    7
    
    (dlv) goroutines
    * Goroutine 1 - User: ./main.go:8 main.main (0x49915a) (thread 4744)
      Goroutine 2 - User: /usr/local/go/src/runtime/proc.go:307 runtime.gopark (0x434e85)
      Goroutine 3 - User: /usr/local/go/src/runtime/proc.go:307 runtime.gopark (0x434e85)
      Goroutine 4 - User: /usr/local/go/src/runtime/proc.go:307 runtime.gopark (0x434e85)
      Goroutine 17 - User: /usr/local/go/src/runtime/mfinal.go:161 runtime.runfinq (0x416340)
    [5 goroutines]
    
  • 选择异常的goroutines并查看

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    
    (dlv) goroutine 1
    Switched from 1 to 1 (thread 4744)
    (dlv) bt
     0  0x0000000000464a01 in runtime.raise
        at /usr/local/go/src/runtime/sys_linux_amd64.s:165
     1  0x000000000044637d in runtime.dieFromSignal
        at /usr/local/go/src/runtime/signal_unix.go:776
     2  0x0000000000446891 in runtime.sigfwdgo
        at /usr/local/go/src/runtime/signal_unix.go:990
     3  0x0000000000445034 in runtime.sigtrampgo
        at /usr/local/go/src/runtime/signal_unix.go:428
     4  0x0000000000464da3 in runtime.sigtramp
        at /usr/local/go/src/runtime/sys_linux_amd64.s:409
     5  0x0000000000464ea0 in runtime.sigreturn
        at /usr/local/go/src/runtime/sys_linux_amd64.s:501
     6  0x000000000043254b in runtime.crash
        at /usr/local/go/src/runtime/signal_unix.go:868
     7  0x000000000043254b in runtime.fatalpanic
        at /usr/local/go/src/runtime/panic.go:1216
     8  0x0000000000431e85 in runtime.gopanic
        at /usr/local/go/src/runtime/panic.go:1064
     9  0x000000000043059b in runtime.panicdivide
        at /usr/local/go/src/runtime/panic.go:191
    10  0x000000000049915a in main.main
        at ./main.go:8
    11  0x0000000000434a89 in runtime.main
        at /usr/local/go/src/runtime/proc.go:204
    12  0x0000000000463201 in runtime.goexit
        at /usr/local/go/src/runtime/asm_amd64.s:1374
    (dlv)
    
  • 查看代码出现问题的地方

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    (dlv) frame 10
    > runtime.raise() /usr/local/go/src/runtime/sys_linux_amd64.s:165 (PC: 0x464a01)
    Warning: debugging optimized function
    Frame 10: ./main.go:8 (PC: 49915a)
         3:	import "fmt"
         4:
         5:	func main() {
         6:	  a := 10
         7:	  for i := 1; i <= 10; i++ {
    =>   8:	    fmt.Println(a/(10-i))
         9:	  }
        10:	}
    
  • 测试完成,基本定位到出问题代码的位置。

总结

dlv不仅仅只是可以分析coredump这边简单的功能,还有非常强大的使用方式,时间原因,先简单的写,后续扩展怎么使用dlv调试。