b891c378f7e0c3b7f74b90540ba92462.png

(题图来自http://monkeyuser.com)

  这篇文章介绍的内容很粗浅,仅仅是通过core文件获取一些基本信息而已,属于面向初学者的文章~本文的内容实际上用一句话就可以概括:用gdb <程序名> <core文件名>命令来载入程序与core文件,之后就可以使用gdb来进行分析啦~


  相信大家在Linux下写程序时都遇到过「段错误(核心已转储)」导致程序崩溃。学过操作系统课程就不难理解「段错误」的概念,简单来说就是访问了不属于你的内存。对于这个概念StackOverflow(What is a segmentation fault?)上已有详细的解释,这里就不多讲了~
  不过这个「核心已转储」是什么意思呢?发生段错误之后,大家很容易注意到,目录下生成了一个名称为core(名称也可能是core.xxxx,xxxx为数字,是进程的pid)的文件,如图所示:

5175b58e445aeded7ac27dc09eaa248d.png
生成core文件

  这个文件可以帮助我们分析程序的错误,我们可以通过这个文件还原程序出错时的现场,查看出错的位置,出错时变量的值等等。当然,有的人会发现程序发生段错误之后什么都没有生成。

eda6dc20d3e3835cb38e1ca3a39866fe.png
没有生成

  这是因为系统设置中core文件的大小上限设为0了。可以用命令ulimit -a 查看,用命令ulimit -c unlimited 改为没有上限。

343d584664d6af6031ccee041cc48288.png
查看上限

b4d086d9b8ed0a445f2d2844f7430d70.png
设置上限

  以前虽然知道段错误后生成的core文件可以用于分析,不过一直没有了解过具体的步骤,昨天在遇到了这个场景,所以学习了一下~
  首先,写一个错误的程序~

b06707effc4fff0d4d3250d40f754293.png
puts(NULL)引起了段错误

  用gcc -g命令来编译这个源码(带上-g参数加入源码信息方便调试),之后就可以./a.out来执行了。程序出错后就会产生core文件。

bfcc75d7f345ca7b1beba6835b42d191.png

  用gdb <程序名> <core文件名>命令来载入程序与core文件,如图(你也可以在gdb中用core <core文件名>来载入core文件)

553fae56bf4955a1900580121c5db5e8.png
gdb

  之后的步骤其实就是使用gdb来获取相关的信息了。比如说,我想看到程序是在哪里出错的,就用where命令来查看调用栈(你也可以使用bt full命令查看完整信息)

f2bc95cab567ac5e4d1d4842b36fca7d.png
where

a3b18dcfca9fa48bd7bd4dad6167de06.png
bt full

  我们可以看到,是main()函数调用了foo()函数,而foo()函数在调用系统函数的时候出现了段错误。这里,我们可以发现行号也一并输出了。所以,可以用list <文件名>:<行号>命令来查看相关的代码。

2cb6d7472b2acd852ccce562ea714dad.png
查看对应源码


  如果想看变量的的值怎么办呢?比如说,我们想看此时foo()函数中变量str的值,虽然用p命令可以查看变量的值,但由于gdb默认在出错的函数栈帧(也就是#0 __strlen__sse2)中,我们是没有看到函数foo()中变量的值的,如图

29d14c0517288afe92211d5d1d2aa2f8.png
无法查看变量

  我们要先切换到对应的函数栈帧中,由bt命令可以看出,foo()的栈帧编号为#2,所以用frame 2命令切换到foo()命令的栈帧,就可以看到当前str的值了。

c72564f0e46a815eaafcd92bbd2fe685.png
切换栈帧后可以查看变量了

  这样,我们就可以查看程序出错时的基本信息了。通过对core文件的简单分析,我们可以快速定位程序出错的地方,从而进一步分析程序出错的原因~

Logo

更多推荐