本文主要介绍如何使用gdb调试golang程序
介绍
- 扩展资料:
- 本地调试首选开发工具
vscode
或 Goland
如何生成 coredump
生成 coredump 文件主要是解决:当程序卡死时,保存卡死时的状态信息,方便程序重启后的环境重现和分析
generate-core-file 命令
# 查看
ulimit -c
# 临时配置不限制 core file size
ulimit -c unlimited
# 永久配置
$ vi /etc/profile
ulimit -c unlimited > /dev/null 2>&1
# kernel.core_uses_pid = 1
kernel.core_pattern=/tmp/core-%e-%p
$ sysctl -p /etc/sysctl.conf
$ gdb attach <pid>
$ generate-core-file
gcore 命令
gcore [-o filename] <pid>
安装 gdb
# ubuntu
apt install gdb -y
# mac
brew install gdb
如何判断文件是否可以 gdb 调试
readelf 信息判断
readelf -S helloWorld | grep debug
gdb 提示信息判断
$ gdb <xxx>
Reading symbols from <xxx>...(no debugging symbols found)...done.
file 命令判断
$ file <xxx>
<xxx>: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, Go BuildID=Yh2hWP1Z5d_8dL4nCZz_/iv3tAH7QSf-UCldvBYHU/RC5nTuSGOsPTxMr8EolO/BlOkw58vu7dijXfFNiJ8, stripped
说明:
stripped
表示文件的符号表信息和调试信息已被去除,文件不能调试
not stripped
可能可以调试
调试的方法
二进制
$ gdb <bin>
# 运行
run
调试已运行程序
$ gdb
(gdb) attach <pid>
# 或
gdb <bin> <pid>
# 或
gdb <bin> --pid <pid>
- 若提示
Could not attach to process
,后文见 F&Q
- 当原进程文件没有调试信息时,使用
file
加载带 debug 的程序文件
$ gdb
(gdb) file <debug-bin>
Reading symbols from hello...done.
(gdb) attach <pid>
go 调试
代码&编译
package main
import "fmt"
func main(){
msg := "hello, world"
fmt.Println(msg)
}
# 初始化
go mod init main
# 编译:关闭内联优化,方便调试(本示例使用)
$ go build -gcflags "-N -l" main.go
# mac build 时,还有添加 `ldflags='-compressdwarf=false'`
# 发布版本,删除调试符号
go build -ldflags "-s -w"
echo "add-auto-load-safe-path /usr/share/go-1.13/src/runtime/runtime-gdb.py" > ~/.gdbinit
# 若未配置,第一次运行时会提示
$ gdb main
...
Reading symbols from main...
warning: File "/usr/share/go-1.13/src/runtime/runtime-gdb.py" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load".
To enable execution of this file add
add-auto-load-safe-path /usr/share/go-1.13/src/runtime/runtime-gdb.py
line to your configuration file "/root/.gdbinit".
To completely disable this security protection add
set auto-load safe-path /
line to your configuration file "/root/.gdbinit".
For more information about this security protection see the
"Auto-loading safe path" section in the GDB manual. E.g., run from the shell:
info "(gdb)Auto-loading safe path"
(gdb)
# 带界面的调试
$ gdb -tui main
# 命令行的调试
$ gdb main
...
Reading symbols from main...
Loading Go Runtime support.
(gdb) b main.main
Breakpoint 1 at 0x48cf20: file /data/abc/main.go, line 5.
(gdb) run
Starting program: /data/abc/main
[New LWP 2247]
[New LWP 2248]
[New LWP 2249]
[New LWP 2250]
[New LWP 2251]
Thread 1 "main" hit Breakpoint 1, main.main () at /data/abc/main.go:5
5 func main(){
(gdb) l
1 package main
2
3 import "fmt"
4
5 func main(){
6 msg := "hello, world"
7 fmt.Println(msg)
8 }
(gdb) n
6 msg := "hello, world"
(gdb) whatis msg
type = string
(gdb) p msg
$1 = 0x40509f "hello, world"
(gdb) info locals
msg = 0x40509f "\353\035H\307\200\240\000\000\000\000\000\000\000H\211\004$H\307D$\b\003\000\000\000\350\262d\002\000H\213D$\020H\205\300t\025\220\220H\205\300t\322H\213\210\240\000\000\000H\211L$\020\353\304H\213l$0H\203\304\070\303H\213D$(H\211\004$\350\033G\000\000H\215\005d\022\n\000H\211\004$H\215\005\tD\r\000H\211D$\b\350/@\002\000H\215\005H\022\n\000H\211\004$H\215\005\255C\r\000H\211D$\b\350\023@\002\000\220\350]\306\004\000\351\210\375\377\377\314\314\314\314\314\314\314\314H\203\354(H\211l$ H\215l$ H\213D$0H\211\004$H\213D$8H\211D$\b\306D$\020\001\350"...
(gdb) info args
No arguments.
(gdb) info frame
Stack level 0, frame at 0xc00008cf60:
rip = 0x48cf41 in main.main (/data/abc/main.go:6); saved rip = 0x42b14e
source language unknown.
Arglist at 0xc00008ced0, args:
Locals at 0xc00008ced0, Previous frame's sp is 0xc00008cf60
Saved registers:
rip at 0xc00008cf58
(gdb) n
7 fmt.Println(msg)
(gdb) n
hello, world
8 }
(gdb) n
runtime.main () at /usr/lib/go-1.13/src/runtime/proc.go:212
212 if atomic.Load(&runningPanicDefers) != 0 {
(gdb) n
225 exit(0)
- 如下通过查看
Entry point
得知入口在 /usr/local/go/src/runtime/rt0_darwin_amd64.s:8
$ GOFLAGS="-ldflags=-compressdwarf=false" go build -o main
$ gdb main
GNU gdb (GDB) 14.2
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from main...
Loading Go Runtime support.
(gdb) info files
Symbols from "/Users/xiexianbin/Downloads/abc/main".
Local exec file:
`/Users/xiexianbin/Downloads/abc/main', file type mach-o-x86-64.
Entry point: 0x105dd80
0x0000000001001000 - 0x00000000010870c8 is .text
0x00000000010870e0 - 0x0000000001087206 is __TEXT.__symbol_stub1
0x0000000001087220 - 0x00000000010c2e9d is __TEXT.__rodata
0x00000000010c2ea0 - 0x00000000010c3444 is __TEXT.__typelink
0x00000000010c3460 - 0x00000000010c34d0 is __TEXT.__itablink
0x00000000010c34d0 - 0x00000000010c34d0 is __TEXT.__gosymtab
0x00000000010c34e0 - 0x0000000001129940 is __TEXT.__gopclntab
0x000000000112a000 - 0x000000000112a150 is __DATA.__go_buildinfo
0x000000000112a150 - 0x000000000112a2d8 is __DATA.__nl_symbol_ptr
0x000000000112a2e0 - 0x000000000112f7c0 is __DATA.__noptrdata
0x000000000112f7c0 - 0x0000000001133490 is .data
0x00000000011334a0 - 0x00000000011613f8 is .bss
0x0000000001161400 - 0x0000000001164c50 is __DATA.__noptrbss
(gdb) b *0x105dd80
Breakpoint 1 at 0x105dd80: file /usr/local/go/src/runtime/rt0_darwin_amd64.s, line 8.
(gdb)
调试命令
-
help
所有帮助信息
-
file <file>
加载要被 gdb 的文件
-
run(r)
执行程序
-
next(n)
下一步,不进入函数
-
step(s)
下一步,会进入函数
-
breakponit(b)
设置断点,使用 tab tab
键提示
b n
指定行打断点
b main.go:n
指定文件行号打断点
b main.main
指定函数打断点,要加包名,如 <project-name>/controller.GetXXX
-
delete(d)
删除断点
-
clear
清楚所有端点
-
list(l)
查看源码,使用 tab tab
键提示
l n
查看行数的下5行代码
l m:n
查看从 m~n 的代码
l main.go:n
查看指定文件行号的下5行代码
l main.main
查看函数,要加包名,如 <project-name>/controller.GetXXX
-
continue(c)
继续执行到下一断点
-
backtrace(bt)
查看当前调用栈
-
print(p)
打印查看变量
-
set variable
改变调试过程中的变量值
-
whatis
查看对象类型
-
info
显示信息
info breakpoints
查看所有的断点
info locals
查看局部变量
info args
查看函数的参数值及要返回的变量值
info frame
堆栈帧信息
info goroutines
查看 goroutines 信息
- 在使用前需配置
echo "source /usr/local/go/src/runtime/runtime-gdb.py"
-
goroutine 1 bt
查看指定序号的 goroutine 调用堆栈
-
quit(q)
退出 GDB
-
回车
执行命令
-
以下 参考
# 显示文件和代码行号、设置断点和反汇编
(gdb) list
(gdb) list line
(gdb) list file.go:line
(gdb) break line
(gdb) break file.go:line
(gdb) disas
# 显示回溯并解除堆栈帧
(gdb) bt
(gdb) frame n
# 显示堆栈帧中局部变量、参数和返回值的名称、类型和位置
(gdb) info locals
(gdb) info args
(gdb) p 变量
(gdb) whatis variable
# 显示全局变量的名称、类型和位置
(gdb) info variables regexp
F&Q
gdb: Could not attach to process
$ attach <pid>
Attaching to process <pid> Could not attach to process. If your uid matches the uid of the target process, check the setting of /proc/sys/kernel/yama/ptrace_scope, or try again as the root user. For more details, see /etc/sysctl.d/10-ptrace.conf ptrace: Operation not permitted.
$ echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
# 修改
$ cat /etc/sysctl.d/10-ptrace.conf
# kernel.yama.ptrace_scope = 1
kernel.yama.ptrace_scope = 0
# 生效
$ sysctl -p
- docker 容器,添加启动参数添加
--cap-add=SYS_PTRACE
- k8s pod
apiVersion: v1
kind: Pod
metadata:
name: xxx
spec:
containers:
- name: xxx
image: "xxx"
securityContext:
capabilities:
add:
- SYS_NICE
drop:
- KILL
...
No debugging symbols found in xxx
编译产物没有调试信息,解决方式:
- 编译时要保留调试信息,如
gcc -c -g xxx.c