This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH] Possible patch to solve PPC multiple mflr issue
- From: Fred Fish <fnf at specifix dot com>
- To: gdb-patches at sources dot redhat dot com
- Cc: fnf at specifix dot com
- Date: Sat, 27 Jan 2007 11:13:04 -0700
- Subject: [PATCH] Possible patch to solve PPC multiple mflr issue
- Reply-to: fnf at specifix dot com
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