什么是Core Dump?

何谓 core?
       在使用半导体作为内存的材料前,人类是利用线圈当作内存的材料(发明 者为王安),线圈就叫作 core ,用线圈做的内存就叫作 core memory。如今 ,半导体工业澎勃发展,已经没有人用 core memory 了,不过,在许多情况下, 人们还是把记忆体叫作 core 。
        何谓 core dump?
        我们在开发(或使用)一个程序时,最怕的就是程序莫明其妙地当掉。虽然系 统没事,但我们下次仍可能遇到相同的问题。于是这时操作系统就会把程序当掉 时的内存内容 dump 出来(现在通常是写在一个叫 core 的 file 里面),让 我们或是 debugger 做为参考。这个动作就叫作 core dump。
       为何会发生 core dump?
       前面说过,在程序当掉时出错。在 C/C++语言中,最常发生错误的地方就是指 针有问题。您可以利用 core 文件和 debugger 把错误找出来(要怎麽在 debugger 中使用 core 文件?man 一下 gdb 吧!)。
       如何用gdb调用core?

当c编写的程序出现core是,可以用gdb programname core,查看core。如果找不到core文件,可以用一下命令查看和修改。

ulimit -a  //查看core文件的大小

ulimit -c  //修改core文件的大小

如果gdb -c core 时遇到一下情况:

#0 0x08048373 in ?? ()

#1 0xbfffd8f8 in ?? ()

#2 0x0804839e in ?? ()

#3 0xb74cc6b3 in ?? ()

#4 0x00000000 in ?? ()

请用以下方法解决:gdb ./a.out core 然后bt就可以了。

除了bt以外还有如下命令:where, frame, up, down, print可以使用。


什么是Core Dump?

Core的意思是内存, Dump的意思是扔出来, 堆出来.

开发和使用Unix程序时, 有时程序莫名其妙的down了, 却没有任何的提示(有时候会提示core dumped). 这时候可以查看一下有没有形如core.进程号的文件生成, 这个文件便是操作系统把程序down掉时的内存内容扔出来生成的, 它可以做为调试程序的参考.

core dump又叫核心转储, 当程序运行过程中发生异常, 程序异常退出时, 由操作系统把程序当前的内存状况存储在一个core文件中, 叫core dump.

如何使用core文件?

gdb -c core文件路径 [应用程序的路径]

进去后输入where回车, 就可以显示程序在哪一行当掉的, 在哪个函数中.

为什么没有core文件生成呢?

有时候程序down了, 但是core文件却没有生成. core文件的生成跟你当前系统的环境设置有关系, 可以用下面的语句设置一下, 然后再运行程序便成生成core文件.

ulimit -c unlimited

core文件生成的位置一般于运行程序的路径相同, 文件名一般为core.进程号

4. 用gdb查看core文件:

下面我们可以在发生运行时信号引起的错误时发生core dump了.

发生core dump之后, 用gdb进行查看core文件的内容, 以定位文件中引发core dump的行.

gdb [exec file] [core file]

如:

gdb ./test test.core

在进入gdb后, 用bt命令查看backtrace以检查发生程序运行到哪里, 来定位core dump的文件->行.


Core Dump 配置与调试
1.core文件的生成开关和大小限制
---------------------------------
1)使用ulimit
-c命令可查看core文件的生成开关。若结果为0,则表示关闭了此功能,不会生成core文件。
2)
使用ulimit
-cfilesize命令,可以限制core文件的大小(filesize的单位为kbyte)。若ulimit
-cunlimited,则表示core文件的大小不受限制。如果生成的信息超过此大小,将会被裁剪,最终生成一个不完整的core文件。在调试此
core文件的时候,gdb会提示错误。
2.core文件的名称和生成路径
----------------------------
若系统生成的core文件不带其它任何扩展名称,则全部命名为core。新的core文件生成将覆盖原来的core文件。
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
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文件生成时的unix时间

%h - insert hostname where the coredump happened into filename
添加主机名

%e - insert coredumping executable name into filename
添加命令名
3.用gdb查看core文件:
下面我们可以在发生运行时信号引起的错误时发生core
dump了.
发生core
dump之后,
用gdb进行查看core文件的内容,
以定位文件中引发core
dump的行.
gdb [exec
file] [core file]
如:
gdb
./test test.core
在进入gdb后,
用bt命令查看backtrace以检查发生程序运行到哪里,
来定位core dump的文件->行.
4.开发板上使用core文件调试
-----------------------------
如果开发板的操作系统也是linux,core调试方法依然适用。如果开发板上不支持gdb,可将开发板的环境(头文件、库)、可执行文件和core文件拷贝到PC的linux下,运行相关命令即可。
注意:待调试的可执行文件,在编译的时候需要加-g,core文件才能正常显示出错信息!
注意的问题:
在Linux下要保证程序崩溃时生成Coredump要注意这些问题:
  一、要保证存放Coredump的目录存在且进程对该目
录有写权限。存放Coredump的目录即进程的当前目录,一般就是当初发出命令启动该进程时所在的目录。但如果是通过脚本启动,则脚本可能会修改当前目
录,这时进程真正的当前目录就会与当初执行脚本所在目录不同。这时可以查看”/proc/进程pid>/cwd“符号链接的目标来确定进程
真正的当前目录地址。通过系统服务启动的进程也可通过这一方法查看。
  二、若程序调用了seteuid()/setegid()改变
了进程的有效用户或组,则在默认情况下系统不会为这些进程生成Coredump。很多服务程序都会调用seteuid(),如MySQL,不论你用什么用
户运行mysqld_safe启动MySQL,mysqld进行的有效用户始终是msyql用户。如果你当初是以用户A运行了某个程序,但在ps里看到的
这个程序的用户却是B的话,那么这些进程就是调用了seteuid了。为了能够让这些进程生成core
dump,需要将/proc/sys/fs
/suid_dumpable文件的内容改为1(一般默认是0)。
  三、这个一般都知道,就是要设置足够大的Core文件大小限制
了。程序崩溃时生成的Core文件大小即为程序运行时占用的内存大小。但程序崩溃时的行为不可按平常时的行为来估计,比如缓冲区溢出等错误可能导致堆栈被
破坏,因此经常会出现某个变量的值被修改成乱七八糟的,然后程序用这个大小去申请内存就可能导致程序比平常时多占用很多内存。因此无论程序正常运行时占用
的内存多么少,要保证生成Core文件还是将大小限制设为unlimited为好。


Linux系统中在应用程序运行过程中经常会遇到程序突然崩溃,提示:Segmentation fault,这是因为应用程序收到了SIGSEGV信号。这个信号提示当进程发生了无效的存储访问,当接收到这个信号时,缺省动作是:终止w/core。 终止w/core的含义是:在进程当前目录生成core文件,并将进程的内存映象复制到core文件中,core文件的默认名称就是“core”(这是Unix类系统的一个由来已久的功能)。
    事实上,并不是只有SIGSEGV信号产生coredump,还有下面一些信号也产生coredump:SIGABRT(异常终止)、SIGBUS(硬件故障)、SIGEMT(硬件故障)、SIGFPE(算术异常)、SIGILL(非法硬件指令)、SIGIOT(硬件故障),SIGQUIT,SIGSYS(无效系统调用),SIGTRAP(硬件故障)等。
    在程序的开发调试阶段(尤其是大型软件开发),发生程序异常崩溃时常规的调试方法常常是无比的痛苦:无穷的log中也不见得有什么有意义的信息。好在GDB提供和利用core文件进行调试的途径,大大方便了这类问题的调试。

    下面我们通过一个简单的例子来看看怎么通过GDB来调试一个违规访问内存导致的程序崩溃。这里我们顺便讲讲动态库的调试。

/******** mylib.h **********/
#ifndef __MY_LIB_H__
#define __MY_LIB_H__

int add(int x, int y);

#endif // __MY_LIB_H__
/******** end **********/



/******** mylib.c **********/
#include <stdlib.h>
#include "mylib.h"

int add(int x, int y)
{
    char* pc = NULL;
    *pc = 10;

    return x + y;
}
/******** end **********/

/******** main.c **********/

#include <stdio.h>
#include <stdlib.h>

#include "mylib.h"

int main (void)
{
    int ret = -1;
    int a = 10, b = 20;
    ret = add(a, b);

    printf("The result is: %d\n", ret);

    return 0;
}
/******** end **********/

#####################################
# File Name: Makefile
#
#####################################

CC = gcc
LD = gcc

all:
        $(CC) mylib.c -g -I. -fPIC -shared -o libmylib.so
        $(CC) main.c -g -I. -L. -lmylib -o test

clean:
        rm *.so test
#############   END   ###############

    首先将上面的代码分别存储到相应的目录,名称为:mylib.h、mylib.c、main.c、Makefile。

1)编译测试代码。注)编译时的 -g 选项是必须的。
[xxx@yyy]$ make
gcc mylib.c -g -I. -fPIC -shared -o libmylib.so
gcc main.c -g -I. -L. -lmylib -o t

通过ls命令我们可以看到生成了测试程序test.
[xxx@yyy]$ ls
libmylib.so main.c Makefile mylib.c mylib.h test

2)执行测试程序
[xxx@yyy]$ ./test
./test: error while loading shared libraries: libmylib.so: cannot open shared object file: No such file or directory

这个错误表明程序在运行阶段不能找到相应的动态库文件,此时需要通过环境变量 LD_LIBRARY_PATH 来指定运行期动态库的搜索目录,我们的动态库就在当前目录,如下:

[xxx@yyy]$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.

3)再次执行测试程序
[leo@localhost debug]$ ./test
Segmentation fault
[leo@localhost debug]$ ls
libmylib.so main.c Makefile mylib.c mylib.h test

4)设置core文件大小
Segmentation fault如期而至,但是却没有我们更想见到的core文件!
原来系统在默认情况下core文件的大小设置为0,换句话讲也就是不产生core文件。我们可以通过 ulimit 命令来修改core文件的大小,unlimited表示不限制core文件的大小,如下(设置core文件的大小需要root权限):
[root@yyy]# ulimit -c unlimited
[root@yyy]# ./test
Segmentation fault (core dumped)
[root@yyy]# ls
core.2890 libmylib.so main.c Makefile mylib.c mylib.h test

5)设置core文件的格式,输出路径
通过下面命令我们还可以指定core文件的命名格式,路径等(需要root权限):
[root@yyy]# echo "core_%e_%s" >/proc/sys/kernel/core_pattern
[root@yyy]# ./test
Segmentation fault (core dumped)
[root@yyy]# ls
core.2890 core_test_11.2898 libmylib.so main.c Makefile mylib.c mylib.h test

6)调试
[root@yyy]# gdb test core.2890
GNU gdb Red Hat Linux (6.5-8.fc6rh)
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".

Core was generated by `./test'.
Program terminated with signal 11, Segmentation fault.
Error while mapping shared library sections:
libmylib.so: Success.
Reading symbols from /home/xxx/tst/libmylib.so...done.
Loaded symbols for libmylib.so
Reading symbols from /lib/i686/libc.so.6...done.
Loaded symbols for /lib/i686/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
#0 0x00a8969c in ?? ()
(gdb)

键入GDB命令 where
(gdb) where
#0 0x001ec44c in ?? ()
#1 0x00000000 in ?? ()

?? ()并不是我们想看到的,之所以这样,是因为GDB不能正确加载我们编写的动态库libmylib.so,我们需要在这里设置GDB的动态库搜索路径,如下:

(gdb) set solib-search-path .
Reading symbols from /home/xxx/test/tst/libmylib.so...done.
Loaded symbols for /home/xxx/test/tst/libmylib.so
Reading symbols from /lib/i686/libc.so.6...done.
Loaded symbols for /lib/i686/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2

可以看到GDB已经加载了libmylib.so,再次键入where命令:
(gdb) where
#0 0x001ec44c in add (x=10, y=20) at mylib.c:8
#1 0x0804847c in main () at main.c:12
(gdb)

这次我们期待的结果出现了,GDB清楚的列出了错误出现的位置:mylib.c的第8行,好了,到那里去改code吧!


你可能感兴趣的:(linux,unix,File,insert,library,makefile)