gdb 调试 golang

说明:作为一门静态语言,似乎支持调试是必须的,而且,Go初学者喜欢问的问题也是:大家都用什么IDE?怎么调试?

其实,Go是为多核和并发而生,真正的项目,你用单步调试,原本没问题的,可能会调出有问题。更好的调试方式是跟PHP这种语言一样,用打印的方式(日志或print)。

当然,简单的小程序,如果单步调试,可以看到一些内部的运行机理,对于学习还是挺有好处的。下面介绍一下用GDB调试Go程序:(目前IDE支持调试Go程序,用的也是GDB。要求GDB 7.1以上)

以下内容来自雨痕的《Go语言学习笔记》(下载Go资源):

默认情况下,编译过的二进制文件已经包含了 DWARFv3 调试信息,只要 GDB7.1 以上版本都可以进行调试。 在OSX下,如无法执行调试指令,可尝试用sudo方式执行gdb。

删除调试符号:go build -ldflags “-s -w”

  • -s: 去掉符号信息。
  • -w: 去掉DWARF调试信息。

关闭内联优化:go build -gcflags “-N -l”

调试相关函数:

  • runtime.Breakpoint():触发调试器断点。
  • runtime/debug.PrintStack():显示调试堆栈。
  • log:适合替代 print显示调试信息。

GDB 调试支持:

  • 参数载入:gdb -d $GCROOT 。
  • 手工载入:source $GCROOT/src/runtime/runtime-gdb.py。

更多细节,请参考: http://golang.org/doc/gdb

调试演示:(OSX 10.8.2, Go1.0.3, GDB7.5.1)

1 package main
2
3 import (
4     "fmt"
5     "runtime"
6 )
7
8 func test(s string, x int) (r string) {
9     r = fmt.Sprintf("test: %s %d", s, x)
10     runtime.Breakpoint()
11     return r
12 }
13 func main() {
14     s := "haha"
15     i := 1234
16     println(test(s, i))
17 }

go build -gcflags “-N -l” // 编译,关闭内联优化。

$ sudo gdb demo // 启动 gdb 调试器,手工载入 Go Runtime 。
GNU gdb (GDB) 7.5.1
Reading symbols from demo…done.
(gdb) source /usr/local/go/src/pkg/runtime/runtime-gdb.py
Loading Go Runtime support.

(gdb) l main.main // 以 .方式查看源码。
9 r = fmt.Sprintf(“test: %s %d”, s, x)
10 runtime.Breakpoint()
11 return r
12 }
13
14 func main() {
15 s := “haha”
16 i := 1234
17 println(test(s, i))
18 }

(gdb) l main.go:8 // 以 :方式查看源码。
3 import (
4 “fmt”
5 “runtime”
6 )
7
8 func test(s string, x int) (r string) {
9 r = fmt.Sprintf(“test: %s %d”, s, x)
10 runtime.Breakpoint()
11 return r
12 }

(gdb) b main.main // 以 .方式设置断点。
Breakpoint 1 at 0×2131: file main.go, line 14.

(gdb) b main.go:17 // 以 :方式设置断点。
Breakpoint 2 at 0×2167: file main.go, line 17.

(gdb) info breakpoints // 查看所有断点。
Num Type Disp Enb Address What
1 breakpoint keep y 0×0000000000002131 in main.main at main.go:14
2 breakpoint keep y 0×0000000000002167 in main.main at main.go:17

(gdb) r // 启动进程,触发第一个断点。
Starting program: demo
[New Thread 0x1c03 of process 4088]
[Switching to Thread 0x1c03 of process 4088]
Breakpoint 1, main.main () at main.go:14
14 func main() {

(gdb) info goroutines // 查看 goroutines 信息。
* 1 running runtime.gosched
* 2 syscall runtime.entersyscall

(gdb) goroutine 1 bt // 查看指定序号的 goroutine 调用堆栈。
#0 0x000000000000f6c0 in runtime.gosched () at pkg/runtime/proc.c:927
#1 0x000000000000e44c in runtime.main () at pkg/runtime/proc.c:244
#2 0x000000000000e4ef in schedunlock () at pkg/runtime/proc.c:267
#3 0×0000000000000000 in ?? ()

(gdb) goroutine 2 bt // 这个 goroutine 貌似跟 GC 有关。
#0 runtime.entersyscall () at pkg/runtime/proc.c:989
#1 0x000000000000d01d in runtime.MHeap_Scavenger () at pkg/runtime/mheap.c:363
#2 0x000000000000e4ef in schedunlock () at pkg/runtime/proc.c:267
#3 0×0000000000000000 in ?? ()

(gdb) c / / 继续执行,触发下一个断点。
Continuing.
Breakpoint 2, main.main () at main.go:17
17! ! println(test(s, i))

(gdb) info goroutines // 当前 goroutine 序号为 1。
* 1 running runtime.gosched
2 runnable runtime.gosched

(gdb) goroutine 1 bt // 当前 goroutine 调用堆栈。
#0 0x000000000000f6c0 in runtime.gosched () at pkg/runtime/proc.c:927
#1 0x000000000000e44c in runtime.main () at pkg/runtime/proc.c:244
#2 0x000000000000e4ef in schedunlock () at pkg/runtime/proc.c:267
#3 0×0000000000000000 in ?? ()

(gdb) bt // 查看当前调堆栈,可以与当前 goroutine 调用堆栈对比。
#0 main.main () at main.go:17
#1 0x000000000000e44c in runtime.main () at pkg/runtime/proc.c:244
#2 0x000000000000e4ef in schedunlock () at pkg/runtime/proc.c:267
#3 0×0000000000000000 in ?? ()

(gdb) info frame // 堆栈帧信息。
Stack level 0, frame at 0x442139f88:
rip = 0×2167 in main.main (main.go:17); saved rip 0xe44c
called by frame at 0x442139fb8
source language go.
Arglist at 0x442139f28, args:
Locals at 0x442139f28, Previous frame’s sp is 0x442139f88
Saved registers:
rip at 0x442139f80

(gdb) info locals // 查看局部变量。
i = 1234
s = “haha”

(gdb) p s // 以 Pretty-Print 方式查看变量。
$1 = “haha”

(gdb) p $len(s) // 获取对象长度($cap)
$2 = 4

(gdb) whatis i // 查看对象类型。
type = int

(gdb) c // 继续执行,触发 breakpoint() 断点。
Continuing.
Program received signal SIGTRAP, Trace/breakpoint trap.
runtime.breakpoint () at pkg/runtime/asm_amd64.s:81
81 RET

(gdb) n // 从 breakpoint() 中出来,执行源码下一行代码。
main.test (s=”haha”, x=1234, r=”test: haha 1234″) at main.go:11
11 return r

(gdb) info args // 从参数信息中,我们可以看到命名返回参数的值。
s = “haha”
x = 1234
r = “test: haha 1234″

(gdb) x/3xw &r // 查看 r 内存数据。(指针 8 + 长度 4)
0x442139f48: 0×42121240 0×00000000 0x0000000f
(gdb) x/15xb 0×42121240 // 查看字符串字节数组
0×42121240: 0×74 0×65 0×73 0×74 0x3a 0×20 0×68 0×61
0×42121248: 0×68 0×61 0×20 0×31 0×32 0×33 0×34

(gdb) c // 继续执行,进程结束。

Continuing.
test: haha 1234
[Inferior 1 (process 4088) exited normally]

(gdb) q // 退出 GDB。

时间: 2025-01-11 02:08:55

gdb 调试 golang的相关文章

mac下配置gdb调试golang

mac下配置gdb调试golang 原文链接 https://sourceware.org/gdb/wiki/BuildingOnDarwin Building GDB for Darwin Creating the binary for Darwin isn't very difficult.  Download a release snapshot or get the current source via git/CVS/FTP, then configure and make as us

Go语言gdb调试踩坑

整个是一个docker环境 docker版本: 1.12.1,镜像是我自己做的基于ubuntu:14.04.05. 容器操作系统版本: Ubuntu 14.04.5 LTS go版本: 1.6.3 在gdb中执行run命令出错! 错误输出: warning:Error disabling address space randomization: Operation not permitted 环境:docker 解决办法: warning:Error disabling address spac

GO的GDB调试

GoLang语言,学了很久,一直觉得它单步调试有较多问题,最近才知道自已对它了解得太少了.原来GO语言对GDB的版本是至少为gdb7以上,才能比较好的打印任意变量,如果低于这个版本,则才会出一些问题.网上说GDB版本为7.1,本人使用GDB7.8版本测试,确实很不错.以下是记录单步调试使用的几个打印变量.info frame,打印当前栈参数.info locals打印局部变量info args打印参数.bt显示当前堆栈x/3xw &r查看内存 删除调试符号:go build -ldflags “

gdb调试

[前言]使用gdb调试前,在编译程序时,要加 -g 选项,否则你将看不见程序的函数名.变量名,所代替的全是运行时的内存地址. 1.开始调试 a.  gdb <program> program也就是你的执行文件,一般在当前目录下. b. gdb <program> core 用gdb同时调试一个运行程序和core文件,core是程序非法执行后core dump后产生的文件. 2.[列出源码],从第n行开始(编译时要加 -g 选项) l n 3.[设置断点]在第N行加断点 break

gdb调试命令

本篇摘自互联网,纯属自己学习笔记,然分享给看到我的博客的人们. 用GDB调试程序 GDB是一个强大的命令行调试工具.大家知道命令行的强大就是在于,其可以形成执行序列,形成脚本.UNIX下的软件全是命令行的,这给程序开发提代供了极大的便利,命令行软件的优势在于,它们可以非常容易的集成在一起,使用几个简单的已有工具的命令,就可以做出一个非常强大的功能. 于是UNIX下的软件比Windows下的软件更能有机地结合,各自发挥各自的长处,组合成更为强劲的功能.而Windows下的图形软件基本上是各自为营,

GDB调试汇编堆栈

GDB调试汇编堆栈 准备工作 终端编译工具: 编译64位Linux版本32位的二进制文件,需要安装一个库,使用指令sudo apt-get install libc6-dev-i386 测试代码: test.c 分析过程 1.生成汇编代码:gcc -g gdbtest.c -o gdbtest -m32 2.调试:gdb test 3.设置断点,因为目的是分析而不是调试bug,所以我们将断点设置在main函数 4.开始gdb调试:r(un),如若想获取此时的汇编代码,可用指令:disassemb

GDB调试汇编分析

GDB调试汇编分析 代码 本次实践我参照了许多先做了的同学的博客,有卢肖明,高其,张梓靖同学.代码借用的是卢肖明同学的代码进行调试运行. GCC编译 使用gcc -g gdbtest.c -o gdbtest -m32命令在64位的机器上产生32位汇编代码 在使用gdb进行调试运行时,有cgdb和gdb两种工具,我建议大家使用张梓靖同学使用的cgdb工具,因为使用时可以随时看到自己的源代码,看到我们的断点在哪里,每一步返回值到了哪行,更加直观. 分析过程 使用b main指令在main函数处设置

20145234黄斐《信息安全系统设计基础》GDB调试汇编堆栈过程分析(1)

堆栈跟踪 首先编辑一个程序 用gcc编译,再使用gdb调试,发现gdb尚未下载 下载后重新运行gdb 设置断点:b+行号或者"main" 运行:r frame:打印出的信息:栈的层编号,当前的函数名,函数参数值,函数所在文件及行号,函数执行到的语句. info frame:打印出的信息:函数地址,调用函数的地址,被调用函数的地址,目前的函数是由什么样的程序语言写成的.函数参数地址及值.局部变量的地址等等. 输入命令disassemble:显示出该代码(main())的汇编形式 info

[转]GDB调试基础

一.gdb常用命令: 命令 描述 backtrace(或bt) 查看各级函数调用及参数 finish 连续运行到当前函数返回为止,然后停下来等待命令 frame(或f) 帧编号 选择栈帧 info(或i) locals 查看当前栈帧局部变量的值 list(或l) 列出源代码,接着上次的位置往下列,每次列10行 list 行号 列出从第几行开始的源代码 list 函数名 列出某个函数的源代码 next(或n) 执行下一行语句 print(或p) 打印表达式的值,通过表达式可以修改变量的值或者调用函