在程序发现段错误等不寻常退出时,内核会在当前工作目录下生成一个core文件(是一个内存映像,同时加上调试信息,编译时加了-g参数)。使用gdb查看生成的core文件,可以很容易找出导致程序出错的代码所在的文件和行数。

1、linux系统下生成及调试core文件

  1.1 开启core文件并设置其大小

  1.1.1)使用ulimit -c命令,如果结果为0,则表示没有开启此功能,即不会生成core文件;如果结果不为unlimited,则表示core文件大小不受限制;如果结果coresize(除了上述两种结果),则说明指定core文件大小为coresize KB。

  1.1.2) 使用ulimit -c coresize命令,设置core文件的大小为coresize(单位为KB);使用ulimit -c unlimited,设置core文件的大小不受限制,如果生成的core文件超过此大小,将会被裁剪,最终生成一个不完整的core文件。在调试此core文件的时候,gdb会提示错误。

       注意:很多系统默认的core文件大小都是0,我们可以通过在shell的启动脚本/etc/bashrc、~/.bashrc或者/etc/profile等地方来加入 ulimit -c 命令来指定core文件大小,从而确保core文件能够生成,在编译的时候需要加-g参数,core文件才能正常显示出错误信息,有时候core信息很大,超出了剩余的空间,从而造成生成的core文件不全(开发板上可以通过挂载来规避这一点)。

  1.2 core文件的名称和生成路径

  core文件生成路径:

  若系统生成的core文件不带任何扩展名称,则全部命名为core,新的core文件生成将覆盖原来的core文件。

  1.2.1) /proc/sys/kernel/core_uses_pid可以控制core文件的文件名中是否添加pid作为扩展名。文件内容为1,表示添加pid作为扩展名,生成的core文件名为core.xxxx;文件内容为0,则表示生成的core文件统一命名为core。

  可通过以下命令来修改该文件:

  echo "1" > /proc/sys/kernel/core_uses_pid


  1.2.2) proc/sys/kernel/core_pattern可以控制core文件保存位置和文件名格式。

  可通过以下命令来修改该文件:

  echo "/corefile/core-%e-%p-%t" > core_pattern,可以将core文件统一生成到/corefile目录下,产生的文件名为core-命令名-pid-时间戳

  以下是参数列表:

  %p - insert pid into filename                                                                  插入当前的pid

  %u - insert current uid into filename                                                      插入当前的uid

  %g - insert current gid into filename                                                      插入当前的gid

  %s - insert signal that caused the coredump into the filename             插入导致产生core文件的信号

  %t - insert UNIX time that the coredump occurred into filename          插入core文件生成时的时间

  %h - insert hostname where the coredump happened into filename    插入主机名

  %e - insert coredumping executable name into filename                     插入程序名

 

    我们还可以通过以下命令来设置:

  sysctl -w kernel.core_pattern=/tmp/core-%e-%p,这些操作一旦计算机重启,则会丢失,如果你想持久化这些操作,可以在 /etc/sysctl.conf文件中增加:kernel.core_pattern=/tmp/core%p,并且可以执行命令:sysctl -p /etc/sysctl.conf使修改立即生效。

 

  1.3 使用gdb来查看core文件

  # gdb test.exe

       ......
       (gdb) core-file core.7209

 

  使用bt或者where命令查看程序出错的地方。

  以下两种命令方式具有相同的效果,但是在有些环境简写和省略参数无效,所以推荐使用上面的命令。

  1.3.1)gdb test.exe -c core.7209

       1.3.2)gdb test.exe -core=core.7209

    (gdb) bt
       #0  0x080483df in main () at core.c:19
       (gdb) where
       #0  0x080483df in main () at core.c:19

  

       1.4 先看一段在linux系统中会造成段错误的程序:

        #include <stdio.h>

        int main()

       {

             char *ptr = NULL;
            *ptr= 5;
            return 0;
      }


  编译运行后结果如下:

       root@lb:~/WorkRoom/Practice# gcc core.c -g -o test.exe
       root@lb:~/WorkRoom/Practice# ./test.exe

       段错误

  此时并没有产生core文件,接下来使用ulimit -a或者ulimit -c查看core文件的大小,然后使用ulimit -c unlimited设置将core文件设置为无限制,再执行./test.exe程序,结果如下:

       root@lb:~/WorkRoom/Practice# ulimit -a
       core file size          (blocks, -c) 0

       ……

       root@lb:~/WorkRoom/Practice# ulimit -c unlimited
       root@lb:~/WorkRoom/Practice# ulimit -a
       core file size          (blocks, -c) unlimited

       ……

       root@lb:~/WorkRoom/Practice# ./test.exe
       段错误 (core dumped)

       root@lb:~/WorkRoom/Practice# ll core.*
       -rw------- 1 root root 151552 07-10 04:22 core.7209
       -rw-r--r-- 1 root root    692 07-10 04:22 core.c

  可见core文件已经生成,接下来可以用gdb分析,查看堆栈情况:

       root@lb:~/WorkRoom/Practice# gdb test.exe
       GNU gdb Fedora (6.8-1.fc9)
       Copyright (C) 2008 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"...
       (gdb) core-file core.7209
       warning: core file may not match specified executable file.
       warning: Can't read pathname for load map: Input/output error.
       Reading symbols from /lib/libc.so.6...done.
       Loaded symbols for /lib/libc.so.6
       Reading symbols from /lib/ld-linux.so.2...done.
       Loaded symbols for /lib/ld-linux.so.2
       Core was generated by `./aa'.
       Program terminated with signal 11, Segmentation fault.
       [New process 7209]
       #0  0x080483df in main () at core.c:19
      19          *ptr= 5;
      Missing separate debuginfos, use: debuginfo-install glibc.i686
      (gdb) where
      #0  0x080483df in main () at core.c:19
      (gdb) bt
      #0  0x080483df in main () at core.c:19
      (gdb)

  从上述输出可以清楚的看到,段错误出现在core.c的第19行,问题已经清晰地定位到了。

  

 

2、开发板上(linux系统)生成及调试core文件 

       2.1 开启core文件并设置其大小

       同1.1

 

       2.2 core文件的名称和生成路径

       同1.2

 

 

    2.3 pc上调试开发板上生成的core文件

  如果开发板的操作系统也是linux,core调试的方法依然适用。如果开发板上不支持gdb,可将开发板的环境(依赖库)、可执行文件和core文件拷贝到PC的linux下,在 PC上调试开发板上产生的core文件,需要使用交叉编译器自带的gdb,并且需要在gdb中指定solib-absolute-prefix和 solib-search-path两个变量以保证gdb能够找到可执行程序的依赖库路径。有一种建立配置文件的方法,不需要每次启动gdb都手动配置以上变量,即:在待运行gdb的路径下建立 .gdbinit。

       配置文件(.gdbinit)内容如下:
          set solib-absolute-prefix /dev/null/
          set solib-search-path /YOUR_PATH1/lib:/YOUR_PATH2/lib

      gdb设置如下:    
          (gdb) set solib-absolute-prefix /dev/null/

          (gdb) set solib-search-path /YOUR_PATH1/lib:/YOUR_PATH2/lib

          (gdb) show solib-absolute-prefix
          The current system root is "/YOUR_PATH1/lib:/YOUR_PATH2/lib".
          (gdb) show solib-search-path
          The search path for loading non-absolute shared library symbol files is /YOUR_PATH1/lib:/YOUR_PATH2/lib.
          (gdb)


      变量说明如下:

          solib-absolute-prefix :设置查找共享库的前缀,作为查找so库路径的前缀;

          solib-search-path :设置so库的查找路径,它是在根据solib-absolute-prefix 查找库失败后使用

 

       2.4 看一段在hisi3716M开发板上的一段会出现段错误的程序

           void TestSegFault(void)
           { 
                  char *ptr = NULL;
                  *ptr=5;
           }

      

           编译运行后结果:

           # ./test.exe
            ROCME malloc size : 28
            ---Info >[DRIVER]:[DRV_OS_MutexCreate]DRV_NO_ERROR
            Segmentation fault (core dumped)

            #

            可见core文件已经生成,接下来可以用交叉编译器来分析,查看堆栈情况:

            root@lb:~/WorkRoom/LocalProject/xxx# arm-hisiv200-linux-gdb test.exe
            GNU gdb (Hisilicon_v200(gcc4.4-290+glibc-2.11+eabi+nptl)) 7.0.50.20100218-cvs
            Copyright (C) 2010 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 "--host=i686-pc-linux-gnu --target=arm-hisiv200-linux-gnueabi".
            For bug reporting instructions, please see:
            <http://www.hisilicon.com/cn/service/claim.html>...
            Reading symbols from /root/WorkRoom/LocalProject/xxx/test.exe...done.
            (gdb) core-file core 
            warning: core file may not match specified executable file.
            [New Thread 937]
            Reading symbols from /YOUR_PATH1/lib:/YOUR_PATH1/libpthread.so.0...(no debugging symbols found)...done.
            Loaded symbols for /YOUR_PATH1/lib:/YOUR_PATH2/lib/libpthread.so.0

            ......
            Loaded symbols for /YOUR_PATH1/lib:/YOUR_PATH2/lib/ld-linux.so.3
            Core was generated by `./test.exe'.
            Program terminated with signal 11, Segmentation fault.
            #0  0x00015040 in main (argc=1, argv=0xbeb6fe24) at main.c:1142
            1142            *ptr=5;
            (gdb) l
            1137    }
            1138
            1139    int main(int argc, char *argv[])
            1140    {
            1141            char *ptr = NULL;
            1142            *ptr=5;
            1143
            1144    #ifdef COUNT_MEMORY
            1145            system_remain_memory("main start");
            1146    #endif
            (gdb) where
            #0  0x00015040 in main (argc=1, argv=0xbeb6fe24) at main.c:1142
            (gdb) bt
            #0  0x00015040 in main (argc=1, argv=0xbeb6fe24) at main.c:1142
            (gdb)
            从上述输出可以清楚的看到,段错误出现在main.c的第1142行,问题已经清晰地定位到了。

 

 

 

Logo

更多推荐