]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
ARM/FDPIC: Allow backtrace to cross signal handler
authorChristophe Lyon <christophe.lyon@linaro.org>
Wed, 14 Apr 2021 14:22:38 +0000 (14:22 +0000)
committerChristophe Lyon <christophe.lyon@linaro.org>
Wed, 14 Apr 2021 14:22:38 +0000 (14:22 +0000)
2021-04-14  Mickael Guene  <mickael.guene@st.com>
Christophe Lyon  <christophe.lyon@st.com>

* gdb/arm-linux-tdep.c (THUMB2_SET_R7_RT_SIGRETURN): New define.
(FDPIC_LDR_R12_WITH_FUNCDESC): New define.
(FDPIC_LDR_R9_WITH_GOT): New define.
(FDPIC_LDR_PC_WITH_RESTORER): New define.
(arm_linux_sigreturn_fdpic_init): New.
(arm_linux_sigreturn_tramp_frame_fdpic): New.
(arm_linux_init_abi): Handle signal handler for FDPIC.

gdb/arm-linux-tdep.c

index b2bdb12685832005b16b2684760ee42aa4f2f7f9..3da10112eb57555c474662862769d6c6959f1d70 100644 (file)
@@ -251,6 +251,12 @@ static const char arm_linux_thumb2_le_breakpoint[] = { 0xf0, 0xf7, 0x00, 0xa0 };
 #define ARM_LDR_PC_SP_12               0xe49df00c
 #define ARM_LDR_PC_SP_4                        0xe49df004
 
+/* FDPIC specific definition.  */
+#define THUMB2_SET_R7_RT_SIGRETURN     0x07adf04f
+#define FDPIC_LDR_R12_WITH_FUNCDESC    0xe59fc004
+#define FDPIC_LDR_R9_WITH_GOT          0xe59c9004
+#define FDPIC_LDR_PC_WITH_RESTORER     0xe59cf000
+
 static void
 arm_linux_sigtramp_cache (struct frame_info *this_frame,
                          struct trad_frame_cache *this_cache,
@@ -337,6 +343,34 @@ arm_linux_sigreturn_init (const struct tramp_frame *self,
                              ARM_SIGCONTEXT_R0);
 }
 
+static void
+arm_linux_sigreturn_fdpic_init (const struct tramp_frame *self,
+                               struct frame_info *this_frame,
+                               struct trad_frame_cache *this_cache,
+                               CORE_ADDR func)
+{
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  CORE_ADDR sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM);
+  CORE_ADDR funcdesc = read_memory_unsigned_integer (func + 12, 4, byte_order);
+  CORE_ADDR handler = read_memory_unsigned_integer (funcdesc, 4, byte_order);
+  unsigned int first_handler_instruction
+    = read_memory_unsigned_integer (handler & ~1, 4, byte_order);
+
+  /* We look for either arm or thumb2 code.  */
+  /* This only works well for libc registered handler.  */
+  if (first_handler_instruction == ARM_SET_R7_RT_SIGRETURN
+      || first_handler_instruction == THUMB2_SET_R7_RT_SIGRETURN)
+    arm_linux_sigtramp_cache (this_frame, this_cache, func,
+                             ARM_NEW_RT_SIGFRAME_UCONTEXT
+                             + ARM_UCONTEXT_SIGCONTEXT
+                             + ARM_SIGCONTEXT_R0);
+  else
+    arm_linux_sigtramp_cache (this_frame, this_cache, func,
+                             ARM_UCONTEXT_SIGCONTEXT
+                             + ARM_SIGCONTEXT_R0);
+}
+
 static void
 arm_linux_rt_sigreturn_init (const struct tramp_frame *self,
                          struct frame_info *this_frame,
@@ -465,6 +499,18 @@ static struct tramp_frame arm_kernel_linux_restart_syscall_tramp_frame = {
   arm_linux_restart_syscall_init
 };
 
+static struct tramp_frame arm_linux_sigreturn_tramp_frame_fdpic = {
+  SIGTRAMP_FRAME,
+  4,
+  {
+    { FDPIC_LDR_R12_WITH_FUNCDESC, -1 },
+    { FDPIC_LDR_R9_WITH_GOT, -1 },
+    { FDPIC_LDR_PC_WITH_RESTORER, -1 },
+    { TRAMP_SENTINEL_INSN }
+  },
+  arm_linux_sigreturn_fdpic_init
+};
+
 /* Core file and register set support.  */
 
 #define ARM_LINUX_SIZEOF_GREGSET (18 * INT_REGISTER_SIZE)
@@ -1264,6 +1310,8 @@ arm_linux_init_abi (struct gdbarch_info info,
                                &arm_linux_restart_syscall_tramp_frame);
   tramp_frame_prepend_unwinder (gdbarch,
                                &arm_kernel_linux_restart_syscall_tramp_frame);
+  tramp_frame_prepend_unwinder (gdbarch,
+                               &arm_linux_sigreturn_tramp_frame_fdpic);
 
   /* Core file support.  */
   set_gdbarch_regset_from_core_section (gdbarch,