调试程序是程序猿的一项必备技能,有多种手段来调试程序,如打印控制台输出,查看日志,以及设置断点,使用 debug 做单步跟踪进去调试。这篇文章主要从 go 使用 debug 为题进行展开。
GDB
介绍
GDB 是 GNU 开源组织发布的一个强大的 UNIX 下的程序调试工具。在 mac 上安装,会有认证方面的问题,查了一些资料,没能解决,就放弃了。使用 vagrant 搭建了一个 go 的环境并安装了 gdb 工具,在需要使用 gdb 时,通常是将代码通过 vagrant 目录映射到 linux 虚拟主机中,然后进行 GDB 调试。这种用的也不是很多,一般主要使用 GDB 提供的 x 命令,查看下内存的值。
debug 目标
- 设置断点
- 查看变量值的输出
- 查看变量内存地址
- 查看变量内存值
- 修改变量的值
基于以上四点,我们通过程序来展示 gdb 的基本用法
gdb 用法
示例程序:
package main
import (
"fmt"
"os"
)
func main() {fmt.Println("go debug.....")
// 命令参数使用
var argc = len(os.Args)
var argv = append([]string{}, os.Args...)
fmt.Printf("argc:%d\n", argc)
fmt.Printf("argv:%v\n", argv)
// 查看变量内存地址及值
var aa = 1
var bb = -1
fmt.Println(aa)
fmt.Println(bb)
}
- 编译程序
go build -gcflags="-N -l" demo.go // -N - l 用于关闭编译器的内联优化
- 启动 gdb
gdb demo
- 设置断点 break
(gdb) b main.main
Breakpoint 1 at 0x488e60: file /home/vagrant/godemo/demo01/demo.go, line 8.
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000488e60 in main.main at /home/vagrant/godemo/demo01/demo.go:8
(gdb)
启动程序 run
(gdb) run arg1 agr2
Starting program: /home/vagrant/godemo/demo01/demo arg1 agr2
[New LWP 5976]
[New LWP 5977]
[New LWP 5978]
Thread 1 "demo" hit Breakpoint 1, main.main () at /home/vagrant/godemo/demo01/demo.go:8
8 func main() {(gdb)
查看代码
(gdb) l
4 "fmt"
5 "os"
6 )
7
8 func main() {9 fmt.Println("go debug.....")
10 // 命令参数使用
11 var argc = len(os.Args)
12 var argv = append([]string{}, os.Args...)
13 fmt.Printf("argc:%d\n", argc)
(gdb)
14 fmt.Printf("argv:%v\n", argv)
15
16 // 查看变量内存地址及值
17 var aa = 1
18 var bb = -1
19
20 fmt.Println(aa)
21 fmt.Println(bb)
22 }
(gdb)
单步执行 next
(gdb) n
go debug.....
11 var argc = len(os.Args)
(gdb) n
12 var argv = append([]string{}, os.Args...)
(gdb) n
13 fmt.Printf("argc:%d\n", argc)
(gdb) n
argc:3
14 fmt.Printf("argv:%v\n", argv)
(gdb) n
argv:[/home/vagrant/godemo/demo01/demo arg1 agr2]
打印命令 p
打印格式
x 按十六进制格式显示变量。
d 按十进制格式显示变量。
u 按十六进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
c 按字符格式显示变量。
f 按浮点数格式显示变量。
17 var aa = 1
(gdb) n
18 var bb = -1
(gdb) p aa
$1 = 1
(gdb) p &aa
$2 = (int *) 0xc00007ce40
(gdb) p/x aa
$3 = 0x1
查看内存值命令 x
x/<n/f/u> <addr>
n、f、u 是可选的参数。
n 是一个正整数,表示显示内存的长度
f 表示显示的格式,参见上面
u 表示字节数,GDB 默认是 4 个 bytes。
b 表示单字节
h 表示双字节
w 表示四字节
g 表示八字节
<addr> 表示一个内存地址
(gdb) p &aa
$2 = (int *) 0xc00007ce40
(gdb) x/1dg 0xc00007ce40
0xc00007ce40: 1
(gdb)
设置值命令
(gdb) set aa = 2
(gdb) p aa
$4 = 2
(gdb)
程序调用栈 bt
显示 goroutines
info goroutines // 显示当前执行的 goroutine 列表,如下代码所示, 带 * 的表示当前执行的
查看变量类型
whatis
这里只列出出来了一些基本的用法,gdb 很强大,还有很多命令,可以深入程序执行的底层,通过以上几个命令,可以完成一个程序的基本调试。
delve
delve 是专为 go 语言打造的 debug 工具,现在的一些 IDE 工具的 debug 功能就是基于这个实现的。
启动 debug 服务
dlv debug demo.go
其它的命令同 gdb 大体相同,初级的调试,高级的使用功能,还未深入研究,另外它还可以 attach 到一个运行的程序进行 debug。
IDE 工具
如果不习惯使用命令行,可以使用集成开发工具 goland,这个带有图形化界面操作的 debug 工具,操作起来比较方便。
喜欢请关注“云端漫记 ”, 持续为你更新