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

时间: 2024-08-04 00:21:12

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

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

Linux中文件的压缩与解压缩命令操作示例集锦

  所谓压缩就是将原有的文件通过不同的编码技术进行运算,以减少数据存储所需要的空间,使用前再利用解压缩还原源文件的内容即可. 和windows一样,在linux下也存在多种压缩与解压缩方法. 1.zip压缩与解压缩 zip是最为广泛使用的压缩程序,经它压缩的文件会产生扩展名为zip的压缩文件,而且这种格式在多种系统上可以使用,像windows中的winzip 下面看一下在linux中如何建立zip文件. 我们在终端中输入zip会出现这个命令的一些介绍和参数的意义. 代码如下: xiaopeng@

GDB调试之core文件(如何定位到Segment fault)

core dump又叫核心转储,当程序运行过程中发生异常,程序异常退出时,由操作系统把程序当前的内存状况存储在一个core文件中,叫core dump.(内部实现是:linux系统中内存越界会收到SIGEGV信号,然后就会core dump) 在程序运行过程中,有的时候我们会遇到Segment fault(段错误)这样的错误.调速起来无从下手,因为没有任何的栈,trace信息输出.该种类型的错误往往与指针操作相关,往往可以通过这样的方式进行定位. 一 造成segment fault,产生core

数据库内核月报 - 2015 / 08-PgSQL · 答疑解惑 · 归档进程cp命令的core文件追查

问题现象 最近我们的几个非生产实例中,均出现了由archiver进程产生的core dump文件,让人如临大敌:是不是遇到了PG的大BUG导致了crash? 先来看看这些core文件.由于我们在/proc/sys/kernel/core_pattern指定了存放core文件的目录,所以可以在这个目录里面找到这些core文件.幸运的是,这些core文件都不大,一般几百KB,没有对文件系统的存储空间造成压力: $du -sh * 248K core.170254 248K core.242719 2

怎样用core文件调试你的linux程序?

core dump 文件对于诊断linux中程序的问题非常有用.当程序异常退出的时候,可能会生成core文件.如,程序写一个不属于他的内存,操作系统出于保护,会发信号给程序,程序可能会因此而退出,退出的时候可能会生成core文件.我们可以通过分析core文件,找出程序中那里有内存问题.这篇文章主要是阐述生成core文件需要做的一些设置. 如何生成core文件 默认linux操作系统是不允许生成core文件的.如下图: <img src="http://www.bo56.com/wp-con

Linux下core文件产生的一些注意问题

前面转载了一篇文章关于core文件的产生和调试使用的设置,但在使用有一些需要注意的问题,如 在什么情况 才会正确地产生core文件. 列出一些常见问题: 一,如何使用core文件 1. 使用core文件 在core文件所在目录下键入: gdb -c core 它会启动GNU的调试器,来调试core文件,并且会显示生成此core文件的程序名,中止此程序的信号等等. 如果你已经知道是由什么程序生成此core文件的,比如MyServer崩溃了生成core.12345,那么用此指令调试: gdb -c

ROS机器人程序设计(原书第2版)3.1.4 设置ROS节点core文件转储

3.1.4 设置ROS节点core文件转储 虽然ROS节点实际上就是一般的可执行文件,但在设置gdb的core文件转储(core dump)时仍有一些棘手的问题需要注意.首先要取消core文件大小限制,当前值可以通过ulimit -a查看.请注意这适用于任何可执行文件,不只是ROS节点:   然后,为了能够创建core文件转储,必须将core文件名设置为默认使用的进程pid,否则无法创建,因为在$ROS_HOME已有一个core目录会防止core文件转储.因此,为了创建core文件转存的名称和路

Linux生成core文件、core文件路径设置

在Linux下产生并调试core文件 先看看我用的是个什么机器: $ uname -aLinux dev 2.4.21-9.30AXsmp #1 SMP Wed May 26 23:37:09 EDT 2004 i686 i686 i386 GNU/Linux 再看看默认的一些参数,注意core file size是个0,程序出错时不会产生core文件了. $ ulimit -acore file size (blocks, -c) 0data seg size (kbytes, -d) unl

Linux下core文件调试方法

在程序不寻常退出时,内核会在当前工作目录下生成一个core文件(是一个内存映像,同时加上调试信息).使用gdb来查看core文件,可以指示出导致程序出错的代码所在文件和行数. 1.core文件的生成开关和大小限制  1)使用ulimit -c命令可查看core文件的生成开关.若结果为0,则表示关闭了此功能,不会生成core文件.  2)使用ulimit -c filesize命令,可以限制core文件的大小(filesize的单位为kbyte).若ulimit -c unlimited,则表示c