? ? 之前文章转载了?LINUX C/C++捕获段错误,打印出错的具体位置(精确到哪一行)?, 但再arm-xilinx-linux-gnueabi-gcc 编译是无法通过,现在把能在arm-xilinx-linux-gnueabi-gcc下编译的源码发布如下:
/*
* 作者: 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 <ucontext.h>
#include <ucontext.h>
#undef __USE_GNU
#else
#include <ucontext.h>
#include <sys/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:");
printf("set segment catch faile!\n");
}
printf("set segment catch ok!\n");
}
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[32];
int nSize = backtrace(array, sizeof(array)/sizeof(array[0]));
printf("signal: %d \n", nSize);
int i;
for (i = nSize-3; i > 2; i--)
{
//头尾几个地址不必输出
//对array修正一下,使地址指向正在执行的代码
printf("signal[%d] catched when running code at 0x%p\n", signum, array[i] - 1);
}
if (NULL != ptr)
{
ucontext_t* ptrUC = (ucontext_t*)ptr;
printf("signal[%d] r0 0x%x\n", signum, ptrUC->uc_mcontext.arm_r0);
printf("signal[%d] r1 0x%x\n", signum, ptrUC->uc_mcontext.arm_r1);
printf("signal[%d] r2 0x%x\n", signum, ptrUC->uc_mcontext.arm_r2);
printf("signal[%d] r3 0x%x\n", signum, ptrUC->uc_mcontext.arm_r3);
printf("signal[%d] r4 0x%x\n", signum, ptrUC->uc_mcontext.arm_r4);
printf("signal[%d] r5 0x%x\n", signum, ptrUC->uc_mcontext.arm_r5);
printf("signal[%d] r6 0x%x\n", signum, ptrUC->uc_mcontext.arm_r6);
printf("signal[%d] r7 0x%x\n", signum, ptrUC->uc_mcontext.arm_r7);
printf("signal[%d] r8 0x%x\n", signum, ptrUC->uc_mcontext.arm_r8);
printf("signal[%d] r9 0x%x\n", signum, ptrUC->uc_mcontext.arm_r9);
printf("signal[%d] r10 0x%x\n",signum, ptrUC->uc_mcontext.arm_r10);
printf("signal[%d] ip 0x%x\n", signum, ptrUC->uc_mcontext.arm_ip);
printf("signal[%d] sp 0x%x\n", signum, ptrUC->uc_mcontext.arm_sp);
printf("signal[%d] fp 0x%x\n", signum, ptrUC->uc_mcontext.arm_fp);
printf("signal[%d] lr 0x%x\n", signum, ptrUC->uc_mcontext.arm_lr);
printf("signal[%d] cpsr 0x%x\n", signum, ptrUC->uc_mcontext.arm_cpsr);
printf("signal[%d] trap_no 0x%x\n", signum, ptrUC->uc_mcontext.trap_no);
printf("signal[%d] error_code 0x%x\n", signum, ptrUC->uc_mcontext.error_code);
printf("fault_address 0x%x\n", ptrUC->uc_mcontext.fault_address);
}
else
{
printf("signal[%d] catched when running code at unknown address\n", signum);
}
abort();
}
#endif // __SEGV_CATCH_H
uc_mcontext 结构体如下
#ifndef _ASMARM_SIGCONTEXT_H
#define _ASMARM_SIGCONTEXT_H
/*
* Signal context structure - contains all info to do with the state
* before the signal handler was invoked. Note: only add new entries
* to the end of the structure.
*/
struct sigcontext {
unsigned long trap_no;
unsigned long error_code;
unsigned long oldmask;
unsigned long arm_r0;
unsigned long arm_r1;
unsigned long arm_r2;
unsigned long arm_r3;
unsigned long arm_r4;
unsigned long arm_r5;
unsigned long arm_r6;
unsigned long arm_r7;
unsigned long arm_r8;
unsigned long arm_r9;
unsigned long arm_r10;
unsigned long arm_fp;
unsigned long arm_ip;
unsigned long arm_sp;
unsigned long arm_lr;
unsigned long arm_pc;
unsigned long arm_cpsr;
unsigned long fault_address;
};
#endif
运行后可以捕捉到错误地址, 但使用arm-xilinx-linux-gnueabi-add2line 出现错误,继续查找原因。
|