让我们通过一个具体的例子来演示如何使用GDB调试器来分析一个简单的C程序产生的core文件。
首先,假设我们有一个简单的C程序,example.c
,如下所示:
#include <stdio.h>
void function_b() { char *ptr = NULL; *ptr = 0; // 故意的空指针解引用导致段错误} void function_a() { function_b(); }
int main()
{
function_a();
return 0;
}
接下来是编译这个程序,并确保带有调试信息:
gcc -g -o example example.c
在运行这个程序之前,我们需要确保操作系统允许生成core文件。在bash shell中,我们可以使用ulimit
命令:
ulimit -c unlimited
现在运行程序,它将崩溃,并生成一个名为core
的core文件(或者可能是带有进程号的core文件,例如core.12345
):
./example
现在我们使用GDB来分析core文件:
gdb ./example core
在GDB中,我们可以使用bt
命令查看崩溃时的堆栈跟踪:
(gdb) bt#0 0x000055555555467a in function_b () at example.c:5#1 0x000055555555469c in function_a () at example.c:9#2 0x00005555555546aa in main () at example.c:13
这个堆栈跟踪显示了崩溃发生在example.c
的第5行。我们可以使用list
命令来查看源码:
(gdb) list 1 #include <stdio.h> 2 3 void function_b() { 4 char *ptr = NULL; 5 *ptr = 0; // 故意的空指针解引用导致段错误 6 } 7 8 void function_a() { 9 function_b(); 10 }
很明显,第5行尝试解引用一个空指针,这是导致程序崩溃的原因。
我们还可以检查当前的函数调用和局部变量:
(gdb) frame 0#0 0x000055555555467a in function_b () at example.c:55 *ptr = 0; // 故意的空指针解引用导致段错误 (gdb) info locals ptr = 0x0
这里,info locals
告诉我们ptr
是一个空指针(值为0x0
)。
通过这些信息,我们可以确定程序崩溃是因为在function_b
中尝试解引用了一个空指针。我们可以通过修改代码来避免这种情况发生,例如通过在解引用之前检查指针是否为NULL。
修复后的function_b
可能看起来像这样:
void function_b() { char *ptr = NULL; if (ptr != NULL) { *ptr = 0; } }
重新编译并运行程序,这次它不应该再崩溃了。这就是使用GDB和core文件来调试和解决问题的基本过程。