gdb-debug-golang
背景
作为一个 cpper ,已经被 C++ 这种超大型的语言给搞怕了,听到 golang 是一门强类型的编译语言,先入为主的觉得不简单。万万没有想到 golang 是这么的实用主义,上手起来是真的快。
之前也一直是用 gdb 来调试程序,看了一下 go 也支持,所以这里就做一个 demo 记录下过程。
第一步 编写一个简单的 golang 程序
写一个简单的数数的程序。
package main
import "fmt"
func hello(i int) {
if i <= 0 {
fmt.Println("i must big then 0 .")
return
}
for j := 0; j < i; j++ {
fmt.Println(j)
}
}
func main() {
// 从 0 数到 4
var i int = 5
hello(i)
}
第二步 编译
默认情况下 go 编译器会帮我们做一系列的优化、内联 ... ,这个就会导致 gdb 的时候调试不了;所以我们要在编译的时候禁用这些东西。
go build -gcflags '-N -l' -o main main.go
编译后生成的文件为 main,下面准备用 gdb debug 。
gdb main
GNU gdb (GDB) Red Hat Enterprise Linux 10.2-10.el9
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from main...
warning: File "/usr/local/go/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/local/go/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) list
2
3 import "fmt"
4
5 func hello(i int) {
6 if i <= 0 {
7 fmt.Println("i must big then 0 .")
8 return
9 }
10
11 for j := 0; j < i; j++ {
(gdb) list
12 fmt.Println(j)
13 }
14 }
15
16 func main() {
17 var i int = 5
18 hello(i)
19 }
(gdb) list
Line number 20 out of range; /tmp/main.go has 19 lines.
(gdb) b main
Function "main" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (main) pending.
(gdb) b 18
Breakpoint 2 at 0x4806bd: file /tmp/main.go, line 18.
(gdb) run
Starting program: /tmp/main
[New LWP 1101193]
[New LWP 1101194]
[New LWP 1101195]
Thread 1 "main" hit Breakpoint 2, main.main () at /tmp/main.go:18
18 hello(i)
(gdb) s
main.hello (i=5) at /tmp/main.go:5
5 func hello(i int) {
(gdb) n
6 if i <= 0 {
(gdb) n
11 for j := 0; j < i; j++ {
(gdb) n
12 fmt.Println(j)
(gdb) print j
$1 = 0
调试过程中的意外收获
- 发现 golang 的程序一起来就会启动 3 个线程,如果加上主线程那么一个 golang 程序会有四个线程。
ps -ef | grep main
root 1101021 1097017 0 21:11 pts/12 00:00:00 gdb main
root 1101189 1101021 0 21:12 pts/12 00:00:00 /tmp/main
root 1102234 1101278 0 21:16 pts/6 00:00:00 grep --color=auto main
top -Hp 1101189
Threads: 4 total, 0 running, 0 sleeping, 4 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 7432.3 total, 1211.3 free, 1261.5 used, 4959.5 buff/cache
MiB Swap: 0.0 total, 0.0 free, 0.0 used. 5851.4 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1101189 root 20 0 709984 2936 804 t 0.0 0.0 0:00.00 main
1101193 root 20 0 709984 2936 804 t 0.0 0.0 0:00.00 main
1101194 root 20 0 709984 2936 804 t 0.0 0.0 0:00.00 main
1101195 root 20 0 709984 2936 804 t 0.0 0.0 0:00.00 main
编译时的参数可以通过这个命令查看
go tool compile -help