Debug Golang With Delve

Golang在其官方文档 说明

Note that Delve is a better alternative to GDB when debugging Go programs built with the standard toolchain. It understands the Go runtime, data structures, and expressions better than GDB. Delve currently supports Linux, OSX, and Windows on amd64. For the most up-to-date list of supported platforms, please see the Delve documentation.

相比于GDB,Delve更适合于Golang程序的Debug操作,为了这句官方的推荐,我们也应该去尝试一下Delve。当前Delve可以支持Linux/OSX/Windows这几个主流平台,基本可以替代GDB的使用。

安装

安装Delve可以参考官方文档,这里以Mac为例。

首先确保xcode以及其插件已经安装好:

xcode-select --install

Delve本身也是用Golang写的,所以接着通过go get安装Delve。

$ go get -u github.com/derekparker/delve/cmd/dlv

安装好之后,通过

dlv version

可以看到当前版本号:

[cz@air_11:delve]$dlv version
Delve Debugger
Version: 1.0.0
Build: 8ce88095c6ea40a1d10ac2e07b7ce950f6dfaa2f

调试程序

现在开始写个简单求和程序

package main

import (
    "fmt"
)

func sum(a, b int) int {
    s := a + b
    return s
}

func main() {
    s := sum(1, 2)
    fmt.Printf("1 + 2 = %d \n", s)
}

在代码目录下执行:

dlv debug

看到:

[cz@air_11:delve]$dlv debug
Type 'help' for list of commands.
(dlv)

进入到debug界面,这里基本和gdb abc_exe一样。这里会自动编译当前目录中的main包并类似gcc一样加上-g选项。

首先在main函数的地方设个断点:

(dlv) b main.main
Breakpoint 1 set at 0x10b4228 for main.main() ./main.go:18

然后,执行到该断点:

(dlv) c
> main.main() ./main.go:18 (hits goroutine(1):1 total:1) (PC: 0x10b4228)
Warning: debugging optimized function
    13: func sum(a, b int) int {
    14:     s := a + b
    15:     return s
    16: }
    17:
=>  18: func main() {
    19:     s := sum(1, 2)
    20:     fmt.Printf("1 + 2 = %d \n", s)
    21: }

这里"b"是"break"的缩写,"c"是"continue" 的缩写。如果熟悉GDB(做后台的别说不熟悉)这里会
有点不同,这里没有"run"命令,而直接是"continue"到第一个断点。如果不带参数的话,其实"run"和“continue”并没有使用上的区别。

在设置断点到sum函数,并运行到该断点:

(dlv) b main.sum
Breakpoint 2 set at 0x10b41d0 for main.sum() ./main.go:13
(dlv) c
> main.sum() ./main.go:13 (hits goroutine(1):1 total:1) (PC: 0x10b41d0)
Warning: debugging optimized function
     8:
     9: import (
    10:     "fmt"
    11: )
    12:
=>  13: func sum(a, b int) int {
    14:     s := a + b
    15:     return s
    16: }
    17:
    18: func main() {

这里看到执行到了sum函数。

接着单步进入函数内:

(dlv) s
> main.sum() ./main.go:14 (PC: 0x10b41e7)
Warning: debugging optimized function
     9: import (
    10:     "fmt"
    11: )
    12:
    13: func sum(a, b int) int {
=>  14:     s := a + b
    15:     return s
    16: }
    17:
    18: func main() {
    19:     s := sum(1, 2)

在函数内部,单步下一句:

(dlv) n
> main.sum() ./main.go:15 (PC: 0x10b41f5)
Warning: debugging optimized function
    10:     "fmt"
    11: )
    12:
    13: func sum(a, b int) int {
    14:     s := a + b
=>  15:     return s
    16: }
    17:
    18: func main() {
    19:     s := sum(1, 2)
    20:     fmt.Printf("1 + 2 = %d \n", s)

如果想查看相关代码。

(dlv) l 13
Showing /Users/cz/Proj/golang/src/test.air/delve/main.go:13 (PC: 0x10b41d0)
   8:
   9:   import (
  10:       "fmt"
  11:   )
  12:
  13:   func sum(a, b int) int {
  14:       s := a + b
  15:       return s
  16:   }
  17:
  18:   func main() {

查看指定行号,或者查看函数:

(dlv) l sum
Showing /Users/cz/Proj/golang/src/test.air/delve/main.go:13 (PC: 0x10b41d0)
   8:
   9:   import (
  10:       "fmt"
  11:   )
  12:
  13:   func sum(a, b int) int {
  14:       s := a + b
  15:       return s
  16:   }
  17:
  18:   func main() {

最后退出:

quit

总的来说。整个操作过程和GDB基本类似。只要熟悉Debug过程,可以很快的上手使用。

指定debug程序

上面的dlv debug是直接编译并开始debug。还可以直接传递包的路径,来指定debug那个程序。

比如:

dlv debug github.com/nsqio/nsq/apps/nsqd

不论在哪个位置,执行上面的命令都会去debug nsqd程序。

因为Golang工具链的test和trace属性,Delve还支持debug 指定的test和trace程序,其实就是和Golang的test机制很好的结合在一起。

比如在相关目录执行:

dlv test

就可以调试这个目录下的单元测试代码,即"_test.go"的代码。同样如果传递一个包目录,就会执行指定目录下的test. 而dlv trace则是执行trace代码。

比如我们到Golang的源码目录下的string包:

cd $GOROOT/src/strings

让后执行:

    [cz@air_11:strings]$dlv test
    Type 'help' for list of commands.
    (dlv) funcs ExampleToUpper
    strings_test.ExampleToUpper
    (dlv) b strings_test.ExampleToUpper
    Breakpoint 1 set at 0x1150fe8 for strings_test.ExampleToUpper() ./example_test.go:270
    (dlv) c
    > strings_test.ExampleToUpper() ./example_test.go:270 (hits goroutine(1):1 total:1) (PC: 0x1150fe8)
    Warning: debugging optimized function
       265:     r := strings.NewReplacer("<", "&lt;", ">", "&gt;")
       266:     fmt.Println(r.Replace("This is <b>HTML</b>!"))
       267:     // Output: This is &lt;b&gt;HTML&lt;/b&gt;!
       268: }
       269:
    => 270: func ExampleToUpper() {
       271:     fmt.Println(strings.ToUpper("Gopher"))
       272:     // Output: GOPHER
       273: }
       274:
       275: func ExampleToLower() {
    (dlv)

这里可以看到是在测试代码的ExampleToUpper函数中断了下来,我们来调试字符串中转换大写的源码。

这里一路"s"下去(split),会看到,最终执行了:

    (dlv) s
    > strings.Map() ./strings.go:518 (PC: 0x10e2aad)
    Warning: debugging optimized function
       513:     var b []byte
       514:     // nbytes is the number of bytes encoded in b.
       515:     var nbytes int
       516:
       517:     for i, c := range s {
    => 518:         r := mapping(c)
       519:         if r == c {
       520:             continue
       521:         }
       522:
       523:         b = make([]byte, len(s)+utf8.UTFMax)
    (dlv) p c
    71

可以看到string包源码中,最终是将"Gopher"中的每个字符去到mapping函数中找到其对应的大写字母,这里打印第一个字符c为71也就是ASCII表示的"G",查表得到为其本身。这样我们就可以单步的去看
Golang标准库源码了。

当然,除了指定debug二进制文件,Delve还和gdb一样可以attach到一个正在运行的进程上面,使用:

dlv attach pid 

以及加载一个coredump文件:

dlv core <executable> <core>

这个操作起来和gdb基本没有任何区别。

CZ_Golang

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容