然后就可以生成核心文件了。这里仍以前面的debugme程序为例,再次执行下面命令将产生核心文件:
# ./debugme
Enter a string to count words:Happy new year!
The number of words is 3.
Segmentation fault (core dumped)
生成的核心文件名根据系统配置的不同会有所差异。要在GDB中分析核心文件,除了要给出核心文件的文件名外,还必须给出生成该核心文件的可执行程序的名称,示例如下:
#gdb debugme core.547
……
Program terminated with signal 11, Segmentation fault.
Reading symbols from /lib/libc.so.6...done.
……
从GDB的输出信息中可以看出,产生这个核心文件的原因是因为程序收到了序号为11的信号。如果想知道程序在崩溃之前运行到了哪里,可以使用“backtrace”或“info stack”命令查看一下堆栈的历史记录。示例如下:
(gdb) info stack
#0 0x4000c6ac in _dl_fini () from /lib/ld-linux.so.2
#1 0x40057940 in exit () from /lib/libc.so.6
#2 0x4004291f in _libc_start_main () from /lib/libc.so.6
由上可知,程序崩溃时正处于_dl_fini()函数之中。但很多时候程序员感兴趣的可能并不是这个,而是exit()或_libc_start_main()函数,因为它们才可能是问题真正的症结所在。GDB提供的“frame”命令可以用来在不同的调用上下文中切换。例如下面的命令可以查看exit()函数在执行时的状况:
(gdb) frame 1
#1 0x40057940 in exit () from /lib/libc.so.6
此外还可以用“up”或“down”命令在不同的函数调用上下文中切换。开发人员使用这三条命令可以很轻松地实现调用栈的遍历。在分析核心文件时,通过将遍历栈的命令和检查变量值的“print”命令结合起来,就能够复原程序运行时的全部景象。
调试其它进程
有时会遇到一种很特殊的调试需求,对当前正在运行的其它进程进行调试。这种情况有可能发生在那些无法直接在调试器中运行的进程身上,例如有的进程只能在系统启动时运行。另外如果需要对进程产生的子进程进行调试的话,也只能采用这种方式。GDB可以对正在执行的程序进行调度,它允许开发人员中断程序并查看其状态,之后还能让这个程序正常地继续执行。
GDB提供了两种方式来调试正在运行的进程:一种是在GDB命令行上指定进程的PID,另一种是在GDB中使用“attach”命令。例如,开发人员可以先启动debugme程序,让其开始等待用户的输入。示例如下:
#./debugme
Enter a string to count words:
接下去在另一个虚拟控制台中用下面的命令查出该进程对应的进程号:
# ps -ax | grep debugme
555 pts/1 S 0:00 ./debugme
得到进程的PID后,就可以使用GDB对其进行调试了:
# gdb debugme 555
GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
Attaching to program: /home/xiaowp/debugme, process 555
Reading symbols from /lib/libc.so.6...done.
……
在上面的输出信息中,以Attaching to program开始的行表明GDB已经成功地附加在PID为555的进程上了。另外一种连接到其它进程的方法是先用file命令加载调试时所需的符号表,然后再通过“attaché”命令进行连接:
(gdb) file /home/xiaowp/debugme
Reading symbols from /home/xiaowp/debugme...done.
(gdb) attach 555
……
如果想知道程序现在运行到了哪里,同样可以使用“backtrace”命令。当然也可以使用“step”命令对程序进行单步调试。
在完成调试之后,不要忘记用detach命令断开连接,让被调试的进程可以继续正常运行: