用gdb分析core文件及常见gdb命令操作示例

来源:互联网 发布:攻是什么感觉知乎 编辑:程序博客网 时间:2024/06/13 21:40

1.概述
在实际的软件开发项目中,程序出现问题是在所难免的。遥想本人参加工作之后首次遇到程序的情景,至今还历历在目。之前的经验告诉我,我们越是惊慌失措,问题就越是解决不了。我们要先让自己平静下来,然后再寻找解决程序问题的办法。
在Linux下做开发的朋友,想必都与core文件打过交道。当看到自己的程序运行之后出现core时,很多人都慌乱了,仿佛天快要塌下来一样。其实,我们大可不必如此,只要我们掌握了用gdb调试core文件的办法,依然可以很快定位程序问题,一举将bug消灭掉。有关Linux core文件的更多介绍,请阅读此文:http://www.cnblogs.com/dongzhiquan/archive/2012/01/20/2328355.html。
本文以一个实际的程序为例,介绍了用gdb分析core文件的方法和步骤,同时演示了常见gdb命令的操作方法。如果大家想对相关gdb命令有更多的了解,请自行百度之。

2.示例程序

/*********************************************************************** 版权所有 (C)2015, Zhou Zhaoxiong。** 文件名称:GdbDebug.c* 文件标识:无* 内容摘要:Gdb命令演示程序* 其它说明:无* 当前版本:V1.0* 作    者:Zhou Zhaoxiong* 完成日期:20151008***********************************************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>// 数据类型重定义typedef unsigned char       UINT8;typedef signed   int        INT32;typedef unsigned int        UINT32;// 函数声明void Sleep(UINT32 iCountMs);void PrintInfo(void);INT32 main();/*********************************************************************** 功能描述:主函数* 输入参数:无* 输出参数:无* 返 回 值:无* 其它说明:无* 修改日期        版本号     修改人            修改内容* -------------------------------------------------------------------* 20151008       V1.0     Zhou Zhaoxiong      创建***********************************************************************/INT32 main(){    PrintInfo();   // 在屏幕上输出消息    return 0;}/********************************************************************** * 功能描述: 在屏幕上输出消息 * 输入参数: 无 * 输出参数: 无 * 返 回 值: 无 * 其它说明: 无 * 修改日期            版本号            修改人           修改内容 * ---------------------------------------------------------------------- * 20151008            V1.0        Zhou Zhaoxiong        创建 ************************************************************************/void PrintInfo(void){    UINT32 iLoopFlag = 0;    UINT32 iSum      = 0;    UINT32 iLen      = 0;    UINT8 *pCtrStr   = NULL;    iLen = strlen(pCtrStr);    for (iLoopFlag = 0; iLoopFlag < iLen; iLoopFlag ++)      // 打印消息iLen次    {        printf("PrintInfo: hello, world!\n");        iSum = iSum + iLoopFlag;        Sleep(10 * 1000);   // 每10s打印一次    }    return;}/*********************************************************************** 功能描述: 程序休眠* 输入参数: iCountMs-休眠时间(单位:ms)* 输出参数: 无* 返 回 值: 无* 其它说明: 无* 修改日期          版本号       修改人              修改内容* ------------------------------------------------------------------* 20151008         V1.0     Zhou Zhaoxiong          创建********************************************************************/void Sleep(UINT32 iCountMs){    struct timeval t_timeout = {0};    if (iCountMs < 1000)    {        t_timeout.tv_sec = 0;        t_timeout.tv_usec = iCountMs * 1000;    }    else    {        t_timeout.tv_sec = iCountMs / 1000;        t_timeout.tv_usec = (iCountMs % 1000) * 1000;    }    select(0, NULL, NULL, NULL, &t_timeout);   // 调用select函数阻塞程序}

3.用gdb分析core文件
在Linux上用“gcc -g -o GdbDebug GdbDebug.c”命令对程序进行编译之后,运行“GdbDebug”命令,发现在当前目录下出现了core文件。利用gdb命令对core文件进行分析的过程如下所示:

~/zhouzhaoxiong/zzx/GdbDebug> gdb GdbDebug core     -- 启动gdb对core文件的分析GNU gdb (GDB) SUSE (7.3-0.6.1)Copyright (C) 2011 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-suse-linux".For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>...Reading symbols from /home/zhou/zhouzhaoxiong/zzx/GdbDebug/GdbDebug...done.Core was generated by `GdbDebug'.Program terminated with signal 11, Segmentation fault.#0  0x00007f4a736f9812 in __strlen_sse2 () from /lib64/libc.so.6(gdb) where          -- 查看程序出问题的地方#0  0x00007f4a736f9812 in __strlen_sse2 () from /lib64/libc.so.6#1  0x000000000040061a in PrintInfo () at GdbDebug.c:64   -- 可以看到,在GdbDebug.c文件的第64行出的问题#2  0x00000000004005e5 in main () at GdbDebug.c:41(gdb) b 41           -- 在GdbDebug.c文件第41行设立断点Breakpoint 1 at 0x4005e0: file GdbDebug.c, line 41.(gdb) b 64           -- 在GdbDebug.c文件第64行设立断点Breakpoint 2 at 0x400611: file GdbDebug.c, line 64.(gdb) info b         -- 显示断点信息Num     Type           Disp Enb Address            What1       breakpoint     keep y   0x00000000004005e0 in main at GdbDebug.c:412       breakpoint     keep y   0x0000000000400611 in PrintInfo at GdbDebug.c:64(gdb) r              -- 运行GdbDebugStarting program: /home/zhou/zhouzhaoxiong/zzx/GdbDebug/GdbDebug Breakpoint 1, main () at GdbDebug.c:4141          PrintInfo();   // 在屏幕上输出消息(gdb) n             -- 执行下一步Breakpoint 2, PrintInfo () at GdbDebug.c:6464              iLen = strlen(pCtrStr);(gdb) p iLen        -- 打印(输出)iLen的值$1 = 0(gdb) p iLoopFlag   -- 打印(输出)iLoopFlag的值$2 = 0(gdb) c             -- 继续执行     Continuing.Program received signal SIGSEGV, Segmentation fault.    -- 程序core掉了0x00007ffff7ae9812 in __strlen_sse2 () from /lib64/libc.so.6(gdb) q             -- 退出gdbA debugging session is active.        Inferior 1 [process 26640] will be killed.Quit anyway? (y or n) y~/zhouzhaoxiong/zzx/GdbDebug>

从以上分析可知,执行GdbDebug.c文件的第64行时程序core掉了。此时仔细分析程序,发现pCtrStr指针为空。当对一个不存在的指针取长度时,由于找不到地址,程序便崩溃了。修改的办法也非常的简单,只需要让pCtrStr指针指向具体的地址即可。

4.常见gdb命令操作示例
修改之后的代码如下:

/*********************************************************************** 版权所有 (C)2015, Zhou Zhaoxiong。** 文件名称:GdbDebug.c* 文件标识:无* 内容摘要:Gdb命令演示程序* 其它说明:无* 当前版本:V1.0* 作    者:Zhou Zhaoxiong* 完成日期:20151008***********************************************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>// 数据类型重定义typedef unsigned char       UINT8;typedef signed   int        INT32;typedef unsigned int        UINT32;// 函数声明void Sleep(UINT32 iCountMs);void PrintInfo(void);INT32 main();/*********************************************************************** 功能描述:主函数* 输入参数:无* 输出参数:无* 返 回 值:无* 其它说明:无* 修改日期        版本号     修改人            修改内容* -------------------------------------------------------------------* 20151008       V1.0    Zhou Zhaoxiong       创建***********************************************************************/INT32 main(){    PrintInfo();   // 在屏幕上输出消息    return 0;}/********************************************************************** * 功能描述: 在屏幕上输出消息 * 输入参数: 无 * 输出参数: 无 * 返 回 值: 无 * 其它说明: 无 * 修改日期            版本号            修改人           修改内容 * ---------------------------------------------------------------------- * 20151008           V1.0         Zhou Zhaoxiong        创建 ************************************************************************/void PrintInfo(void){    UINT32 iLoopFlag = 0;    UINT32 iSum      = 0;    UINT32 iLen      = 0;    UINT8 *pCtrStr   = "hello, world!";  // 修改了这行代码    iLen = strlen(pCtrStr);    for (iLoopFlag = 0; iLoopFlag < iLen; iLoopFlag ++)      // 打印消息iLen次    {        printf("PrintInfo: hello, world!\n");        iSum = iSum + iLoopFlag;        Sleep(10 * 1000);   // 每10s打印一次    }    return;}/*********************************************************************** 功能描述: 程序休眠* 输入参数: iCountMs-休眠时间(单位:ms)* 输出参数: 无* 返 回 值: 无* 其它说明: 无* 修改日期          版本号       修改人              修改内容* ------------------------------------------------------------------* 20151008         V1.0     Zhou Zhaoxiong          创建********************************************************************/void Sleep(UINT32 iCountMs){    struct timeval t_timeout = {0};    if (iCountMs < 1000)    {        t_timeout.tv_sec = 0;        t_timeout.tv_usec = iCountMs * 1000;    }    else    {        t_timeout.tv_sec = iCountMs / 1000;        t_timeout.tv_usec = (iCountMs % 1000) * 1000;    }    select(0, NULL, NULL, NULL, &t_timeout);   // 调用select函数阻塞程序}

编译并运行之后,程序正常,说明问题已被我们解决掉。下面是常见的gdb命令的操作示例:

~/zhouzhaoxiong/zzx/GdbDebug> gdb GdbDebug    -- 启动gdb调试GNU gdb (GDB) SUSE (7.3-0.6.1)Copyright (C) 2011 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-suse-linux".For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>...Reading symbols from /home/zhou/zhouzhaoxiong/zzx/GdbDebug/GdbDebug...done.(gdb) b 64     -- 在GdbDebug.c文件第64行设立断点Breakpoint 1 at 0x400611: file GdbDebug.c, line 64.(gdb) b 72     -- 在GdbDebug.c文件第72行设立断点Breakpoint 2 at 0x400637: file GdbDebug.c, line 72.(gdb) info b   -- 显示断点信息Num     Type           Disp Enb Address            What1       breakpoint     keep y   0x0000000000400611 in PrintInfo at GdbDebug.c:642       breakpoint     keep y   0x0000000000400637 in PrintInfo at GdbDebug.c:72(gdb) r        -- 运行GdbDebugStarting program: /home/zhou/zhouzhaoxiong/zzx/GdbDebug/GdbDebug Breakpoint 1, PrintInfo () at GdbDebug.c:6464              iLen = strlen(pCtrStr);(gdb) p iLen    -- 打印(输出)iLen的值$1 = 0(gdb) n         -- 执行下一步66              for (iLoopFlag = 0; iLoopFlag < iLen; iLoopFlag ++)      // 打印消息iLen次(gdb) n         -- 执行下一步68              printf("PrintInfo: hello, world!\n");(gdb) p iLoopFlag   -- 打印(输出)iLoopFlag的值$2 = 0(gdb) p iLen    -- 打印(输出)iLen的值$3 = 13(gdb) n         -- 执行下一步PrintInfo: hello, world!    -- 程序的输出结果70                      iSum = iSum + iLoopFlag;(gdb) p iSum    -- 打印(输出)iSum的值$4 = 0(gdb) n        -- 执行下一步Breakpoint 2, PrintInfo () at GdbDebug.c:7272                      Sleep(10 * 1000);   // 每10s打印一次(gdb) n      66              for (iLoopFlag = 0; iLoopFlag < iLen; iLoopFlag ++)      // 打印消息iLen次(gdb) p iLoopFlag$5 = 0(gdb) n68              printf("PrintInfo: hello, world!\n");(gdb) p iLoopFlag$6 = 1(gdb) nPrintInfo: hello, world!70                      iSum = iSum + iLoopFlag;(gdb) p iSum$7 = 0(gdb) nBreakpoint 2, PrintInfo () at GdbDebug.c:7272                      Sleep(10 * 1000);   // 每10s打印一次(gdb) p iSum$8 = 1(gdb) finish        -- 一直运行到函数返回Run till exit from #0  PrintInfo () at GdbDebug.c:72PrintInfo: hello, world!Breakpoint 2, PrintInfo () at GdbDebug.c:7272                      Sleep(10 * 1000);   // 每10s打印一次(gdb) c           -- 继续执行 Continuing.PrintInfo: hello, world!Breakpoint 2, PrintInfo () at GdbDebug.c:7272                      Sleep(10 * 1000);   // 每10s打印一次(gdb) bt            -- 打印当前的函数调用栈的所有信息#0  PrintInfo () at GdbDebug.c:72#1  0x00000000004005e5 in main () at GdbDebug.c:41(gdb) q              -- 退出gdbA debugging session is active.        Inferior 1 [process 26685] will be killed.Quit anyway? (y or n) y~/zhouzhaoxiong/zzx/GdbDebug> 

作为Linux下调试C/C++程序的工具,大家一定要熟练掌握gdb的用法。

1 0
原创粉丝点击