diff options
author | Ed Maste <emaste@FreeBSD.org> | 2014-02-25 21:42:16 +0000 |
---|---|---|
committer | Ed Maste <emaste@FreeBSD.org> | 2014-02-25 21:42:16 +0000 |
commit | 03b99097822ca3ac69252d9afae716a584ed56c4 (patch) | |
tree | e0f754ea0922908b0f1be8f01c4efbdfc20462eb /source/Plugins/Process/Utility | |
parent | 866dcdacfe59f5f448e008fe2c4cb9dfcf72b2ec (diff) |
Notes
Diffstat (limited to 'source/Plugins/Process/Utility')
-rw-r--r-- | source/Plugins/Process/Utility/RegisterContextLLDB.cpp | 115 | ||||
-rw-r--r-- | source/Plugins/Process/Utility/RegisterContextLLDB.h | 20 | ||||
-rw-r--r-- | source/Plugins/Process/Utility/UnwindLLDB.cpp | 36 |
3 files changed, 119 insertions, 52 deletions
diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp index f87db58107406..f209d538a7129 100644 --- a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -50,6 +50,7 @@ RegisterContextLLDB::RegisterContextLLDB m_thread(thread), m_fast_unwind_plan_sp (), m_full_unwind_plan_sp (), + m_fallback_unwind_plan_sp (), m_all_registers_available(false), m_frame_type (-1), m_cfa (LLDB_INVALID_ADDRESS), @@ -764,8 +765,10 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () { m_fast_unwind_plan_sp.reset(); unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one); - if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc)) + if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc) && unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolYes) + { return unwind_plan_sp; + } } // Ask the DynamicLoader if the eh_frame CFI should be trusted in this frame even when it's frame zero @@ -791,6 +794,15 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread); if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc)) { + if (unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo) + { + // We probably have an UnwindPlan created by inspecting assembly instructions, and we probably + // don't have any eh_frame instructions available. + // The assembly profilers work really well with compiler-generated functions but hand-written + // assembly can be problematic. We'll set the architecture default UnwindPlan as our fallback + // UnwindPlan in case this doesn't work out when we try to unwind. + m_fallback_unwind_plan_sp = arch_default_unwind_plan_sp; + } UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString()); return unwind_plan_sp; } @@ -808,6 +820,16 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () // We'd prefer to use an UnwindPlan intended for call sites when we're at a call site but if we've // struck out on that, fall back to using the non-call-site assembly inspection UnwindPlan if possible. unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread); + if (unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo) + { + // We probably have an UnwindPlan created by inspecting assembly instructions, and we probably + // don't have any eh_frame instructions available. + // The assembly profilers work really well with compiler-generated functions but hand-written + // assembly can be problematic. We'll set the architecture default UnwindPlan as our fallback + // UnwindPlan in case this doesn't work out when we try to unwind. + m_fallback_unwind_plan_sp = arch_default_unwind_plan_sp; + } + if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset)) { UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString()); @@ -1176,21 +1198,22 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat m_full_unwind_plan_sp->GetSourceName().GetCString()); // Throw away the full unwindplan; install the arch default unwindplan - InvalidateFullUnwindPlan(); - - // Now re-fetch the pc value we're searching for - uint32_t arch_default_pc_reg = LLDB_INVALID_REGNUM; - UnwindPlan::RowSP active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); - if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, m_full_unwind_plan_sp->GetRegisterKind(), arch_default_pc_reg) - && arch_default_pc_reg != LLDB_INVALID_REGNUM - && active_row - && active_row->GetRegisterInfo (arch_default_pc_reg, unwindplan_regloc)) + if (TryFallbackUnwindPlan()) { - have_unwindplan_regloc = true; - } - else - { - have_unwindplan_regloc = false; + // Now re-fetch the pc value we're searching for + uint32_t arch_default_pc_reg = LLDB_INVALID_REGNUM; + UnwindPlan::RowSP active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); + if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, m_full_unwind_plan_sp->GetRegisterKind(), arch_default_pc_reg) + && arch_default_pc_reg != LLDB_INVALID_REGNUM + && active_row + && active_row->GetRegisterInfo (arch_default_pc_reg, unwindplan_regloc)) + { + have_unwindplan_regloc = true; + } + else + { + have_unwindplan_regloc = false; + } } } } @@ -1333,54 +1356,48 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat } // If the Full unwindplan has been determined to be incorrect, this method will -// replace it with the architecture's default unwindplna, if one is defined. +// replace it with the architecture's default unwindplan, if one is defined. // It will also find the FuncUnwinders object for this function and replace the // Full unwind method for the function there so we don't use the errant Full unwindplan // again in the future of this debug session. // We're most likely doing this because the Full unwindplan was generated by assembly // instruction profiling and the profiler got something wrong. -void -RegisterContextLLDB::InvalidateFullUnwindPlan () +bool +RegisterContextLLDB::TryFallbackUnwindPlan () { UnwindPlan::Row::RegisterLocation unwindplan_regloc; - ExecutionContext exe_ctx (m_thread.shared_from_this()); - Process *process = exe_ctx.GetProcessPtr(); - ABI *abi = process ? process->GetABI().get() : NULL; - if (abi) + if (m_fallback_unwind_plan_sp.get() == NULL) + return false; + + UnwindPlanSP original_full_unwind_plan_sp = m_full_unwind_plan_sp; + UnwindPlan::RowSP active_row = m_fallback_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); + + if (active_row && active_row->GetCFARegister() != LLDB_INVALID_REGNUM) { - UnwindPlanSP original_full_unwind_plan_sp = m_full_unwind_plan_sp; - UnwindPlanSP arch_default_unwind_plan_sp; - arch_default_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); - abi->CreateDefaultUnwindPlan(*arch_default_unwind_plan_sp); - if (arch_default_unwind_plan_sp) + FuncUnwindersSP func_unwinders_sp; + if (m_sym_ctx_valid && m_current_pc.IsValid() && m_current_pc.GetModule()) { - UnwindPlan::RowSP active_row = arch_default_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); - - if (active_row && active_row->GetCFARegister() != LLDB_INVALID_REGNUM) + func_unwinders_sp = m_current_pc.GetModule()->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx); + if (func_unwinders_sp) { - FuncUnwindersSP func_unwinders_sp; - if (m_sym_ctx_valid && m_current_pc.IsValid() && m_current_pc.GetModule()) - { - func_unwinders_sp = m_current_pc.GetModule()->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx); - if (func_unwinders_sp) - { - func_unwinders_sp->InvalidateNonCallSiteUnwindPlan (m_thread); - } - } - m_registers.clear(); - m_full_unwind_plan_sp = arch_default_unwind_plan_sp; - addr_t cfa_regval = LLDB_INVALID_ADDRESS; - if (ReadGPRValue (arch_default_unwind_plan_sp->GetRegisterKind(), active_row->GetCFARegister(), cfa_regval)) - { - m_cfa = cfa_regval + active_row->GetCFAOffset (); - } - - UnwindLogMsg ("full unwind plan '%s' has been replaced by architecture default unwind plan '%s' for this function from now on.", - original_full_unwind_plan_sp->GetSourceName().GetCString(), arch_default_unwind_plan_sp->GetSourceName().GetCString()); + func_unwinders_sp->InvalidateNonCallSiteUnwindPlan (m_thread); } } + m_registers.clear(); + m_full_unwind_plan_sp = m_fallback_unwind_plan_sp; + addr_t cfa_regval = LLDB_INVALID_ADDRESS; + if (ReadGPRValue (m_fallback_unwind_plan_sp->GetRegisterKind(), active_row->GetCFARegister(), cfa_regval)) + { + m_cfa = cfa_regval + active_row->GetCFAOffset (); + } + + UnwindLogMsg ("full unwind plan '%s' has been replaced by architecture default unwind plan '%s' for this function from now on.", + original_full_unwind_plan_sp->GetSourceName().GetCString(), m_fallback_unwind_plan_sp->GetSourceName().GetCString()); + m_fallback_unwind_plan_sp.reset(); } + + return true; } // Retrieve a general purpose register value for THIS frame, as saved by the NEXT frame, i.e. the frame that diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.h b/source/Plugins/Process/Utility/RegisterContextLLDB.h index bf9dd9a29319d..0a60bfe382b5e 100644 --- a/source/Plugins/Process/Utility/RegisterContextLLDB.h +++ b/source/Plugins/Process/Utility/RegisterContextLLDB.h @@ -160,8 +160,20 @@ private: const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); - void - InvalidateFullUnwindPlan (); + //------------------------------------------------------------------ + /// If the unwind has to the caller frame has failed, try something else + /// + /// If lldb is using an assembly language based UnwindPlan for a frame and + /// the unwind to the caller frame fails, try falling back to a generic + /// UnwindPlan (architecture default unwindplan) to see if that might work + /// better. This is mostly helping to work around problems where the + /// assembly language inspection fails on hand-written assembly code. + /// + /// @return + /// Returns true if a fallback unwindplan was found & was installed. + //------------------------------------------------------------------ + bool + TryFallbackUnwindPlan (); // Get the contents of a general purpose (address-size) register for this frame // (usually retrieved from the next frame) @@ -191,8 +203,10 @@ private: // i.e. where THIS frame saved them /// - lldb::UnwindPlanSP m_fast_unwind_plan_sp; // may be NULL + lldb::UnwindPlanSP m_fast_unwind_plan_sp; // may be NULL lldb::UnwindPlanSP m_full_unwind_plan_sp; + lldb::UnwindPlanSP m_fallback_unwind_plan_sp; // may be NULL + bool m_all_registers_available; // Can we retrieve all regs or just nonvolatile regs? int m_frame_type; // enum FrameType diff --git a/source/Plugins/Process/Utility/UnwindLLDB.cpp b/source/Plugins/Process/Utility/UnwindLLDB.cpp index a3a7002ea099c..5db08e5c26de5 100644 --- a/source/Plugins/Process/Utility/UnwindLLDB.cpp +++ b/source/Plugins/Process/Utility/UnwindLLDB.cpp @@ -158,6 +158,12 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi) if (reg_ctx_sp.get() == NULL) { + // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return + // true. Subsequent calls to TryFallbackUnwindPlan() will return false. + if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) + { + return AddOneMoreFrame (abi); + } if (log) log->Printf ("%*sFrame %d did not get a RegisterContext, stopping.", cur_idx < 100 ? cur_idx : 100, "", cur_idx); @@ -166,6 +172,12 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi) if (!reg_ctx_sp->IsValid()) { + // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return + // true. Subsequent calls to TryFallbackUnwindPlan() will return false. + if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) + { + return AddOneMoreFrame (abi); + } if (log) { log->Printf("%*sFrame %d invalid RegisterContext for this frame, stopping stack walk", @@ -175,6 +187,12 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi) } if (!reg_ctx_sp->GetCFA (cursor_sp->cfa)) { + // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return + // true. Subsequent calls to TryFallbackUnwindPlan() will return false. + if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) + { + return AddOneMoreFrame (abi); + } if (log) { log->Printf("%*sFrame %d did not get CFA for this frame, stopping stack walk", @@ -189,6 +207,12 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi) // these. if (reg_ctx_sp->IsTrapHandlerFrame() == false) { + // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return + // true. Subsequent calls to TryFallbackUnwindPlan() will return false. + if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) + { + return AddOneMoreFrame (abi); + } if (log) { log->Printf("%*sFrame %d did not get a valid CFA for this frame, stopping stack walk", @@ -199,6 +223,12 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi) } if (!reg_ctx_sp->ReadPC (cursor_sp->start_pc)) { + // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return + // true. Subsequent calls to TryFallbackUnwindPlan() will return false. + if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) + { + return AddOneMoreFrame (abi); + } if (log) { log->Printf("%*sFrame %d did not get PC for this frame, stopping stack walk", @@ -208,6 +238,12 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi) } if (abi && !abi->CodeAddressIsValid (cursor_sp->start_pc)) { + // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return + // true. Subsequent calls to TryFallbackUnwindPlan() will return false. + if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) + { + return AddOneMoreFrame (abi); + } if (log) { log->Printf("%*sFrame %d did not get a valid PC, stopping stack walk", |