[PATCH 1/3] Skip 'bx reg' trampoline on arm-none-eabi

Yao Qi yao@codesourcery.com
Mon Jun 9 02:15:00 GMT 2014


After this patch
<https://gcc.gnu.org/ml/gcc-patches/2005-01/msg00813.html> applied to
GCC, a new trampoline is generated but GDB doesn't recognize it.  This
patch is to teach GDB to understand this trampoline.  See details
about this trampoline and the heuristics in the comments.

gdb:

2014-06-09  Yao Qi  <yao@codesourcery.com>

	* arm-tdep.c (arm_skip_bx_reg): New function.
	(arm_skip_stub): Call arm_skip_bx_reg.
---
 gdb/arm-tdep.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 67 insertions(+), 1 deletion(-)

diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 74942b1..2430a86 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -9214,6 +9214,64 @@ arm_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
   return 1;
 }
 
+/* Recognize GCC's trampoline for thumb call-indirect.  If we are in a
+   trampoline, return the target PC.  Otherwise return 0.
+
+   void call0a (char c, short s, int i, long l) {}
+
+   int main (void)
+   {
+     (*pointer_to_call0a) (c, s, i, l);
+   }
+
+   Instead of calling a stub library function  _call_via_xx (xx is
+   the register name), GCC may inline the trampoline in the object
+   file as below (register r2 has the address of call0a).
+
+   .global main
+   .type main, %function
+   ...
+   bl .L1
+   ...
+   .size main, .-main
+
+   .L1:
+   bx r2
+
+   The trampoline 'bx r2' doesn't belong to main.  */
+
+static CORE_ADDR
+arm_skip_bx_reg (struct frame_info *frame, CORE_ADDR pc)
+{
+  /* The heuristics of recognizing such trampoline is that FRAME is
+     executing in Thumb mode and the instruction on PC is 'bx Rm'.  */
+  if (arm_frame_is_thumb (frame))
+    {
+      gdb_byte buf[2];
+
+      if (target_read_memory (pc, buf, 2) == 0)
+	{
+	  struct gdbarch *gdbarch = get_frame_arch (frame);
+	  enum bfd_endian byte_order_for_code
+	    = gdbarch_byte_order_for_code (gdbarch);
+	  uint16_t insn
+	    = extract_unsigned_integer (buf, 2, byte_order_for_code);
+
+	  if ((insn & 0xff80) == 0x4700)  /* bx <Rm> */
+	    {
+	      CORE_ADDR dest
+		= get_frame_register_unsigned (frame, bits (insn, 3, 6));
+
+	      /* Clear the LSB so that gdb core sets step-resume
+		 breakpoint at the right address.  */
+	      return UNMAKE_THUMB_ADDR (dest);
+	    }
+	}
+    }
+
+  return 0;
+}
+
 /* Recognize GCC and GNU ld's trampolines.  If we are in a trampoline,
    return the target PC.  Otherwise return 0.  */
 
@@ -9226,7 +9284,15 @@ arm_skip_stub (struct frame_info *frame, CORE_ADDR pc)
 
   /* Find the starting address and name of the function containing the PC.  */
   if (find_pc_partial_function (pc, &name, &start_addr, NULL) == 0)
-    return 0;
+    {
+      /* Trampoline 'bx reg' doesn't belong to any functions.  Do the
+	 check here.  */
+      start_addr = arm_skip_bx_reg (frame, pc);
+      if (start_addr != 0)
+	return start_addr;
+
+      return 0;
+    }
 
   /* If PC is in a Thumb call or return stub, return the address of the
      target PC, which is in a register.  The thunk functions are called
-- 
1.9.0



More information about the Gdb-patches mailing list