[ARM/FDPIC,11/21,ARM] FDPIC: Add support to unwind FDPIC signal frame

Message ID 20180525080354.13295-12-christophe.lyon@st.com
State New
Headers show
Series
  • FDPIC ARM for ARM
Related show

Commit Message

Christophe Lyon May 25, 2018, 8:03 a.m.
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

-- 
2.6.3

Comments

Kyrill Tkachov June 8, 2018, 10:53 a.m. | #1
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

>

Patch

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;
     }