ARM v7 BKPT instruction doesn't work correctly on Linux 2.6.35

后端 未结 1 1057
梦毁少年i
梦毁少年i 2021-01-14 10:38

I have a problem is connected with BKPT instruction on ARM v7 on Linux 2.6.35. The main reason is that the address of fault instruction (bkpt) is not correct and does not co

1条回答
  •  傲寒
    傲寒 (楼主)
    2021-01-14 11:19

    The assumption that si_addr is precise (i.e. the actual address operated on when the fault occurred) for a breakpoint trap is not necessarily true / portable.

    You do need to inspect the saved register state, i.e. the third parameter to the signal handler, which can be cast to ucontext_t*. The state is not portable between CPUs and hence the generic interface only passes a void *; GDB inspects it (so that info registers works) and extracts the program counter of the fault from there, that's why it's able to point you to the breakpoint instruction.

    The situation you're encountering on ARM here is similar as to what you'd get on 64bit x86 if you tried:

    volatile char *ptr = (char*)0x1234567890abcdef;
    char crashme = *ptr;
    

    and you expect the fault address in si_addr to be 0x1234567890abcdef. That won't be the case because this address on access will create a #GPF not #PF fault, and the former doesn't set the fault address register on x86. If you look into the program counter saved as part of ucontext_t / struct sigcontext (embedded in there) you'll see the faulting instruction address though, and that'll be precise.

    Change your signal handler to:

    void SigBusHandler(
         int  signum,  
         siginfo_t  *pAct,  
         void  *context
        )
    {
        struct sigcontext *ctx = &(((ucontext_t*)context)->uc_mcontext);
        uintptr_t fault_address = ctx->arm_pc;    /* that's what you'll see on ARM */
        ...
    }
    

    Problem, as said, is that figuring out CPU register state necessarily gives you CPU-dependent code. You'll have to make some adaptations / wrappers to keep this portable, like:

    #if defined(ARM)
    #define GET_PC_FROM_CONTEXT(c) (((ucontext_t *)(c))->uc_mcontext.arm_pc)
    #elsif defined(__i386__)
    define GET_PC_FROM_CONTEXT(c) (((ucontext_t *)(c))->uc_mcontext.eip)
    #elsif defined(__amd64__)
    define GET_PC_FROM_CONTEXT(c) (((ucontext_t *)(c))->uc_mcontext.rip)
    #endif
    
    uintptr_t instr_address = GET_PC_FROM_CONTEXT(context);
    

    Hope that helps !

    0 讨论(0)
提交回复
热议问题