This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
[RFC] DWARF2 unwinder on SPARC
- From: Mark Kettenis <kettenis at gnu dot org>
- To: gdb-patches at sources dot redhat dot com
- Date: Mon, 7 Mar 2005 22:03:44 +0100 (CET)
- Subject: [RFC] DWARF2 unwinder on SPARC
I'm working on enabling the DWARF2 unwinder on 32-bit and 64-bit
SPARC. It's basically working for me on FreeBSD/sparc64, but there
are two issues that I'd like some opinions about.
1. I'll need to handle DW_CFA_GNU_window_save. I suppose its
interpretation will be really machine specific, but it really only
makes sense for register window architectures. And I can only
think of a single example of such an architecture that's still
around. Now the problem I'm facing is the choice between two
evils:
a. Contaminate dwarf2-frame.c with a bit of target-specific code.
b. Contaminate dwarf2-frame.c with another architecture-specific
operation that will only be used for SPARC.
Can someone make a choice for me ;-)
2. We need a mechanism for return addresses that are not quite the
contents of a register or memory slot. On SPARC, the address of
the call instruction is stored in a register instead of the address
where we should return to. So the proper way to unwind the pc is
to take this register and add 8 to it. There's also npc, which
should be calculated in a similar way by adding 12. We'll need
something similar for PA-RISC and m88k will need it too if it ever
gains a dwarf2 unwinder. There might be more architectures out
there that need this.
My proposal is to change the definition of DWARF2_FRAME_REG_RA such
that the offset member of `struct dwarf2_frame_state_reg' can be
used to specify the amount to add to the value yielded by the
return address column. This is compatible with the existing use
since currently that offset member is initialized to zero. As an
alternative, we can add a new constant DWARF2_FRAME_REG_RA_OFFSET
for this usage.
Attached is my preliminary patch that implements this stuff.
Mark
Index: dwarf2-frame.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2-frame.c,v
retrieving revision 1.48
diff -u -p -r1.48 dwarf2-frame.c
--- dwarf2-frame.c 11 Feb 2005 18:13:49 -0000 1.48
+++ dwarf2-frame.c 7 Mar 2005 21:03:14 -0000
@@ -445,6 +445,20 @@ bad CFI data; mismatched DW_CFA_restore_
/* cfa_how deliberately not set. */
break;
+ case DW_CFA_GNU_window_save:
+ dwarf2_frame_state_alloc_regs (&fs->regs, 32);
+ for (reg = 8; reg < 16; reg++)
+ {
+ fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_REG;
+ fs->regs.reg[reg].loc.reg = reg + 16;
+ }
+ for (reg = 16; reg < 32; reg++)
+ {
+ fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_OFFSET;
+ fs->regs.reg[reg].loc.offset = (reg - 16) * 8;
+ }
+ break;
+
case DW_CFA_GNU_args_size:
/* Ignored. */
insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
@@ -588,6 +602,9 @@ struct dwarf2_frame_cache
/* Saved registers, indexed by GDB register number, not by DWARF
register number. */
struct dwarf2_frame_state_reg *reg;
+
+ /* Return address register. */
+ struct dwarf2_frame_state_reg retaddr_reg;
};
static struct dwarf2_frame_cache *
@@ -733,16 +750,29 @@ incomplete CFI data; unspecified registe
what GCC does on some targets. It turns out that GCC
assumes that the return address can be found in the
register corresponding to the return address column.
- Incidentally, that's how should treat a return address
- column specifying "same value" too. */
+ Incidentally, that's how we should treat a return
+ address column specifying "same value" too. */
if (fs->retaddr_column < fs->regs.num_regs
&& retaddr_reg->how != DWARF2_FRAME_REG_UNSPECIFIED
&& retaddr_reg->how != DWARF2_FRAME_REG_SAME_VALUE)
- cache->reg[regnum] = *retaddr_reg;
+ {
+ if (cache->reg[regnum].loc.offset == 0)
+ cache->reg[regnum] = *retaddr_reg;
+ else
+ cache->retaddr_reg = *retaddr_reg;
+ }
else
{
- cache->reg[regnum].loc.reg = fs->retaddr_column;
- cache->reg[regnum].how = DWARF2_FRAME_REG_SAVED_REG;
+ if (cache->reg[regnum].loc.offset == 0)
+ {
+ cache->reg[regnum].loc.reg = fs->retaddr_column;
+ cache->reg[regnum].how = DWARF2_FRAME_REG_SAVED_REG;
+ }
+ else
+ {
+ cache->retaddr_reg.loc.reg = fs->retaddr_column;
+ cache->retaddr_reg.how = DWARF2_FRAME_REG_SAVED_REG;
+ }
}
}
}
@@ -864,6 +894,21 @@ dwarf2_frame_prev_register (struct frame
}
break;
+ case DWARF2_FRAME_REG_RA:
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ if (valuep)
+ {
+ CORE_ADDR pc = cache->reg[regnum].loc.offset;
+
+ regnum = DWARF2_REG_TO_REGNUM (cache->retaddr_reg.loc.reg);
+ pc += frame_unwind_register_unsigned (next_frame, regnum);
+ store_typed_address (valuep, builtin_type_void_func_ptr, pc);
+ }
+ break;
+
default:
internal_error (__FILE__, __LINE__, _("Unknown register rule."));
}