[RFC/RFA/sparc] problem with prologue analyzer

Joel Brobecker brobecker@adacore.com
Fri Nov 26 22:34:00 GMT 2004


Hello,

Using break.exp, we have a function marker2 defined in break1.c as
follow (sic):

        int marker2 (a) int a; { return (1); }  /* set breakpoint 9 here */

Because the entire declaration is on one single line, the function
that skips prologue can not use the line number information from
debugging data (sparc32_skip_prologue()):

  /* This is the preferred method, find the end of the prologue by
     using the debugging information.  */
  if (find_pc_partial_function (start_pc, NULL, &func_start, &func_end))
    {
      sal = find_pc_line (func_start, 0);

      if (sal.end < func_end
          && start_pc <= sal.end)
        return sal.end;
    }

So sparc32_skip_prologue() fallsback to sparc_analyze_prologue().
Unfortunately, this function recognizes the prologue instructions
only up to the "save" instruction. But the prologue of a function
can contain store instructions that home the input registers into
their stack location. This is the case of our function marker2
above:

        (gdb) disass &marker2
        Dump of assembler code for function marker2:
        0x00010aa8 <marker2+0>: save  %sp, -112, %sp
        0x00010aac <marker2+4>: st  %i0, [ %fp + 0x44 ]
        0x00010ab0 <marker2+8>: mov  1, %g1
        0x00010ab4 <marker2+12>:        mov  %g1, %i0
        0x00010ab8 <marker2+16>:        nop 
        0x00010abc <marker2+20>:        ret 
        0x00010ac0 <marker2+24>:        restore 
        End of assembler dump.

A visible consequence of this problem is that GDB will insert
a breakpoint inside marker2 one instruction too earlier, and
hence just before parameter a has been homed. And that causes
the following FAIL in the GDB testsuite:

   (gdb) PASS: gdb.base/break.exp: run until file:function(1) breakpoint
   continue
   Continuing.
   720
   
   Breakpoint 2, 0x00010aac in marker2 (a=720) at break1.c:41
   41      int marker2 (a) int a; { return (1); }  /* set breakpoint 9 here */
   (gdb) FAIL: gdb.base/break.exp: run until quoted breakpoint

The value for parameter a is incorrect, it should be 43.

This test used to pass with 5.3. Doing a bit of archeology, I discovered
that the code analyzing problogues has been heavily rewritten at the end
of 2003, and that the piece of code that handles these store insns got
lost during one large code rewrite.

Assuming this was an accident, I put the code back more or less blindly.
I did exclude the part of the code that recognizes an instruction adding
and offset to sp, as I haven't seen evidences that this is needed, and
removed one if block that could only be executed in that case. But I'd
be happy to put the entire code back, if it is felt more appropriate.

2004-11-26  Joel Brobecker  <brobecker@gnat.com>

        * sparc-tdep.c (sparc_analyze_prologue): Recognize certain store
        instructions following the save instructions as part of the
        prologue.

Tested on sparc-solaris 2.8, with GCC (based on a 3.4.x backend).
Fixes:
  . break.exp: run until quoted breakpoint
    (the case I used to study the problem)
  . funcargs.exp: print *stp

Ok to apply?

Thanks,
-- 
Joel
-------------- next part --------------
Index: sparc-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/sparc-tdep.c,v
retrieving revision 1.157
diff -u -p -r1.157 sparc-tdep.c
--- sparc-tdep.c	23 Nov 2004 18:59:13 -0000	1.157
+++ sparc-tdep.c	26 Nov 2004 22:12:15 -0000
@@ -80,6 +80,7 @@ struct regset;
 #define X_OP2(i) (((i) >> 22) & 0x7)
 #define X_IMM22(i) ((i) & 0x3fffff)
 #define X_OP3(i) (((i) >> 19) & 0x3f)
+#define X_RS1(i) (((i) >> 14) & 0x1f)
 #define X_I(i) (((i) >> 13) & 1)
 /* Sign extension macros.  */
 #define X_DISP22(i) ((X_IMM22 (i) ^ 0x200000) - 0x200000)
@@ -575,7 +576,59 @@ sparc_analyze_prologue (CORE_ADDR pc, CO
   if (X_OP (insn) == 2 && X_OP3 (insn) == 0x3c)
     {
       cache->frameless_p = 0;
-      return pc + offset + 4;
+      offset += 4;
+
+      insn = sparc_fetch_instruction (pc + offset);
+
+      while (1)
+        {
+          /* Recognize stores into the frame from the input registers.
+             This recognizes all non alternate stores of an input register,
+             into a location offset from the frame pointer between
+             +68 and +92.  */
+
+          /* The above will fail for arguments that are promoted 
+             (eg. shorts to ints or floats to doubles), because the compiler
+             will pass them in positive-offset frame space, but the prologue
+             will save them (after conversion) in negative frame space at an
+             unpredictable offset.  Therefore I am going to remove the 
+             restriction on the target-address of the save, on the theory
+             that any unbroken sequence of saves from input registers must
+             be part of the prologue.  In un-optimized code (at least), I'm
+             fairly sure that the compiler would emit SOME other instruction
+             (eg. a move or add) before emitting another save that is actually
+             a part of the function body.
+
+             Besides, the reserved stack space is different for SPARC64 anyway.
+
+             MVS  4/23/2000  */
+
+          if (X_OP (insn) == 3
+              && (X_OP3 (insn) & 0x3c)   == 4   /* Store, non-alternate.  */
+              && (X_RD (insn) & 0x18) == 0x18   /* Input register.  */
+              && X_I (insn)                     /* Immediate mode.  */
+              && X_RS1 (insn) == 30)            /* Off of frame pointer.  */
+            ; /* empty statement -- fall thru to end of loop */
+          else if ((gdbarch_ptr_bit (current_gdbarch) == 64)
+                   && X_OP (insn) == 3
+                   && (X_OP3 (insn) & 0x3c) == 12       /* store, extended (64-bit) */
+                   && (X_RD (insn) & 0x18) == 0x18      /* input register */
+                   && X_I (insn)                        /* immediate mode */
+                   && X_RS1 (insn) == 30)               /* off of frame pointer */
+            ; /* empty statement -- fall thru to end of loop */
+          else if (X_OP (insn) == 3
+                   && (X_OP3 (insn) & 0x3c) == 36       /* store, floating-point */
+                   && X_I (insn)                        /* immediate mode */
+                   && X_RS1 (insn) == 30)               /* off of frame pointer */
+            ; /* empty statement -- fall thru to end of loop */
+          else
+            break;
+
+          offset += 4;
+          insn = sparc_fetch_instruction (pc + offset);
+        }
+
+      return pc + offset;
     }
 
   return pc;


More information about the Gdb-patches mailing list