linux gdb调试总结

日期:2015-04-03点击次数:8619

虽然在linux下调试大部分时间用的是日志或者使用prinf打印,但掌握一点gdb调试,能达到事半功倍的效果。最近用了一段时间linux,在调试程序时用到了gdb调试,也总结了下,虽然网上资料一大堆,但毕竟不是自己掌握的,现总结下常用方法:
要使用gdb调试,编译选项要加上-g选项,否则调试时符号与文件行号对应不上。具体命令使用网上可以查询。
 
1. 调试Core文件
假如运行程序时,程序崩溃,如果生成了core文件,就能使用gdb查看程序崩溃时的堆栈。如:
#./test
#Segment fault (core dumped)
如果生成的是12345.core文件,那么使用如下命令调试core文件。
#gdb test –core 12345.core
此方法利用core文件,进行事后分析,但前提是保证系统会生成core文件。
要知道系统会不会生成core文件,可以输入如下命令:
# ulimit –a
查看当前core文件大小限制,如果为0,则需改为unlimited。
#ulimit –S –c unlimited
然后就可以使用bt命令查看堆栈。
 
注意 如果程序安装了 SIGSEGV异常处理函数,那么使用gdb test –core 12345.core时显示的崩溃堆栈是不准确的,要得到真实出错点,必须去掉异常处理函数。
 
2. 调试已运行的程序
假如运行的程序为test,那么先得查询出进程号:
#pidof test
假如pid为12345,则使用attach命令附加此进程:
#gdb
#attach 12345 开始 一个正在运行的程序
后面就可以使用调试命令跟踪程序运行。
如果想停止调试当前正在调试的进程,那么不能使用quit退出gdb,否则被调试进程可能被直接杀死。使用detach直接脱离gdb控制就行了。
#detach
 
如果是在开发模式,想不退出gdb而对当前正在调试的应用程序重新编译,链接,可以在gdb中使用kill杀掉子进程,等编译链接后,再重新执行run,gdb可以加载新的可执行程序启动调试。
 
如果程序崩溃是必现的话,可以使用gdb直接运行此程序,程序崩溃时,gdb会自动中断,并打印堆栈信息。如:
# gdb test
 
3. 多线程调试
多线程/多进程比较难以调试,在gdb中主要使用下面的几个命令进行调试:
多线程调试的一般步骤:
(1) info threads 查看当前进程中所有线程
(2) thread threadno 然后切换当前线程到由threadno指定的线程
(3) bt 查看当前线程的堆栈
(4) frame n  切换到指定帧
(5) 使用print显示一些变量的值
(6) up n 或者down n可以在堆栈中向上或向下跳动n帧。
 
可以使用thread apply命令对所有线程或者特定线程执行设置的命令:
# thread apply [threadno] [all] cmds  对指定(或所有)线程执行由cmds指定的命令。
 
 
4.多进程调试
多进程调试比较少用,此多进程调试只适用于fork/vfork生成的子进程
一般情况下,fork后,gdb仍然调试的是父进程,如果要改变此模式,使用如下命令:
# set follow-fork-mode mode: 设置gdb行为,mode为parent时,与缺省情况一样;mode为child时,fork之后,gdb进入子进程调试,与父进程再没有关系。
 
注意:此方法只适用于fork/vfork,如果程序调用的是system()函数,或者使用execve系列函数生成子进程,是不适用的。
 
gdb高版本还提供了一种调试多进程的方法,能同时调试多个进程,由于使用不多,在此不表。
 
5.信号捕获
gdb有能力在你调试程序的时候处理任何一种信号,你可以告诉gdb需要处理哪一种信号。你可以要求gdb收到你所指定的信号时, 马上停住正在运行的程序,以供你进行调试。你可以用gdb的handle命令来完成这一功能。
handle signal keywords
在gdb中定义一个信号处理。信号可以以SIG开头或不以SIG开头,可以用定义一个要处理信号的范围 (如:SIGIO- SIGKILL,表示处理从SIGIO信号到SIGKILL的信号,其中包括SIGIO,SIGIOT,SIGKILL三 个信号),也可以使用关键字 all来标明要处理所有的信号。一旦被调试的程序接收到信号,运行程序马上会被gdb停住,以供调试。 其<keywords>可以是以下几种关键字的一个或多个。
nostop当被调试的程序收到信号时,gdb不会停住程序的运行,但会打出消息告诉你收到这种信号。
stop 当被调试的程序收到信号时,gdb会停住你的程序。
print 当被调试的程序收到信号时,gdb会显示出一条信息。
noprint 当被调试的程序收到信号时,gdb不会告诉你收到信号的信息。
pass
noignore
当被调试的程序收到信号 时,gdb不处理信号。这表示,gdb会把这个信号交给被调试程序会处理。
nopass
ignore
当被调试的程序 收到信号时,gdb不会让被调试程序来处理这个信号。
info signals
info handle
查看有哪些信号在被 GDB检测中。

信号捕获在调试一些莫名其妙程序就无声无息退出的情况下,比较管用,因为此时,你能判断出程序是收到哪个信号后,程序被迫退出的。
 
以上总结的技巧,可以用于实际的项目开发中,并能提高开发效率和软件质量,掌握它只是多花一点时间而已,技不压身嘛。
 
 




软件部          向国春