【VC++开源代码栏目提醒】:网学会员在VC++开源代码频道为大家收集整理了“linux下GDB教程 - 技术总结“提供大家参考,希望对大家有所帮助!
GDBGDBGDBGDB教程GDB是一个强大的命令行调试工具。
大家知道命令行的强大就是在于其可以形成执行序列形成脚本。
UNIX下的软件全是命令行的这给程序开发提供了极大的便利命令行软件的优势在于他们可以非常容易的集成在一起使用几个简单的已有工具的命令就可以做出一个非常强大的功能。
于是UNIX下的软件比windows下的
软件更能有机的结合各自发挥各自的长处组合成更为强筋的功能。
而windows下的图形软件基本上各自为营互相不能条用很不利于各种软件的相互集成。
在这里并不是要和windows做个什么比较所谓“寸有所长尺有所短”图形化工具还是有不如命令行的地方。
用GDBGDBGDBGDB调试程序GDBGDBGDBGDB概述GDB是GNU
开源组织发布的一个强大的UNIX下调试程序工具。
或许各位比较喜欢那种图形界面方式的像VCBCB等IDE的调试但如果你是在UNIX平台下作软件你会发现GDB这个调试工具有比VCBCB的图形化调试器更强大的功能。
所谓“寸有所长尺有所短”就是这个道理。
一般来说GDB主要帮助你完成下面四个方面的功能1、启动你的程序可以按照你自定义的要求随心所欲的运行程序。
2、可以让调试程序在你所指定的位置的断点处停止。
3、当程序停止时可以检查此时你的程序中所发生的事情。
4、动态的改变你程序的执行环境。
从上面看来GDB和一般的调试工具没有什么两样基本上也是完成这些功能不过在细节上你会发现GDB这个调试工具的强大大家可能习惯图形化的调试工具但有时候命令行的调试工具却有着图形化工具所不能完成的功能。
让我们来看一个例子源程序test.c1includeltstdio.hgt23intfuncintn45intsum0i6fori0iltni78sumi910returnsum11121314main1516inti17longresult018fori1ilt100i1920resulti212223printfquotresult1-100dnquotresult24printfquotresult1-250dnquotfunc25025编译生成执行文件ltbybgtgcc–gtest.c–otest使用GDB调试ltbybgtgdbtest——————启动GDBGNUgdb5.1.1Copyright2002FreeSoftwareFoundationInc.GDBisfreesoftwarecoveredbytheGNUGeneralPublicLicenseandyouarewelcometochangeitand/ordistributecopiesofitundercertainconditions.Typequotshowcopyingquottoseetheconditions.ThereisabsolutelynowarrantyforGDB.Typequotshowwarrantyquotfordetails.ThisGDBwasconfiguredasquoti386-suse-
linuxquot...gdbgdbgdbgdblist——————从第一行列出源码1includeltstdio.hgt23intfuncintn45intsum0i6fori0iltni78sumi910returnsumgdbgdbgdbgdb——————直接回车表示重复上一次命令11121314main1516inti17longresult018fori1ilt100i1920resultigdbgdbgdbgdbbreak16——————设置断点在源程序第16行处。
Breakpoint1at0x8048496:filetst.cline16.gdbgdbgdbgdbbreakfunc——————设置断点在函数func入口处。
Breakpoint2at0x8048456:filetst.cline5.gdbgdbgdbgdbinfobreak——————查看断点信息。
NumTypeDispEnbAddressWhat1breakpointkeepy0x08048496inmainattst.c:162breakpointkeepy0x08048456infuncattst.c:5gdbgdbgdbgdbrun——————运行程序Startingprogram:/home/hchen/test/tstBreakpoint1mainattst.c:17——————在断点处停住。
17longresult0gdbgdbgdbgdbnext——————单条语句执行。
18fori1ilt100igdbgdbgdbgdbn20resultigdbgdbgdbgdbn18fori1ilt100igdbgdbgdbgdbn20resultigdbgdbgdbgdbcontinue——————继续运行程序Continuing.result1-1005050——————程序输出。
Breakpoint2funcn250attst.c:55intsum0igdbgdbgdbgdbn6fori1iltnigdbgdbgdbgdbprinti——————打印变量i的值。
1134513808gdbgdbgdbgdbn8sumigdbgdbgdbgdbn6fori1iltnigdbgdbgdbgdbpsum21gdbgdbgdbgdbn8sumigdbgdbgdbgdbpi32gdbgdbgdbgdbn6fori1iltnigdbgdbgdbgdbpsum——————p是print的缩写43gdbgdbgdbgdbbt——————查看函数堆栈0funcn250attst.c:510x080484e4inmainattst.c:2420x400409edin__libc_start_mainfrom/lib/libc.so.6gdbgdbgdbgdbfinish——————推出函数Runtillexitfrom0funcn250attst.c:50x080484e4inmainattst.c:2424printfquotresult1-250dnquotfunc250Valuereturnedis631375gdbgdbgdbgdbcontinueContinuing.result1-25031375——————程序输出。
Programexitedwithcode027.——————程序退出调试结束。
gdbgdbgdbgdbquit——————退出gdb好了有了以上的感性认识还是让我们来系统的认识一下gdb吧。
使用GDBGDBGDBGDB一般来说GDB主要调试的是C/C程序。
要调试C/C程序首先在编译时我们必须要把调试信息加到可执行文件中。
使用编译器cc/gcc/g的-g参数可以做到这一点如cc–ghello.c–ohellog-ghello.cpp–ohello如果没有-g你将看不见程序的函数名变量名所代替的全是运行的内存地址。
当你用-g把调试信息假如之后并成功编译目标
代码以后让我们来看看如果用GDB调试它。
启动GDB的方法有以下几种1、gdbltprogramgtprogram也就是你的执行文件一般在当前目录下。
2、gdbltprogramgtcore用gdb同时调试一个运行程序和core文件core是程序非法执行后coredump后产生的文件。
3、gdbltprogramgtltPIDgt如果你的程序是一个服务程序那么你可以指定这个服务程序运行时的进程ID。
gdb会自动attach上去并调试它。
program应该在PATH环境变量中搜索到。
GDB启动时可以加上一些GDB的启动开关详细的开关可以用gdb–help来查看。
下面只列举一些比较
常用的参数-symbolsltfilegt-sltfilegt从指定文件中读取符号表。
-sefile从指定文件中读取符号表信息并把他用在可执行文件中。
-coreltfilegt-cltfilegt调试coredump的core文件。
-directoryltdirectorygt-dltdirectorygt加入一个源文件的
搜索路径。
默认搜索路径是环境变量中PATH所定义的路径。
GDB的命令概貌启动gdb后就进入了gdb的调试环境就可以使用gdb的命令开始调试程序了gdb的命令可以使用help命令来查看如下所示gdbgdbgdbgdbhelpListofclassesofcommands:aliases--Aliasesofothercommandsbreakpoints--Makin
gprogramstopatcertainpointsdata--Examiningdatafiles--Specifyingandexaminingfilesinternals--Maintenancecommandsobscure--Obscurefeaturesrunning--Runningtheprogramstack--Examiningthestackstatus--Statusinquiriessupport--Supportfacilitiestracepoints--Tracingofprogramexecutionwithoutstoppingtheprogramuser-defined--User-definedcommandsTypequothelpquotfollowedbyaclassnameforalistofcommandsinthatclass.Typequothelpquotfollowedbycommandnameforfulldocumentation.Commandnameabbreviationsareallowedifunambiguous.gdbgdbgdbgdbgdb的命令很多gdb把之分成很多种类。
help命令只是列出了gdb的命令种类如果要看种类中的命令使用helpltclassgt命令如helpbreakpoints查看设置断点的所有命令。
也可以直接helpltcommandgt来查看命令的帮助。
Gdb中输入命令时可以不用打全命令只用打命令的前几个字符就可以了当然命令的前几个字符要标志着一个唯一的命令在linux下可以敲击两次TAB键来补齐命令的全称如果有重复的gdb会把其列出来。
示例一在进入函数func时设置一个断点。
可以敲击breakfunc或者直接就是bfuncgdbgdbgdbgdbbfuncBreakpoint1at0x8048458:filehello.cline10.示例二敲入b按两次TAB键你会看到所有b开头的命令gdbgdbgdbgdbbbacktracebreakbt示例三只记得函数的前缀可以这样gdbgdbgdbgdbbmake_lt按TAB键gtmake_a_section_from_filemake_environmake_abs_sectionmake_function_typemake_blockvectormake_pointer_typemake_cleanupmake_reference_typemake_commandmake_symbol_completion_listgdbgdbgdbgdbbmake_GDB把所有make开头的函数全部列出来给你查看。
示例四调试C程序可以函数名一样。
如gdbgdbgdbgdbb‘bubblelt按两次TAB键gtbubbledoubledoublebubbleintintgdbgdbgdbgdbb‘bubble你可以查看到C中所有的重载函数以及参数要退出GDB只要quit或命令简称q就行了。
GDBGDBGDBGDB中运行UNIXUNIXUNIXUNIX的ShellShellShellShell程序在gdb环境中你可以执行UNIX的shell命令使用gdb的shell命令来完成shellltcommandstringgt调用UNIX的shell来执行ltcommandstringgt环境变量SHELL中定义的UNIX的shell将会被用来执行ltcommandstringgt如果SHELL没有定义那就使用UNIX的标准shell/bin/sh还有一个gdb命令是makemakeltmake-argsgt可以在gdb中执行make命令来重新build自己的程序。
这个命令等价于“makemakeltmake-argsgt”在GDBGDBGDBGDB中运行程序当以gdbltprogramgt方式启动gdb后gdb会在PATH路径和当前目录中所搜ltprogramgt的源文件。
如要确认gdb是否读到源文件可使用l或者list命令看gdb是否能列出源
代码。
在gdb中运行程序使用r或者run命令程序的运行有可能需要设置下面四方面的事1、程序的运行参数。
setargs可指定运行时参数。
如setargs1020304050showargs命令可以查看设置好的运行参数。
2、运行环境pathltdirgt可设定程序的运行路径。
showpaths查看程序的运行路径。
setenvironmentvarnamevalue设置环境变量。
如setenvUSERhchenshowenvironmentvarname查看环境变量3、工作目录cdltdirgt相当于shell的cd命令。
pwd显示当前的
工作目录。
4、程序的输入输出infoterminal显示程序用到的终端的模式使用重定向空值程序输出。
如rungtoutfiletty命令可以指定写输入输出的终端设备。
如tty/dev/ttyb调试已运行的程序两种方法1、在UNIX下用ps查看正在运行的程序的PID进程ID然后用gdbltprogramgtPID格式挂接正在运行的程序。
2、先用gdbltprogramgt关联上源
代码并进行gdb在gdb中用attach命令来挂接进程的PID并用detach来取消挂接的程序。
暂停////恢复程序运行调试程序中暂停进程运行时必须的GDB可以方便的暂停程序的运行。
你可以设置程序在哪停住在什么条件下停住在收到什么信号时停住等等。
你便于你查看运行的变量以及运行时的流程。
当进程被gdb停住时你可以使用infoprogram来查看程序是否在运行、进程号、被暂停的原因。
在gdb中我们可以有以下几种暂停方式断点breakpoint、观察点watchpoint、捕捉点catchpoint、信号signals、线程停止threadstops。
如果要恢复
程序运行可以使用c或者continue命令。
一、设置断点breakpointbreakpointbreakpointbreakpoint我们用break命令设置断点。
下面有几点设置断点的方法breakltfunctiongt在进入指定函数时停住。
C中可以使用class::function或functiontypetype格式来指定函数名。
breakltlinenumgt在指定行号停住。
breakoffsetbreak–offset在当前行号的前面或者后面的offset行停住。
Offset为自然数。
breakfilename:linenum在源文件filename的linenum行处停住。
breakfilename:function在源文件filename的function函数的入口处停住。
breakaddress在程序运行的内存地址处停住。
breakbreak命令没有参数时表示在下一条指令处停住。
break…ifltconditiongt…可以是上述的参数condition表示条件在条件成立时停住。
比如在循环体中可以设置breakifi100表示当i为100时停住程序。
查看断点时可使用命令info命令如下所示注n表示断点号infobreakpointsninfobreakn二、设置捕捉点catchpointcatchpointcatchpointcatchpoint我们可以设置捕捉点来捕捉程序运行时的一些事件。
如载入共享库动态链接库或是C的一场设置捕捉点的格式为catchlteventgt当event发生时停住程序。
Event可以是下面的内容1、throw一个C抛出的异常throw为关键字2、catch一个C捕捉到的异常catch为关键字3、exec调用系统调用exec时exec为关键字目前此功能只在HP-UX下有用4、fork调用
系统调用fork时。
fork为关键字目前此功能只在HP-UX下有用5、vfork调用系统调用vfork时。
vfork为关键字目前此功能只在HP-UX下有用6、load或loadltlibnamegt载入共享库动态链接库时。
load为关键字目前此功能只在HP-UX下有用7、unload或unloadltlibnamegt卸载共享库动态链接库时。
unload为关键字目前此功能只在HP-UX下有用tcatchlteventgt只设置一次捕捉当程序停住后断点被自动删除。
三、维护停止点上面说了如何设置程序的停止点GDB中的停止点也就是上述的三类。
在GDB中如果你觉得已定义好的停止点没有用了你可以使用delete、clear、disable、enable这几个命令来进程维护。
clear清楚所有已定义的停止点。
clearltfunctiongtclearltfilename:functiongt清楚所有设置在函数上的停止点。
clearltlinenumgtclearltfilename:linenumgt清楚所有设定在指定行上的停止。
deletebreakpointsrange…删除指定的断点breakpoints为断点号。
如果不指定断点号则表示删除所有的断点。
range表示断点号的范围如2-7其简写命令为d。
比删除更好的一种方法是disable停止点disable了的停止点GDB不会删除当你还需要时enable即可就好像回收站一样。
enablebreakpointsrange…enable所指定的停止点breakpoints为停止号。
enablebreakpointsoncerangeenable所指定的停止点一次当程序停止后该停止点马上被GDB自动disable。
enablebreakpointsdeleterangeenable所指定的停止点一次当程序停止后该停止点马上被GDB自动删除。
四、停止条件维护前面在说到设置断点时我们提到过可设置一个条件当条件成立时程序自动停止这是一个非常强大的功能这里专门说说这个条件相关维护命令。
一般来说为断点设置一个条件我们使用if关键字后面跟其断点条件。
并且条件设置好后我们可以用condition命令来修改断点的条件只有break和watch命令支持ifcatch目前暂不支持ifconditionltbnumgtltexpressiongt修改断点号为bnum的停止条件为expressionconditionltbnumgt清除断点号为bnum的停止条件。
还有一个比较特殊的维护命令ignore可以指定程序运行时忽略停止条件几次。
ignoreltbnumgtltcountgt表示忽略断点号为bnum的停止条件count次。
五、为停止点设定运行命令我们可以使用GDB提供的command命令来设置停止点的运行命令。
也就是说当运行的程序在被停止住时我们可以让你自动运行一些别的命令这很有利于自动化调试。
对给予GDB的自动化调试是一个很强大的支持。
commandbnum…command–list…end为断点号bnum指定一个命令列表。
当程序被该断点停住时gdb会依次运行命令列表中的命令。
例如breakfooifxgt0commandsprintf“xisdn”xcontinueend断点设置在函数foo中断点条件是xgt0如果程序符合条件被停住后也就是一旦x的值在foo函数中大于0GDB会自动打印出x的值并继续运行程序。
如果要清楚断点上的命令序列那么只要简单的执行以下commands命令并直接再打个end就行了。
六、断点菜单在C中可能会出现同一个名字的函数若干次函数重载在这种情况下breakltfunctiongt不能告诉GDB要停在哪个函数的入口。
当然你也可以使用breakltfunctiontypegt也就是把函数的参数类型告诉GDB以指定一个函数。
否则的话GDB会给你列出一个断点菜单供你选择你所需要的断点。
你只要输入菜单
列表中的编号就可以了。
如gdbgdbgdbgdbbString::after0cancel1all2file:String.cclinenumber:8673file:String.cclinenumber:8604file:String.cclinenumber:8755file:String.cclinenumber:8536file:String.cclinenumber:8467file:String.cclinenumber:735gt246Breakpoint1at0xb26c:fileString.ccline867.Breakpoint2at0xb344:fileString.ccline875.Breakpoint3at0xafcc:fileString.ccline846.Multiplebreakpointswereset.Usethequotdeletequotcommandtodeleteunwantedbreakpoints.gdbgdbgdbgdb可见GDB列出了所有after的重载函数你可以选以下列表编号就行了。
0表示放弃设置断点1表示所有函数都设置断点。
七、恢复程序运行和单步调试当程序被停住后你可以用continue命令恢复程序的运行直到程序结束或下一个断点的到来。
也可以使用step或next命令单步跟踪程序。
continueignore-countcignore-countfgignore-count恢复程序运行直到程序结束或是下一个断点到来。
Ignore-count表示忽略其后的断点次数。
continuecfg三个命令都是一样的意思。
stepltcountgt单步跟踪如果有函数调用他会进入该函数。
进入函数的前提是次函数被编译有debug信息。
像
VC等工具中的stepin。
后面可以加count也可以不加不加表示一条一条地执行加表示执行后面的count条指令然后再停住。
nextltcountgt同样单步跟踪如果有函数调用他不会进入函数。
想
VC等工具中的stepover。
后面可以加count也可以不加。
不加表示一条条的执行加表示执行后面的count指令然后再停住。
setstep-modesetstep-modeon打开step-mode模式于是在进行单步跟踪时程序不会因为没有debug信息而不停住。
这个参数很有利于查看机器码。
setstep-modeoff运行程序直到当前函数完成返回。
并打印函数返回时的堆栈地址和返回值及参数值信息。
finish运行程序直到当前函数完成返回。
并打印函数返回时的堆栈地址和返回值及参数值信心。
until或u当你厌倦了在一个循环体内单步跟踪时这个命令可以运行程序知道退出循环体。
stepi或sinexti或ni单步跟踪一条机器指令一条程序
代码有可能由数条机器指令完成stepi和nexti可以单步执行机器指令。
与之一样有相同功能的命令式“display/Ipc”当运行完这个命令后单步跟踪会在打出
代码的同时打出机器指令也就是汇编
代码八、信号signalssignalssignalssignals信号是一种软中断是一种处理异步事件的方法。
一般来说操作系统都支持许多信号。
尤其是UNIX比较重要的应用程序一般都会处理信号。
UNIX定义了很多信号比如SIGINT表示中断字符信号也就是ctrlC的信号SIGBUS表示硬件故障的信号SIGCHLD表示子进程状态改变信号SIGKILL表示终止程序运行的信号等等。
信号量编程时UNIX下非常重要的一种技术。
GDB有能力在你调试程序的时候处理任何一种信号我们可以告诉GDB需要处理哪一种信号。
我们可以要求GDB收到你所指定的信号时马上停住正在运行的程序以供你进行调试。
你可以用GDB的handle命令来完成这一功能。
handleltsignalgtltkeywords…gt在GDB中定义一个信号处理。
信号ltsignalgt可以以SIG开头或不以SIG开头可以用定义一个要处理信号范围如SIGIO-SIGKILL表示处理从ISGIO信号到SIGKILL的信号其中包括SIGIOSIGIOTSIGKILL三个信号也可以使用关键字all来表明要处理的所有信号。
一旦被调试的程序接收到信号运行程序马上会被GDB停住以供调试。
其ltkey
wordsgt可以是以下几种关键字的一个或多个。
nostop当被调试的程序收到信号时GDB不会停住程序的运行但会打出消息告诉你收到这种信号。
stop当被调试的程序收到信号时GDB会停住你的程序。
print当被调试的程序收到信号时GDB会显示出一条信息。
noprint当被调试的程序收到信号时GDB不会告诉你收到信号的信息。
passnoignore当被调试程序收到信号时GDB不处理信号。
这表示GDB会把这个信号交给调试程序处理。
nopassignore当被调试的程序收到信号时GDB不会让被调试程序来处理这个信号。
infosignalsinfohandle查看有哪些信号在被GDB检测中。
九、线程threadthreadthreadthreadstopsstopsstopsstops如果你的程序时多线程的话你可以定义你的断点是否在所有的线程上或是在某个特定的线程。
GDB很容易帮你完成这一工作。
breakltlinespecgtthreadltthreadnogtbreakltlinespecgtthreadltthreadnogtif…linespec指定了断点是这在源程序的行号。
Threadno指定了线程ID注意这个ID是GDB分配的你可以通过“infothreads”命令来查看正在运行程序中的线程信.