博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
用gdb分析core文件及常见gdb命令操作示例
阅读量:7083 次
发布时间:2019-06-28

本文共 10400 字,大约阅读时间需要 34 分钟。

1.概述

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

2.示例程序

/*********************************************************************** 版权所有 (C)2015, Zhou Zhaoxiong。** 文件名称:GdbDebug.c* 文件标识:无* 内容摘要:Gdb命令演示程序* 其它说明:无* 当前版本:V1.0* 作    者:Zhou Zhaoxiong* 完成日期:20151008***********************************************************************/#include 
#include
#include
// 数据类型重定义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 
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:
...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 
#include
#include
// 数据类型重定义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 
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:
...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的用法。

转载地址:http://wgmml.baihongyu.com/

你可能感兴趣的文章
Java SE (3) 之 事件监听
查看>>
1.php代码块
查看>>
现代软件工程 第五章 【团队和流程】练习与讨论
查看>>
[Git] 解决 insufficient permission for adding an object to repository database
查看>>
Android应用插件式开发解决方法[转]
查看>>
[J2ME] 基本框架框架
查看>>
Git 常用命令详解(二)
查看>>
三星S4 i9508 4.4.2 root 教程
查看>>
c#编程基础之枚举
查看>>
Java之线程———GUI线程(包含打字游戏和计时器俩个GUI实列)
查看>>
Firefly框架参考
查看>>
Android-关于屏幕适配的一些经验
查看>>
Struts ongl 集合伪属性
查看>>
android 内存泄露调试
查看>>
C#操作Word (1)Word对象模型
查看>>
使用brew安装软件
查看>>
memwatch的使用
查看>>
WWF3控制流程类型活动<第二篇>
查看>>
c++11新增的一些便利的算法
查看>>
笔试面试(1)腾讯2014校园招聘软件开发类笔试试题
查看>>