[3/4] Stop prologue analysis when past the epilogue

Message ID 1404367792-23234-4-git-send-email-yao@codesourcery.com
State New, archived
Headers

Commit Message

Yao Qi July 3, 2014, 6:09 a.m. UTC
  We see a fail in gdb.trace/entry-values.exp on armv4t thumb,

bt^M
#0  0x000086fc in foo (i=0, i@entry=<optimized out>, j=2, j@entry=<optimized out>)^M
#1  0x00000002 in ?? ()^M
Backtrace stopped: previous frame identical to this frame (corrupt stack?)^M
(gdb) FAIL: gdb.trace/entry-values.exp: bt (1) (pattern 1)

The fail is caused by incorrect prologue analysis, which can be illustrated by
setting a breakpoint on function foo,

(gdb) disassemble foo
Dump of assembler code for function foo:
   0x000086e8 <+0>:	push	{r7, lr}
   0x000086ea <+2>:	sub	sp, #8
   0x000086ec <+4>:	add	r7, sp, #0
   0x000086ee <+6>:	str	r0, [r7, #4]
   0x000086f0 <+8>:	str	r1, [r7, #0]
   0x000086f2 <+10>:	movs	r3, #0
   0x000086f4 <+12>:	adds	r0, r3, #0
   0x000086f6 <+14>:	mov	sp, r7
   0x000086f8 <+16>:	add	sp, #8
   0x000086fa <+18>:	pop	{r7}
   0x000086fc <+20>:	pop	{r1}
   0x000086fe <+22>:	bx	r1
End of assembler dump.
(gdb) b foo
Breakpoint 1 at 0x86fc

As we can see, GDB analyzes the prologue and skip the prologue to the last
instruction but one.  The breakpoint is set within the epilogue, and GDB
skips too many instruction for prologue.  This patch teaches GDB to stop
prologue analysis when goes into the epilogue.  With this patch applied,
GDB is able to unwind correctly,

(gdb) bt
#0  0x000086f6 in foo (i=0, i@entry=2, j=2, j@entry=3)
#1  0x00008718 in bar (i=<optimized out>)
#2  0x00008758 in main ()

gdb:

2014-07-02  Yao Qi  <yao@codesourcery.com>

	* arm-tdep.c (thumb_analyze_prologue): Break the loop if
	thumb_instruction_restores_sp return true.
---
 gdb/arm-tdep.c | 5 +++++
 1 file changed, 5 insertions(+)
  

Comments

Will Newton July 3, 2014, 8:39 a.m. UTC | #1
On 3 July 2014 07:09, Yao Qi <yao@codesourcery.com> wrote:
> We see a fail in gdb.trace/entry-values.exp on armv4t thumb,
>
> bt^M
> #0  0x000086fc in foo (i=0, i@entry=<optimized out>, j=2, j@entry=<optimized out>)^M
> #1  0x00000002 in ?? ()^M
> Backtrace stopped: previous frame identical to this frame (corrupt stack?)^M
> (gdb) FAIL: gdb.trace/entry-values.exp: bt (1) (pattern 1)
>
> The fail is caused by incorrect prologue analysis, which can be illustrated by
> setting a breakpoint on function foo,
>
> (gdb) disassemble foo
> Dump of assembler code for function foo:
>    0x000086e8 <+0>:     push    {r7, lr}
>    0x000086ea <+2>:     sub     sp, #8
>    0x000086ec <+4>:     add     r7, sp, #0
>    0x000086ee <+6>:     str     r0, [r7, #4]
>    0x000086f0 <+8>:     str     r1, [r7, #0]
>    0x000086f2 <+10>:    movs    r3, #0
>    0x000086f4 <+12>:    adds    r0, r3, #0
>    0x000086f6 <+14>:    mov     sp, r7
>    0x000086f8 <+16>:    add     sp, #8
>    0x000086fa <+18>:    pop     {r7}
>    0x000086fc <+20>:    pop     {r1}
>    0x000086fe <+22>:    bx      r1
> End of assembler dump.
> (gdb) b foo
> Breakpoint 1 at 0x86fc
>
> As we can see, GDB analyzes the prologue and skip the prologue to the last
> instruction but one.  The breakpoint is set within the epilogue, and GDB
> skips too many instruction for prologue.  This patch teaches GDB to stop
> prologue analysis when goes into the epilogue.  With this patch applied,
> GDB is able to unwind correctly,
>
> (gdb) bt
> #0  0x000086f6 in foo (i=0, i@entry=2, j=2, j@entry=3)
> #1  0x00008718 in bar (i=<optimized out>)
> #2  0x00008758 in main ()
>
> gdb:
>
> 2014-07-02  Yao Qi  <yao@codesourcery.com>
>
>         * arm-tdep.c (thumb_analyze_prologue): Break the loop if
>         thumb_instruction_restores_sp return true.
> ---
>  gdb/arm-tdep.c | 5 +++++
>  1 file changed, 5 insertions(+)

This patch looks good to me too.

> diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
> index 153ef42..72beeb1 100644
> --- a/gdb/arm-tdep.c
> +++ b/gdb/arm-tdep.c
> @@ -754,6 +754,11 @@ thumb_analyze_prologue (struct gdbarch *gdbarch,
>           regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
>                                                  -offset);
>         }
> +      else if (thumb_instruction_restores_sp (insn))
> +       {
> +         /* Don't scan past the epilogue.  */
> +         break;
> +       }
>        else if ((insn & 0xf800) == 0xa800)      /* add Rd, sp, #imm */
>         regs[bits (insn, 8, 10)] = pv_add_constant (regs[ARM_SP_REGNUM],
>                                                     (insn & 0xff) << 2);
> --
> 1.9.0
>
  
Joel Brobecker July 11, 2014, 1:25 p.m. UTC | #2
> 2014-07-02  Yao Qi  <yao@codesourcery.com>
> 
> 	* arm-tdep.c (thumb_analyze_prologue): Break the loop if
> 	thumb_instruction_restores_sp return true.

OK to push.
  

Patch

diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 153ef42..72beeb1 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -754,6 +754,11 @@  thumb_analyze_prologue (struct gdbarch *gdbarch,
 	  regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
 						 -offset);
 	}
+      else if (thumb_instruction_restores_sp (insn))
+	{
+	  /* Don't scan past the epilogue.  */
+	  break;
+	}
       else if ((insn & 0xf800) == 0xa800)	/* add Rd, sp, #imm */
 	regs[bits (insn, 8, 10)] = pv_add_constant (regs[ARM_SP_REGNUM],
 						    (insn & 0xff) << 2);