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]

[PATCH] Possible patch to solve PPC multiple mflr issue


For the source code fragment:

    void *
    kzalloc (size_t size)
    {
        void *block;
    
        block = alloc_inline(&kernel_heap, size, "kzalloc");
        if (block)
            (void)memset(block, 0, size);
    
        return(block);
    }

A powerpc-eabi toolchain can produce this code when using the
option -fstack-limit-register=r2 :

    kzalloc:
	addi 0,2,24
	mflr 5
	twllt 1,0
	stwu 1,-24(1)
	mflr 0
	stw 29,12(1)
	mr 29,3
	lis 3,kernel_heap@ha
	mr 4,29
	la 3,kernel_heap@l(3)
	stw 31,20(1)
	stw 0,28(1)

Note the first move of the link register to r5.  The skip_prologue
code in rs6000-tdep.c specifically ignores all but the first mflr, so
gdb never detects that the link register was saved on the stack.  This
interferes with gdb's ability to do a proper backtrace.  Older
versions of gdb (like 6.1) actually work around this by assuming that
the link register was saved in it's normal offset relative to the
stack pointer and default to getting it from there.

Attached is the patch I've tested, and it works, but it still has the
potential to fail if there are more than two mflr's, or if one of the
results of a preceding mflr is stored to the stack before the real
save of the link register.

-Fred


2007-01-27  Fred Fish  <fnf@specifix.com>

	* rs6000-tdep.c (skip_prologue): Remove lr_reg and replace with
	lr_reg_0 and lr_reg_1.  Use them to save two potential candidate
	mflr reg numbers and assume first one stored to the stack is the
	real save of the link register.

Index: rs6000-tdep.c
===================================================================
RCS file: /services/cvs/cvsroot/gnusense/gdb/gdb/rs6000-tdep.c,v
retrieving revision 1.1.1.6.4.2
diff -u -p -r1.1.1.6.4.2 rs6000-tdep.c
--- rs6000-tdep.c	2 Nov 2006 06:58:05 -0000	1.1.1.6.4.2
+++ rs6000-tdep.c	27 Jan 2007 17:58:56 -0000
@@ -912,7 +912,8 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR l
   unsigned long op;
   long offset = 0;
   long vr_saved_offset = 0;
-  int lr_reg = -1;
+  int lr_reg_0 = -1;
+  int lr_reg_1 = -1;
   int cr_reg = -1;
   int vr_reg = -1;
   int ev_reg = -1;
@@ -991,9 +992,11 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR l
 
 	     remember just the first one, but skip over additional
 	     ones.  */
-	  if (lr_reg == -1)
-	    lr_reg = (op & 0x03e00000);
-          if (lr_reg == 0)
+	  if (lr_reg_0 == -1)
+	    lr_reg_0 = (op & 0x03e00000);
+	  else if (lr_reg_1 == -1)
+	    lr_reg_1 = (op & 0x03e00000);
+          if ((lr_reg_0 == 0) || (lr_reg_1 == 0))
             r0_contains_arg = 0;
 	  continue;
 	}
@@ -1061,19 +1064,26 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR l
 	  continue;
 
 	}
-      else if (lr_reg >= 0 &&
+      else if ((lr_reg_0 >= 0 &&
 	       /* std Rx, NUM(r1) || stdu Rx, NUM(r1) */
-	       (((op & 0xffff0000) == (lr_reg | 0xf8010000)) ||
+	       (((op & 0xffff0000) == (lr_reg_0 | 0xf8010000)) ||
 		/* stw Rx, NUM(r1) */
-		((op & 0xffff0000) == (lr_reg | 0x90010000)) ||
+		((op & 0xffff0000) == (lr_reg_0 | 0x90010000)) ||
 		/* stwu Rx, NUM(r1) */
-		((op & 0xffff0000) == (lr_reg | 0x94010000))))
+		((op & 0xffff0000) == (lr_reg_0 | 0x94010000)))) ||
+	       (lr_reg_1 >= 0 &&
+	       /* std Rx, NUM(r1) || stdu Rx, NUM(r1) */
+	       (((op & 0xffff0000) == (lr_reg_1 | 0xf8010000)) ||
+		/* stw Rx, NUM(r1) */
+		((op & 0xffff0000) == (lr_reg_1 | 0x90010000)) ||
+		/* stwu Rx, NUM(r1) */
+		((op & 0xffff0000) == (lr_reg_1 | 0x94010000)))))
 	{	/* where Rx == lr */
 	  fdata->lr_offset = offset;
 	  fdata->nosavedpc = 0;
-	  /* Invalidate lr_reg, but don't set it to -1.
-	     That would mean that it had never been set.  */
-	  lr_reg = -2;
+	  /* Invalidate lr_reg values, but don't set them to -1.
+	     That would mean that they had never been set.  */
+	  lr_reg_0 = lr_reg_1 = -2;
 	  if ((op & 0xfc000003) == 0xf8000000 ||	/* std */
 	      (op & 0xfc000000) == 0x90000000)		/* stw */
 	    {
@@ -1104,7 +1114,7 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR l
 	  continue;
 
 	}
-      else if ((op & 0xfe80ffff) == 0x42800005 && lr_reg != -1)
+      else if ((op & 0xfe80ffff) == 0x42800005 && (lr_reg_0 != -1 || lr_reg_1 != -1))
 	{
 	  /* bcl 20,xx,.+4 is used to get the current PC, with or without
 	     prediction bits.  If the LR has already been saved, we can

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