diff options
author | Jan Kratochvil <jan.kratochvil@redhat.com> | 2011-10-09 19:26:44 +0000 |
---|---|---|
committer | Jan Kratochvil <jan.kratochvil@redhat.com> | 2011-10-09 19:26:44 +0000 |
commit | 111c64899c7b1811c3a04c711f4a0dc95776eecc (patch) | |
tree | ceae0851734071568fa8693459000c13eac48cf1 /gdb/dwarf2-frame.c | |
parent | bb984ff154d9e532deccdb52b3527496852c5930 (diff) | |
download | gdb-111c64899c7b1811c3a04c711f4a0dc95776eecc.zip gdb-111c64899c7b1811c3a04c711f4a0dc95776eecc.tar.gz gdb-111c64899c7b1811c3a04c711f4a0dc95776eecc.tar.bz2 |
gdb/
Recognize virtual tail call frames.
* Makefile.in (SFILES): Add dwarf2-frame-tailcall.c.
(HFILES_NO_SRCDIR): Add dwarf2-frame-tailcall.h.
(COMMON_OBS): Add dwarf2-frame-tailcall.o.
* dwarf2-frame-tailcall.c: New file.
* dwarf2-frame-tailcall.h: New file.
* dwarf2-frame.c: Include dwarf2-frame-tailcall.h.
(execute_cfa_program): New function comment. Return INSN_PTR. Reset
REGS.PREV only after CIE execution.
(struct dwarf2_frame_cache): New field tailcall_cache.
(dwarf2_frame_cache): New variables entry_pc, entry_cfa_sp_offset,
entry_cfa_sp_offset_p and instr. Execute FDE instructions in two
parts, try to find entry_cfa_sp_offset. Call
dwarf2_tailcall_sniffer_first.
(dwarf2_frame_prev_register): Call dwarf2_tailcall_prev_register_first
when appropriate.
(dwarf2_frame_dealloc_cache): New function.
(dwarf2_frame_sniffer): Preinitialize cache by dwarf2_frame_cache.
(dwarf2_frame_unwind): Install dwarf2_frame_dealloc_cache.
(dwarf2_signal_frame_unwind): Do not install dwarf2_frame_dealloc_cache.
(dwarf2_append_unwinders): Add dwarf2_tailcall_frame_unwind.
(dwarf2_frame_cfa): Support also dwarf2_tailcall_frame_unwind.
* dwarf2loc.c (func_addr_to_tail_call_list)
(tailcall_dump, call_sitep, VEC (call_sitep), chain_candidate)
(call_site_find_chain_1, call_site_find_chain): New.
* dwarf2loc.h (struct call_site_chain): New.
(call_site_find_chain): New declaration.
* frame.c (get_frame_address_in_block): Support also TAILCALL_FRAME.
* frame.h (enum frame_type): New entry TAILCALL_FRAME.
* python/py-frame.c (gdbpy_initialize_frames): Add TAILCALL_FRAME.
* stack.c (frame_info): Support also TAILCALL_FRAME.
gdb/doc/
Recognize virtual tail call frames.
* gdb.texinfo (Optimized Code): Add reference to Tail Call Frames.
(Tail Call Frames): New node.
(Frames In Python): Add gdb.TAILCALL_FRAME.
gdb/testsuite/
Recognize virtual tail call frames.
* gdb.arch/amd64-entry-value.cc (c, a, b, amb_z, amb_y, amb_x, amb)
(amb_b, amb_a): New.
(main): Call a and b.
* gdb.arch/amd64-entry-value.exp (tailcall: breakhere, tailcall: bt)
(tailcall: p i, tailcall: p j, set $sp0=$sp, up, p $sp0 == $sp, frame 3)
(p $sp0 + sizeof (void *) == $sp, ambiguous: breakhere, ambiguous: bt):
New tests.
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); } |