diff options
-rw-r--r-- | gdb/ChangeLog | 10 | ||||
-rw-r--r-- | gdb/arm-linux-tdep.c | 44 | ||||
-rw-r--r-- | gdb/arm-tdep.c | 2 | ||||
-rw-r--r-- | gdb/arm-tdep.h | 3 |
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); |