Chinaunix首页 | 论坛 | 博客
  • 博客访问: 622454
  • 博文数量: 166
  • 博客积分: 970
  • 博客等级: 准尉
  • 技术积分: 547
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-06 15:16
个人简介

Believe youself!

文章分类

全部博文(166)

文章存档

2017年(1)

2016年(5)

2015年(117)

2014年(14)

2013年(11)

2012年(5)

2010年(4)

2009年(1)

2008年(8)

我的朋友

分类: LINUX

2015-04-17 15:48:28

From: http://blog.sina.com.cn/s/blog_45497dfa0100mddb.html

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


信号类型

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

A类信号

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


会产生coredump文件的信号为:
terminate+core:  

SIGABRT

abnormal termination (abort)

SIGBUS

hardware fault

SIGEMT

hardware fault

SIGFPE

arithmetic exception

SIGILL

illegal instruction

SIGIO

asynchronous I/O

SIGIOT

hardware fault

SIGQUIT

terminal quit character

SIGSEGV

invalid memory reference

SIGSYS

invalid system call

SIGTRAP

hardware fault

SIGXCPU

CPU limit exceeded (setrlimit)

SIGXFSZ

file size limit exceeded (setrlimit)


阅读(5329) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~