`
vaqeteart
  • 浏览: 306594 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

利用Core Dump调试程序

阅读更多
利用Core Dump调试程序

[描述]
这里介绍Linux环境下使用gdb结合core dump文件进行程序的调试和定位。

[简介]
当用户程序运行,可能会由于某些原因发生崩溃(crash),这个时候可以产生一个Core Dump文件,记录程序发生崩溃时候内存的运行状况。这个Core Dump文件,一般名称为core或者core.pid(pid就是应用程序运行时候的pid号),它可以帮助我们找出程序崩溃的原因。
对于一个运行出错的程序,我们可以有多种方法调试它,以便发生错误的原因:a)通过阅读代码;b)通过在代码中设置一些打印语句(插旗子);c)通过使用gdb设置断点来跟踪程序的运行。但是这些方法对于调试程序运行崩溃这样类似的错误,定位都不够迅速,如果程序代码很多的话,显然前面的方法有很多缺陷。在后面,我们来看看另外一种可以定位错误的方法:d)使用gdb结合Core Dump文件来迅速定位到这个错误。这个方法,如果程序运行崩溃,那么可以迅速找到导致程序崩溃的原因。
当然,调试程序,没有哪个方法是最好的,这里只对最后一种方法重点讲解,实际过程中,往往根据需要和其他方法结合使用。

[举例]
下面,给出一个实际的操作过程,描述我们使用gdb调试工具,结合Core Dump文件,定位程序崩溃的位置。
一、程序源代码
下面是我们的程序源代码:
  1 #include <iostream>
  2 using std::cerr;
  3 using std::endl;
  4
  5 void my_print(int d1, int d2);
  6 int main(int argc, char *argv[])
  7 {
  8     int a = 1;
  9     int b = 2;
10     my_print(a,b);
11     return 0;
12 }
13
14 void my_print(int d1, int d2)
15 {
16     int *p1=&d1;
17     int *p2 = NULL;
18     cerr<<"first is:"<<*p1<<",second is:"<<*p2<<endl;
19 }
这里,程序代码很少,我们可以直接通过代码看到这个程序第17行的p2是NULL,而18行却用*p2来进行引用,明显这样访问一个空的地址是一个错误(也许我们的初衷是使用p2来指向d2)。
我们可以有多种方法调试这个程序,以便发生上面的错误:a)通过阅读代码;b)通过在代码中设置一些打印语句(插旗子);c)通过使用gdb设置断点来跟踪程序的运行。但是这些方法对于这个程序中类似的错误,定位都不够迅速,如果程序代码很多的话,显然前面的方法有很多缺陷。在后面,我们来看看另外一种可以定位错误的方法:d)使用gdb结合Core Dump文件来迅速定位到这个错误。

二、编译程序:
编译过程如下:
[root@lv-k test]# ls
main.cpp
[root@lv-k test]# g++ -g main.cpp
[root@lv-k test]# ls
a.out  main.cpp
这样,编译main.cpp生成了可执行文件a.out,一定注意,因为我们要使用gdb进行调试,所以我们使用'g++'的'-g'选项。

三、运行程序
运行过程如下:
[root@lv-k test]# ./a.out
段错误
[root@lv-k test]# ls
a.out  main.cpp
这里,如我们所期望的,会打印段错误的信息,但是并没有生成Core Dump文件。

配置生成Core Dump文件的选项,并生成Core Dump:
[root@lv-k test]# ulimit -c unlimited
[root@lv-k test]# ./a.out
段错误 (core dumped)
[root@lv-k test]# ls
a.out  core.30557  main.cpp
这里,我们看到,使用'ulimit'配置之后,程序崩溃的时候就会生成Core Dump文件了,这里的文件是core.30557,文件名称不同的系统生成的名称有一点不同,这里linux生成的名称是:"core"+".pid"。

四、调试程序
使用Core Dump文件,结合gdb工具进行调试,过程如下:
1)初步定位:
[root@lv-k test]# gdb a.out core.30557
GNU gdb (GDB) Red Hat Enterprise Linux (7.0.1-23.el5_5.2)
Copyright (C) 2009 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 "i386-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/test/a.out...done.
Reading symbols from /usr/lib/libstdc++.so.6...(no debugging symbols found)...done.
Loaded symbols for /usr/lib/libstdc++.so.6
Reading symbols from /lib/libm.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib/libm.so.6
Reading symbols from /lib/libgcc_s.so.1...(no debugging symbols found)...done.
Loaded symbols for /lib/libgcc_s.so.1
Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib/ld-linux.so.2
Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault.
#0  0x0804870e in my_print (d1=1, d2=2) at main.cpp:18
18              cerr<<"first is:"<<*p1<<",second is:"<<*p2<<endl;
这里,我们就进入了gdb的调试交互界面,看到gdb直接定位到导致程序出错的位置了。我们还可以使用如下命令:"#gdb a.out --core=core.30557"。
通过错误,我们知道程序由于"signal 11"导致终止,如果想要大致了解"signal 11",那么我们可查看signal的man手册:
#man 7 signal
这样,在输出的信息中我们可以看见“SIGSEGV      11       Core    Invalid memory reference”这样的字样,意思是说,signal(信号)11表示非法内存引用。注意这里使用"man 7 signal"而不是"man signal",因为我们要查看的不是signal函数或者signal命令,而是signal的其他信息,其他的信息在man手册的第7节,具体需要了解一些使用man的命令。

2)查看具体调用关系
(gdb) bt
#0  0x0804870e in my_print (d1=1, d2=2) at main.cpp:18
#1  0x08048799 in main (argc=<value optimized out>, argv=<value optimized out>) at main.cpp:10
这里,我们通过backtrace(简写为bt)命令可以看到,导致崩溃那条语句是通过什么调用途径被调用到的。

3)设置断点,并进行调试等:
(gdb) b main.cpp:10
Breakpoint 1 at 0x8048787: file main.cpp, line 10.
(gdb) r
Starting program: /root/test/a.out

Breakpoint 1, main (argc=<value optimized out>, argv=<value optimized out>) at main.cpp:10
10              my_print(a,b);
(gdb) s
my_print (d1=1, d2=2) at main.cpp:16
16              int *p1=&d1;
(gdb) n
17              int *p2 = NULL;
(gdb) n
18              cerr<<"first is:"<<*p1<<",second is:"<<*p2<<endl;
(gdb) p d1
$1 = 1
(gdb) p d2
$2 = 2
(gdb) p *p1
$1 = 1
(gdb) p *p2
Cannot access memory at address 0x0
(gdb) n

Program received signal SIGSEGV, Segmentation fault.
0x0804870e in my_print (d1=1, d2=2) at main.cpp:18
18              cerr<<"first is:"<<*p1<<",second is:"<<*p2<<endl;
这里,我们在开始初步的定位的基础上,通过设置断点(break),运行(run),gdb的单步跟进(step),单步跳过(next),变量的打印(print)等各种gdb命令,来了解产生崩溃时候的具体情况,确定产生崩溃的原因。

4)退出gdb:
(gdb) q
A debugging session is active.

        Inferior 3 [process 30584] will be killed.
        Inferior 1 [process 1] will be killed.

Quit anyway? (y or n) y
Quitting: Couldn't get registers: 没有那个进程.
[root@lv-k test]#
[root@lv-k test]# ls
a.out core.30557 core.30609 main.cpp
这里,我们看到又产生了一个core文件。因为刚才调试,导致又产生了一个core文件。实际,如果我们只使用"gdb a.out core.30557"初步定位之后,不进行调试就退出gdb的话,就不会再生成core文件。

五、修正错误
1)通过上面的过程我们最终修正错误,得到正确的源代码如下:
  1 #include <iostream>
  2 using std::cerr;
  3 using std::endl;
  4
  5 void my_print(int d1, int d2);
  6 int main(int argc, char *argv[])
  7 {
  8     int a = 1;
  9     int b = 2;
10     my_print(a,b);
11     return 0;
12 }
13
14 void my_print(int d1, int d2)
15 {
16     int *p1=&d1;
17     //int *p2 = NULL;//lvkai-
18     int *p2 = &d2;//lvkai+
19     cerr<<"first is:"<<*p1<<",second is:"<<*p2<<endl;
20 }

2)编译并运行这个程序,最终产生结果如下:
[root@lv-k test]# g++ main.cpp
[root@lv-k test]# ls
a.out  main.cpp
[root@lv-k test]# ./a.out
first is:1,second is:2
这里,得到了我们预期的结果。

另外,有个小技巧,如果对Makefile有些了解的话可以充分利用make的隐含规则来编译单个源文件的程序,
过程如下:
[root@lv-k test]# ls
main.cpp
[root@lv-k test]# make main
g++     main.cpp   -o main
[root@lv-k test]# ls
main  main.cpp
[root@lv-k test]# ./main
first is:1,second is:2
这里注意,make的目标参数必须是源文件"main.cpp"去掉后缀之后的"main",等价于"g++ main.cpp -o main",这样编译的命令比较简单。

[其它]
其它内容有待添加。
认真地工作并且思考,是最好的老师。在工作的过程中思考自己所缺乏的技术,以及学习他人的经验,才能在工作中有所收获。这篇文章原来是工作中我的一个同事加朋友的经验,我站在这样的经验的基础上,进行了这样总结。

以上文章,如果有什么问题或者更好的建议,都可以联系我,谢谢。^_^
作者:QuietHeart
Email:quiet_heart000@126.com
分享到:
评论

相关推荐

    window COREdump文件生成 c++代码

    在Windows操作系统上,...通过以上步骤,你可以在C++程序中有效地生成和利用Coredump文件,以便于诊断和修复程序崩溃问题。在实际开发中,结合版本控制、日志记录以及持续集成等最佳实践,能进一步提高问题排查的效率。

    SegmentFault(coredump)调试方法.pdf

    这时,利用core dump进行调试可以帮助开发者找出问题的根源。core dump是操作系统在程序异常终止时生成的一种文件,它包含了程序崩溃时的内存状态和调试信息。以下是对core dump调试方法的详细说明: 1. **获取gdb...

    Coredump简介及使用

    Coredump机制广泛存在于多个操作系统中,包括但不限于Linux,它是用来在程序异常退出时记录下程序的运行状态,包括内存状态、寄存器状态和堆栈信息等,以便开发者调试程序。 一、什么是Coredump Coredump是系统在...

    Linux应用程序调试之debug_coredump

    本文将深入探讨如何利用core dump进行Linux应用程序的调试,特别关注使用gdb工具来解析core文件。 ### coredump的核心概念 #### 1. 何时产生core dump? 当进程接收到某些信号(如SIGSEGV)时,如果内核被配置为...

    高通core dump解析工具

    对于开发者来说,利用Core Dump进行问题排查能够帮助我们快速定位和修复软件中的错误。本篇文章主要针对“高通core dump解析工具”进行详细讲解。 首先,我们需要理解“高通”在这个场景下可能指的是高通公司的芯片...

    ubuntu-linux下程序崩溃生成coredump的方法.pdf

    ### Ubuntu Linux 下程序...总之,在 Ubuntu Linux 系统中,通过合理配置 core dump 的生成和存储路径,以及确保关闭 apport.service 服务程序,可以有效地利用 core dump 文件来帮助开发者定位和解决程序崩溃的问题。

    Linux Debugging: coredump 分析入门的材料

    本篇文章将围绕`coredump`分析进行入门讲解,结合实例深入探讨如何利用`coredump`来解决实际问题。 首先,我们要理解什么是`coredump`。当一个运行在Linux上的应用程序因为某种原因异常终止(如段错误、除零错误等...

    Linux Debugging(五): coredump 分析入門1

    在Linux系统中,调试是解决程序异常和错误的关键步骤,特别是在遇到程序崩溃并产生coredump时。coredump是操作系统在程序异常终止时保存的内存映像,包含了程序运行时的状态,如内存布局、堆栈信息、全局变量和...

    coredump使用

    通过上述步骤,我们可以有效地利用 coredump 文件来定位和解决程序中的错误。这对于提高软件质量和稳定性具有重要意义。正确地配置和使用 coredump 功能,不仅可以帮助开发者更快地找到问题根源,还可以避免因程序...

    Linux下MySQL数据库使用coredump注意事项

    在Linux环境下,MySQL数据库的使用过程中,遇到故障或者异常情况时,我们可能需要利用coredump来分析程序崩溃的原因。coredump是系统记录进程崩溃时内存状态的文件,它可以帮助开发者定位问题所在。以下是对在Linux...

    Linux Debugging: coredump 分析的材料

    这个文件包含了程序运行时的内存状态,包括变量值、调用栈信息等,是调试程序的关键工具。 描述中提到的链接可能是一个博客文章,提供了具体案例来讲解`coredump`的分析方法。`unzip`和`tar xf`是两个常见的Linux...

    C++_Core_dump问题定位方法

    1. **调试符号**:为了能够有效地利用 core dump 进行问题定位,程序在编译时必须包含调试符号。这些符号包含了变量名、函数名以及函数调用栈等关键信息。在 Windows 下,这些信息通常会被保存在 .pdb 文件中。 - ...

    coredump_article

    通过 `gdb program core` 命令,可以加载程序和核心 dump 文件进行调试。 2. addr2line 和 nm:这两个工具可以将内存地址转换为源代码行号,帮助理解崩溃位置。 3. Valgrind:虽然主要用作内存错误检测工具,但也...

    qt vs编译器下生成dump文件,方便调试。

    总结来说,利用Qt和VS环境生成dump文件是调试复杂问题的有效方法。通过集成UDumper库,我们可以轻松地在Qt应用中实现dump文件的自动化生成,从而提高调试效率。在实际开发中,理解并熟练掌握这一技巧,有助于快速...

    Linux下怎么产生core dump文件及GDB怎么调试core.pptx

    ### Linux下产生Core Dump文件及使用GDB调试详解 #### 一、Core文件的基本概念与作用 当一个程序因为某些原因而崩溃时,系统内核会自动创建一个名为`core`的文件,这个文件包含了程序崩溃时刻的内存映像以及其他...

    浅析Linux下利用coredump技术追查进程崩溃原因

    本文将深入探讨如何利用coredump来追查进程崩溃的原因。 首先,我们需要理解什么是coredump。当一个程序在Linux环境下因为某种错误(如除零错误、非法指令等)导致崩溃时,如果系统设置允许coredump,那么系统会将...

    Windows调试(通过dump文件定位崩溃)

    在Windows操作系统中,当应用程序发生异常崩溃时,为了找出导致崩溃的原因,我们通常会借助于dump文件进行调试。Dump文件是系统在程序崩溃时记录的内存快照,它包含了程序运行时的关键信息,如进程内存、线程状态、...

    Unix环境下core dump 分析

    Core dump文件记录了进程在崩溃瞬间的内存状态,包括进程的全局变量、堆栈信息、打开的文件描述符等,它是调试和诊断程序错误的重要工具。本篇将深入探讨Unix环境下core dump的分析方法。 首先,理解core dump的...

    利用core文件排查系统崩溃的信息详细步骤

    利用core文件排查系统崩溃的信息详细步骤 核心dump(Core Dump)是计算机系统崩溃或出现严重错误时,操作系统将当前进程的内存内容写入磁盘的文件,用于调试和故障排除。以下是利用 Core 文件排查系统崩溃的信息...

Global site tag (gtag.js) - Google Analytics