Message ID | 20180525080354.13295-12-christophe.lyon@st.com |
---|---|
State | Superseded |
Headers | show |
Series | FDPIC ARM for ARM | expand |
Hi Christophe, I'll be honest, I'm not very familiar with this part of the compiler. I'll let Ramana or Richard comment on the approach. A description of what this patch does and how would be appreciated. Some comments inline nevertheless :) Thanks, Kyrill On 25/05/18 09:03, Christophe Lyon wrote: > 2018-XX-XX Christophe Lyon <christophe.lyon@st.com> > Mickaël Guêné <mickael.guene@st.com> > > libgcc/ > * unwind-arm-common.inc (ARM_SET_R7_RT_SIGRETURN) > (THUMB2_SET_R7_RT_SIGRETURN, FDPIC_LDR_R12_WITH_FUNCDESC) > (FDPIC_LDR_R9_WITH_GOT, FDPIC_LDR_PC_WITH_RESTORER) > (FDPIC_FUNCDESC_OFFSET, ARM_NEW_RT_SIGFRAME_UCONTEXT) > (ARM_UCONTEXT_SIGCONTEXT, ARM_SIGCONTEXT_R0): New. > (__gnu_personality_sigframe_fdpic): New. > (get_eit_entry): Add FDPIC signal frame support. > > Change-Id: I7f9527cc50665dd1a731b7badf71c319fb38bf57 > > diff --git a/libgcc/unwind-arm-common.inc b/libgcc/unwind-arm-common.inc > index f5415c1..80d1e88 100644 > --- a/libgcc/unwind-arm-common.inc > +++ b/libgcc/unwind-arm-common.inc > @@ -30,6 +30,21 @@ > #include <sys/sdt.h> > #endif > > +#if __FDPIC__ > +/* Load r7 with rt_sigreturn value. */ > +#define ARM_SET_R7_RT_SIGRETURN 0xe3a070ad > +#define THUMB2_SET_R7_RT_SIGRETURN 0x07adf04f > +/* FDPIC jump to restorer sequence. */ > +#define FDPIC_LDR_R12_WITH_FUNCDESC 0xe59fc004 > +#define FDPIC_LDR_R9_WITH_GOT 0xe59c9004 > +#define FDPIC_LDR_PC_WITH_RESTORER 0xe59cf000 > +#define FDPIC_FUNCDESC_OFFSET 12 > +/* Signal frame offsets. */ > +#define ARM_NEW_RT_SIGFRAME_UCONTEXT 0x80 > +#define ARM_UCONTEXT_SIGCONTEXT 0x14 > +#define ARM_SIGCONTEXT_R0 0xc > +#endif I think these are instruction opcodes? If so, please include their expected disassembly in a comment next to them. That way we stand a chance of validating whether they actually do what we want them to do. > + > /* We add a prototype for abort here to avoid creating a dependency on > target headers. */ > extern void abort (void); > @@ -195,6 +210,46 @@ search_EIT_table (const __EIT_entry * table, int nrec, _uw return_address) > } > } > > +#if __FDPIC__ > +/* FIXME: partial support (VFP not restored) but should be sufficient > + to allow unwinding. */ Not a fan of these FIXMEs in patch submissions. Is the patch incomplete? Does the missing support not matter? If VFP is not supported properly then we should be rejecting building such configurations for the time being. > +static _Unwind_Reason_Code > +__gnu_personality_sigframe_fdpic (_Unwind_State state, > + _Unwind_Control_Block *ucbp, > + _Unwind_Context *context) > +{ > + unsigned int sp; > + unsigned int pc; > + unsigned int funcdesc; > + unsigned int handler; > + unsigned int first_handler_instruction; > + int i; > + > + _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &sp); > + _Unwind_VRS_Get (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, &pc); > + > + funcdesc = *(unsigned int *)(pc + FDPIC_FUNCDESC_OFFSET); > + handler = *(unsigned int *)(funcdesc); > + first_handler_instruction = *(unsigned int *)(handler & ~1); > + > + /* Adjust SP to point to the start of registers according to > + signal type. */ > + if (first_handler_instruction == ARM_SET_R7_RT_SIGRETURN > + || first_handler_instruction == THUMB2_SET_R7_RT_SIGRETURN) > + sp += ARM_NEW_RT_SIGFRAME_UCONTEXT > + + ARM_UCONTEXT_SIGCONTEXT > + + ARM_SIGCONTEXT_R0; > + else > + sp += ARM_UCONTEXT_SIGCONTEXT > + + ARM_SIGCONTEXT_R0; > + /* Restore regs saved on stack by the kernel. */ > + for (i = 0; i < 16; i++) > + _Unwind_VRS_Set (context, _UVRSC_CORE, i, _UVRSD_UINT32, sp + 4 * i); > + > + return _URC_CONTINUE_UNWIND; > +} > +#endif > + > /* Find the exception index table eintry for the given address. > Fill in the relevant fields of the UCB. > Returns _URC_FAILURE if an error occurred, _URC_OK on success. */ > @@ -218,6 +273,24 @@ get_eit_entry (_Unwind_Control_Block *ucbp, _uw return_address) > &nrec); > if (!eitp) > { > +#if __FDPIC__ > + /* If we are unwinding a signal handler then perhaps we have > + reached a trampoline. Try to detect jump to restorer > + sequence. */ > + _uw *pc = (_uw *)((return_address+2) & ~3); > + if (pc[0] == FDPIC_LDR_R12_WITH_FUNCDESC > + && pc[1] == FDPIC_LDR_R9_WITH_GOT > + && pc[2] == FDPIC_LDR_PC_WITH_RESTORER) > + { As I said, I'll let Richard or Ramana comment on the approach but I don't see any other code in this file doing such instruction matching... > + struct funcdesc_t *funcdesc = (struct funcdesc_t *) > + &__gnu_personality_sigframe_fdpic; > + > + UCB_PR_ADDR (ucbp) = funcdesc->ptr; > + UCB_PR_GOT (ucbp) = funcdesc->got; > + > + return _URC_OK; > + } > +#endif > UCB_PR_ADDR (ucbp) = 0; > return _URC_FAILURE; > } > @@ -232,6 +305,24 @@ get_eit_entry (_Unwind_Control_Block *ucbp, _uw return_address) > > if (!eitp) > { > +#if __FDPIC__ > + /* If we are unwinding a signal handler then perhaps we have > + reached a trampoline. Try to detect jump to restorer > + sequence. */ > + _uw *pc = (_uw *)((return_address+2) & ~3); > + if (pc[0] == FDPIC_LDR_R12_WITH_FUNCDESC > + && pc[1] == FDPIC_LDR_R9_WITH_GOT > + && pc[2] == FDPIC_LDR_PC_WITH_RESTORER) > + { > + struct funcdesc_t *funcdesc = (struct funcdesc_t *) > + &__gnu_personality_sigframe_fdpic; > + > + UCB_PR_ADDR (ucbp) = funcdesc->ptr; > + UCB_PR_GOT (ucbp) = funcdesc->got; > + > + return _URC_OK; > + } > +#endif > UCB_PR_ADDR (ucbp) = 0; > return _URC_FAILURE; > } > @@ -240,6 +331,24 @@ get_eit_entry (_Unwind_Control_Block *ucbp, _uw return_address) > /* Can this frame be unwound at all? */ > if (eitp->content == EXIDX_CANTUNWIND) > { > +#if __FDPIC__ > + /* If we are unwinding a signal handler then perhaps we have > + reached a trampoline. Try to detect jump to restorer > + sequence. */ > + _uw *pc = (_uw *)((return_address+2) & ~3); > + if (pc[0] == FDPIC_LDR_R12_WITH_FUNCDESC > + && pc[1] == FDPIC_LDR_R9_WITH_GOT > + && pc[2] == FDPIC_LDR_PC_WITH_RESTORER) > + { > + struct funcdesc_t *funcdesc = (struct funcdesc_t *) > + &__gnu_personality_sigframe_fdpic; > + > + UCB_PR_ADDR (ucbp) = funcdesc->ptr; > + UCB_PR_GOT (ucbp) = funcdesc->got; > + > + return _URC_OK; > + } > +#endif > UCB_PR_ADDR (ucbp) = 0; > return _URC_END_OF_STACK; > } > -- > 2.6.3 >
diff --git a/libgcc/unwind-arm-common.inc b/libgcc/unwind-arm-common.inc index f5415c1..80d1e88 100644 --- a/libgcc/unwind-arm-common.inc +++ b/libgcc/unwind-arm-common.inc @@ -30,6 +30,21 @@ #include <sys/sdt.h> #endif +#if __FDPIC__ +/* Load r7 with rt_sigreturn value. */ +#define ARM_SET_R7_RT_SIGRETURN 0xe3a070ad +#define THUMB2_SET_R7_RT_SIGRETURN 0x07adf04f +/* FDPIC jump to restorer sequence. */ +#define FDPIC_LDR_R12_WITH_FUNCDESC 0xe59fc004 +#define FDPIC_LDR_R9_WITH_GOT 0xe59c9004 +#define FDPIC_LDR_PC_WITH_RESTORER 0xe59cf000 +#define FDPIC_FUNCDESC_OFFSET 12 +/* Signal frame offsets. */ +#define ARM_NEW_RT_SIGFRAME_UCONTEXT 0x80 +#define ARM_UCONTEXT_SIGCONTEXT 0x14 +#define ARM_SIGCONTEXT_R0 0xc +#endif + /* We add a prototype for abort here to avoid creating a dependency on target headers. */ extern void abort (void); @@ -195,6 +210,46 @@ search_EIT_table (const __EIT_entry * table, int nrec, _uw return_address) } } +#if __FDPIC__ +/* FIXME: partial support (VFP not restored) but should be sufficient + to allow unwinding. */ +static _Unwind_Reason_Code +__gnu_personality_sigframe_fdpic (_Unwind_State state, + _Unwind_Control_Block *ucbp, + _Unwind_Context *context) +{ + unsigned int sp; + unsigned int pc; + unsigned int funcdesc; + unsigned int handler; + unsigned int first_handler_instruction; + int i; + + _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &sp); + _Unwind_VRS_Get (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, &pc); + + funcdesc = *(unsigned int *)(pc + FDPIC_FUNCDESC_OFFSET); + handler = *(unsigned int *)(funcdesc); + first_handler_instruction = *(unsigned int *)(handler & ~1); + + /* Adjust SP to point to the start of registers according to + signal type. */ + if (first_handler_instruction == ARM_SET_R7_RT_SIGRETURN + || first_handler_instruction == THUMB2_SET_R7_RT_SIGRETURN) + sp += ARM_NEW_RT_SIGFRAME_UCONTEXT + + ARM_UCONTEXT_SIGCONTEXT + + ARM_SIGCONTEXT_R0; + else + sp += ARM_UCONTEXT_SIGCONTEXT + + ARM_SIGCONTEXT_R0; + /* Restore regs saved on stack by the kernel. */ + for (i = 0; i < 16; i++) + _Unwind_VRS_Set (context, _UVRSC_CORE, i, _UVRSD_UINT32, sp + 4 * i); + + return _URC_CONTINUE_UNWIND; +} +#endif + /* Find the exception index table eintry for the given address. Fill in the relevant fields of the UCB. Returns _URC_FAILURE if an error occurred, _URC_OK on success. */ @@ -218,6 +273,24 @@ get_eit_entry (_Unwind_Control_Block *ucbp, _uw return_address) &nrec); if (!eitp) { +#if __FDPIC__ + /* If we are unwinding a signal handler then perhaps we have + reached a trampoline. Try to detect jump to restorer + sequence. */ + _uw *pc = (_uw *)((return_address+2) & ~3); + if (pc[0] == FDPIC_LDR_R12_WITH_FUNCDESC + && pc[1] == FDPIC_LDR_R9_WITH_GOT + && pc[2] == FDPIC_LDR_PC_WITH_RESTORER) + { + struct funcdesc_t *funcdesc = (struct funcdesc_t *) + &__gnu_personality_sigframe_fdpic; + + UCB_PR_ADDR (ucbp) = funcdesc->ptr; + UCB_PR_GOT (ucbp) = funcdesc->got; + + return _URC_OK; + } +#endif UCB_PR_ADDR (ucbp) = 0; return _URC_FAILURE; } @@ -232,6 +305,24 @@ get_eit_entry (_Unwind_Control_Block *ucbp, _uw return_address) if (!eitp) { +#if __FDPIC__ + /* If we are unwinding a signal handler then perhaps we have + reached a trampoline. Try to detect jump to restorer + sequence. */ + _uw *pc = (_uw *)((return_address+2) & ~3); + if (pc[0] == FDPIC_LDR_R12_WITH_FUNCDESC + && pc[1] == FDPIC_LDR_R9_WITH_GOT + && pc[2] == FDPIC_LDR_PC_WITH_RESTORER) + { + struct funcdesc_t *funcdesc = (struct funcdesc_t *) + &__gnu_personality_sigframe_fdpic; + + UCB_PR_ADDR (ucbp) = funcdesc->ptr; + UCB_PR_GOT (ucbp) = funcdesc->got; + + return _URC_OK; + } +#endif UCB_PR_ADDR (ucbp) = 0; return _URC_FAILURE; } @@ -240,6 +331,24 @@ get_eit_entry (_Unwind_Control_Block *ucbp, _uw return_address) /* Can this frame be unwound at all? */ if (eitp->content == EXIDX_CANTUNWIND) { +#if __FDPIC__ + /* If we are unwinding a signal handler then perhaps we have + reached a trampoline. Try to detect jump to restorer + sequence. */ + _uw *pc = (_uw *)((return_address+2) & ~3); + if (pc[0] == FDPIC_LDR_R12_WITH_FUNCDESC + && pc[1] == FDPIC_LDR_R9_WITH_GOT + && pc[2] == FDPIC_LDR_PC_WITH_RESTORER) + { + struct funcdesc_t *funcdesc = (struct funcdesc_t *) + &__gnu_personality_sigframe_fdpic; + + UCB_PR_ADDR (ucbp) = funcdesc->ptr; + UCB_PR_GOT (ucbp) = funcdesc->got; + + return _URC_OK; + } +#endif UCB_PR_ADDR (ucbp) = 0; return _URC_END_OF_STACK; }