diff options
Diffstat (limited to 'gdb/dwarf2-frame.c')
-rw-r--r-- | gdb/dwarf2-frame.c | 106 |
1 files changed, 97 insertions, 9 deletions
diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c index cd62529..265383f 100644 --- a/gdb/dwarf2-frame.c +++ b/gdb/dwarf2-frame.c @@ -41,6 +41,7 @@ #include "ax.h" #include "dwarf2loc.h" #include "exceptions.h" +#include "dwarf2-frame-tailcall.h" struct comp_unit; @@ -399,7 +400,11 @@ Not implemented: computing unwound register using explicit value operator")); } -static void +/* Execute FDE program from INSN_PTR possibly up to INSN_END or up to inferior + PC. Modify FS state accordingly. Return current INSN_PTR where the + execution has stopped, one can resume it on the next call. */ + +static const gdb_byte * execute_cfa_program (struct dwarf2_fde *fde, const gdb_byte *insn_ptr, const gdb_byte *insn_end, struct gdbarch *gdbarch, CORE_ADDR pc, struct dwarf2_frame_state *fs) @@ -682,9 +687,14 @@ bad CFI data; mismatched DW_CFA_restore_state at %s"), } } - /* Don't allow remember/restore between CIE and FDE programs. */ - dwarf2_frame_state_free_regs (fs->regs.prev); - fs->regs.prev = NULL; + if (fs->initial.reg == NULL) + { + /* Don't allow remember/restore between CIE and FDE programs. */ + dwarf2_frame_state_free_regs (fs->regs.prev); + fs->regs.prev = NULL; + } + + return insn_ptr; } @@ -976,6 +986,13 @@ struct dwarf2_frame_cache /* The .text offset. */ CORE_ADDR text_offset; + + /* If not NULL then this frame is the bottom frame of a TAILCALL_FRAME + sequence. If NULL then it is a normal case with no TAILCALL_FRAME + involved. Non-bottom frames of a virtual tail call frames chain use + dwarf2_tailcall_frame_unwind unwinder so this field does not apply for + them. */ + void *tailcall_cache; }; static struct dwarf2_frame_cache * @@ -989,6 +1006,10 @@ dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache) struct dwarf2_frame_state *fs; struct dwarf2_fde *fde; volatile struct gdb_exception ex; + CORE_ADDR entry_pc; + LONGEST entry_cfa_sp_offset; + int entry_cfa_sp_offset_p = 0; + const gdb_byte *instr; if (*this_cache) return *this_cache; @@ -1040,8 +1061,25 @@ dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache) fs->initial = fs->regs; fs->initial.reg = dwarf2_frame_state_copy_regs (&fs->regs); + if (get_frame_func_if_available (this_frame, &entry_pc)) + { + /* Decode the insns in the FDE up to the entry PC. */ + instr = execute_cfa_program (fde, fde->instructions, fde->end, gdbarch, + entry_pc, fs); + + if (fs->regs.cfa_how == CFA_REG_OFFSET + && (gdbarch_dwarf2_reg_to_regnum (gdbarch, fs->regs.cfa_reg) + == gdbarch_sp_regnum (gdbarch))) + { + entry_cfa_sp_offset = fs->regs.cfa_offset; + entry_cfa_sp_offset_p = 1; + } + } + else + instr = fde->instructions; + /* Then decode the insns in the FDE up to our target PC. */ - execute_cfa_program (fde, fde->instructions, fde->end, gdbarch, + execute_cfa_program (fde, instr, fde->end, gdbarch, get_frame_pc (this_frame), fs); TRY_CATCH (ex, RETURN_MASK_ERROR) @@ -1182,6 +1220,12 @@ incomplete CFI data; unspecified registers (e.g., %s) at %s"), do_cleanups (old_chain); + /* Try to find a virtual tail call frames chain with bottom (callee) frame + starting at THIS_FRAME. */ + dwarf2_tailcall_sniffer_first (this_frame, &cache->tailcall_cache, + (entry_cfa_sp_offset_p + ? &entry_cfa_sp_offset : NULL)); + return cache; } @@ -1227,6 +1271,22 @@ dwarf2_frame_prev_register (struct frame_info *this_frame, void **this_cache, CORE_ADDR addr; int realnum; + /* Non-bottom frames of a virtual tail call frames chain use + dwarf2_tailcall_frame_unwind unwinder so this code does not apply for + them. If dwarf2_tailcall_prev_register_first does not have specific value + unwind the register, tail call frames are assumed to have the register set + of the top caller. */ + if (cache->tailcall_cache) + { + struct value *val; + + val = dwarf2_tailcall_prev_register_first (this_frame, + &cache->tailcall_cache, + regnum); + if (val) + return val; + } + switch (cache->reg[regnum].how) { case DWARF2_FRAME_REG_UNDEFINED: @@ -1296,6 +1356,18 @@ dwarf2_frame_prev_register (struct frame_info *this_frame, void **this_cache, } } +/* Proxy for tailcall_frame_dealloc_cache for bottom frame of a virtual tail + call frames chain. */ + +static void +dwarf2_frame_dealloc_cache (struct frame_info *self, void *this_cache) +{ + struct dwarf2_frame_cache *cache = dwarf2_frame_cache (self, &this_cache); + + if (cache->tailcall_cache) + dwarf2_tailcall_frame_unwind.dealloc_cache (self, cache->tailcall_cache); +} + static int dwarf2_frame_sniffer (const struct frame_unwind *self, struct frame_info *this_frame, void **this_cache) @@ -1322,7 +1394,14 @@ dwarf2_frame_sniffer (const struct frame_unwind *self, this_frame)) return self->type == SIGTRAMP_FRAME; - return self->type != SIGTRAMP_FRAME; + if (self->type != NORMAL_FRAME) + return 0; + + /* Preinitializa the cache so that TAILCALL_FRAME can find the record by + dwarf2_tailcall_sniffer_first. */ + dwarf2_frame_cache (this_frame, this_cache); + + return 1; } static const struct frame_unwind dwarf2_frame_unwind = @@ -1332,7 +1411,8 @@ static const struct frame_unwind dwarf2_frame_unwind = dwarf2_frame_this_id, dwarf2_frame_prev_register, NULL, - dwarf2_frame_sniffer + dwarf2_frame_sniffer, + dwarf2_frame_dealloc_cache }; static const struct frame_unwind dwarf2_signal_frame_unwind = @@ -1342,7 +1422,10 @@ static const struct frame_unwind dwarf2_signal_frame_unwind = dwarf2_frame_this_id, dwarf2_frame_prev_register, NULL, - dwarf2_frame_sniffer + dwarf2_frame_sniffer, + + /* TAILCALL_CACHE can never be in such frame to need dealloc_cache. */ + NULL }; /* Append the DWARF-2 frame unwinders to GDBARCH's list. */ @@ -1350,6 +1433,10 @@ static const struct frame_unwind dwarf2_signal_frame_unwind = void dwarf2_append_unwinders (struct gdbarch *gdbarch) { + /* TAILCALL_FRAME must be first to find the record by + dwarf2_tailcall_sniffer_first. */ + frame_unwind_append_unwinder (gdbarch, &dwarf2_tailcall_frame_unwind); + frame_unwind_append_unwinder (gdbarch, &dwarf2_frame_unwind); frame_unwind_append_unwinder (gdbarch, &dwarf2_signal_frame_unwind); } @@ -1401,7 +1488,8 @@ dwarf2_frame_cfa (struct frame_info *this_frame) /* This restriction could be lifted if other unwinders are known to compute the frame base in a way compatible with the DWARF unwinder. */ - if (! frame_unwinder_is (this_frame, &dwarf2_frame_unwind)) + if (!frame_unwinder_is (this_frame, &dwarf2_frame_unwind) + && !frame_unwinder_is (this_frame, &dwarf2_tailcall_frame_unwind)) error (_("can't compute CFA for this frame")); return get_frame_base (this_frame); } |