深入探索Linux coredump调试技巧
2009-10-15 17:01
429 查看
1.
coredump
产生的原理和局限
1.1.
如何产生
core
文件
要素一,必须有信号产生:从上面的信号定义和说明可以看出,进程中止前肯定会产生信号,然后内核根据信号的类型来决定是否要产生
core
文件。
要素二,编译器支持:
要产生
core
文件,编译器必须支持把当前进程的镜像以某种格式
dump
到一个文件中,常见的比如
gcc/g++
的
-g
选项。
要素三,环境参数支持:
通过
ulimit –a
查看
core file size
是否为
0
,如果为
0
则不能产生
core
文件。
通过
ulimit –c unlimited
可以系统能支持的产生足够大的
core
文件,也可以设置为具体值。
特别说明:
core
文件的产生不是
POSIX.1
所属部分,而是很多
UNIX/Linux
版本的实现特征。
1.2.
Unix/Linux
对信号的处理方式
UNIX System signals | ||||||||
Name | Description | ISO C | SUS | FreeBSD 5.2.1 | Linux 2.4.22 | Mac OS X 10.3 | Solaris 9 | Default action |
SIGABRT | abnormal termination (abort ) | • | • | • | • | • | • | terminate+core |
SIGALRM | timer expired (alarm ) | • | • | • | • | • | terminate | |
SIGBUS | hardware fault | • | • | • | • | • | terminate+core | |
SIGCANCEL | threads library internal use | • | ignore | |||||
SIGCHLD | change in status of child | • | • | • | • | • | ignore | |
SIGCONT | Continue stopped process | • | • | • | • | • | continue/ignore | |
SIGEMT | hardware fault | • | • | • | • | terminate+core | ||
SIGFPE | arithmetic exception | • | • | • | • | • | • | terminate+core |
SIGFREEZE | checkpoint freeze | • | ignore | |||||
SIGHUP | hangup | • | • | • | • | • | terminate | |
SIGILL | illegal instruction | • | • | • | • | • | • | terminate+core |
SIGINFO | status request from keyboard | • | • | ignore | ||||
SIGINT | terminal interrupt character | • | • | • | • | • | • | terminate |
SIGIO | asynchronous I/O | • | • | • | • | terminate/ignore | ||
SIGIOT | hardware fault | • | • | • | • | terminate+core | ||
SIGKILL | termination | • | • | • | • | • | terminate | |
SIGLWP | threads library internal use | • | ignore | |||||
SIGPIPE | write to pipe with no readers | • | • | • | • | • | terminate | |
SIGPOLL | pollable event (poll ) | XSI | • | • | terminate | |||
SIGPROF | profiling time alarm (setitimer ) | XSI | • | • | • | • | terminate | |
SIGPWR | power fail/restart | • | • | terminate/ignore | ||||
SIGQUIT | terminal quit character | • | • | • | • | • | terminate+core | |
SIGSEGV | invalid memory reference | • | • | • | • | • | • | terminate+core |
SIGSTKFLT | coprocessor stack fault | • | terminate | |||||
SIGSTOP | stop | • | • | • | • | • | stop process | |
SIGSYS | invalid system call | XSI | • | • | • | • | terminate+core | |
SIGTERM | termination | • | • | • | • | • | • | terminate |
SIGTHAW | checkpoint thaw | • | ignore | |||||
SIGTRAP | hardware fault | XSI | • | • | • | • | terminate+core | |
SIGTSTP | terminal stop character | • | • | • | • | • | stop process | |
SIGTTIN | background read from control tty | • | • | • | • | • | stop process | |
SIGTTOU | background write to control tty | • | • | • | • | • | stop process | |
SIGURG | urgent condition (sockets) | • | • | • | • | • | ignore | |
SIGUSR1 | user-defined signal | • | • | • | • | • | terminate | |
SIGUSR2 | user-defined signal | • | • | • | • | • | terminate | |
SIGVTALRM | virtual time alarm (setitimer ) | XSI | • | • | • | • | terminate | |
SIGWAITING | threads library internal use | • | ignore | |||||
SIGWINCH | terminal window size change | • | • | • | • | ignore | ||
SIGXCPU | CPU limit exceeded (setrlimit ) | XSI | • | • | • | • | terminate+core/ignore | |
SIGXFSZ | file size limit exceeded (setrlimit ) | XSI | • | • | • | • | terminate+core/ignore | |
SIGXRES | resource control exceeded | • | ignore |
2.
core
文件的使用
3.
core
文件的局限
core文件提供了当前进程的所有线程的堆栈信息,但是也有他的局限性。
由于
core
是对当前进程地址空间的镜像,所以
core
文件一般比较巨大,特别是针对服务器程序。
这样如果服务器程序自动重启几次,可能就会导致磁盘空间占满。
另外,由于
core
文件巨大,不删除的话占用大量磁盘空间,下载下来又比较费时。
对于缓冲区溢出导致的
coredump
,进程的调用堆栈已经被覆盖破坏了,
core
文件显示的堆栈信息往往错误。
一些信号导致进程崩溃,但是不产生
core
文件,比如
SIGPIPE
。
只能在进程中止时才可以产生
core,
不能实时产生。
4.
堆栈打印
4.1.
如何打印堆栈
1、通过backtrace
和backtrace_symbols
或backtrace_symbols_fd
实现当前线程的堆栈打印。
堆栈打印的一个简单示例:
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
/* Obtain a backtrace and print it to stdout. */
void print_trace (void)
{
void *array[10];
size_t size;
size_t i;
size = backtrace (array, 10);
printf ("Obtained %zd stack frames./n", size);
for (i = 0; i < size; i++)
printf ("%
p
/n",
array
[i]);
}
/* A dummy function to make the backtrace more interesting. */
void dummy_function (void)
{
print_trace ();
}
int main (void)
{
dummy_function ();
return 0;
}
2
、编译时必须加上
-rdynamic –ldl
选项。
3
、如果要打印崩溃线程的堆栈信息,则必须在信号处理函数中打印堆栈。注意要通过
setjmp/longjmp
或
sigsetjmp/siglongjmp
来跳转,否则会陷于死循环。因为信号是软件中断,处理完后会返回到发生异常的地方继续执行,这样又会重新产生异常。
4
、我写了一个
coredump
组件,支持打印崩溃线程的堆栈信息和寄存器变量,捕捉
SIGINT
、
SIGTERM
、
SIGFPE
、
SIGABRT SIGSEGV
等信号引起的异常崩溃,打印信息输出到一个文本文件。该组件将会放到
SGDP
中供项目组选用。具体使用方法请看
readme
和
example
。
4.2.
打印堆栈的优缺点
优点:1
、不依赖
core
文件。
2
、可以打印当前崩溃线程的堆栈调用信息。
3
、输出到文件占用的磁盘空间很小。
缺点:
1、
只能打印当前线程的堆栈信息。
2、
只能打印堆栈调用信息。
3、
不能打印当前线程的所有变量值。
4、
输出函数名没有
gdb
的
core
文件可读性好。
5、
对于
abort
异常定位,需要和
nm
等代码分析工具配合使用。
6、
5.
GCC/G++
对内存错误的处理
GCC对内存错误的检查,在不同版本都有一定的体现。
GCC
对内存错误的检查主要依靠
3
个选项:
-fstack-check -fbounds-check
-fstack-protector-all
。
其中
-fstack-check
的准确性较差,特别是在代码执行了
O2
以上的优化后。
-fbounds-check
可以执行数组边界错误,主要是检查对数组赋值越界。
-fstack-protector-all
可以防止缓冲区溢出攻击,也可以利用此选项来检查代码是否有缓冲区溢出的错误。
GCC
4.1
以前的版本支持
-fstack-check
-fbounds-check
,
GCC 4.1
以后版本支持
-fstack-check -fbounds-check
-fstack-protector-all
。
GCC
4.1
以前的版本对于缓冲区溢出检查没有很好的解决方案,如果调用堆栈被破坏的不多还有可能定位出错函数的位置,否则只是一个错误的堆栈信息甚至无信息。
-fstack-protector-all
选项加上后会在标准输出上打印当前崩溃线程的堆栈调用信息,但是有时也不准确,同时产生
core
文件,
core
文件中的出错堆栈信息相对比较准确性。
6.
SGDP
的
coredump
组件
我们自己开发了一个Linux
版打印进程崩溃堆栈信息的
coredump
组件,放在
SGDP
的工具里面。
coredump
组件支持打印崩溃线程的堆栈信息和寄存器变量,捕捉SIGINT
、SIGTERM
、SIGFPE
、SIGABRT
和SIGSEGV
等信号引起的异常崩溃,打印信息输出到一个文本文件。
使用方法:1
、代码中包含coredump.h
。
2
、在main
函数开始的地方调用setup_sigcoredump()
。
如果大家需要的话,可以联系服务器引擎部,提供二进制版本的库和示例代码。
7.
Google coredumper
7.1.
项目介绍
在进程不中止的情况下可以产生core
文件,该
core
文件可以使用
gdb
调试,对于多线程调试有重要意义。
在产生
core
文件时会挂起所有线程,所以是线程安全的。
版权声明为
BSD
授权。
当前最新版本为
1.2.1
。
项目链接: http://code.google.com/p/google-coredumper/
7.2.
安装方法
与标准的开源项目基本上差不多:./configure
、
make
、
make install
。
需要注意的是编译生成的库在当前目录和标准目录中都没有,具体需要查看
libcoredumper.la
描述信息,方法:
vi libcoredumper.la
。
否则有可能找不到动态库或静态库。
7.3.
使用方法
1、包含
src
目录下的
google/coredumper.h
。
2、
调用
GetCoreDump
或
WriteCoreDump
等系列接口生成
core
文件。
3、
在
coredumper.h
中大部分函数都有
man
帮助。
4、
特别注意的是
WriteCoreDump
实际上是调用
GetCoreDump
,语义上好像是有点问题,看接口名称是有点困惑,我是看代码才发现的。
5、
可以指定预定义的压缩器来生成压缩的
core
文件,也可以自定义压缩算法生成
core
文件。
6
、
相关文章推荐
- 深入探索Linux coredump调试技巧
- 深入探索Linux coredump调试技巧
- 深入探索Linux coredump调试技巧
- linux coredump配置与调试
- LINUX调试技巧一则
- ios 开发中 coredump 调试技巧 [1]
- linux调试工具ipcs的深入分析
- linux coredump调试
- 嵌入式linux调试技巧
- linux驱动调试技巧:灌寄存器---------以mma7660为例
- linux命令之调试工具strace的深入分析
- Linux 程序开发打印 Debug 信息的使用技巧--C语言中几种输出调试信息的方法
- Linux c c++ 开发调试技巧
- linux-C 开发及调试工具 (vim-gcc-gdb-coredump)总结
- linux内核调试技巧一:printk
- 【转】linux内核调试技巧之一 dump_stack
- linux coredump配置及其调试出core文件
- 深入探索 Linux listen() 函数 backlog 的含义
- linux coredump配置与调试
- 用 GDB 调试Linux程序及有用技巧