深入探索Linux coredump调试技巧
2015-07-26 20:28
736 查看
转自:http://blog.csdn.net/forever_feng/article/details/4676420
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 对信号的处理方式
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 文件的局限
1) core 文件提供了当前进程的所有线程的堆栈信息,但是也有他的局限性。
2) 由于 core 是对当前进程地址空间的镜像,所以 core 文件一般比较巨大,特别是针对服务器程序。这样如果服务器程序自动重启几次,可能就会导致磁盘空间占满。另外,由于 core 文件巨大,不删除的话占用大量磁盘空间,下载下来又比较费时。
3) 对于缓冲区溢出导致的 coredump ,进程的调用堆栈已经被覆盖破坏了, core 文件显示的堆栈信息往往错误。
4) 一些信号导致进程崩溃,但是不产生 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 等代码分析工具配合使用。
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 文件。
相关文章推荐
- 慕课网-Linux达人养成计划学习笔记
- linux中的file命令简介
- centos7.1 QT5编译出现:cannot find -lGL 和 collect2:error:ld returned 1 exit status 错误
- Centos7.1安装CUDA7.0
- ftp工具root登入linux设置
- linux安装mysql
- Linux使用Java将C++程序发布为webservice(wsdl)
- linux内核bootsect.S和setup.S流程
- linux查看jar包内文件命令
- Linux下如何安全退出线程
- 解决linux下set_loginuid failed opening loginuid报错问题
- linux ssh 别名登录小技巧
- 【Vbox】centos虚拟机安装usb网卡驱动
- 【Vbox】centos虚拟机安装usb网卡驱动
- Linux md raid
- linux多线程驱动中调用udelay()对整个系统造成的影响(by liukun321咕唧咕唧)
- SecureCRT 连接本地linux虚拟机(二)
- Linux devive mapper multipath
- linux系统编程:线程同步-信号量(semaphore)
- 本地虚拟机下的centOS安装jdk1.7