98 lines
2.9 KiB
C++
98 lines
2.9 KiB
C++
/*
|
||
* 作者: leehomwu
|
||
* 日期: 2011-05-14
|
||
* 修订: 2011-06-11, 处理部分处理器会将出错时的 EIP 也入栈的情况
|
||
* 描述: 捕获段错误、浮点错误,输出发生错误时的具体位置、调用路径
|
||
* 使用: 在 main 函数所在文件包含该头文件即可
|
||
* 示例: 当发生段错误或浮点错误时,会向STDOUT打印调用路径上的指令地址,类似:
|
||
signal[8] catched when running code at 80486f0
|
||
signal[8] catched when running code at 80488ea
|
||
signal[8] catched when running code at 80488d9
|
||
|
||
进一步运行命令行,解析指令地址:
|
||
addr2line 80486f0 80488ea 80488d9 -s -C -f -e
|
||
[可执行文件]
|
||
|
||
得到输出:
|
||
main
|
||
newsig.cpp:14
|
||
a()
|
||
kk.cpp:23
|
||
b()
|
||
kk.cpp:19
|
||
*/
|
||
|
||
#ifndef __SEGV_CATCH_H
|
||
#define __SEGV_CATCH_H
|
||
#include <execinfo.h>
|
||
#include <signal.h>
|
||
#include <stdio.h>
|
||
|
||
#ifndef __USE_GNU
|
||
#define __USE_GNU
|
||
#include <sys/ucontext.h>
|
||
#include <ucontext.h>
|
||
#undef __USE_GNU
|
||
#else
|
||
#include <sys/ucontext.h>
|
||
#include <ucontext.h>
|
||
#endif
|
||
|
||
#ifdef __cplusplus
|
||
static void initSegvCatch(void);
|
||
class C_SEGVCATCH {
|
||
public:
|
||
C_SEGVCATCH() { initSegvCatch(); }
|
||
};
|
||
static C_SEGVCATCH C_segv_catch;
|
||
#else
|
||
static void initSegvCatch(void) __attribute__((constructor));
|
||
#endif
|
||
|
||
static void OnSIGSEGV(int, siginfo_t*, void*);
|
||
static void initSegvCatch() {
|
||
struct sigaction act;
|
||
sigemptyset(&act.sa_mask);
|
||
act.sa_sigaction = OnSIGSEGV;
|
||
act.sa_flags = SA_SIGINFO;
|
||
if (sigaction(SIGSEGV, &act, NULL) < 0 || sigaction(SIGFPE, &act, NULL) < 0) {
|
||
perror("sigaction:");
|
||
}
|
||
}
|
||
|
||
static void OnSIGSEGV(int signum, siginfo_t* info, void* ptr) {
|
||
static int iTime;
|
||
if (iTime++ >=
|
||
1) { /* 容错处理:如果访问 ucontext_t 结构体时产生错误会进入该分支 */
|
||
printf("ReEnter %s is not allowed!\n", __FUNCTION__);
|
||
abort();
|
||
}
|
||
|
||
void* array[25];
|
||
int nSize = backtrace(array, sizeof(array) / sizeof(array[0]));
|
||
int i;
|
||
for (i = nSize - 3; i > 2; i--) { /* 头尾几个地址不必输出 */
|
||
/* 对array修正一下,使地址指向正在执行的代码 */
|
||
printf("signal[%d] catched when running code at %x\n", signum,
|
||
(long)array[i] - 1);
|
||
}
|
||
|
||
if (NULL != ptr) {
|
||
ucontext_t* ptrUC = (ucontext_t*)ptr;
|
||
int* pgregs = (int*)(&(ptrUC->uc_mcontext.gregs));
|
||
int eip = pgregs[REG_RIP];
|
||
if (eip != (long)array[i]) { /* 有的处理器会将出错时的 EIP 入栈 */
|
||
printf("signal[%d] catched when running code at %x\n", signum,
|
||
(long)array[i] - 1);
|
||
}
|
||
printf("signal[%d] catched when running code at %x\n", signum,
|
||
eip); /* 出错时的指令地址 */
|
||
} else {
|
||
printf("signal[%d] catched when running code at unknown address\n", signum);
|
||
}
|
||
|
||
abort();
|
||
}
|
||
|
||
#endif // __SEGV_CATCH_H
|