想要准确的跟踪段错误需要以下几点
1、C程序中加入信号捕获和段错误地址打印代码
2、编译程序时,加入 -g -DDEBUG 选项
3、段错误发生时,利用打印出的地址,使用addr2line追踪,或者nm工具追踪。
下面分别说明:
1、段错误捕获及地址打印
void SIGSEGV_handler( int signum, siginfo_t* sig_info, void* context)
{
void *str_array[16];
int size;
char **str = (char **)NULL;
void *pnt = NULL;
ucontext_t* uc = (ucontext_t*) context;
int i;
printf("\n****** Segmentation fault caught ....\n");
size = backtrace (str_array, 15);
str = backtrace_symbols (str_array, size);
pnt = (void*) uc->uc_mcontext.arm_lr;
str_array[1] = pnt;
printf("Faulty address is %p, called from %p\n", sig_info->si_addr, pnt);
printf ("Totally Obtained %zd stack frames. signal number =%d \n", size, signum);
if(signum == SIGSEGV)
{
printf(" Signal number = %d, Signal errno = %d\n",
sig_info->si_signo, sig_info->si_errno);
switch(sig_info->si_code)
{
case 1: printf(" SI code = %d (Address not mapped to object)\n",
sig_info->si_code);
break;
case 2: printf(" SI code = %d (Invalid permissions for \
mapped object)\n",sig_info->si_code);
break;
default: printf("SI code = %d (Unknown SI Code)\n",sig_info->si_code);
break;
}
printf(" Fault addr = %p \n",sig_info->si_addr);
}
printf("[bt] Execution path:\n");
for (i = 0; i < size; i++)
{
printf ("[bt] %s\n", str[i]);
}
exit(0);
}
static void env_init()
{
struct sigaction sa;
sa.sa_sigaction = (void *)SIGSEGV_handler;
sigemptyset (&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_SIGINFO;
sigaction(SIGSEGV, &sa, NULL);
}
int main()
{
env_init();
return 0;
}
举例:
当段错误发生时,就会输出如下打印:
****** Segmentation fault caught ....
Faulty address is 0x5, called from 0x6e6d8
Totally Obtained 0 stack frames. signal number =11
Signal number = 11, Signal errno = 0
SI code = 1 (Address not mapped to object)
Fault addr = 0x5
0x6e6d8 就是发生段错误的地方
2、程序编译
在Makefile中加入 -g -DDEBUG
编译好之后,可使用 nm -n a.out 来查看是否有符号表输出
如果加了 -g ,但是nm命令还是打印 no symbols,可能是makefile中加了strip,去掉strip即可
3、使用addr2line追踪段错误
以上面第一条中举例的段错误地址为例
直接在编译平台(ubuntu)中,输入
addr2line 0x6e678 -e a.out -f,直接定位在哪个函数的哪行
我的段错误就是发生在函数的参数中,使用了一个野指针导致的。