2003-09-08 Andrew Cagney <cagney@redhat.com>
* dwarf2-frame.c (enum dwarf2_reg_rule): New, replace anonymous enum. Add REG_UNSPECIFIED, rename REG_UNSAVED to REG_UNDEFINED and REG_UNMODIFIED to REG_SAME_VALUE. (execute_cfa_program): Update. (dwarf2_frame_cache): Update. Initialize table to REG_UNSPECIFIED, complain if CFI fails to specify a register's location. (dwarf2_frame_prev_register): Update. Handle REG_UNSPECIFIED.
This commit is contained in:
parent
39efb398a9
commit
3e2c403395
@ -1,3 +1,14 @@
|
||||
2003-09-08 Andrew Cagney <cagney@redhat.com>
|
||||
|
||||
* dwarf2-frame.c (enum dwarf2_reg_rule): New, replace anonymous
|
||||
enum. Add REG_UNSPECIFIED, rename REG_UNSAVED to REG_UNDEFINED
|
||||
and REG_UNMODIFIED to REG_SAME_VALUE.
|
||||
(execute_cfa_program): Update.
|
||||
(dwarf2_frame_cache): Update. Initialize table to
|
||||
REG_UNSPECIFIED, complain if CFI fails to specify a register's
|
||||
location.
|
||||
(dwarf2_frame_prev_register): Update. Handle REG_UNSPECIFIED.
|
||||
|
||||
2003-09-08 Andrew Cagney <cagney@redhat.com>
|
||||
|
||||
* gnu-nat.c: Remove "inline" function attribute.
|
||||
|
@ -97,6 +97,28 @@ static struct dwarf2_fde *dwarf2_frame_find_fde (CORE_ADDR *pc);
|
||||
|
||||
/* Structure describing a frame state. */
|
||||
|
||||
enum dwarf2_reg_rule
|
||||
{
|
||||
/* Make certain that 0 maps onto the correct enum value - the
|
||||
corresponding structure is being initialized using memset zero.
|
||||
This indicates that CFI didn't provide any information at all
|
||||
about a register - leaving how to obtain it's 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". */
|
||||
/* NOTE: cagney/2003-09-08: GCC uses the less formal term "unsaved"
|
||||
- it's definition is a combination of REG_UNDEFINED and
|
||||
REG_UNSPECIFIED - the failure to differentiate the two helps
|
||||
explain a few problems with the CFI GCC outputs. */
|
||||
REG_UNDEFINED,
|
||||
REG_SAVED_OFFSET,
|
||||
REG_SAVED_REG,
|
||||
REG_SAVED_EXP,
|
||||
REG_SAME_VALUE
|
||||
};
|
||||
|
||||
struct dwarf2_frame_state
|
||||
{
|
||||
/* Each register save state can be described in terms of a CFA slot,
|
||||
@ -111,13 +133,7 @@ struct dwarf2_frame_state
|
||||
unsigned char *exp;
|
||||
} loc;
|
||||
ULONGEST exp_len;
|
||||
enum {
|
||||
REG_UNSAVED,
|
||||
REG_SAVED_OFFSET,
|
||||
REG_SAVED_REG,
|
||||
REG_SAVED_EXP,
|
||||
REG_UNMODIFIED
|
||||
} how;
|
||||
enum dwarf2_reg_rule how;
|
||||
} *reg;
|
||||
int num_regs;
|
||||
|
||||
@ -354,13 +370,13 @@ execute_cfa_program (unsigned char *insn_ptr, unsigned char *insn_end,
|
||||
case DW_CFA_undefined:
|
||||
insn_ptr = read_uleb128 (insn_ptr, insn_end, ®);
|
||||
dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
|
||||
fs->regs.reg[reg].how = REG_UNSAVED;
|
||||
fs->regs.reg[reg].how = REG_UNDEFINED;
|
||||
break;
|
||||
|
||||
case DW_CFA_same_value:
|
||||
insn_ptr = read_uleb128 (insn_ptr, insn_end, ®);
|
||||
dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
|
||||
fs->regs.reg[reg].how = REG_UNMODIFIED;
|
||||
fs->regs.reg[reg].how = REG_SAME_VALUE;
|
||||
break;
|
||||
|
||||
case DW_CFA_register:
|
||||
@ -460,11 +476,10 @@ static struct dwarf2_frame_cache *
|
||||
dwarf2_frame_cache (struct frame_info *next_frame, void **this_cache)
|
||||
{
|
||||
struct cleanup *old_chain;
|
||||
int num_regs = NUM_REGS + NUM_PSEUDO_REGS;
|
||||
const int num_regs = NUM_REGS + NUM_PSEUDO_REGS;
|
||||
struct dwarf2_frame_cache *cache;
|
||||
struct dwarf2_frame_state *fs;
|
||||
struct dwarf2_fde *fde;
|
||||
int reg;
|
||||
|
||||
if (*this_cache)
|
||||
return *this_cache;
|
||||
@ -535,34 +550,65 @@ dwarf2_frame_cache (struct frame_info *next_frame, void **this_cache)
|
||||
internal_error (__FILE__, __LINE__, "Unknown CFA rule.");
|
||||
}
|
||||
|
||||
/* Save the register info in the cache. */
|
||||
for (reg = 0; reg < fs->regs.num_regs; reg++)
|
||||
{
|
||||
int regnum;
|
||||
/* Initialize things so that all registers are marked as
|
||||
unspecified. */
|
||||
{
|
||||
int regnum;
|
||||
for (regnum = 0; regnum < num_regs; regnum++)
|
||||
cache->reg[regnum].how = REG_UNSPECIFIED;
|
||||
}
|
||||
|
||||
/* Skip the return address column. */
|
||||
if (reg == fs->retaddr_column)
|
||||
/* NOTE: cagney/2003-06-07: Is this right? What if the
|
||||
RETADDR_COLUM corresponds to a real register (and, worse,
|
||||
that isn't the PC_REGNUM)? I'm guessing that the PC_REGNUM
|
||||
further down is trying to handle this. That can't be right
|
||||
though - PC_REGNUM may not be valid (it can be -ve). I
|
||||
think, instead when RETADDR_COLUM isn't a real register, it
|
||||
should map itself onto frame_pc_unwind. */
|
||||
continue;
|
||||
/* Go through the DWARF2 CFI generated table and save its register
|
||||
location information in the cache. */
|
||||
{
|
||||
int column; /* CFI speak for "register number". */
|
||||
for (column = 0; column < fs->regs.num_regs; column++)
|
||||
{
|
||||
int regnum;
|
||||
|
||||
/* Skip the return address column. */
|
||||
if (column == fs->retaddr_column)
|
||||
/* NOTE: cagney/2003-06-07: Is this right? What if
|
||||
RETADDR_COLUMN corresponds to a real register (and,
|
||||
worse, that isn't the PC_REGNUM)? I'm guessing that the
|
||||
PC_REGNUM further down is trying to handle this. That
|
||||
can't be right though - PC_REGNUM may not be valid (it
|
||||
can be -ve). I think, instead when RETADDR_COLUM isn't a
|
||||
real register, it should map itself onto frame_pc_unwind. */
|
||||
continue;
|
||||
|
||||
/* Use the GDB register number as index. */
|
||||
regnum = DWARF2_REG_TO_REGNUM (reg);
|
||||
/* Use the GDB register number as the destination index. */
|
||||
regnum = DWARF2_REG_TO_REGNUM (column);
|
||||
|
||||
if (regnum >= 0 && regnum < num_regs)
|
||||
cache->reg[regnum] = fs->regs.reg[reg];
|
||||
}
|
||||
/* If there's no corresponding GDB register, ignore it. */
|
||||
if (regnum < 0 || regnum >= num_regs)
|
||||
continue;
|
||||
|
||||
/* NOTE: cagney/2003-09-05: CFI should specify the disposition
|
||||
of all debug info registers. If it doesn't complain (but
|
||||
not too loudly). It turns out that GCC, assumes that an
|
||||
unspecified register implies "same value" when CFI (draft
|
||||
7) specifies nothing at all. Such a register could equally
|
||||
be interpreted as "undefined". Also note that this check
|
||||
isn't sufficient - it only checks that all registers in the
|
||||
range [0 .. max column] are specified - and won't detect
|
||||
problems when a debug info register falls outside of the
|
||||
table. Need a way of iterating through all the valid
|
||||
DWARF2 register numbers. */
|
||||
if (fs->regs.reg[column].how == REG_UNSPECIFIED)
|
||||
complaint (&symfile_complaints,
|
||||
"Incomplete CFI data; unspecified registers at 0x%s",
|
||||
paddr (fs->pc));
|
||||
|
||||
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 ra column register. */
|
||||
if (fs->retaddr_column < fs->regs.num_regs
|
||||
&& fs->regs.reg[fs->retaddr_column].how != REG_UNSAVED)
|
||||
&& fs->regs.reg[fs->retaddr_column].how != REG_UNDEFINED)
|
||||
{
|
||||
/* See comment above about a possibly -ve PC_REGNUM. If this
|
||||
assertion fails, it's a problem with this code and not the
|
||||
@ -572,7 +618,7 @@ dwarf2_frame_cache (struct frame_info *next_frame, void **this_cache)
|
||||
}
|
||||
else
|
||||
{
|
||||
reg = DWARF2_REG_TO_REGNUM (fs->retaddr_column);
|
||||
int reg = DWARF2_REG_TO_REGNUM (fs->retaddr_column);
|
||||
if (reg != PC_REGNUM)
|
||||
{
|
||||
/* See comment above about PC_REGNUM being -ve. If this
|
||||
@ -611,7 +657,9 @@ dwarf2_frame_prev_register (struct frame_info *next_frame, void **this_cache,
|
||||
|
||||
switch (cache->reg[regnum].how)
|
||||
{
|
||||
case REG_UNSAVED:
|
||||
case REG_UNDEFINED:
|
||||
/* If CFI explicitly specified that the value isn't defined,
|
||||
mark it as optimized away - the value isn't available. */
|
||||
*optimizedp = 1;
|
||||
*lvalp = not_lval;
|
||||
*addrp = 0;
|
||||
@ -636,6 +684,13 @@ dwarf2_frame_prev_register (struct frame_info *next_frame, void **this_cache,
|
||||
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)
|
||||
{
|
||||
@ -687,7 +742,59 @@ dwarf2_frame_prev_register (struct frame_info *next_frame, void **this_cache,
|
||||
}
|
||||
break;
|
||||
|
||||
case REG_UNMODIFIED:
|
||||
case REG_UNSPECIFIED:
|
||||
/* GCC, in its infinite wisdom decided to not provide unwind
|
||||
information for registers that are "same value". Since
|
||||
DWARF2 (3 draft 7) doesn't define such behavior, said
|
||||
registers are actually undefined (which is different to CFI
|
||||
"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 complain.
|
||||
Unfortunatly 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);
|
||||
break;
|
||||
|
||||
case REG_SAME_VALUE:
|
||||
frame_register_unwind (next_frame, regnum,
|
||||
optimizedp, lvalp, addrp, realnump, valuep);
|
||||
break;
|
||||
|
Loading…
x
Reference in New Issue
Block a user