This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH] Improve detection of end-of-prologue with no debug info on ppc
- From: Kwok Cheung Yeung <kcy at codesourcery dot com>
- To: <gdb-patches at sourceware dot org>
- Date: Wed, 15 May 2013 19:01:31 +0100
- Subject: [PATCH] Improve detection of end-of-prologue with no debug info on ppc
This patch improves the accuracy of skip_prologue, which is used to skip the
prologue of a function if no debug info is provided. The problem is with code
like this:
10000478 <f>:
void f(int a, int b, int c, int d, int e, int f, int g, int h)
{
10000478: 94 21 ff c0 stwu r1,-64(r1)
1000047c: 93 e1 00 3c stw r31,60(r1)
10000480: 7c 3f 0b 78 mr r31,r1
10000484: 90 7f 00 18 stw r3,24(r31)
10000488: 90 9f 00 1c stw r4,28(r31)
1000048c: 90 bf 00 20 stw r5,32(r31)
10000490: 90 df 00 24 stw r6,36(r31)
10000494: 90 ff 00 28 stw r7,40(r31)
10000498: 91 1f 00 2c stw r8,44(r31)
1000049c: 91 3f 00 30 stw r9,48(r31)
100004a0: 91 5f 00 34 stw r10,52(r31)
int x = 1;
100004a4: 39 20 00 01 li r9,1
100004a8: 91 3f 00 08 stw r9,8(r31)
}
100004ac: 39 7f 00 40 addi r11,r31,64
100004b0: 83 eb ff fc lwz r31,-4(r11)
100004b4: 7d 61 5b 78 mr r1,r11
100004b8: 4e 80 00 20 blr
'break f' sets the breakpoint at 0x100004ac because skip_prologue recognises the
'stw r9,9(r31)' as a prologue instruction that saves a register containing an
incoming argument on the frame stack, when in fact it is actually writing back a
local variable.
This patch improves on this by noting that the prologue will not save the same
argument register twice. store_param_on_stack_p is modified to keep track of the
registers that have been saved on the stack frame so far, and will return 0 if
an instruction that saves an already saved register is given. In doing this I
have tidied up the code by regrouping the checks so that all the integer and
floating-point stores are grouped together.
I also noticed and fixed what appear to be some bugs here. According to the
System V ABI and EABI, f1 is also used during parameter passing, in addition to
f2-f8 which are currently accounted for. Also, the code that checked for saves
of r3-r10 also checked 'stfd' using the range for integer registers (i.e. f3-f10
instead of f1-f8).
Is this code also called for PPC64? If so, the 64-bit ABI states that f1-f13 are
used for parameter passing, and the range will need to be modified accordingly.
Kwok
gdb/ChangeLog:
gdb/
* rs6000-tdep.c (store_param_on_stack_p): Track register assigned
to r0. Track saved registers. Return false if a register has
already been saved. Fix range used for parameters passed in
floating-point registers.
(skip_prologue): Add variables used to keep track of saved
registers and pass to store_param_on_stack_p.
diff -rup src.old/gdb/rs6000-tdep.c src/gdb/rs6000-tdep.c
--- src.old/gdb/rs6000-tdep.c 2013-05-15 15:31:07.732018965 +0100
+++ src/gdb/rs6000-tdep.c 2013-05-15 17:33:17.379026892 +0100
@@ -1177,10 +1177,14 @@ static int max_skip_non_prologue_insns =
/* Return nonzero if the given instruction OP can be part of the prologue
of a function and saves a parameter on the stack. FRAMEP should be
set if one of the previous instructions in the function has set the
- Frame Pointer. */
+ Frame Pointer. If the parameter has already been saved on the stack by
+ a previous prologue instruction, then OP is not considered to be part
+ of the prologue. */
static int
-store_param_on_stack_p (unsigned long op, int framep, int *r0_contains_arg)
+store_param_on_stack_p (unsigned long op, int framep, int *r0_contains_arg,
+ unsigned int *saved_gp_params,
+ unsigned int *saved_fp_params)
{
/* Move parameters from argument registers to temporary register. */
if ((op & 0xfc0007fe) == 0x7c000378) /* mr(.) Rx,Ry */
@@ -1192,7 +1196,7 @@ store_param_on_stack_p (unsigned long op
if (rx_regno == 0 && ry_regno >= 3 && ry_regno <= 10)
{
- *r0_contains_arg = 1;
+ *r0_contains_arg = ry_regno;
return 1;
}
else
@@ -1200,45 +1204,45 @@ store_param_on_stack_p (unsigned long op
}
/* Save a General Purpose Register on stack. */
+ if ((op & 0xfc1f0003) == 0xf8010000 || /* std Rx,NUM(r1) */
+ (framep && (op & 0xfc1f0000) == 0x901f0000) || /* stw Rx,NUM(r31) */
+ (framep && (op & 0xfc1f0000) == 0x981f0000)) /* stb Rx,NUM(r31) */
- if ((op & 0xfc1f0003) == 0xf8010000 || /* std Rx,NUM(r1) */
- (op & 0xfc1f0000) == 0xd8010000) /* stfd Rx,NUM(r1) */
- {
- /* Rx: Only r3 - r10 are used for parameter passing. */
- const int rx_regno = GET_SRC_REG (op);
-
- return (rx_regno >= 3 && rx_regno <= 10);
- }
-
- /* Save a General Purpose Register on stack via the Frame Pointer. */
-
- if (framep &&
- ((op & 0xfc1f0000) == 0x901f0000 || /* st rx,NUM(r31) */
- (op & 0xfc1f0000) == 0x981f0000 || /* stb Rx,NUM(r31) */
- (op & 0xfc1f0000) == 0xd81f0000)) /* stfd Rx,NUM(r31) */
{
/* Rx: Usually, only r3 - r10 are used for parameter passing.
However, the compiler sometimes uses r0 to hold an argument. */
- const int rx_regno = GET_SRC_REG (op);
+ int rx_regno = GET_SRC_REG (op);
- return ((rx_regno >= 3 && rx_regno <= 10)
- || (rx_regno == 0 && *r0_contains_arg));
- }
+ if (rx_regno == 0 && *r0_contains_arg)
+ rx_regno = *r0_contains_arg;
- if ((op & 0xfc1f0000) == 0xfc010000) /* frsp, fp?,NUM(r1) */
- {
- /* Only f2 - f8 are used for parameter passing. */
- const int src_regno = GET_SRC_REG (op);
-
- return (src_regno >= 2 && src_regno <= 8);
+ if (rx_regno >= 3 && rx_regno <= 10 &&
+ !(*saved_gp_params & (1 << rx_regno)))
+ {
+ *saved_gp_params |= 1 << rx_regno;
+ return 1;
+ }
+ else
+ return 0;
}
- if (framep && ((op & 0xfc1f0000) == 0xfc1f0000)) /* frsp, fp?,NUM(r31) */
+ /* Save a Floating Point Register on stack. */
+ if ((op & 0xfc1f0000) == 0xd8010000 || /* stfd Fx,NUM(r1) */
+ (op & 0xfc1f0000) == 0xfc010000 || /* frsp Fx,NUM(r1) */
+ (framep && (op & 0xfc1f0000) == 0xd81f0000) || /* stfd Fx,NUM(r31) */
+ (framep && (op & 0xfc1f0000) == 0xfc1f0000)) /* frsp Fx,NUM(r31) */
{
- /* Only f2 - f8 are used for parameter passing. */
+ /* Only f1 - f8 are used for parameter passing. */
const int src_regno = GET_SRC_REG (op);
- return (src_regno >= 2 && src_regno <= 8);
+ if (src_regno >= 1 && src_regno <= 8 &&
+ !(*saved_fp_params & (1 << src_regno)))
+ {
+ *saved_fp_params |= 1 << src_regno;
+ return 1;
+ }
+ else
+ return 0;
}
/* Not an insn that saves a parameter on stack. */
@@ -1513,6 +1517,8 @@ skip_prologue (struct gdbarch *gdbarch,
int prev_insn_was_prologue_insn = 1;
int num_skip_non_prologue_insns = 0;
int r0_contains_arg = 0;
+ unsigned int saved_gp_params = 0;
+ unsigned int saved_fp_params = 0;
const struct bfd_arch_info *arch_info = gdbarch_bfd_arch_info (gdbarch);
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -1820,7 +1826,9 @@ skip_prologue (struct gdbarch *gdbarch,
/* store parameters in stack */
}
/* Move parameters from argument registers to temporary register. */
- else if (store_param_on_stack_p (op, framep, &r0_contains_arg))
+ else if (store_param_on_stack_p (op, framep, &r0_contains_arg,
+ &saved_gp_params,
+ &saved_fp_params))
{
continue;