使用GDB调试Go语言
用Go语言已经有一段时间了,总结一下如何用GDB来调试它!
ps:网上有很多文章都有描述,但是都不是很全面,这里将那些方法汇总一下
GDB简介
GDB是GNU开源组织发布的⼀一个强⼤大的UNIX下的程序调试⼯工具。或许,各位⽐比较喜欢那种图形界⾯面⽅方式的,像VC、BCB等IDE的调试,但如果你是在UNIX平台下做软件,你会 发现GDB这个调试⼯工具有⽐比VC、BCB的图形化调试器更强⼤大的功能。所谓“⼨寸有所⻓长,尺有所短”就是这个道理。
目前支持的语言 (GNU gdb (GDB) 7.8)
进入 gdb之后输入 set language 可以查看支持的语言列表
$ gdb
(gdb) set language
Requires an argument. Valid arguments are auto, local, unknown, ada, c, c++, asm, minimal, d, fortran, objective-c, go, java, modula-, opencl, pascal.
(gdb)
准备工作
首先看下已经编写好的一个简单的go语言程序
➜ go-debug-example tree
.
├── lib
│ └── calc.go
└── main.go directory, files
main.go
package main import (
"fmt"
"github.com/beyondblog/go-debug-example/lib"
"os"
"runtime"
//"runtime/debug"
) func main() {
var modify string
argsLen := len(os.Args)
if argsLen < {
fmt.Printf("Usage go-debug-example [username] \r\n")
os.Exit(-)
}
username := os.Args[]
var password string
fmt.Printf("%s welcome!\r\nplease input password:", username)
fmt.Scanf("%s", &password)
fmt.Printf("%s password: %s\r\n", username, password) sum :=
for i := ; i < ; i++ {
sum += i
if i == {
modify = "modify!"
}
} fmt.Println(lib.Add(sum, )) runtime.Breakpoint()
//debug.PrintStack()
fmt.Println(sum)
fmt.Println(modify)
}
calc.go
package lib func Add(a int, b int) int {
c :=
a = c + b
return a + b
}
程序很简单,就是从命令行获取一个值然后做了写简单的计算,最后输出一下
那么我们编译一下 ^.^
go build
然后生成了我们要的文件,然后我们执行 gdb go-debug-example
输入 run(简写r)命令运行程序,这个时候可能会有一个提示
(gdb) run
Starting program: /Users/****/gopath/src/github.com/beyondblog/go-debug-example/go-debug-example
Unable to find Mach task port for process-id : (os/kern) failure (0x5).
(please check gdb is codesigned - see taskgated())
如果你用的是OSX应该就能看到这个,这个提示签名错误,
Darwin kernel出于安全考虑,在没有特殊授权的情况下不允许gdb调试任何程序,因为可以调试就掌握了进程的控制权。不过如果是root用户就没有这个问题,不过谁愿意用root来调试程序呢
解决办法可以通过[这篇文章](http://blog.csdn.net/powerlly/article/details/30323015)来查看
或者启动gdb的时候 加个sudo呗,那么重新来过
sudo gdb go-debug-example
r
然后提示了
(gdb) r
Starting program: /Users/****/gopath/src/github.com/beyondblog/go-debug-example/go-debug-example
Usage go-debug-example [username]
[Inferior (process ) exited with code ]
程序成功执行,但是我们那个Go程序提示需要加一个参数才能够继续下去
可以直接 r [参数] 获取在 使用 set args [参数]
ps:可以用 r > file 或者 >> file 支持结果重定向到文件
set args 这个命令是设置参数信息
show args 查看启动的参数信息
既然调试代码就能看到源码啊,使用list(简写l) 命令查看代码执行位置附近10行
(gdb) list
package main import (
"fmt"
"github.com/beyondblog/go-debug-example/lib"
"os"
"runtime"
//"runtime/debug"
) (gdb)
默认显示了10行 查看更多的话可以在输入list 或者敲回车(gdb 会默认记住上一个指令然后回车就能继续执行了 -,- )
查看list帮助
(gdb) help list
List specified function or line.
With no argument, lists ten more lines after or around previous listing.
"list -" lists the ten lines before a previous ten-line listing.
One argument specifies a line, and ten lines are listed around that line.
Two arguments with comma between specify starting and ending lines to list.
Lines can be specified in these ways:
LINENUM, to list around that line in current file,
FILE:LINENUM, to list around that line in that file,
FUNCTION, to list around beginning of that function,
FILE:FUNCTION, to distinguish among like-named static functions.
*ADDRESS, to list around the line containing that address.
With two args if one is empty it stands for ten lines away from the other arg.
(gdb)
大概的意思就是
list //查看第20行周围的10行 list - //查看上一个list代码之前的10行 list , //查看1到100行 如果不足100行就显示末尾 list main //查看main函数
执行这个命令的时候会发现显示的不是main函数的信息而是一段汇编代码 (gdb) list main
MOVQ (SP), DI // argc
MOVQ $main(SB), AX
JMP AX TEXT main(SB),NOSPLIT,$-
MOVQ $runtime·rt0_go(SB), AX
JMP AX
(gdb) 大概的意思是go程序的真正入口点应该是这玩意 (ps: $main(SB) SB = ,=)
这个时候用 list main.main 即可 意思是查看main.go文件里面main函数附近的10行 list main.main, //查看从main文件中main函数中从函数开始到第20行 l main.go: //以 :方式查看指定文件源码
l calc.go: //查看calc.go的源码
l github.com/beyondblog/go-debug-example/lib/calc.go: //绝对文件路径查看 还可以搜索代码用 search text //可显示在当前文件中包含text串的下一行
reverse-search text //显示包含text 的前一行
forward-search text //不解释
现在设置一个断点看看,命令是 break (简写b) 后面的参数和list命令后面的参数大致一样,例如
b main.main //在main下设置断点
b //在11行设置断点 //查看断点
info breakpoints (gdb) info breakpoints
Num Type Disp Enb Address What
breakpoint keep y 0x0000000000002000 in main.main at /Users/****/github.com/ beyondblog/go-debug-example/main.go:
breakpoint keep y 0x000000000000203b in main.main at /Users/****/github.com/ beyondblog/go-debug-example/main.go: 能够显示详细的信息,注意这上面有个End 是是否启用的意思可以使用
disable Num或者 enable Num 来设置断点是否有效 //删除断点 delete(简写d) //不带参数清空所有断点
d //删除编号为1的断点 //条件断点 非常实用!
b Num if [表达式] //在第Num设置断点当满足表达式的条件是触发
例如
b if i=
下面让程序运行起来
Argument list to give program being debugged when it is started is "".
(gdb) set args beyond
(gdb) show args
Argument list to give program being debugged when it is started is "beyond".
(gdb) b main.main
Breakpoint at 0x2000: file /Users/****/gopath/src/github.com/beyondblog/go-debug-example/main.go, line .
(gdb) r
Starting program: /Users/****/gopath/src/github.com/beyondblog/go-debug-example/go-debug-example beyond
[New Thread 0x1617 of process ]
[New Thread 0x1803 of process ] Breakpoint , main.main () at /Users/****/github.com/beyondblog/go-debug-example/main.go:
func main() {
(gdb) n
var modify string
(gdb)
next(简写n) //下一步
step(简写s) //单步执行,例如跳进函数内部
finish //退出该函数返回到它的调用函数中
until(简写u) //直接执行到下一行,如果遇到循环语句,会执行完当前循环
u Num //指哪打哪,继续执行直到Num行时触发断点
continue(简写c) //从断点开始继续执行 例如
(gdb) u
beyond welcome!
please input password:
main.main () at /Users/****/gopath/src/github.com/beyondblog/go-debug-example/main.go:
fmt.Printf("%s password: %s\r\n", username, password)
(gdb) frame(简写f) //查看当前命令帧,也就是看当前程序执行到那一行了 info locals //查看当前变量信息
(gdb) info locals
sum =
&password = 0x2081b4210
username = 0x7fff5fbffc58 "beyond"
modify = 0x0 ""
这个时候会发现,怎么有些变量没显示出来,官方说默认的编译会给调试带来一些不变的优化,可以使用
go build -gcflags "-N -l" 来关闭这个优化从而方便调试
那么重新编译后运行在 info local 下
(gdb) info locals
sum =
i =
argsLen =
&password = 0x2081b4210
username = 0x7fff5fbffc58 "beyond"
modify = 0x0 "" 会发现 i 和 sum的值不是一个预期的0,这个是我们程序还没执行到初始化那一块,默认取的一个随机数吧
ps: 虽然从代码上看好像程序在这个时候还没有声明 i 和 sum,但是最终生成的go语言程序应该是有自己的优化自动声明了 类似的还有很多种命令就不一一介绍了,下面来个逼格高的
layout src 或者 ctrl x + ctrl a 启动 tui 界面
或者启动gdb 的时候加上 tui参数
例如
gdb -tui
逼格满满有木有哇!
tui有4中窗口模式分别是
command 命令窗口. 可以键入调试命令
source 源代码窗口. 显示当前行,断点等信息
assembly 汇编代码窗口
register 寄存器窗口
详细的说明:https://sourceware.org/gdb/current/onlinedocs/gdb/TUI.html#TUI
这个时候想查看源代码可以用list 也可以用方向键
首先先将窗口的焦点设置到源代码窗口上
focus src
然后就可以用方向键来查看源代码了,这个时候如果想回到command窗口同理只需要
focus cmd
这个时候你执行命令n 会有一个文本的图形界面还显示
gdb 还有一个特别有用的jump命令,它允许强制的跳转,不会改变栈的结构.
意思就是 如果我的程序运行到第10行的时候我现在想回到第5行调试看看又不想重新运行一边
举个栗子
现在我们执行到第32行,直接输入命令
u B+>│ fmt.Println(lib.Add(sum, )) s //单步进入 func Add(a int, b int) int {
(gdb) list
package lib func Add(a int, b int) int {
c :=
a = c + b
return a + b
}
(gdb) n
c :=
(gdb) n
a = c + b
(gdb) f
# github.com/beyondblog/go-debug-example/lib.Add (a=, b=, ~r2=) at /Users/****/github.com/beyondblog/go-debug-example/lib/calc.go:
a = c + b
这个时候已经到了第5行 我现在要回到第4行,jump 4 发现没有用因为jump是跳转到第4行开始执行,但不触发断点所以一般先在要跳转的行号哪儿设置个断点
github.com/beyondblog/go-debug-example/lib.Add (a=, b=, ~r2=) at /Users/****/github.com/beyondblog/go-debug-example/lib/calc.go:
func Add(a int, b int) int {
(gdb) b
Breakpoint at 0x50fed: file /Users/****/github.com/beyondblog/go-debug-example/lib/calc.go, line .
(gdb) n Breakpoint , github.com/beyondblog/go-debug-example/lib.Add (a=, b=, ~r2=) at /Users/****/github.com/beyondblog/go-debug-example/lib/calc.go:
c :=
(gdb) n
a = c + b
(gdb) n
return a + b
(gdb) jump
Continuing at 0x50fed. Breakpoint , github.com/beyondblog/go-debug-example/lib.Add (a=, b=, ~r2=) at /Users/****/github.com/beyondblog/go-debug-example/lib/calc.go:
c :=
(gdb) n
a = c + b
(gdb)
return a + b
(gdb) jump
Continuing at 0x50fed. Breakpoint , github.com/beyondblog/go-debug-example/lib.Add (a=, b=, ~r2=) at /Users/****/github.com/beyondblog/go-debug-example/lib/calc.go:
c :=
(gdb) //还可以使用set 命令来设置变量的值 例如
set b =
最后附上gdb的官方文档
https://sourceware.org/gdb/current/onlinedocs/gdb/
这个example的链接
https://github.com/beyondblog/go-debug-example.git
----
参考文章:
[0] http://blog.csdn.net/haoel/article/details/2879
[1] http://blog.studygolang.com/2012/12/gdb%E8%B0%83%E8%AF%95go%E7%A8%8B%E5%BA%8F/
[2] http://laokaddk.blog.51cto.com/368606/945057/
[3] http://blog.csdn.net/lwbeyond/article/details/7839225
使用GDB调试Go语言的更多相关文章
- GDB调试D语言
GDB7.2后开始支持对D语言的调试 GUI前端 http://beej.us/guide/bggdb/#compiling GDB教程 http://blog.csdn.net/haoel/arti ...
- c语言之gdb调试。
1.此文档演示如何使用gdb调试c语言代码. 代码如下: #include <stdio.h> /*函数声明*/ void digui(int n); int main() { ; dig ...
- 比较全面的gdb调试命令 (转载)
转自http://blog.csdn.net/dadalan/article/details/3758025 用GDB调试程序 GDB是一个强大的命令行调试工具.大家知道命令行的强大就是在于,其可以形 ...
- 经典的GDB调试命令
在你调试程序时,当程序被停住时,你可以使用print命令(简写命令为p),或是同义命令inspect来查看当前程序的运行数据.print命令的格式是: printprint /是表达式,是你所调试的程 ...
- GDB 调试解析
GDB(GNU Debugger)是一个强大的命令行调试工具.大家知道命令行的强大就是在于,其可以形成执行序 列,形成脚本.UNIX下的软件全是命令行的,这给程序开发提代供了极大的便利,命令行软件的优 ...
- 经典的GDB调试命令,包括查看变量,查看内存
经典的GDB调试命令,包括查看变量,查看内存 在你调试程序时,当程序被停住时,你可以使用print命令(简写命令为p),或是同义命令inspect来查看当前程序的运行数据.print命令的格式是: p ...
- Linux下用gdb 调试、查看代码堆栈
Linux中用gdb 查看代码堆栈的信息 core dump 一般是在segmentation fault(段错误)的情况下产生的文件,需要通过ulimit来设置才会得到的. 调试的话输入: gd ...
- windows下用eclipse+goclipse插件+gdb搭建go语言开发调试环境
windows下用eclipse+goclipse插件+gdb搭建go语言开发调试环境 http://rongmayisheng.com/post/windows%E4%B8%8B%E7%94%A ...
- 【嵌入式开发】C语言 命令行参数 函数指针 gdb调试
. 作者 : 万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/21551397 | http://www.hanshul ...
随机推荐
- Visual Studio (VS IDE) 你必须知道的功能和技巧 - 【.Net必知系列】
前言 本文主要阐述一些Visual Studio开发下需要知道的少部分且比较实用的功能,也是很多人忽略的部分.一些不常用而且冷门的功能不在本文范围,当然本文的尾巴[.Net必知系列]纯属意淫,如有雷同 ...
- Mac Android开发环境变量的配置(java、sdk、ndk、gradle)
1.打开terminal 2.然后输入 vi .bash_profile 后按"e"进入编辑模式 3.输入想要配置的环境变量(Java.sdk.ndk.gradle): expor ...
- 通过 listboxitem 查找属于listbox第几条数据
public override System.Windows.Style SelectStyle(object item, System.Windows.DependencyObject contai ...
- some useful linux commands
# best way to see log file less +F /var/log/syslog (equals: less /var/log/syslog, then shift+f) # se ...
- Python2 新手 编码问题 吐血总结
什么是编码 任何一种语言.文字.符号等等,计算都是将其以一种类似字典的形式存起来的,比如最早的计算机系统将英文文字转为数字存储(ASCII码),这种文字与数字(或其他)一一对应的关系我们称之为编码.由 ...
- 【原】iOS学习之tableView的常见BUG
1.TableView头视图不随视图移动,头视图出现错位 错误原因:tableView的 UITableViewStyle 没有明确的声明 解决方法:在tableView声明的时候明确为 UITabl ...
- 如何查看bash shell 帮助信息?
man bash 查看bash的命令帮助 info bash 查看bash的文档 help 命令显示bash支持的命令: 如果想看某个命令的帮助可以 help 命令.如 help cd 对bash的命 ...
- delay(和setTimeout()的区别
近来几日在写游戏代码时,频繁会用到定时器,偶尔想到有个.delay()方法,用了几次发现两者效果相差很大,遂就仔细考究了一下两者的区别! 1. setTimeout函数是从页面开始的时候计算time的 ...
- java分享第十五天(log4j 格式详解)
log4j 格式详解 log4j.rootLogger=日志级别,appender1, appender2, -. 日志级别:ALL<DEBUG<INFO<WARN<ERRO ...
- 前端自动化工具gulp自动添加版本号
之前,我介绍了学习安装并配置前端自动化工具Gulp,觉得gulp确实比grunt的配置简单很多,于是我决定再深入学习一下gulp,就去网上查了资料,发现gulp还可以自动添加版本号,这个功能就为我平时 ...