Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Daniel Jacobowitz <dan@codesourcery.com>
To: Ulrich Weigand <uweigand@de.ibm.com>
Cc: gdb-patches@sourceware.org, rearnsha@arm.com
Subject: Re: [rfa] Fix software-watchpoint failures by adding epilogue detection
Date: Wed, 22 Sep 2010 20:01:00 -0000	[thread overview]
Message-ID: <20100922193753.GA25020@caradoc.them.org> (raw)
In-Reply-To: <201009221846.o8MIklfl003240@d12av02.megacenter.de.ibm.com>

On Wed, Sep 22, 2010 at 08:46:47PM +0200, Ulrich Weigand wrote:
> Hello,
> 
> I've been seeing failures in software watchpoint tests on ARM (Thumb-2),
> due to missing modeling of precise unwind states during function
> epilogues.  This problem is well known from other architectures,
> and is usually fixed by skipping epilogue during sofware watchpoint
> single-stepping via the gdbarch_in_function_epilogue_p callback.
> 
> However, ARM currently does not define this routine.  The following
> patch adds an implementation that detects common Thumb epilogue
> sequences (ARM is missing, but could be added in an analogous way).

Hi Ulrich,

One of the patches we haven't had a chance to submit took the same
approach to solve these failures.  I also did ARM mode, as well as
some additional sequences - probably those used by RealView.  I've
attached it.

We have at least one other patch related to ARM testsuite failures,
specifically an ERROR (probably infinite backtrace) in gdb1250.exp.
I can extract it for you if you'd like, but I'm not sure it's in
condition to be merged.

I haven't retested this patch against HEAD, but it's in all our
builds.

-- 
Daniel Jacobowitz
CodeSourcery

2010-07-02  Daniel Jacobowitz  <dan@codesourcery.com>

	* arm-tdep.c (thumb_in_function_epilogue_p)
	(arm_in_function_epilogue_p): New.
	(thumb_insn_size): Move higher.
	(arm_gdbarch_init): Install arm_in_function_epilogue_p as
	gdbarch_in_function_epilogue_p callback.

--- /net/henry4/scratch/gcc/src/gdb-mainline/gdb/arm-tdep.c	2010-08-30 10:47:04.000000000 -0700
+++ gdb/arm-tdep.c	2010-09-13 12:32:50.000000000 -0700
@@ -1706,6 +1815,168 @@ arm_dwarf2_frame_init_reg (struct gdbarc
     }
 }
 
+/* Return the size in bytes of the complete Thumb instruction whose
+   first halfword is INST1.  */
+
+static int
+thumb_insn_size (unsigned short inst1)
+{
+  if ((inst1 & 0xe000) == 0xe000 && (inst1 & 0x1800) != 0)
+    return 4;
+  else
+    return 2;
+}
+
+/* Return 1 if the stack frame has already been destroyed by the
+   function epilogue.  */
+
+static int
+thumb_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
+  unsigned int inst1, inst2;
+  int found_return, found_stack_adjust;
+  CORE_ADDR func_start, func_end;
+
+  if (!find_pc_partial_function (pc, NULL, &func_start, &func_end))
+    return 0;
+
+  /* We are in the epilogue if the previous instruction was a stack
+     adjustment and the next instruction is a possible return (bx, mov
+     pc, or pop).  We could have to scan backwards to find the stack
+     adjustment, or forwards to find the return, but this is a decent
+     approximation.  First scan forwards.  */
+
+  found_return = 0;
+  inst1 = read_memory_unsigned_integer (pc, 2, byte_order_for_code);
+
+  if ((inst1 & 0xff00) == 0xbc00 && pc + 2 < func_end)
+    /* POP (without PC).  Potentially loading the return address for BX.  */
+    inst1 = read_memory_unsigned_integer (pc + 2, 2, byte_order_for_code);
+
+  if ((inst1 & 0xff80) == 0x4700)
+    /* BX lr is typically used for returns.  */
+    found_return = 1;
+  else if ((inst1 & 0xff00) == 0xbd00)
+    /* POP, including PC.  */
+    found_return = 1;
+  else if (thumb_insn_size (inst1) == 4)
+    {
+      inst2 = read_memory_unsigned_integer (pc, 2, byte_order_for_code);
+
+      if (inst1 == 0xe8bd && (inst2 & 0x8000) == 0x8000)
+	/* POP.W, including PC.  */
+	found_return = 1;
+      else if (inst1 == 0xf85d && inst2 == 0xfb04)
+	/* POP.W, only PC.  */
+	found_return = 1;
+    }
+
+  if (!found_return)
+    return 0;
+
+  /* Scan backwards.  This is just a heuristic, so do not worry about
+     false positives from mode changes or 16-bit vs 32-bit instructions.  */
+
+  if (pc < func_start + 4)
+    return 0;
+
+  found_stack_adjust = 0;
+  inst1 = read_memory_unsigned_integer (pc - 4, 2, byte_order_for_code);
+  inst2 = read_memory_unsigned_integer (pc - 2, 2, byte_order_for_code);
+  if ((inst2 & 0xff00) == 0xbc00)
+    /* POP (without PC).  */
+    found_stack_adjust = 1;
+  else if (inst1 == 0xe8bd)
+    /* POP.W (register list).  */
+    found_stack_adjust = 1;
+  else if (inst1 == 0xf85d && (inst2 & 0x0fff) == 0x0b04)
+    /* POP.W (one register).  */
+    found_stack_adjust = 1;
+  else if ((inst2 & 0xff00) == 0xb000)
+    /* ADD SP, imm or SUB SP, imm.  */
+    found_stack_adjust = 1;
+
+  /* There are many other stack adjusting instructions which could be
+     recognized here.  */
+
+  if (found_stack_adjust)
+    return 1;
+
+  return 0;
+}
+
+/* Return 1 if the stack frame has already been destroyed by the
+   function epilogue.  */
+
+static int
+arm_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
+  unsigned int insn;
+  int found_return, found_stack_adjust;
+  CORE_ADDR func_start, func_end;
+
+  if (arm_pc_is_thumb (gdbarch, pc))
+    return thumb_in_function_epilogue_p (gdbarch, pc);
+
+  if (!find_pc_partial_function (pc, NULL, &func_start, &func_end))
+    return 0;
+
+  /* We are in the epilogue if the previous instruction was a stack
+     adjustment and the next instruction is a possible return (bx, mov
+     pc, or pop).  We could have to scan backwards to find the stack
+     adjustment, or forwards to find the return, but this is a decent
+     approximation.  First scan forwards.  */
+
+  found_return = 0;
+  insn = read_memory_unsigned_integer (pc, 4, byte_order_for_code);
+  if (bits (insn, 28, 31) != INST_NV)
+    {
+      if ((insn & 0x0ffffff0) == 0x012fff10)
+	/* BX.  */
+	found_return = 1;
+      else if ((insn & 0x0ffffff0) == 0x01a0f000)
+	/* MOV PC.  */
+	found_return = 1;
+      else if ((insn & 0x0fff0000) == 0x08bd0000
+	  && (insn & 0x0000c000) != 0)
+	/* POP (LDMIA), including PC or LR.  */
+	found_return = 1;
+    }
+
+  if (!found_return)
+    return 0;
+
+  /* Scan backwards.  This is just a heuristic, so do not worry about
+     false positives from mode changes.  */
+
+  if (pc < func_start + 4)
+    return 0;
+
+  insn = read_memory_unsigned_integer (pc - 4, 4, byte_order_for_code);
+  if (bits (insn, 28, 31) != INST_NV)
+    {
+      if ((insn & 0x0df0f000) == 0x0080d000)
+	/* ADD SP (register or immediate).  */
+	found_stack_adjust = 1;
+      else if ((insn & 0x0df0f000) == 0x0040d000)
+	/* SUB SP (register or immediate).  */
+	found_stack_adjust = 1;
+      else if ((insn & 0x0ffffff0) == 0x01a0d000)
+	/* MOV SP.  */
+	found_return = 1;
+      else if ((insn & 0x0fff0000) == 0x08bd0000)
+	/* POP (LDMIA).  */
+	found_stack_adjust = 1;
+    }
+
+  if (found_stack_adjust)
+    return 1;
+
+  return 0;
+}
+
 /* When arguments must be pushed onto the stack, they go on in reverse
    order.  The code below implements a FILO (stack) to do this.  */
 
@@ -2647,18 +2918,6 @@ bitcount (unsigned long val)
   return nbits;
 }
 
-/* Return the size in bytes of the complete Thumb instruction whose
-   first halfword is INST1.  */
-
-static int
-thumb_insn_size (unsigned short inst1)
-{
-  if ((inst1 & 0xe000) == 0xe000 && (inst1 & 0x1800) != 0)
-    return 4;
-  else
-    return 2;
-}
-
 static int
 thumb_advance_itstate (unsigned int itstate)
 {
@@ -6881,6 +7160,7 @@ arm_gdbarch_init (struct gdbarch_info in
   /* Advance PC across function entry code.  */
   set_gdbarch_skip_prologue (gdbarch, arm_skip_prologue);
 
+  set_gdbarch_in_function_epilogue_p (gdbarch, arm_in_function_epilogue_p);
   /* Skip trampolines.  */
   set_gdbarch_skip_trampoline_code (gdbarch, arm_skip_stub);
 


  reply	other threads:[~2010-09-22 19:38 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-09-22 19:20 Ulrich Weigand
2010-09-22 20:01 ` Daniel Jacobowitz [this message]
2010-09-23 16:13   ` Ulrich Weigand
2010-09-24 16:11     ` Ulrich Weigand
2010-09-28 20:23       ` Daniel Jacobowitz
2010-09-28 21:47         ` Ulrich Weigand
2010-09-28 21:49           ` Daniel Jacobowitz
2010-09-29 15:24             ` Richard Earnshaw
2010-10-07 16:12             ` [rfa, v3] Fix software-watchpoint failures on ARM " Ulrich Weigand
2010-10-08 13:01               ` Richard Earnshaw
2010-10-08 13:27                 ` Ulrich Weigand
2010-09-29 14:43           ` [rfa] Fix software-watchpoint failures " Yao Qi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20100922193753.GA25020@caradoc.them.org \
    --to=dan@codesourcery.com \
    --cc=gdb-patches@sourceware.org \
    --cc=rearnsha@arm.com \
    --cc=uweigand@de.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox