使用 GDB 工具调试 Go(4)

如果我等待 WaitGroup 执行完毕再检查 pairs slice 的结果,我们可以预期到内容是完全相同的,虽然它的排序可能有些出入。gdb 真正的威力来自于它可以在 goroutines 正在运行时进行检查:

(gdb) b main.go:43 

Breakpoint 1 at 0x400f7f: file /home/bfosberry/.go/src/github.com/bfosberry/gdb_sandbox/main.go, line 43. 

(gdb) run 

Starting program: /home/bfosberry/.go/src/github.com/bfosberry/gdb_sandbox/gdb_sandbox

 

Breakpoint 1, main.handleNumber (i=0, ~r1=0x0) 

    at /home/bfosberry/.go/src/github.com/bfosberry/gdb_sandbox/main.go:43 

43         y: val, 

(gdb) l 

38     if i%2 == 0 { 

39         val = f(i) 

40     } 

41     return &pair{ 

42         x: i, 

43         y: val, 

44     } 

45 } 

46 

47 func f(x int) int { 

(gdb) info args 

i = 0 

~r1 = 0x0 

(gdb) p val 

$1 = 0

你会发现我们在 goroutine 要执行的代码段中放置了一个断点,从这里我们可以检查到局部变量,和进程中的其它 goroutines:

(gdb) info goroutines 

  1 waiting runtime.gopark 

  2 waiting runtime.gopark 

  3 waiting runtime.gopark 

  4 waiting runtime.gopark 

* 5 running main.main.func1 

  6 runnable main.main.func1 

  7 runnable main.main.func1 

  8 runnable main.main.func1 

  9 runnable main.main.func1 

* 10 running main.main.func1 

  11 runnable main.main.func1 

  12 runnable main.main.func1 

  13 runnable main.main.func1 

  14 runnable main.main.func1 

  15 waiting runtime.gopark 

(gdb) goroutine 11 bt

#0 main.main.func1 (val=6, pairChan=0xc82001a180, &wg=0xc82000a3a0)

    at /home/bfosberry/.go/src/github.com/bfosberry/gdb_sandbox/main.go:19

#1 0x0000000000454991 in runtime.goexit () at /usr/local/go/src/runtime/asm_amd64.s:1696

#2 0x0000000000000006 in ?? ()

#3 0x000000c82001a180 in ?? ()

#4 0x000000c82000a3a0 in ?? ()

#5 0x0000000000000000 in ?? ()

(gdb) goroutine 11 l 

48         return x*x + x 

49     } 

(gdb) goroutine 11 info args 

val = 6 

pairChan = 0xc82001a180 

&wg = 0xc82000a3a0 

(gdb) goroutine 11 p val 

$2 = 6

在这里我们做的第一件事就是列出所有正在运行的 goroutine,并确定我们正在处理的那一个。然后我们可以看到一些回溯,并发送任何调试命令到 goroutine。这个回溯和列表清单并不太准确,如何让回溯更准确,goroutine 上的 info args 显示了我们的局部变量,以及主函数中的可用变量,goroutine 函数之外的使用前缀&

结论

当调试应用时,gdb 的强大令人难以置信。但它仍然是一个相当新的事物,并不是所有的地方工作地都很完美。使用最新的稳定版 gdb,go 1.5 beta2,有不少地方有突破:

Interfaces

根据 go 博客上的文章, go 的 interfaces 应该已经支持了,这允许在 gdb 中动态的投影其基类型。这应该算一个突破。

Interface{} 类型

目前没有办法转换 interface{} 为它的类型。

列出 goroutine 的不同点

在其他 goroutine 中列出周边代码会导致一些行数的漂移,最终导致 gdb 认为当前的行数超出文件范围并抛出一个错误:

(gdb) info goroutines 

  1 waiting runtime.gopark 

  2 waiting runtime.gopark 

  3 waiting runtime.gopark 

  4 waiting runtime.gopark 

* 5 running main.main.func1 

  6 runnable main.main.func1 

  7 runnable main.main.func1 

  8 runnable main.main.func1 

  9 runnable main.main.func1 

* 10 running main.main.func1 

  11 runnable main.main.func1 

  12 runnable main.main.func1 

  13 runnable main.main.func1 

  14 runnable main.main.func1 

  15 waiting runtime.gopark 

(gdb) goroutine 11 bt

#0 main.main.func1 (val=6, pairChan=0xc82001a180, &wg=0xc82000a3a0)

    at /home/bfosberry/.go/src/github.com/bfosberry/gdb_sandbox/main.go:19

#1 0x0000000000454991 in runtime.goexit () at /usr/local/go/src/runtime/asm_amd64.s:1696

#2 0x0000000000000006 in ?? ()

#3 0x000000c82001a180 in ?? ()

#4 0x000000c82000a3a0 in ?? ()

#5 0x0000000000000000 in ?? ()

(gdb) goroutine 11 l 

48         return x*x + x 

49     } 

(gdb) goroutine 11 l 

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/8a0741e1279c3f128596ebdad24eba19.html