summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@gnu.org>2003-12-27 23:15:00 +0000
committerMark Kettenis <kettenis@gnu.org>2003-12-27 23:15:00 +0000
commit9b1a720f91d2bbaa9684ca663ec75c380fcde4a9 (patch)
tree68692ac16ea35060976d76ca967803185d325c60
parent42260a8023cfa941407d65eb4cf8001db19c4636 (diff)
downloadgdb-9b1a720f91d2bbaa9684ca663ec75c380fcde4a9.tar.gz
* dwarf2-frame.c (dwarf2_reg_rule): Add REG_RA and REG_CFA.
(dwarf2_frame_cache): Initialize PC_REGNUM with REG_RA and SP_REGNUM with REG_CFA. Don't overwrite the initialized register rule for registers left unspecified by the CFI. Remove the special handling of PC_REGNUM. Add code to eleminate any REG_RA rules. (dwarf2_frame_prev_register): Remove the special handling of SP_REGNUM. Add support for the REG_CFA rule.
-rw-r--r--gdb/ChangeLog11
-rw-r--r--gdb/dwarf2-frame.c187
2 files changed, 90 insertions, 108 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 698ccc923fd..7c6d39cbc23 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,14 @@
+2003-12-27 Mark Kettenis <kettenis@gnu.org>
+
+ * dwarf2-frame.c (dwarf2_reg_rule): Add REG_RA and REG_CFA.
+ (dwarf2_frame_cache): Initialize PC_REGNUM with REG_RA and
+ SP_REGNUM with REG_CFA. Don't overwrite the initialized register
+ rule for registers left unspecified by the CFI. Remove the
+ special handling of PC_REGNUM. Add code to eleminate any REG_RA
+ rules.
+ (dwarf2_frame_prev_register): Remove the special handling of
+ SP_REGNUM. Add support for the REG_CFA rule.
+
2003-12-26 Mark Kettenis <kettenis@gnu.org>
* i386obsd-tdep.c: Include "regset.h", "gdb_assert.h" and
diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c
index aed3f3a10d6..84bc1c2d50c 100644
--- a/gdb/dwarf2-frame.c
+++ b/gdb/dwarf2-frame.c
@@ -105,6 +105,7 @@ enum dwarf2_reg_rule
about a register, leaving how to obtain its value totally
unspecified. */
REG_UNSPECIFIED = 0,
+
/* The term "undefined" comes from the DWARF2 CFI spec which this
code is moddeling; it indicates that the register's value is
"undefined". GCC uses the less formal term "unsaved". Its
@@ -115,7 +116,12 @@ enum dwarf2_reg_rule
REG_SAVED_OFFSET,
REG_SAVED_REG,
REG_SAVED_EXP,
- REG_SAME_VALUE
+ REG_SAME_VALUE,
+
+ /* These aren't defined by the DWARF2 CFI specification, but are
+ used internally by GDB. */
+ REG_RA, /* Return Address. */
+ REG_CFA /* Call Frame Address. */
};
struct dwarf2_frame_state
@@ -547,13 +553,43 @@ dwarf2_frame_cache (struct frame_info *next_frame, void **this_cache)
internal_error (__FILE__, __LINE__, "Unknown CFA rule.");
}
- /* Initialize things so that all registers are marked as
- unspecified. */
+ /* Initialize the register rules. 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 serves as the stack pointer,
+ arrange for it to be filled with the call frame address (CFA).
+ The other registers are marked as unspecified.
+
+ We copy the return address to the program counter, since many
+ parts in GDB assume that it is possible to get the return address
+ by unwind the program counter register. However, on ISA's with a
+ dedicated return address register, the CFI usually only contains
+ information to unwind that return address register.
+
+ The reason we're treating the stack pointer special here is
+ because in many cases GCC doesn't emit CFI for the stack pointer
+ and implicitly assumes that it is equal to the CFA. This makes
+ some sense since the DWARF specification (version 3, draft 8,
+ p. 102) says that:
+
+ "Typically, the CFA is defined to be the value of the stack
+ pointer at the call site in the previous frame (which may be
+ different from its value on entry to the current frame)."
+
+ However, this isn't true for all platforms supported by GCC
+ (e.g. IBM S/390 and zSeries). For those targets we should
+ override the defaults given here. */
{
int regnum;
for (regnum = 0; regnum < num_regs; regnum++)
- cache->reg[regnum].how = REG_UNSPECIFIED;
+ {
+ if (regnum == PC_REGNUM)
+ cache->reg[regnum].how = REG_RA;
+ else if (regnum == SP_REGNUM)
+ cache->reg[regnum].how = REG_CFA;
+ else
+ cache->reg[regnum].how = REG_UNSPECIFIED;
+ }
}
/* Go through the DWARF2 CFI generated table and save its register
@@ -590,35 +626,33 @@ dwarf2_frame_cache (struct frame_info *next_frame, void **this_cache)
complaint (&symfile_complaints,
"Incomplete CFI data; unspecified registers at 0x%s",
paddr (fs->pc));
-
- cache->reg[regnum] = fs->regs.reg[column];
+ else
+ cache->reg[regnum] = fs->regs.reg[column];
}
}
- /* Store the location of the return addess. If the return address
- column (adjusted) is not the same as GDB's PC_REGNUM, then this
- implies a copy from the return address column register. */
- if (fs->retaddr_column < fs->regs.num_regs
- && fs->regs.reg[fs->retaddr_column].how != REG_UNDEFINED)
- {
- /* See comment above about a possibly negative PC_REGNUM. If
- this assertion fails, it's a problem with this code and not
- the architecture. */
- gdb_assert (PC_REGNUM >= 0);
- cache->reg[PC_REGNUM] = fs->regs.reg[fs->retaddr_column];
- }
- else
- {
- if (DWARF2_REG_TO_REGNUM (fs->retaddr_column) != PC_REGNUM)
- {
- /* See comment above about PC_REGNUM being negative. If
- this assertion fails, it's a problem with this code and
- not the architecture. */
- gdb_assert (PC_REGNUM >= 0);
- cache->reg[PC_REGNUM].loc.reg = fs->retaddr_column;
- cache->reg[PC_REGNUM].how = REG_SAVED_REG;
- }
- }
+ /* Eliminate any REG_RA rules. */
+ {
+ int regnum;
+
+ for (regnum = 0; regnum < num_regs; regnum++)
+ {
+ if (cache->reg[regnum].how == REG_RA)
+ {
+ if (fs->retaddr_column < fs->regs.num_regs)
+ cache->reg[regnum] = fs->regs.reg[fs->retaddr_column];
+ else
+ {
+ /* It turns out that GCC assumes that if the return
+ address column is "empty" the return address can be
+ found in the register corresponding to the return
+ address column. */
+ cache->reg[regnum].loc.reg = fs->retaddr_column;
+ cache->reg[regnum].how = REG_SAVED_REG;
+ }
+ }
+ }
+ }
do_cleanups (old_chain);
@@ -654,42 +688,7 @@ dwarf2_frame_prev_register (struct frame_info *next_frame, void **this_cache,
*lvalp = not_lval;
*addrp = 0;
*realnump = -1;
- if (regnum == SP_REGNUM)
- {
- /* GCC defines the CFA as the value of the stack pointer
- just before the call instruction is executed. Do other
- compilers use the same definition? */
- /* DWARF V3 Draft 7 p102: Typically, the CFA is defined to
- be the value of the stack pointer at the call site in the
- previous frame (which may be different from its value on
- entry to the current frame). */
- /* DWARF V3 Draft 7 p103: The first column of the rules
- defines the rule which computes the CFA value; it may be
- either a register and a signed offset that are added
- together or a DWARF expression that is evaluated. */
- /* FIXME: cagney/2003-07-07: I don't understand this. The
- CFI info should have provided unwind information for the
- SP register and then pointed ->cfa_reg at it, not the
- reverse. Assuming that SP_REGNUM isn't negative, there
- is a very real posibility that CFA is an offset from some
- other register, having nothing to do with the unwound SP
- value. */
- /* FIXME: cagney/2003-09-05: I think I understand. GDB was
- lumping the two states "unspecified" and "undefined"
- together. Here SP_REGNUM was "unspecified", GCC assuming
- that in such a case CFA would be used. This branch of
- the if statement should be deleted - the problem of
- SP_REGNUM is now handed by the case REG_UNSPECIFIED
- below. */
- *optimizedp = 0;
- if (valuep)
- {
- /* Store the value. */
- store_typed_address (valuep, builtin_type_void_data_ptr,
- cache->cfa);
- }
- }
- else if (valuep)
+ if (valuep)
{
/* In some cases, for example %eflags on the i386, we have
to provide a sane value, even though this register wasn't
@@ -740,48 +739,8 @@ dwarf2_frame_prev_register (struct frame_info *next_frame, void **this_cache,
"undefined"). Code above issues a complaint about this.
Here just fudge the books, assume GCC, and that the value is
more inner on the stack. */
- if (SP_REGNUM >= 0 && regnum == SP_REGNUM)
- {
- /* Can things get worse? Yep! One of the registers GCC
- forgot to provide unwind information for was the stack
- pointer. Outch! GCC appears to assumes that the CFA
- address can be used - after all it points to the inner
- most address of the previous frame before the function
- call and that's always the same as the stack pointer on
- return, right? Wrong. See GCC's i386 STDCALL option for
- an ABI that has a different entry and return stack
- pointer. */
- /* DWARF V3 Draft 7 p102: Typically, the CFA is defined to
- be the value of the stack pointer at the call site in the
- previous frame (which may be different from its value on
- entry to the current frame). */
- /* DWARF V3 Draft 7 p103: The first column of the rules
- defines the rule which computes the CFA value; it may be
- either a register and a signed offset that are added
- together or a DWARF expression that is evaluated. */
- /* NOTE: cagney/2003-09-05: Should issue a complaint.
- Unfortunately it turns out that DWARF2 CFI has a problem.
- Since CFI specifies the location at which a register was
- saved (not its value) it isn't possible to specify
- something like "unwound(REG) == REG + constant" using CFI
- as will almost always occure with the stack pointer. I
- guess CFI should be point SP at CFA. Ref: danielj,
- "Describing unsaved stack pointers", posted to dwarf2
- list 2003-08-15. */
- *optimizedp = 0;
- *lvalp = not_lval;
- *addrp = 0;
- *realnump = -1;
- if (valuep)
- /* Store the value. */
- store_typed_address (valuep, builtin_type_void_data_ptr,
- cache->cfa);
- }
- else
- /* Assume that the register can be found in the next inner
- most frame. */
- frame_register_unwind (next_frame, regnum,
- optimizedp, lvalp, addrp, realnump, valuep);
+ frame_register_unwind (next_frame, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
break;
case REG_SAME_VALUE:
@@ -789,6 +748,18 @@ dwarf2_frame_prev_register (struct frame_info *next_frame, void **this_cache,
optimizedp, lvalp, addrp, realnump, valuep);
break;
+ case REG_CFA:
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ if (valuep)
+ {
+ /* Store the value. */
+ store_typed_address (valuep, builtin_type_void_data_ptr, cache->cfa);
+ }
+ break;
+
default:
internal_error (__FILE__, __LINE__, "Unknown register rule.");
}