This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[rfc v2, arm] Backtrace out of restart handler in vector page


> 	* arm-linux-tdep.c: Include "frame-unwind.h".
> 	(struct arm_linux_stub_cache): New data structure.
> 	(arm_linux_make_stub_cache): New function.
> 	(arm_linux_stub_this_id): Likewise.
> 	(arm_linux_stub_prev_register): Likewise.
> 	(arm_linux_stub_unwind_sniffer): Likewise.
> 	(arm_linux_stub_unwind): New global variable.
> 	(arm_linux_init_abi): Install unwinder.
> 	* arm-tdep.c (arm_psr_thumb_bit): Make global.
> 	* arm-tdep.c (arm_psr_thumb_bit): Add prototype.

I just noticed that this can be simplified quite a bit by using
the tramp-frame mechanism.  In fact, arm-linux-tdep.c *already*
attemps to recognize the system call restart frame in that manner;
this simply fails for two reasons:

- the format of the code stub has changed a while ago when the
  stub was moved from the stack into the vector page

- the existing code doesn't handle Thumb vs. ARM transition

I've rewritten the patch to just fix these two issues, and then
the existing code handles the restart frame just fine.

Re-tested with the same results on armv7l-linux-gnueabi.

Bye,
Ulrich

ChangeLog:

	* 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.


diff -urNp gdb-orig/gdb/arm-linux-tdep.c gdb-head/gdb/arm-linux-tdep.c
--- gdb-orig/gdb/arm-linux-tdep.c	2011-02-02 16:28:10.000000000 +0100
+++ gdb-head/gdb/arm-linux-tdep.c	2011-02-24 16:11:58.000000000 +0100
@@ -239,6 +239,7 @@ static const char arm_linux_thumb2_le_br
    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 st
 				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_rest
   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)
@@ -1008,6 +1046,8 @@ arm_linux_init_abi (struct gdbarch_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 -urNp gdb-orig/gdb/arm-tdep.c gdb-head/gdb/arm-tdep.c
--- gdb-orig/gdb/arm-tdep.c	2011-02-17 14:00:14.000000000 +0100
+++ gdb-head/gdb/arm-tdep.c	2011-02-24 15:49:28.000000000 +0100
@@ -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 -urNp gdb-orig/gdb/arm-tdep.h gdb-head/gdb/arm-tdep.h
--- gdb-orig/gdb/arm-tdep.h	2011-02-09 15:28:26.000000000 +0100
+++ gdb-head/gdb/arm-tdep.h	2011-02-24 15:49:28.000000000 +0100
@@ -310,6 +310,9 @@ extern void arm_displaced_step_fixup (st
 				      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);


-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]