Post

go debug(ai)

介绍如何在 Go 程序中进行调试。

go debug(ai)

虽然 Go 语言官方推荐使用 Delve (dlv) 作为调试器,但如果你必须使用 GDB(例如在某些受限环境或习惯原因),以下是详细的步骤。

1. 编译代码(关键步骤)

默认情况下,Go 编译器会进行内联优化和变量寄存器化,这会让 GDB 无法准确断点或查看变量。必须使用 -gcflags "-N -l" 参数来禁用优化和内联。

1
2
# 假设你的入口文件在 cmd/main.go
go build -gcflags "all=-N -l" -o myapp cmd/main.go
  • -N: 禁用优化。
  • -l: 禁用内联。

2. 启动 GDB

加载编译好的二进制文件:

1
gdb ./myapp

注意:如果在加载时看到 “Dwarf Error”,说明你的 GDB 版本可能太老,不支持 Go 生成的 DWARF 信息。

3. GDB 常用调试命令 (针对 Go)

Go 的函数名在 GDB 中包含包路径。例如 main 包下的 main 函数通常是 main.main

设置断点

(gdb) break main.main
# 或者在特定文件行号
(gdb) break /path/to/project/cmd/main.go:15

运行程序

(gdb) run
# 如果需要传参
(gdb) run arg1 arg2

查看源码

(gdb) list

单步调试

(gdb) next  # 单步执行(不进入函数)
(gdb) step  # 单步执行(进入函数)

查看变量

(gdb) print varName
(gdb) info locals

查看 Goroutines (GDB 的弱项)

Go 运行时提供了一个 python 脚本扩展来帮助 GDB 理解 Goroutine。

(gdb) info goroutines

如果没有加载,你可能需要手动 source Go 安装目录下的 src/runtime/runtime-gdb.py

4. 强烈建议:使用 Delve (dlv)

Delve 是 Go 语言官方推荐的调试器,它对 Go 的运行时(Runtime)、数据结构(Map, Channel, Interface)和并发模型(Goroutines)有原生且完美的支持。

4.1 安装 Delve

1
go install github.com/go-delve/delve/cmd/dlv@latest

安装完成后,确保 $(go env GOPATH)/bin 在你的系统 PATH 中。

4.2 启动调试

Delve 提供了多种启动模式,适应不同场景:

A. 源码调试 (最常用) 直接编译并启动调试,无需手动 go build

1
2
# 也就是 go run 的调试版
dlv debug ./cmd/main.go -- arg1 arg2

B. 调试测试代码 调试 _test.go 文件。

1
2
# 也就是 go test 的调试版
dlv test ./pkg/somepackage -- -test.v

C. 调试已编译的二进制 如果你已经编译好了(记得加 -gcflags "all=-N -l"),可以直接加载。

1
dlv exec ./bin/caracal-gateway-debug -- arg1 arg2

D. 附加到运行中的进程 调试正在运行的服务(生产环境排查神器)。

1
2
# 需要 root 权限
dlv attach <PID>

4.3 Delve 常用交互命令

启动 dlv 后,你会进入 (dlv) 交互终端。

断点管理 (Breakpoints)

  • break (或 b):设置断点。
    • b main.main:在 main 函数入口断点。
    • b ./cmd/main.go:15:在指定文件行号断点。
    • b pkg/core/http_jwt.go:45:支持相对路径。
  • breakpoints (或 bp):列出所有断点。
  • clear <id>:清除指定 ID 的断点。
  • clearall:清除所有断点。

流程控制 (Execution)

  • continue (或 c):运行直到断点或程序结束。
  • next (或 n):单步执行(进入函数内部)。
  • step (或 s):单步执行(进入函数内部)。
  • stepout:执行完当前函数并返回到调用者。
  • restart (或 r):重新启动进程。

变量与状态 (Variables & State)

  • print (或 p):打印变量值。支持 Go 表达式。
    • p req.Username
    • p len(slice)
  • locals:打印当前函数栈帧内的所有局部变量。
  • args:打印当前函数的输入参数。
  • vars <regex>:搜索并打印全局变量。
  • whatis <expr>:查看表达式的类型信息。

堆栈与协程 (Stack & Goroutines) —— Delve 的强项

  • stack (或 bt):查看当前协程的调用栈。
  • goroutines:列出所有 Goroutine。
    • goroutines -t:展开显示每个 Goroutine 的栈顶信息。
  • goroutine <id>:切换到指定的 Goroutine 上下文。
    • 切换后,再用 stacklocals 查看的就是那个协程的状态。

4.4 IDE 集成

  • VS Code / GoLand:这些编辑器的图形化调试功能底层调用的就是 dlv。如果你配置了 launch.json (VS Code) 或 Run Configuration (GoLand),你实际上正在使用 Delve。
  • 配置建议:在 IDE 中调试时,如果遇到变量被优化掉显示不全的情况,请确保使用了 -gcflags "all=-N -l" 构建参数(参考本文档第 1 节)。

总结: 如果只是简单的逻辑调试,GDB 配合 -gcflags "-N -l" 可以使用;但如果是涉及并发、复杂数据结构的调试,请务必使用 Delve。

This post is licensed under CC BY 4.0 by the author.