aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Lyon <christophe.lyon@linaro.org>2021-04-14 14:22:38 +0000
committerChristophe Lyon <christophe.lyon@linaro.org>2021-04-14 14:22:38 +0000
commit666c20f65ebe79576949e989640d938928daad05 (patch)
treeb4b80ca9bce9f6ff844a6ffb59e8851f21d7720a
parent82934b09cd4edee8ab0c005c3b4b25bee7c51910 (diff)
downloadbinutils-666c20f65ebe79576949e989640d938928daad05.zip
binutils-666c20f65ebe79576949e989640d938928daad05.tar.gz
binutils-666c20f65ebe79576949e989640d938928daad05.tar.bz2
ARM/FDPIC: Allow backtrace to cross signal handler
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.
-rw-r--r--gdb/arm-linux-tdep.c48
1 files changed, 48 insertions, 0 deletions
diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c
index b2bdb12..3da1011 100644
--- a/gdb/arm-linux-tdep.c
+++ b/gdb/arm-linux-tdep.c
@@ -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,
@@ -338,6 +344,34 @@ arm_linux_sigreturn_init (const struct tramp_frame *self,
}
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,
struct trad_frame_cache *this_cache,
@@ -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,