aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog10
-rw-r--r--gdb/arm-linux-tdep.c44
-rw-r--r--gdb/arm-tdep.c2
-rw-r--r--gdb/arm-tdep.h3
4 files changed, 56 insertions, 3 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 2507c90..af94f8d 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,13 @@
+2011-03-01 Ulrich Weigand <ulrich.weigand@linaro.org>
+
+ * arm-linux-tdep.c (ARM_LDR_PC_SP_4): Add define.
+ (arm_linux_restart_syscall_init): Handle both on-stack and in-kernel
+ versions of the trampoline. Handle Thumb vs. ARM addresses.
+ (arm_kernel_linux_restart_syscall_tramp_frame): New global.
+ (arm_linux_init_abi): Install it.
+ * arm-tdep.c (arm_psr_thumb_bit): Make global.
+ * arm-tdep.c (arm_psr_thumb_bit): Add prototype.
+
2011-02-28 Michael Snyder <msnyder@vmware.com>
* ui-out.c (ui_out_field_core_addr): Make local char buffer
diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c
index ff649d6..f60ecc3 100644
--- a/gdb/arm-linux-tdep.c
+++ b/gdb/arm-linux-tdep.c
@@ -239,6 +239,7 @@ static const char arm_linux_thumb2_le_breakpoint[] = { 0xf0, 0xf7, 0x00, 0xa0 };
whenever OABI support has been enabled in the kernel. */
#define ARM_OABI_SYSCALL_RESTART_SYSCALL 0xef900000
#define ARM_LDR_PC_SP_12 0xe49df00c
+#define ARM_LDR_PC_SP_4 0xe49df004
static void
arm_linux_sigtramp_cache (struct frame_info *this_frame,
@@ -355,10 +356,36 @@ arm_linux_restart_syscall_init (const struct tramp_frame *self,
struct trad_frame_cache *this_cache,
CORE_ADDR func)
{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
CORE_ADDR sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM);
+ CORE_ADDR pc = get_frame_memory_unsigned (this_frame, sp, 4);
+ CORE_ADDR cpsr = get_frame_register_unsigned (this_frame, ARM_PS_REGNUM);
+ ULONGEST t_bit = arm_psr_thumb_bit (gdbarch);
+ int sp_offset;
+
+ /* There are two variants of this trampoline; with older kernels, the
+ stub is placed on the stack, while newer kernels use the stub from
+ the vector page. They are identical except that the older version
+ increments SP by 12 (to skip stored PC and the stub itself), while
+ the newer version increments SP only by 4 (just the stored PC). */
+ if (self->insn[1].bytes == ARM_LDR_PC_SP_4)
+ sp_offset = 4;
+ else
+ sp_offset = 12;
+
+ /* Update Thumb bit in CPSR. */
+ if (pc & 1)
+ cpsr |= t_bit;
+ else
+ cpsr &= ~t_bit;
- trad_frame_set_reg_addr (this_cache, ARM_PC_REGNUM, sp);
- trad_frame_set_reg_value (this_cache, ARM_SP_REGNUM, sp + 12);
+ /* Remove Thumb bit from PC. */
+ pc = gdbarch_addr_bits_remove (gdbarch, pc);
+
+ /* Save previous register values. */
+ trad_frame_set_reg_value (this_cache, ARM_SP_REGNUM, sp + sp_offset);
+ trad_frame_set_reg_value (this_cache, ARM_PC_REGNUM, pc);
+ trad_frame_set_reg_value (this_cache, ARM_PS_REGNUM, cpsr);
/* Save a frame ID. */
trad_frame_set_id (this_cache, frame_id_build (sp, func));
@@ -417,6 +444,17 @@ static struct tramp_frame arm_linux_restart_syscall_tramp_frame = {
arm_linux_restart_syscall_init
};
+static struct tramp_frame arm_kernel_linux_restart_syscall_tramp_frame = {
+ NORMAL_FRAME,
+ 4,
+ {
+ { ARM_OABI_SYSCALL_RESTART_SYSCALL, -1 },
+ { ARM_LDR_PC_SP_4, -1 },
+ { TRAMP_SENTINEL_INSN }
+ },
+ arm_linux_restart_syscall_init
+};
+
/* Core file and register set support. */
#define ARM_LINUX_SIZEOF_GREGSET (18 * INT_REGISTER_SIZE)
@@ -1000,6 +1038,8 @@ arm_linux_init_abi (struct gdbarch_info info,
&arm_eabi_linux_rt_sigreturn_tramp_frame);
tramp_frame_prepend_unwinder (gdbarch,
&arm_linux_restart_syscall_tramp_frame);
+ tramp_frame_prepend_unwinder (gdbarch,
+ &arm_kernel_linux_restart_syscall_tramp_frame);
/* Core file support. */
set_gdbarch_regset_from_core_section (gdbarch,
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index e5e9055..8248418 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -262,7 +262,7 @@ int arm_apcs_32 = 1;
/* Return the bit mask in ARM_PS_REGNUM that indicates Thumb mode. */
-static int
+int
arm_psr_thumb_bit (struct gdbarch *gdbarch)
{
if (gdbarch_tdep (gdbarch)->is_m)
diff --git a/gdb/arm-tdep.h b/gdb/arm-tdep.h
index ef02002..de3f6cc 100644
--- a/gdb/arm-tdep.h
+++ b/gdb/arm-tdep.h
@@ -309,6 +309,9 @@ extern void arm_displaced_step_fixup (struct gdbarch *,
struct displaced_step_closure *,
CORE_ADDR, CORE_ADDR, struct regcache *);
+/* Return the bit mask in ARM_PS_REGNUM that indicates Thumb mode. */
+extern int arm_psr_thumb_bit (struct gdbarch *);
+
/* Is the instruction at the given memory address a Thumb or ARM
instruction? */
extern int arm_pc_is_thumb (struct gdbarch *, CORE_ADDR);