|
| 1 | +# 1.17 如何使用 GDB 调试 Go 程序? |
| 2 | + |
| 3 | +做为新手,熟练掌握一个好的调试工具,对于我们学习语言或者排查问题的时候,非常有帮助。 |
| 4 | + |
| 5 | +你如果使用 VS Code 或者 Goland ,可以直接上手,我就不再写这方面的文章了。 |
| 6 | + |
| 7 | +其实相比有用户界面的 IDE 调试工具,我更喜欢简单直接的命令行调试,原因有三点: |
| 8 | + |
| 9 | +1. 速度快,个人感觉在 Windows 下速度巨慢 |
| 10 | +2. 依赖少,在 Linux 服务器上 也能轻松调试 |
| 11 | +3. 指令简单,我习惯只使用快捷键就能操作 |
| 12 | + |
| 13 | +如果你有和我一样的感受和习惯,可以看下今天的文章,介绍的是 GDB 调试工具。 |
| 14 | + |
| 15 | +## 1. 下载安装 Go |
| 16 | + |
| 17 | +在 Linux 上进行调试,那咱所以得先安装 Go ,由于第一节里只讲了 Windows 的下载安装,并没有讲到在 Linux 上如何安装。所以这里要先讲一下,已经安装过了可以直接跳过。 |
| 18 | + |
| 19 | +首先在 go 下载页面上(https://golang.org/dl/),查看并复制源码包的的下载地址 |
| 20 | + |
| 21 | + |
| 22 | + |
| 23 | +登陆 linux 机器 ,使用 wget 下载 |
| 24 | + |
| 25 | +```shell |
| 26 | +$ wget https://dl.google.com/go/go1.14.2.linux-amd64.tar.gz |
| 27 | +``` |
| 28 | + |
| 29 | + |
| 30 | + |
| 31 | + |
| 32 | + |
| 33 | +将下载的源码包解压到 `/usr/local` 目录下,并设置环境变量 |
| 34 | + |
| 35 | +```SHELL |
| 36 | +[root@localhost ~]# tar -C /usr/local -xzf go1.14.2.linux-amd64.tar.gz |
| 37 | +[root@localhost ~]# |
| 38 | +[root@localhost ~]# export PATH=$PATH:/usr/local/go/bin |
| 39 | +[root@localhost ~]# which go |
| 40 | +/usr/local/go/bin/go |
| 41 | +[root@localhost ~]# |
| 42 | +[root@localhost ~]# go version |
| 43 | +go version go1.14.2 linux/amd64 |
| 44 | +[root@localhost ~]# |
| 45 | +``` |
| 46 | + |
| 47 | +## 2. 开始进行调试 |
| 48 | + |
| 49 | +调试使用的是 GDB (好像要求版本 7.1 + ),使用前,请先确保你的机器上已经安装 GDB |
| 50 | + |
| 51 | +``` |
| 52 | +[root@localhost code]# which gdb |
| 53 | +/usr/bin/gdb |
| 54 | +``` |
| 55 | + |
| 56 | + |
| 57 | + |
| 58 | +准备就绪后,先在目录下写一个测试文件 |
| 59 | + |
| 60 | +```go |
| 61 | +package main |
| 62 | + |
| 63 | +import "fmt" |
| 64 | + |
| 65 | +func main(){ |
| 66 | + msg := "hello, world" |
| 67 | + fmt.Println(msg) |
| 68 | +} |
| 69 | +``` |
| 70 | + |
| 71 | +然后执行 如下命令进行编译,里面有好多个参数,我还没去了解是什么意思,有疑问的可以自行搜索引擎 |
| 72 | + |
| 73 | +```shell |
| 74 | +$ go build -gcflags "-N -l" demo.go |
| 75 | +``` |
| 76 | + |
| 77 | +最后使用 GDB 命令进入调试界面 |
| 78 | + |
| 79 | +```shell |
| 80 | +# 如果你喜欢这种界面的话,用这条命令 |
| 81 | +$ gdb -tui demo |
| 82 | + |
| 83 | +# 如果你跟我一样不喜欢不习惯用界面,就使用这个命令 |
| 84 | +$ gdb demo |
| 85 | +``` |
| 86 | + |
| 87 | +完整操作如下: |
| 88 | + |
| 89 | + |
| 90 | + |
| 91 | +进入 GDB 调试界面后,并不是立即可用,你先需要回车,然后再你敲入几行命令,调试窗口就会出现代码。 |
| 92 | + |
| 93 | +```shell |
| 94 | +(gdb) b main.main # 在 main 包里的 main 函数 加断点 |
| 95 | +Breakpoint 1 at 0x4915c0: file /home/wangbm/code/demo.go, line 5. |
| 96 | +(gdb) run # 执行进程 |
| 97 | +Starting program: /home/wangbm/code/demo |
| 98 | +Breakpoint 1, main.main () at /home/wangbm/code/demo.go:5 |
| 99 | +(gdb) |
| 100 | +``` |
| 101 | + |
| 102 | + |
| 103 | + |
| 104 | + |
| 105 | + |
| 106 | + |
| 107 | + |
| 108 | +## 3. 详解调试指令 |
| 109 | + |
| 110 | +要熟练使用 GDB ,你得熟悉的掌握它的指令,这里列举一下 |
| 111 | + |
| 112 | +- `r`:run,执行程序 |
| 113 | +- `n`:next,下一步,不进入函数 |
| 114 | +- `s`:step,下一步,会进入函数 |
| 115 | +- `b`:breakponit,设置断点 |
| 116 | +- `l`:list,查看源码 |
| 117 | +- `c`:continue,继续执行到下一断点 |
| 118 | +- `bt`:backtrace,查看当前调用栈 |
| 119 | +- `p`:print,打印查看变量 |
| 120 | +- `q`:quit,退出 GDB |
| 121 | +- `whatis`:查看对象类型 |
| 122 | +- `info breakpoints`:查看所有的断点 |
| 123 | +- `info locals`:查看局部变量 |
| 124 | +- `info args`:查看函数的参数值及要返回的变量值 |
| 125 | +- `info frame`:堆栈帧信息 |
| 126 | +- ` info goroutines`:查看 goroutines 信息。在使用前 ,需要注意先执行 /usr/local/go/src/runtime/runtime-gdb.py |
| 127 | + |
| 128 | +- `goroutine 1 bt`:查看指定序号的 goroutine 调用堆栈 |
| 129 | +- 回车:重复执行上一次操作 |
| 130 | + |
| 131 | + |
| 132 | + |
| 133 | +其中有几个指令的使用比较灵活 |
| 134 | + |
| 135 | +比如 l - list,查看代码 |
| 136 | + |
| 137 | +``` |
| 138 | +# 查看指定行数上下5行 |
| 139 | +(gdb) l 8 |
| 140 | +
|
| 141 | +# 查看指定范围的行数 |
| 142 | +(gdb) l 5:8 |
| 143 | +
|
| 144 | +# 查看指定文件的行数上下5行 |
| 145 | +l demo.go:8 |
| 146 | +
|
| 147 | +# 可以查看函数,记得加包名 |
| 148 | +l main.main |
| 149 | +``` |
| 150 | + |
| 151 | +把上面的 `l` 换成 `b` ,大多数也同样适用 |
| 152 | + |
| 153 | +``` |
| 154 | +# 在指定行打断点 |
| 155 | +(gdb) b 8 |
| 156 | +
|
| 157 | +
|
| 158 | +# 在指定指定文件的行打断点 |
| 159 | +b demo.go:8 |
| 160 | +
|
| 161 | +# 在指定函数打断点,记得加包名 |
| 162 | +b main.main |
| 163 | +``` |
| 164 | + |
| 165 | +还有 p - print,打印变量 |
| 166 | + |
| 167 | +``` |
| 168 | +# 查看变量 |
| 169 | +(gdb) p var |
| 170 | +
|
| 171 | +# 查看对象长度或容量 |
| 172 | +(gdb) p $len(var) |
| 173 | +(gdb) p $cap(var) |
| 174 | +
|
| 175 | +# 查看对象的动态类型 |
| 176 | +(gdb) p $dtype(var) |
| 177 | +(gdb) iface var |
| 178 | +
|
| 179 | +# 举例如下 |
| 180 | +(gdb) p i |
| 181 | +$4 = {str = "cbb"} |
| 182 | +(gdb) whatis i |
| 183 | +type = regexp.input |
| 184 | +(gdb) p $dtype(i) |
| 185 | +$26 = (struct regexp.inputBytes *) 0xf8400b4930 |
| 186 | +(gdb) iface i |
| 187 | +regexp.input: struct regexp.inputBytes * |
| 188 | +``` |
| 189 | + |
| 190 | + |
| 191 | + |
| 192 | +以上就是关于 GDB 的使用方法,非常简单,可以自己手动敲下体验一下。 |
| 193 | + |
| 194 | + |
| 195 | + |
| 196 | + |
0 commit comments