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");
- iSumiSum = 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 What
- 1 breakpoint keep y 0x00000000004005e0 in main at GdbDebug.c:41
- 2 breakpoint keep y 0x0000000000400611 in PrintInfo at GdbDebug.c:64
- (gdb) r -- 运行GdbDebug
- Starting program: /home/zhou/zhouzhaoxiong/zzx/GdbDebug/GdbDebug
- Breakpoint 1, main () at GdbDebug.c:41
- 41 PrintInfo(); // 在屏幕上输出消息
- (gdb) n -- 执行下一步
- Breakpoint 2, PrintInfo () at GdbDebug.c:64
- 64 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 -- 退出gdb
- A 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");
- iSumiSum = 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 What
- 1 breakpoint keep y 0x0000000000400611 in PrintInfo at GdbDebug.c:64
- 2 breakpoint keep y 0x0000000000400637 in PrintInfo at GdbDebug.c:72
- (gdb) r -- 运行GdbDebug
- Starting program: /home/zhou/zhouzhaoxiong/zzx/GdbDebug/GdbDebug
- Breakpoint 1, PrintInfo () at GdbDebug.c:64
- 64 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 iSumiSum = iSum + iLoopFlag;
- (gdb) p iSum -- 打印(输出)iSum的值
- $4 = 0
- (gdb) n -- 执行下一步
- Breakpoint 2, PrintInfo () at GdbDebug.c:72
- 72 Sleep(10 * 1000); // 每10s打印一次
- (gdb) n
- 66 for (iLoopFlag = 0; iLoopFlag < iLen; iLoopFlag ++) // 打印消息iLen次
- (gdb) p iLoopFlag
- $5 = 0
- (gdb) n
- 68 printf("PrintInfo: hello, world!\n");
- (gdb) p iLoopFlag
- $6 = 1
- (gdb) n
- PrintInfo: hello, world!
- 70 iSumiSum = iSum + iLoopFlag;
- (gdb) p iSum
- $7 = 0
- (gdb) n
- Breakpoint 2, PrintInfo () at GdbDebug.c:72
- 72 Sleep(10 * 1000); // 每10s打印一次
- (gdb) p iSum
- $8 = 1
- (gdb) finish -- 一直运行到函数返回
- Run till exit from #0 PrintInfo () at GdbDebug.c:72
- PrintInfo: hello, world!
- Breakpoint 2, PrintInfo () at GdbDebug.c:72
- 72 Sleep(10 * 1000); // 每10s打印一次
- (gdb) c -- 继续执行
- Continuing.
- PrintInfo: hello, world!
- Breakpoint 2, PrintInfo () at GdbDebug.c:72
- 72 Sleep(10 * 1000); // 每10s打印一次
- (gdb) bt -- 打印当前的函数调用栈的所有信息
- #0 PrintInfo () at GdbDebug.c:72
- #1 0x00000000004005e5 in main () at GdbDebug.c:41
- (gdb) q -- 退出gdb
- A debugging session is active.
- Inferior 1 [process 26685] will be killed.
- Quit anyway? (y or n) y
- ~/zhouzhaoxiong/zzx/GdbDebug>
作为Linux下调试C/C++程序的工具,大家一定要熟练掌握gdb的用法。
【本文是51CTO专栏作者周兆熊的原创文章,作者微信公众号:周氏逻辑(logiczhou)】