ARM v7 BKPT instruction doesn't work correctly on Linux 2.6.35 -
i have problem connected bkpt instruction on arm v7 on linux 2.6.35. main reason address of fault instruction (bkpt) not correct , not correspond arm v7 manual.
here steps reproducing:
redefine os sigbus handler sigbus handler:
void initsigbushandler() { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_flags = sa_siginfo; sigfillset(&sa.sa_mask); sa.sa_sigaction = sigbushandler; sigaction(sigbus, &sa, null); }
use inline _asm , put "bkpt" instruction code in main() function:
int main(int argc, char **argv) { initsigbushandler(); __asm ( "bkpt\n\t" ); return 0; }
here sigbus handler:
void sigbushandler( int signum, siginfo_t *pact, void *poldact ) { write(2, (const char *)msg_sigbus_in_handler, strlen((const char *)msg_sigbus_in_handler) ); uint32_t faultaddr = (uint32_t)pact->si_addr; memcpy((void *)buffer, (void *)msg_sigbus_fault_addr, strlen(msg_sigbus_fault_addr) ); write(2, (const char *)msg_sigbus_fault_addr, strlen((const char *)msg_sigbus_fault_addr) ); sprintf(buffer, "%x\n", faultaddr); write(2, buffer, strlen(buffer)); }
the problem fault adress of instruction (bkpt) wrong , not correspond arm v7 specification. here console output after program worked:
in sigbus handler:
fault address: 86b0
in sigbus handler:
fault address: 86c0
in sigbus handler:
fault address: 86c0
in sigbus handler:
fault address: 86c0
in sigbus handler:
fault address: 86c0
in sigbus handler:
fault address: 86b0
in sigbus handler:
fault address: 86a8
in sigbus handler:
fault address: 86f0
on x86 architecture sample works correctly. on arm v7 architecture sample has strange behavior.
if use gdb on arm v7, catches bkpt instruction correct address.
maybe knows wrong ?
the assumption si_addr
precise (i.e. actual address operated on when fault occurred) breakpoint trap not true / portable.
you need inspect saved register state, i.e. third parameter signal handler, can cast ucontext_t*
. state not portable between cpus , hence generic interface passes void *
; gdb inspects (so info registers
works) , extracts program counter of fault there, that's why it's able point breakpoint instruction.
the situation you're encountering on arm here similar you'd on 64bit x86 if tried:
volatile char *ptr = (char*)0x1234567890abcdef; char crashme = *ptr;
and expect fault address in si_addr
0x1234567890abcdef
. won't case because address on access create #gpf
not #pf
fault, , former doesn't set fault address register on x86. if program counter saved part of ucontext_t
/ struct sigcontext
(embedded in there) you'll see faulting instruction address though, , that'll precise.
change 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 you'll see on arm */ ... }
problem, said, figuring out cpu register state gives cpu-dependent code. you'll have make adaptations / wrappers keep 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 helps !
Comments
Post a Comment