深入探索Linux coredump调试技巧

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 、通过backtracebacktrace_symbolsbacktrace_symbols_fd 实现当前线程的堆栈打印。

堆栈打印的一个简单示例:

     #include

     #include

     #include

    

     /* 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 ("% /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 组件支持打印崩溃线程的堆栈信息和寄存器变量,捕捉SIGINTSIGTERMSIGFPE SIGABRTSIGSEGV 等信号引起的异常崩溃,打印信息输出到一个文本文件。

使用方法: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

 

 

你可能感兴趣的:(Unix/Linux开发)