This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH]: Handle sparc skipping unimp instruction with dwarf2
- From: "David S. Miller" <davem at davemloft dot net>
- To: gdb-patches at sources dot redhat dot com
- Date: Tue, 04 Apr 2006 21:55:02 -0700 (PDT)
- Subject: [PATCH]: Handle sparc skipping unimp instruction with dwarf2
This is a followon to my previous posting entitled:
[PATCH]: Setup sparc32 to support dwarf2 unwind sniffer
and this patch is relative to that one.
If you actually enable the dwarf2 unwind sniffer on sparc 32-bit
you'll hit a bunch of regressions in gdb.base/struct.exp, and
the reason is simple. The dwarf2 unwinder doesn't know about the
convention where we should skip the caller's unimp instruction
when returning from a function that returns a structure.
This is very easy to fix with just a little bit of infrastructure
adjustments. What we do is we pass in the fs->pc to the dwarf2 reg
init function. We use this PC to find out if the function we are
analyzing returns a struct or not. If so, we adjust the PC and NPC
by 4.
Sparc64 doesn't have this funny convention so all of this is not
relevant there.
I tested using the dwarf2 unwinder for sparc32 Linux/Sparc and there
are no regressions, and using dwarf2 in fact fixes a few of the
remaining threading testcase failures (there are still some more to
tackle alas :).
Comments?
2006-04-04 David S. Miller <davem@sunset.davemloft.net>
* dwarf2-frame.c (dwarf2_frame_ops init_reg): Add CORE_ADDR "pc"
argument.
(dwarf2_frame_default_init_reg): Likewise.
(dwarf2_frame_set_init_reg): Update init_reg arg.
(dwarf2_frame_init_reg): Take "pc" and pass it to ops->init_reg().
(dwarf2_frame_cache): Pass fs->pc to dwarf2_frame_init_reg.
* dwarf2-frame.h (dwarf2-frame_set_init_reg): Update declaration.
* cris-tdep.c (cris_dwarf2_frame_init_reg): Add "pc" argument.
* s390-tdep.c (s390_dwarf2_frame_init_reg): Likewise.
* sh-tdep.c (sh_dwarf2_frame_init_reg): Likewise.
* sparc64-tdep.c (sparc64_dwarf2_frame_init_reg): Likewise.
* sparc-tdep.c (sparc_dwarf2_frame_init_reg): Likewise, and use
it to determine if the function returns a structure and thus we
have to indicate the return PC and NPC are 4 bytes later than
usual.
--- dwarf2-frame.h.~1~ 2006-02-25 15:04:58.000000000 -0800
+++ dwarf2-frame.h 2006-04-04 21:35:50.000000000 -0700
@@ -79,7 +79,8 @@ struct dwarf2_frame_state_reg
extern void dwarf2_frame_set_init_reg (struct gdbarch *gdbarch,
void (*init_reg) (struct gdbarch *, int,
- struct dwarf2_frame_state_reg *));
+ struct dwarf2_frame_state_reg *,
+ CORE_ADDR));
/* Set the architecture-specific signal trampoline recognition
function for GDBARCH to SIGNAL_FRAME_P. */
--- dwarf2-frame.c.~1~ 2006-02-25 15:04:58.000000000 -0800
+++ dwarf2-frame.c 2006-04-04 21:36:40.000000000 -0700
@@ -506,7 +506,8 @@ static struct gdbarch_data *dwarf2_frame
struct dwarf2_frame_ops
{
/* Pre-initialize the register state REG for register REGNUM. */
- void (*init_reg) (struct gdbarch *, int, struct dwarf2_frame_state_reg *);
+ void (*init_reg) (struct gdbarch *, int, struct dwarf2_frame_state_reg *,
+ CORE_ADDR);
/* Check whether the frame preceding NEXT_FRAME will be a signal
trampoline. */
@@ -518,7 +519,8 @@ struct dwarf2_frame_ops
static void
dwarf2_frame_default_init_reg (struct gdbarch *gdbarch, int regnum,
- struct dwarf2_frame_state_reg *reg)
+ struct dwarf2_frame_state_reg *reg,
+ CORE_ADDR pc)
{
/* If we have a register that acts as a program counter, mark it as
a destination for the return address. If we have a register that
@@ -570,7 +572,8 @@ dwarf2_frame_init (struct obstack *obsta
void
dwarf2_frame_set_init_reg (struct gdbarch *gdbarch,
void (*init_reg) (struct gdbarch *, int,
- struct dwarf2_frame_state_reg *))
+ struct dwarf2_frame_state_reg *,
+ CORE_ADDR))
{
struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data);
@@ -581,11 +584,12 @@ dwarf2_frame_set_init_reg (struct gdbarc
static void
dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
- struct dwarf2_frame_state_reg *reg)
+ struct dwarf2_frame_state_reg *reg,
+ CORE_ADDR pc)
{
struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data);
- ops->init_reg (gdbarch, regnum, reg);
+ ops->init_reg (gdbarch, regnum, reg, pc);
}
/* Set the architecture-specific signal trampoline recognition
@@ -713,7 +717,7 @@ dwarf2_frame_cache (struct frame_info *n
int regnum;
for (regnum = 0; regnum < num_regs; regnum++)
- dwarf2_frame_init_reg (gdbarch, regnum, &cache->reg[regnum]);
+ dwarf2_frame_init_reg (gdbarch, regnum, &cache->reg[regnum], fs->pc);
}
/* Go through the DWARF2 CFI generated table and save its register
--- cris-tdep.c.~1~ 2006-02-25 15:04:58.000000000 -0800
+++ cris-tdep.c 2006-04-04 21:36:50.000000000 -0700
@@ -1852,7 +1852,8 @@ cris_dwarf2_reg_to_regnum (int reg)
static void
cris_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
- struct dwarf2_frame_state_reg *reg)
+ struct dwarf2_frame_state_reg *reg,
+ CORE_ADDR pc)
{
/* The return address column. */
if (regnum == PC_REGNUM)
--- s390-tdep.c.~1~ 2006-02-25 15:05:02.000000000 -0800
+++ s390-tdep.c 2006-04-04 21:36:56.000000000 -0700
@@ -2279,7 +2279,8 @@ s390_unwind_sp (struct gdbarch *gdbarch,
static void
s390_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
- struct dwarf2_frame_state_reg *reg)
+ struct dwarf2_frame_state_reg *reg,
+ CORE_ADDR pc)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
--- sh-tdep.c.~1~ 2006-04-04 14:52:27.000000000 -0700
+++ sh-tdep.c 2006-04-04 21:37:07.000000000 -0700
@@ -2123,7 +2123,8 @@ sh_sh2a_register_sim_regno (int nr)
static void
sh_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
- struct dwarf2_frame_state_reg *reg)
+ struct dwarf2_frame_state_reg *reg,
+ CORE_ADDR pc)
{
/* Mark the PC as the destination for the return address. */
if (regnum == PC_REGNUM)
--- sparc64-tdep.c.~1~ 2006-02-25 15:05:03.000000000 -0800
+++ sparc64-tdep.c 2006-04-04 21:37:16.000000000 -0700
@@ -1106,7 +1106,8 @@ sparc64_return_value (struct gdbarch *gd
static void
sparc64_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
- struct dwarf2_frame_state_reg *reg)
+ struct dwarf2_frame_state_reg *reg,
+ CORE_ADDR pc)
{
switch (regnum)
{
--- sparc-tdep.c.~2~ 2006-04-04 20:19:46.000000000 -0700
+++ sparc-tdep.c 2006-04-04 21:35:29.000000000 -0700
@@ -995,9 +995,33 @@
|| (sparc_floating_p (type) && TYPE_LENGTH (type) == 16));
}
+static int
+sparc32_dwarf2_struct_return_p (CORE_ADDR pc)
+{
+ struct symbol *sym;
+
+ sym = find_pc_function (pc);
+ if (sym)
+ {
+ struct type *type = check_typedef (SYMBOL_TYPE (sym));
+ enum type_code code = TYPE_CODE (type);
+
+ if (code == TYPE_CODE_FUNC || code == TYPE_CODE_METHOD)
+ {
+ type = check_typedef (TYPE_TARGET_TYPE (type));
+ if (sparc_structure_or_union_p (type)
+ || (sparc_floating_p (type) && TYPE_LENGTH (type) == 16))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
static void
sparc32_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
- struct dwarf2_frame_state_reg *reg)
+ struct dwarf2_frame_state_reg *reg,
+ CORE_ADDR pc)
{
switch (regnum)
{
@@ -1012,11 +1036,11 @@
break;
case SPARC32_PC_REGNUM:
reg->how = DWARF2_FRAME_REG_RA_OFFSET;
- reg->loc.offset = 8;
+ reg->loc.offset = (sparc32_dwarf2_struct_return_p (pc) ? 12 : 8);
break;
case SPARC32_NPC_REGNUM:
reg->how = DWARF2_FRAME_REG_RA_OFFSET;
- reg->loc.offset = 12;
+ reg->loc.offset = (sparc32_dwarf2_struct_return_p (pc) ? 16 : 12);
break;
}
}