您的位置:首页 > 其它

GDB调试工具使用总结

2015-07-19 16:44 330 查看
1、使用前须知

一般来说GDB主要调试的是C/C++的程序。要调试C/C++的程序,首先在编译时,我们必须要把调试信息加到可执行文件中。使用编译器(gcc/gcc/g++)的 -g 参数可以做到这一点。如:

gcc -g hello.c -o hello

g++ -g hello.cpp -o hello

如果没有-g,你将看不见程序的函数名、变量名,所代替的全是运行时的内存地址。当你用-g把调试信息加入之后,并成功编译目标代码以后,让我们来看看如何用gdb来调试他。

2、GDB启动方式

1)gdb “program”(常用)

program是你的C/C++源文件编译成功后的产生可执行文件,一般在当前目录下。

2) gdb “program” core

用gdb同时调试一个运行程序和core文件;

core是程序非法执行后core dump后产生的文件。

3) gdb “program”“PID”

如果你的程序是一个服务程序,那么你可以指定这个服务程序运行时的进程ID。gdb会自动attach上去,并调试他。program应该在PATH环境变量中搜索得到。

3、GDB启动后的环境

$ gdb

GNU gdb 6.7.1-debian

Copyright (C) 2007 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-linux-gnu”.

(gdb) ### ——->此处出入命令

注意:gdb的命令可以使用help命令来查看,help命令只是例出gdb的命令种类,如果要看种类中的命令,可以使用help “class”命令,如:help breakpoints,查看设置断点的所有命令。也可以直接help “command“ 来查看命令的帮助。

4、GDB命令输入

gdb中,输入命令时,可以不用打全命令,只用打命令的前几个字符就可以了,当然,命令的前几个字符应该要标志着一个唯一的命令,在Linux下,你可以敲击两次TAB键来补齐命令的全称,如果有重复的,那么gdb会把其例出来。

For example:

1)在进入函数func时,设置一个断点。可以敲入break func是直接就是b func

(gdb) b func

Breakpoint 1 at 0x8048458: file hello.c, line 10.

2)敲入b按两次TAB键,你会看到所有b打头的命令:

(gdb) b

backtrace break bt

3)只记得函数的前缀,可以这样:

(gdb) b make_ <按TAB键>

(再按下一次TAB键,你会看到:)

make_a_section_from_file make_environ

make_abs_section make_function_type

make_blockvector make_pointer_type

make_cleanup make_reference_type

make_command make_symbol_completion_list

(gdb) b make_

GDB把所有make开头的函数全部例出来给你查看。

4)调试C++的程序时,有可以函数名一样。如:

(gdb) b ‘bubble( M-?

bubble(double,double) bubble(int,int)

(gdb) b ‘bubble(

你可以查看到C++中的所有的重载函数及参数。(注:M-?和“按两次TAB键”是一个意思)

5、GDB程序运行中

当以gdb ”program“方式启动gdb后,gdb会在PATH路径和当前目录中搜索 ”program“ 的源文件。如要确认gdb是否读到源文件,可使用l或list命令,看看gdb是否能列出源代码。在gdb中,运行程序使用r或是run命令

6、调试已运行的程序

两种方法:

1、在 Linux 下用 ps 命令 查看正在运行的程序的PID(进程ID),然后用gdb ”program” PID格式挂接正在运行的程序。

2、先用gdb “program” 关联上源代码,并进行gdb,在gdb中用attach命令来挂接进程的PID,用detach来取消挂接的进程

7、GDB中如何暂停/恢复程序运行

调试程序中,暂停程序运行是必须的,GDB可以方便地暂停程序的运行。你可以设置程序的在哪行停住,在什么条件下停住,在收到什么信号时停往等等。以便于你查看运行时的变量,以及运行时的流程。

当进程被gdb停住时,你可以使用info program来查看程序的是否在运行,进程号,被暂停的原因。

在gdb中,我们可以有以下几种暂停方式断点(BreakPoint)、观察点(WatchPoint)、捕捉点(CatchPoint)、信号(Signals)、线程停止(Thread Stops)。如果要恢复程序运行,可以使用c或是continue命令。

1)设置断点的方式

break “function”在进入指定函数时停住。
break “linenum”在指定行号停住
break +或- offset在当前行号的前面或后面的offset行停住。offset为自然数
break filename:linenum在源文件filename的linenum行处停住
break filename:function在源文件filename的function函数的入口处停住
break *address在程序运行的内存地址处停住
breakbreak命令没有参数时,表示在下一条指令处停住
break … if “condition”…可以是上述的参数,condition表示条件,在条件成立时停住。比如在循环境体中,可以设置break if i=100,表示当i为100时停住程序
info breakpoints
查看断点时,可使用info命令,(注:n表示断点号)
2)关于设置观察点

作用:观察点一般来观察某个表达式(变量也是一种表达式)的值是否有变化了,如果有变化,马上停住程序。

② 如何设置:

watch < expr >为表达式(变量)expr设置一个观察点。一但表达式值有变化时,马上停住程序。

rwatch < expr >当表达式(变量)expr 被读时,停住程序。

awatch < expr >当表达式(变量)的值被读或被写时,停住程序。

info watchpoints 列出当前所设置了的所有观察点。

3)关于设置捕捉点

作用:你可设置捕捉点来捕捉程序运行时的一些事件。

如:载入共享库(动态链接库)或是C++的异常。

② 如何设置:catch < event >tcatch < event >

可用 help catch 和 help tcatch 来看具体用法。

//以上断点、观察点和捕捉点为GDB中三类断点。

4)停止点维护

① 作用:在GDB中,如果你觉得已定义好的停止点(即上述三类断点)没有用了,你可以使用delete、clear、disable、enable这几个命令来进行维护。

② 具体操作:

clear:清除停止点。

clear < function >,clear < filename:function >

作用:清除所有设置在函数上的停止点。

clear < linenum >,clear < filename:linenum >

作用:清除所有设置在指定行上的停止点。

delete:删除断点

delete [breakpoints] [range…]

作用: 删除指定的断点,breakpoints为断点号。如果不指定断点号,则表示删除所有的断点。range 表示断点号的范围,其简写命令为d。

disable:将停止点放入回收站

enable:将停止点从回收站中恢复

优势:比删除更好的方法是disable停止点,disable了的停止点,GDB不会删除,当你还需要时,enable即可,就好像回收站一样。

具体操作

disable [breakpoints] [range…]

作用:disable所指定的停止点,breakpoints为停止点号。如果什么都不指定,表示disable所有的停止点。简写命令是dis

enable [breakpoints] [range…]

作用:enable所指定的停止点,breakpoints为停止点号。

enable [breakpoints] once range…

作用:enable所指定的停止点一次,当程序停止后,该停止点马上被GDB自动disable。

enable [breakpoints] delete range…

作用:enable所指定的停止点一次,当程序停止后,该停止点马上被GDB自动删除。

5)停在条件维护

condition < bnum >< expression >

作用:修改断点号为bnum的停止条件为expression

condition < bnum >

作用:清除断点号为bnum的停止条件

ignore < bnum >< count >

作用:表示忽略断点号为bnum的停止条件count次

6)为停止点设定运行命令

① 含义:我们可以使用GDB提供的command命令来设置停止点的运行命令。也就是说,当运行的程序在被停止住时,我们可以让其自动运行一些别的命令,这很有利行自动化调试。对基于GDB的自动化调试是一个强大的支持。

② 格式:

commands [bnum]

… command-list …

end

为断点号bnum指写一个命令列表。当程序被该断点停住时,gdb会依次运行命令列表中的命令。

③ example:

break foo if x>0

commands

printf “x is %d\n”,x

continue

end

断点设置在函数foo中,断点条件是x>0,如果程序被断住后,也就是,一旦x的值在foo函数中大于0,GDB会自动打印出x的值,并继续运行程序。如果你要清除断点上的命令序列,那么只要简单的执行一下commands命令,并直接在打个end就行了。

7)断点菜单

① 含义:在C++中,可能会重复出现同一个名字的函数若干次(函数重载),在这种情况下,break < function >不能告诉GDB要停在哪个函数的入口。当然,你可以使用break < function(type) >也就是把函数的参数类型告诉GDB,以指定一个函数。否则的话,GDB会给你列出一个断点菜单供你选择你所需要的断点。你只要输入你菜单列表中的编号就可以了。

② example:

(gdb) b String::after

[0] cancel

//0表示放弃设置断点

[1] al

//1表示所有函数都设置断点

[2] file:String.cc; line number:867

[3] file:String.cc; line number:860

[4] file:String.cc; line number:875

[5] file:String.cc; line number:853

[6] file:String.cc; line number:846

[7] file:String.cc; line number:735

$ 2 4 6

Breakpoint 1 at 0xb26c: file String.cc, line 867.

Breakpoint 2 at 0xb344: file String.cc, line 875.

Breakpoint 3 at 0xafcc: file String.cc, line 846.

Multiple breakpoints were set.

Use the “delete” command to delete unwanted breakpoints.

(gdb)

可见,GDB列出了所有after的重载函数,你可以选一下列表编号就行了

8)恢复程序运行和单步调试

当程序被停住后:

continue 命令[c]:恢复程序的运行直到程序结束或下一个断点到来

注意:continue, c, fg 三个命令都是一样的意思。

step/next命令[s/n]:单步跟踪程序(常用)

注意:step < count >:后面可以加 count 也可以不加,不加表示一条条地执行,加表示执行后面的count条指令,然后再停住。单步跟踪,如果有函数调用,他会进入该函数。

注意:next < count >:同上,但单步跟踪,如果有函数调用,他不会进入该函数。

一般用 n 表示一步步执行,用 s 表示进入这个函数。

注意点:(不常用)

set step-mode,set step-mode on

打开step-mode模式,于是,在进行单步跟踪时,程序不会因为没有debug信息而不停住。这个参数有很利于查看机器码。

set step-mod off

关闭step-mode模式。

Finish:运行程序,直到当前函数完成返回。并打印函数返回时的堆栈地址和返回值及参数值等信息。

until[u]:当你厌倦了在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体。

stepi [si]或nexti [ni]:单步跟踪一条机器指令!一条程序代码有可能由数条机器指令完成,stepi和nexti可以单步执行机器指令

8、GDB中常用辅助命令

1)显示源代码

list < linenum >:显示程序第linenum行的周围的源程序。

list < function >:显示函数名为function的函数的源程序。

list :显示当前行后面的源程序。

list - :显示当前行前面的源程序。

list < first >, < last >:显示从first行到last行之间的源代码。

list , < last >:显示从当前行到last行之间的源代码。

list +: 往后显示源代码。

set listsize < count >:设置一次显示源代码的行数。

show listsize:查看当前 listsize 的设置。

2)搜索源代码

forward-search < regexp >,search < regexp >向前面搜索。

reverse-search < regexp >全部搜索。

其中< regexp >是正则表达式,也主一个字符串的匹配模式

3)info

i**nfo line**:命令来查看源代码在内存中的地址。

info line后面可以跟“行号”,“函数名”,“文件名:行号”,“文件名:函数名”,这个命令会打印出所指定的源码在运行时的内存地址,如:

(gdb) info line tst.c:func

Line 5 of “tst.c” starts at address 0x8048456 < func+6 > and ends at 0x804845d < func+13 > 。

info args: 打印出当前函数的参数名及其值。

info locals: 打印出当前函数中所有局部变量及其值。

info catch:打印出当前的函数中的异常处理信息。

4)显示运行数据:print [p]

print < expr >

print /< f > < expr >

< expr >是表达式,是你所调试的程序的语言的表达式(GDB可以调试多种编程语言),会计算表达式的值。

< f >是输出的格式,比如,如果要把表达式按16进制的格式输出,那么就是/x。

/x 按十六进制格式显示变量。

/d 按十进制格式显示变量。

/u 按十六进制格式显示无符号整型。

/o 按八进制格式显示变量。

/t 按二进制格式显示变量。

/a 按十六进制格式显示变量。

/c 按字符格式显示变量。

/f 按浮点数格式显示变量。

5)修改变量值

例1:

(gdb) print x=4

x=4这个表达式是C/C++的语法,意为把变量x的值修改为4。

例2:

在某些时候,很有可能你的变量和GDB中的参数冲突,如:

(gdb) whatis width

type = double

(gdb) p width

$4 = 13

(gdb) set width=47

Invalid syntax in expression.

因为,set width是GDB的命令,所以,出现了“Invalid syntax in expression”的设置错误,此时,你可以使用set var命令来告诉GDB,width不是你GDB的参数,而是程序的变量名,如:

(gdb) set var width=47

另外,还可能有些情况,GDB并不报告这种错误,所以保险起见,在你改变程序变量取值时,最好都使用set var格式的GDB命令。

6)跳转执行

一般来说,被调试程序会按照程序代码的运行顺序依次执行。GDB提供了乱序执行的功能,也就是说,GDB可以修改程序的执行顺序,可以让程序执行随意跳跃。这个功能可以由GDB的jump命令来完:

jump < linespec >

作用:指定下一条语句的运行点。< linespce > 可以是文件的行号,可以是file:line格式,也可以是+num这种偏移量格式。表示着下一条运行语句从哪里开始。

jump < address >

作用:注意 < address > 在这里表示代码行的内存地址。

注意,jump命令不会改变当前的程序栈中的内容,所以,当你从一个函数跳到另一个函数时,当函数运行完返回时进行弹栈操作时必然会发生错误,可能结果还是非常奇怪的,甚至于产生程序Core Dump。所以最好是同一个函数中进行跳转

一旦使用GDB挂上被调试程序,当程序运行起来后,你可以根据自己的调试思路来动态地在GDB中更改当前被调试程序的运行线路或是其变量的值,这个强大的功能能够让你更好的调试你的程序,比如,你可以在程序的一次运行中走遍程序的所有分支。

7)强制函数返回,return 命令

如果你的调试断点在某个函数中,并还有语句没有执行完。你可以使用return命令强制函数忽略还没有执行的语句并返回。

return,return < expression >

作用:使用return命令取消当前函数的执行,并立即返回,如果指定了< expression >,那么该表达式的值会被认作函数的返回值。

8)强制调用函数,call 命令

call < expr >

作用:< expr >表达式中可以是函数名,以此达到强制调用函数的目的。并显示函数的返回值,如果函数返回值是void,那么就不显示。

另一个相似的命令也可以完成这一功能—print,print后面可以跟表达式,所以也可以用他来调用函数,print 和 call的不同是,如果函数返回void,call则不显示,print则显示函数返回值,并把该值存入历史数据中。

注意:GDB尚有很多功能,这里只整理了一些自己用到的功能

/点滴积累,我的一小步O(∩_∩)O~/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: