diff options
author | Andrew Cagney <cagney@redhat.com> | 2003-09-09 03:31:07 +0000 |
---|---|---|
committer | Andrew Cagney <cagney@redhat.com> | 2003-09-09 03:31:07 +0000 |
commit | 3e2c403395e32572a8b6f0ed4cc4f8f73d8040c0 (patch) | |
tree | d018d22ee227b10d77ad4df63ff61f24321536ba /gdb/dwarf2-frame.c | |
parent | 39efb398a9e7bdd98f5f838ab2ea23e758bbddce (diff) | |
download | gdb-3e2c403395e32572a8b6f0ed4cc4f8f73d8040c0.zip gdb-3e2c403395e32572a8b6f0ed4cc4f8f73d8040c0.tar.gz gdb-3e2c403395e32572a8b6f0ed4cc4f8f73d8040c0.tar.bz2 |
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.
Diffstat (limited to 'gdb/dwarf2-frame.c')
-rw-r--r-- | gdb/dwarf2-frame.c | 177 |
1 files changed, 142 insertions, 35 deletions
diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c index c1a79ce..d6b8f26 100644 --- a/gdb/dwarf2-frame.c +++ b/gdb/dwarf2-frame.c @@ -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; - - /* 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; + /* 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; + } + + /* 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; |