linux core文件介绍

来源:互联网 发布:天际线 网络存档 编辑:程序博客网 时间:2024/05/16 18:44
core文件的简单介绍
  2007-04-13 12:06:30  Linux联盟收集整理 

//---------------------------------------------------------------
1. core文件的简单介绍
//---------------------------------------------------------------

在一个程序崩溃时,它一般会在指定目录下生成一个core文件。core文件仅仅是一个内存映象(同时加上调试信息),主要是用来调试的。


//---------------------------------------------------------------
2. 开启或关闭core文件的生成
//---------------------------------------------------------------

用以下命令来阻止系统生成core文件:
ulimit -c 0
下面的命令可以检查生成core文件的选项是否打开:
ulimit -a
该命令将显示所有的用户定制,其中选项-a代表“all”。

也可以修改系统文件来调整core选项
在/etc/profile通常会有这样一句话来禁止产生core文件,通常这种设置是合理的:
# No core files by default
ulimit -S -c 0 > /dev/null 2>&1
但是在开发过程中有时为了调试问题,还是需要在特定的用户环境下打开core文件产生的设置
在用户的~/.bash_profile里加上ulimit -c unlimited来让特定的用户可以产生core文件
如果ulimit -c 0 则也是禁止产生core文件,而ulimit -c 1024则限制产生的core文件的大小不能超过1024kb


//---------------------------------------------------------------
3. 设置Core Dump的核心转储文件目录和命名规则
//---------------------------------------------------------------

/proc/sys/kernel/core_uses_pid可以控制产生的core文件的文件名中是否添加pid作为扩展,如果添加则文件内容为1,否则为0

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

proc/sys/kernel/core_pattern可以设置格式化的core文件保存位置或文件名,比如原来文件内容是core-%e
可以这样修改:
echo "/corefile/core-%e-%p-%t" > core_pattern

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

将会控制所产生的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 添加命令名


//---------------------------------------------------------------
4. 使用core文件
//---------------------------------------------------------------

在core文件所在目录下键入:
gdb -c core
它会启动GNU的调试器,来调试core文件,并且会显示生成此core文件的程序名,中止此程序的信号等等
如果你已经知道是由什么程序生成此core文件的,比如MyServer崩溃了生成core.12345,那么用此指令调试:
gdb -c core MyServer
以下怎么办就该去学习gdb的使用了


//---------------------------------------------------------------
5. 一个小方法来测试产生core文件
//---------------------------------------------------------------

直接输入指令:
kill -s SIGSEGV $$

 

以前写的一个文档,有同学反馈不能用,恰好手头有一个堆栈被破坏的core文件要查看,跑了一遍重新更新了一下原来的文档。

-----------------------------------------------------

调试core文件的时候,偶尔会遇到调用堆栈被破坏的情况,一大串问号令人头痛。类似下面:

echou大师介绍了一种手动恢复调用堆栈的方法,cesc研究了一下,跟大家share下。

源文档见http://devpit.org/wiki/x86ManualBacktrace

 

首先回顾一些背景知识:

 %esp 是堆栈指针寄存器,它指向当前堆栈储存区域的顶部.

 �p 是基址寄存器,它指向当前堆栈储存区域的底部.

 %eip 是指令指针,是下一条要执行的指令地址.

当发生函数调用时,程序如下操作:首先把参数压入堆栈;然后保存指令寄存器(EIP)中的内容做为返回地址(RET);第三个放入堆栈的是基址寄存器(EBP);然后把当前的栈指针(ESP)拷贝到EBP,做为新的基地址;最后为本地变量留出一定空间,把ESP减去适当的数值。如下所示:

Low addresses

-----------------------------------

0(%esp)  | 栈顶

---------|-------------------------

-n(�p) | 被调函数的栈空间,局部变量在此分配,这段是可变的

0(�p)  |上层函数调用的栈基地址

4(�p)  |返回地址

n(�p)  |一系列函数参数

-----------------------------------

High addresses

 

思路就是:通过查看寄存器内容,一步步得到每一层调用的返回地址,最后恢复函数调用链。

1.        首先,查看寄存器信息,找到ebp ,即当前函数调用堆栈的基址

这就是当前调用栈:

StackFrame Pointer | Instruction Pointer

------------------------------------------

0xb50c41a8(ebp)  | 0xb7b15197(eip)

2. 然后,查看ebp中的地址内容,获取上层调用的ebpeip

0xb50c41a8 这地址存放的就是上层调用栈的基址,0xb50c41a8  存放上层调用的EIP

看一下内存地址 0xb50c41a8附近的内容,在里面找上层�p  �p+4的内容,下面已经用方框标出

注意,这里的地址内容是小端字节序,整理后是这样的

0xb50c41a8     0xb50c41b8   0xb79ec77f  ……

下面这就是我们恢复的coredump时候的几层堆栈信息:

StackFrame Pointer | Instruction Pointer

-----------------------------------------------

  0xb50c41a8       0xb7b15197

0xb50c41a8:      0xb50c41b8   0xb79ec77f

0xb50c41b8:      0xb50c4218   0xb79e0822

0xb50c4218:      0xb50c4258   0xb79e0251

0xb50c4258:      0xb50c4278   0xb79df41c

0xb50c4278:      0xb50c42a8   0xb7e2cd86

0xb50c42a8:      0xb50c5468   0x0805be44  ……

这样找下去,可以一直找到最上一层调用,到达栈底;不过,一般不需要找到头

3.        有了每一层调用发生时的返回地址(EIP), 直接用指令格式查看内存内容就行了:

0xb79ec77f <_ZN7log4cpp3NDC3getEv+31>:  add    $0x4,%esp

前半段就是当前调用函数symbol name。走到这里,调用堆栈已经恢复了。




在Unix系统下,如果sendrecvwrite在等待协议传送数据时网络断开的话,调用send的进程会接收到一个SIGPIPE信号,进程对该信号的默认处理是进程终止。此种情况应用就很难查处理进程为什么退出。

 

SIGPIPE信号:

对 一个已经收到FIN包的socket调用read方法, 如果接收缓冲已空, 则返回0, 这就是常说的表示连接关闭. 但第一次对其调用write方法 时, 如果发送缓冲没问题, 会返回正确写入(发送). 但发送的报文会导致对端发送RST报文, 因为对端的socket已经调用了close, 完全 关闭, 既不发送, 也不接收数据. 所以, 第二次调用write方法(假设在收到RST之后), 会生成SIGPIPE信号, 导致进程退出。如果对SIGPIPE进行忽略处理,二次调用write方法时, 会返回-1, 同时errno置为SIGPIPE.

处理方法:

在初始化时调用signal(SIGPIPE,SIG_IGN)忽略该信号(只需一次)SIGPIPE交给了系统处理。此时sendrecvwrite函数将返回-1,errno为EPIPE,可视情况关闭socket或其他处理    

SIGPIPE被忽略的情况下,如果服务器采用了fork的话,要收集垃圾进程,防止僵尸进程的产生,可以这样处理:  signal(SIGCHLD,SIG_IGN); 交给系统init去回收。这样子进程就不会产生僵尸进程了。

 

 

 

Coredump生成过程:

系统关键/核心进程,产生严重的无法恢复的错误,为了避免系统相关资源受到更大损害,操作系统都会强行停止运行,并将当前内存中的各种结构、核心进程出错位置及其代码状态,保存下来,以便以后分析最常见的原因是指令走飞,或者缓冲区溢出,或者内存访问越界

进程退出,未发现core的原因有一下几种:

1、core文件的生成开关被关闭

a) 查看core文件的生成开关

boss@Tencent:~> ulimit -c

0

b) 打开core文件的生成开关

ulimit -c unlimited

2、core文件的生成开关已被打开,当前路径下找不到core文件

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

echo  "core"  >/proc/sys/kernel/core_pattern  当前目录生成core

b) 系统生成的core文件pid作为扩展名称

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

3、系统中存在某个逻辑上return错误地使用了exit_exitabort

exit_exitabort它们会直接退出进程,而不是返回堆栈。此情况系统是系统被正常的退出了,而不是出现异常。

4、系统中的异常信号没有进行处理,操作系统结束了此进程

操作系统对信号有以下几种默认操作,对于A类信号如果进程不做处理,进程会被操作系统终止,也不会产生core

信号类型

缺省的动作是终止进程
缺省的动作是忽略此信号
缺省的动作是终止进程并进行内核映像转储(dump core)
缺省的动作是停止进程
信号不能被捕获
信号不能被忽略

A类信号

SIGHUP 终端挂起或者控制进程终止
SIGINT 键盘中断(如break键被按下)
SIGPIPE 13 管道破裂: 写一个没有读端口的管道
SIGALRM 14 由alarm(2)发出的信号
SIGTERM 15 终止信号
SIGUSR1 30,10,16 用户自定义信号1
SIGUSR2 31,12,17 用户自定义信号2
SIGPROF 27,27,29 Profiling定时器到
SIGVTALRM 26,26,28 实际时间报警时钟信号(4.2 BSD)
SIGSTKFLT -,16,- 协处理器堆栈错误
SIGIO 23,29,22 某I/O操作现在可以进行了(4.2 BSD)
SIGCLD -,-,18 与SIGCHLD同义
SIGPWR 29,30,19 电源故障(System V)
SIGLOST -,-,- 文件锁丢失


转自:http://blog.sina.com.cn/s/blog_45497dfa0100mddb.html

原创粉丝点击