天天看点

C程序中的段错误跟踪

想要准确的跟踪段错误需要以下几点

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,直接定位在哪个函数的哪行

我的段错误就是发生在函数的参数中,使用了一个野指针导致的。

继续阅读