Go 博客

调试 Go 代码(状态报告)

Luuk van Dijk
2010 年 11 月 2 日

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

在最新版本(2010-11-02)中,6l 和 8l 链接器在编写 ELF(Linux, FreeBSD)或 Mach-O(Mac OS X)二进制文件时会发出 DWARF3 调试信息。DWARF 代码足够丰富,可以让你做到以下几点:

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

仍然存在一些不便之处

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

有些功能尚不可用

  • 无法检查通道、函数、接口和映射变量。
  • 只有 Go 变量带有类型信息注解;运行时中的 C 变量则没有。
  • Windows 和 ARM 二进制文件不包含 DWARF 调试信息,因此无法使用 GDB 进行检查。

在接下来的几个月里,我们打算通过更改编译器和链接器或使用 GDB 的 Python 扩展来解决这些问题。在此期间,我们希望 Go 程序员能从获得对这个著名调试工具的更好访问权限中受益。

附注:除 GDB 外,其他工具也可以读取 DWARF 信息。例如,在 Linux 上,你可以将其与 sysprof 系统范围的性能分析器一起使用。

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