corejump 怎么用gdb调试
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了corejump 怎么用gdb调试相关的知识,希望对你有一定的参考价值。
参考技术A 1: 对于在应用程序中加入参数进行调试的方法: 直接用 gdb app -p1 -p2 这样进行调试是不行的。 需要像以下这样使用: #gdb app (gdb) r -p1 -p2 或者在运行run命令前使用set args命令: (gdb) set args p1 p2 可以用show args 命令来查看2. 加入断点: break <linenumber> break <funcName> break +offset break -offset (在当前行号的前面或后面的offset行停住。) break filename:linenum 在源文件filename的linenum行处停住。 break filename:function 在源文件filename的function函数的入口处停住。 break ... if ...可以是上述的参数,condition表示条件,在条件成立时停住。比如在循环境体中,可以设置 break if i=100,表示当i为100时停住程序。3. 查看运行时的堆栈: 使用bt命令4. 打印某个变量的值: print val5. 单步: n 继续运行: c step 单步跟踪,如果有函数调用,他会进入该函数。 next 同样单步跟踪,如果有函数调用,他不会进入该函数。很像VC等工具中的step over。后面可以加count也可以不加,不加表示一条条地执行,加表示执行后面的count条指令,然后再停住。 set step-mode set step-mode on 打开step-mode模式,于是,在进行单步跟踪时,程序不会因为没有debug信息而不停住。这个参数有很利于查看机器码。 set step-mod off 关闭step-mode模式。 finish 运行程序,直到当前函数完成返回。并打印函数返回时的堆栈地址和返回值及参数值等信息。 until 或 u 当你厌倦了在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体。 6.在GDB中执行shell命令: 在gdb环境中,你可以执行UNIX的shell的命令,使用gdb的shell命令来完成: eg. shell make 7. 运行环境 可设定程序的运行路径。 show paths 查看程序的运行路径。 set environment varname [=value] 设置环境变量。如:set env USER=hchen show environment [varname] 查看环境变量。8.观察点(WatchPoint) 观察点一般来观察某个表达式(变量也是一种表达式)的值是否有变化了,如果有变化,马上停住程 序。我们有下面的几种方法来设置观察点: watch 为表达式(变量)expr设置一个观察点。一量表达式值有变化时,马上停住程序。 rwatch 当表达式(变量)expr被读时,停住程序。 awatch 当表达式(变量)的值被读或被写时,停住程序。 info watchpoints 列出当前所设置了的所有观察点。9. 维护breakpoint clear 清除所有的已定义的停止点。 clear func 清除所有设置在函数上的停止点。 delete [breakpoints] [range...] 删除指定的断点,breakpoints为断点号。如果不指定断点号,则表示删除所有的断点。range 表示断点号的范围(如:3-7)。其简写命令为d。 比删除更好的一种方法是disable停止点,disable了的停止点,GDB不会删除,当你还需要时,enable即可,就好像回收站一样。 disable [breakpoints] [range...] disable所指定的停止点,breakpoints为停止点号。如果什么都不指定,表示disable所有的停止 点。简写命令是dis. enable [breakpoints] [range...] enable所指定的停止点,breakpoints为停止点号。10、程序变量查看文件中某变量的值:file::variablefunction::variable可以通过这种形式指定你所想查看的变量,是哪个文件中的或是哪个函数中的。例如,查看文件f2.c中的全局变量x的值:gdb) p 'f2.c'::x查看数组的值有时候,你需要查看一段连续的内存空间的值。比如数组的一段,或是动态分配的数据的大小。你可以使用GDB的“@”操作符,“@”的左边是第一个内存的地址的值,“@”的右边则你你想查看内存的长度。例如,你的程序中有这样的语句:int *array = (int *) malloc (len * sizeof (int));于是,在GDB调试过程中,你可以以如下命令显示出这个动态数组的取值:p *array@len如果是静态数组的话,可以直接用print数组名,就可以显示数组中所有数据的内容了。11.输出格式一般来说,GDB会根据变量的类型输出变量的值。但你也可以自定义GDB的输出的格式。例如,你想输出一个整数的十六进制,或是二进制来查看这个整型变量的中的位的情况。要做到这样,你可以使用GDB的数据显示格式:x 按十六进制格式显示变量。d 按十进制格式显示变量。u 按十六进制格式显示无符号整型。o 按八进制格式显示变量。t 按二进制格式显示变量。a 按十六进制格式显示变量。c 按字符格式显示变量。f 按浮点数格式显示变量。(gdb) p i$21 = 101(gdb) p/a i$22 = 0x65(gdb) p/c i$23 = 101 'e'(gdb) p/f i$24 = 1.41531145e-43(gdb) p/x i$25 = 0x65(gdb) p/t i$26 = 110010111.查看内存使用examine命令(简写是x)来查看内存地址中的值。x命令的语法如下所示:x/n、f、u是可选的参数。n 是一个正整数,表示显示内存的长度,也就是说从当前地址向后显示几个地址的内容。f 表示显示的格式,参见上面。如果地址所指的是字符串,那么格式可以是s,如果地十是指令地址,那么格式可以是i。u 表示从当前地址往后请求的字节数,如果不指定的话,GDB默认是4个bytes。u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字节,g表示八字节。当我们指定了字节长度后,GDB会从指内存定的内存地址开始,读写指定字节,并把其当作一个值取出来。n/f/u三个参数可以一起使用。例如:命令:x/3uh 0x54320 表示,从内存地址0x54320读取内容,h表示以双字节为一个单位,3表示三个单位,u表示按十六进制显示。12.自动显示你可以设置一些自动显示的变量,当程序停住时,或是在你单步跟踪时,这些变量会自动显示。相关的GDB命令是display。displaydisplay/display/ exprexpr是一个表达式,fmt表示显示的格式,addr表示内存地址,当你用display设定好了一个或多个表达式后,只要你的程序被停下来,GDB会自动显示你所设置的这些表达式的值。格式i和s同样被display支持,一个非常有用的命令是:display/i $pcundisplaydelete display删除自动显示,dnums意为所设置好了的自动显式的编号。disable displayenable displaydisable和enalbe不删除自动显示的设置,而只是让其失效和恢复。info display查看display设置的自动显示的信息。GDB会打出一张表格,向你报告当然调试中设置了多少个自动显示设置,其中包括,设置的编号,表达式,是否enable。13. 设置显示选项set print addressset print address on打开地址输出,当程序显示函数信息时,GDB会显出函数的参数地址。系统默认为打开的,show print address查看当前地址显示选项是否打开。set print arrayset print array on打开数组显示,打开后当数组显示时,每个元素占一行,如果不打开的话,每个元素则以逗号分隔。这个选项默认是关闭的。与之相关的两个命令如下,我就不再多说了。set print array offshow print arrayset print elements这个选项主要是设置数组的,如果你的数组太大了,那么就可以指定一个来指定数据显示的最大长度,当到达这个长度时,GDB就不再往下显示了。如果设置为0,则表示不限制。show print elements查看print elements的选项信息。set print null-stop如果打开了这个选项,那么当显示字符串时,遇到结束符则停止显示。这个选项默认为off。set print pretty on如果打开printf pretty这个选项,那么当GDB显示结构体时会比较漂亮。14.关于显示源码listgdb 调试 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。
以上是关于corejump 怎么用gdb调试的主要内容,如果未能解决你的问题,请参考以下文章