Go 博客

Go 代码调试(现状报告)

Luuk van Dijk
2010 年 11 月 2 日

谈到调试,没有什么比一些策略性的打印语句来检查变量或一个恰当的 panic 来获取堆栈跟踪更有效了。然而,有时候你可能缺乏耐心或没有源代码,在这些情况下,一个好的调试器是无价的。正因为如此,在过去几个版本中,我们一直在改进 Go 的 gc 链接器 (6l, 8l) 对 GNU 调试器 GDB 的支持。

在最新的版本 (2010-11-02) 中,6l 和 8l 链接器在生成 ELF (Linux, FreeBSD) 或 Mach-O (Mac OS X) 二进制文件时会发出 DWARF3 调试信息。DWARF 代码足够丰富,可以实现以下功能:

  • 在 GDB 7.x 版本中加载 Go 程序,
  • 按行显示所有 Go、C 和汇编源代码文件(Go 运行时的一部分是用 C 和汇编编写的),
  • 按行设置断点并单步执行代码,
  • 打印堆栈跟踪并检查堆栈帧,以及
  • 查找大多数变量的地址并打印其内容。

仍然存在一些不便之处

  • 生成的 DWARF 代码无法被 Mac OS X 自带的 GDB 6.x 版本读取。我们乐意接受使 DWARF 输出与标准 OS X GDB 兼容的补丁,但在修复之前,您需要在 OS X 下下载、构建和安装 GDB 7.x 才能使用它。源代码可以在 http://sourceware.org/gdb/download/ 找到。由于 OS X 的特殊性,您需要在本地文件系统上使用 chgrp procmodchmod g+s 命令安装该二进制文件。
  • 名称使用包名进行限定,并且由于 GDB 不理解 Go 包,您必须使用完整的名称来引用每个项。例如,在 main 包中名为 v 的变量必须引用为 'main.v',并用单引号括起来。由此带来的一个后果是变量和函数名的 tab 自动补全功能不起作用。
  • 词法作用域信息有些模糊。如果存在多个同名变量,第 n 个实例会带有一个形如 ‘#n’ 的后缀。我们计划修复这个问题,但这需要对编译器和链接器之间交换的数据进行一些更改。
  • Slice 和 string 变量在运行时库中表示为其底层结构。它们看起来像 {data = 0x2aaaaab3e320, len = 1, cap = 1}。对于 slice,您必须解引用数据指针才能查看其元素。

有些功能尚不起作用

  • Channel、function、interface 和 map 变量无法查看。
  • 只有 Go 变量标注了类型信息;运行时的 C 变量没有。
  • Windows 和 ARM 二进制文件不包含 DWARF 调试信息,因此无法用 GDB 查看。

在接下来的几个月里,我们打算解决这些问题,无论是通过修改编译器和链接器,还是通过使用 GDB 的 Python 扩展。与此同时,我们希望 Go 程序员能从更好地使用这个知名的调试工具中受益。

附注:DWARF 信息也可以被 GDB 以外的工具读取。例如,在 Linux 上,您可以将其与 sysprof 系统级分析器一起使用。

下一篇文章:Go:一年前的今天
上一篇文章:Go 实际项目:SmartTwitter 和 web.go
博客目录