ARM快速定位segment fault

概要

ARM平台调试段错误很麻烦,主要原因有一下几点:

  • gdb不容易跑,嵌入式系统一般内存不够大
  • valgrind也需要占用很大的内存
  • 有的平台工具链不支持backtrace

有一种办法是捕获发生段错误时的信号,打印出发生段错误时的各种寄存器的值,其中非常关键的一个寄存器就是pc寄存器的值,通过objdump反汇编出源码之后,可以快速定位到发生错误的代码行,代码如下:

// Last Update:2019-03-15 11:49:54
/**
 * @file segfault.c
 * @brief 
 * @author felix
 * @version 0.1.00
 * @date 2019-03-15
 */

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>

static void catch_segfault ( int signal, siginfo_t *_si, void *ctx )
{
    unsigned long int *addr = NULL;
    char * registers[] =
    {
        "trap_no",
        "error_code",
        "oldmask",
        "arm_r0",
        "arm_r1",
        "arm_r2",
        "arm_r3",
        "arm_r4",
        "arm_r5",
        "arm_r6",
        "arm_r7",
        "arm_r8",
        "arm_r9",
        "arm_r10",
        "arm_fp",
        "arm_ip",
        "arm_sp",
        "arm_lr",
        "arm_pc",
        "arm_cpsr",
        "fault_address",
    };   
    int i = 0;

    if ( signal == SIGSEGV ) {
        printf("signal : SIGSEGV\n");
        if ( _si ) {
            printf("signo : %d\n", _si->si_signo );
            printf("errno : %d\n", _si->si_errno );
            printf("addr : %p\n", _si->si_addr );
            printf("pid : %p\n", _si->si_pid );
        } else {
            printf("_si is NULL\n");
        }

        if ( ctx ) {
            addr = ( unsigned long int *)(ctx + sizeof(unsigned long ) + sizeof( void *) + sizeof( stack_t ));
            for ( i=0; i<sizeof(registers)/sizeof(registers[0]); i++ ) {
                printf("%s : 0x%lx\n", registers[i], *addr++ );
            }
        } else {
            printf("ctx is NULL\n");
        }
    }
    exit(1);
}


static void __attribute__ ((constructor)) install_handler (void)
{
    struct sigaction sa;
    stack_t ss;
    void *stack_mem = malloc (2 * SIGSTKSZ);

    sa.sa_handler = (void *) catch_segfault;
    sa.sa_flags = SA_SIGINFO;
    sigemptyset (&sa.sa_mask);


    if (stack_mem != NULL) {
        ss.ss_sp = stack_mem;
        ss.ss_flags = 0;
        ss.ss_size = 2 * SIGSTKSZ;

        if (sigaltstack (&ss, NULL) == 0)
            sa.sa_flags |= SA_ONSTACK;
    }

    sigaction (SIGSEGV, &sa, NULL);

}

代码加入自己工程

  • 只需要将此代码保存一个.c,和自己的工程一起编译即可

说明

猜你喜欢

转载自blog.csdn.net/qq_39977813/article/details/88773911