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

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            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");

        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            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                      iSum = 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                      iSum = 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的用法。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2025-01-02 15:20:58

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

Unix 用gdb分析core dump文件

产生core文件条件 用ulimit -c 指定core文件大小来开启core文件的生成,如:ulimit -c unlimited 用gdb分析core文件的条件 可执行程序在编译时,需加入-g参数,否则gdb无法找到symbol信息,从而无法定位问题. 例如,如下两个cpp文件中,test.cpp会导致crash. // test.cpp void testCrash() { int *p = 0; *p = 3; } // main.cpp #include <stdio.h> void

gdb调试core文件

什么是Core Dump?Core的意思是内存, Dump的意思是扔出来, 堆出来.开发和使用Unix程序时, 有时程序莫名其妙的down了, 却没有任何的提示(有时候会提示core dumped). 这时候可以查看一下有没有形如core.进程号的文件生成, 这个文件便是操作系统把程序down掉时的内存内容扔出来生成的, 它可以做为调试程序的参考.core dump又叫核心转储, 当程序运行过程中发生异常, 程序异常退出时, 由操作系统把程序当前的内存状况存储在一个core文件中, 叫core

Linux下交叉编译gdb,gdbserver+gdb的使用以及通过gdb调试core文件

交叉编译gdb和gdbserver 1.下载gdb:下载地址为:http://ftp.gnu.org/gnu/gdb/按照一般的想法,最新版本越好,因此下载7.2这个版本.当然,凡事无绝对.我们以gdb-7.2.tar.bz2 这个文件为例.2.解压缩: $ tar jxvf gdb-7.2.tar.bz2 注:小技巧:Linux下一般压缩文件后缀为.tar.bz2和.tar.gz,它们解压命令有两三个选项是一致的: xf(v),前者再加上j选项,后者再加上z选项. 3.进入该目录 $ cd g

解决gdb 调试 core 文件函数名显示为问号的问题

关于gdb调试core文件总是一堆问号的问题 问题描述:已经在编译选项中加入了-g,但是查看core文件时,还是一堆问号,使用的命令为:gdb -c core 解决方案:由于gdb -c core这样的使用在有些系统下支持不是很好,所以推荐用如下两种方法: 1) gdb exe (gdb) core-file core 2) gdb -c core (gdb) file exe

常见Bash命令操作

常见Bash命令操作 查看当前目录 pwd 查看目录下的文件 ls 进入某个目录 cd 返回上一级目录 cd .. 创建一个目录 mkdir abc 创建一个文件 touch a.html 保存文件退出 :wq 不保存文件退出 :q Git常用命令 第一次使用git时,需要设置用户信息 git config --global user.email "随便邮箱" git config --global user.name "随便用户名" 初始化仓库 git init

[Debug]用gdb分析coredump文件

1,系统默认是不产生coredump文件的,需要用以下命令使系统产生coredump文件 查看core文件的限制,此时为0,即不成生core文件 ulimit -c 0 打开core文件的限制,不限制core文件的大小,使程序可以产生core文件 ulimit -c unlimited ulimit -c unlimited 2,以下是内存访问错误示例 [cpp] view plaincopy 1 #include<stdio.h> 2 int main() 3 { 4      char* 

【Linux】gdb调试core文件

编写服务器端程序,很容易遇到Crash问题,比较幸运的是Linux提供了core file,保留了Crash的现场.有时候,根据当前的调用栈,并且打印出当前栈的变量就可以分析出crash的原因,但是,有时候看到调用栈却束手无策.下面就介绍自己通过GDB的几个命令的结合,发现一个crash的原因的过程. 下面让我们一起进入现场,来逐步发现其中的原因. 首先,还是运行gdb 命令,gdb wbxgs core.5797,来看看现场. [[email protected] bin]# gdb wbxg

gd调试命令,gdb调试core文件

使用 gcc -g test.c -o test.out 编译程序,只有加-g参数才支持gdb调试: 然后 gdb ./test.out 运行可执行文件,进入gdb调试模式(gdb),在括号后面的输入命令: (gdb)help:查看命令帮助 (gdb)start:单行执行 (gdb)l:查看源程序 (gdb)n:执行下一行 (gdb)s:进入被调函数里面 (gdb)bt:查看函数调用栈 (gdb)p 变量:打印变量值 (gdb)f:切换函数栈帧 (gdb)run:重新开始运行文件 (gdb)fi

Linux中目录结构以及VI编辑器常见的命令操作

1.每个目录的详细介绍,先放一张目录的整体结构在这里 /bin:是Binary的缩写,用于存放经常使用的命令 /sbin:s代表Super User,用于存放系统管理员使用的命令 /home:存放普通用户的主目录,在Linux中每个用户都有一个自己的目录,一般该目录名是以用户的账号命名的 /root:管理员的主目录 /lib:系统开机所需要的最基本的动态连接共享库,相当于Windows系统里面的dll文件,几乎所有的应用程序都需要使用到这些共享库 /lost+found:当系统非法关机后,这里会