diff options
Diffstat (limited to 'source/Symbol/FuncUnwinders.cpp')
-rw-r--r-- | source/Symbol/FuncUnwinders.cpp | 142 |
1 files changed, 106 insertions, 36 deletions
diff --git a/source/Symbol/FuncUnwinders.cpp b/source/Symbol/FuncUnwinders.cpp index 4c96b1a2bb1b4..2fa41b84cb259 100644 --- a/source/Symbol/FuncUnwinders.cpp +++ b/source/Symbol/FuncUnwinders.cpp @@ -22,6 +22,7 @@ #include "lldb/Target/Thread.h" #include "lldb/Target/Target.h" #include "lldb/Target/UnwindAssembly.h" +#include "lldb/Utility/RegisterNumber.h" using namespace lldb; using namespace lldb_private; @@ -30,27 +31,27 @@ using namespace lldb_private; /// constructor //------------------------------------------------ -FuncUnwinders::FuncUnwinders (UnwindTable& unwind_table, AddressRange range) : - m_unwind_table (unwind_table), - m_range (range), - m_mutex (Mutex::eMutexTypeRecursive), - m_unwind_plan_assembly_sp (), - m_unwind_plan_eh_frame_sp (), - m_unwind_plan_eh_frame_augmented_sp (), - m_unwind_plan_compact_unwind (), - m_unwind_plan_arm_unwind_sp (), - m_unwind_plan_fast_sp (), - m_unwind_plan_arch_default_sp (), - m_unwind_plan_arch_default_at_func_entry_sp (), - m_tried_unwind_plan_assembly (false), - m_tried_unwind_plan_eh_frame (false), - m_tried_unwind_plan_eh_frame_augmented (false), - m_tried_unwind_plan_compact_unwind (false), - m_tried_unwind_plan_arm_unwind (false), - m_tried_unwind_fast (false), - m_tried_unwind_arch_default (false), - m_tried_unwind_arch_default_at_func_entry (false), - m_first_non_prologue_insn () +FuncUnwinders::FuncUnwinders(UnwindTable &unwind_table, AddressRange range) + : m_unwind_table(unwind_table), + m_range(range), + m_mutex(), + m_unwind_plan_assembly_sp(), + m_unwind_plan_eh_frame_sp(), + m_unwind_plan_eh_frame_augmented_sp(), + m_unwind_plan_compact_unwind(), + m_unwind_plan_arm_unwind_sp(), + m_unwind_plan_fast_sp(), + m_unwind_plan_arch_default_sp(), + m_unwind_plan_arch_default_at_func_entry_sp(), + m_tried_unwind_plan_assembly(false), + m_tried_unwind_plan_eh_frame(false), + m_tried_unwind_plan_eh_frame_augmented(false), + m_tried_unwind_plan_compact_unwind(false), + m_tried_unwind_plan_arm_unwind(false), + m_tried_unwind_fast(false), + m_tried_unwind_arch_default(false), + m_tried_unwind_arch_default_at_func_entry(false), + m_first_non_prologue_insn() { } @@ -65,7 +66,7 @@ FuncUnwinders::~FuncUnwinders () UnwindPlanSP FuncUnwinders::GetUnwindPlanAtCallSite (Target &target, int current_offset) { - Mutex::Locker locker (m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); UnwindPlanSP unwind_plan_sp = GetEHFrameUnwindPlan (target, current_offset); if (unwind_plan_sp) @@ -90,7 +91,7 @@ FuncUnwinders::GetCompactUnwindUnwindPlan (Target &target, int current_offset) if (m_tried_unwind_plan_compact_unwind) return UnwindPlanSP(); - Mutex::Locker lock (m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); m_tried_unwind_plan_compact_unwind = true; if (m_range.GetBaseAddress().IsValid()) { @@ -117,7 +118,7 @@ FuncUnwinders::GetEHFrameUnwindPlan (Target &target, int current_offset) if (m_unwind_plan_eh_frame_sp.get() || m_tried_unwind_plan_eh_frame) return m_unwind_plan_eh_frame_sp; - Mutex::Locker lock (m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); m_tried_unwind_plan_eh_frame = true; if (m_range.GetBaseAddress().IsValid()) { @@ -141,7 +142,7 @@ FuncUnwinders::GetArmUnwindUnwindPlan (Target &target, int current_offset) if (m_unwind_plan_arm_unwind_sp.get() || m_tried_unwind_plan_arm_unwind) return m_unwind_plan_arm_unwind_sp; - Mutex::Locker lock (m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); m_tried_unwind_plan_arm_unwind = true; if (m_range.GetBaseAddress().IsValid()) { @@ -175,7 +176,7 @@ FuncUnwinders::GetEHFrameAugmentedUnwindPlan (Target &target, Thread &thread, in return m_unwind_plan_eh_frame_augmented_sp; } - Mutex::Locker lock (m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); m_tried_unwind_plan_eh_frame_augmented = true; UnwindPlanSP eh_frame_plan = GetEHFrameUnwindPlan (target, current_offset); @@ -206,10 +207,14 @@ FuncUnwinders::GetEHFrameAugmentedUnwindPlan (Target &target, Thread &thread, in UnwindPlanSP FuncUnwinders::GetAssemblyUnwindPlan (Target &target, Thread &thread, int current_offset) { - if (m_unwind_plan_assembly_sp.get() || m_tried_unwind_plan_assembly) + if (m_unwind_plan_assembly_sp.get() + || m_tried_unwind_plan_assembly + || m_unwind_table.GetAllowAssemblyEmulationUnwindPlans () == false) + { return m_unwind_plan_assembly_sp; + } - Mutex::Locker lock (m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); m_tried_unwind_plan_assembly = true; UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler(target)); @@ -224,16 +229,81 @@ FuncUnwinders::GetAssemblyUnwindPlan (Target &target, Thread &thread, int curren return m_unwind_plan_assembly_sp; } +// This method compares the pc unwind rule in the first row of two UnwindPlans. +// If they have the same way of getting the pc value (e.g. "CFA - 8" + "CFA is sp"), +// then it will return LazyBoolTrue. +LazyBool +FuncUnwinders::CompareUnwindPlansForIdenticalInitialPCLocation (Thread& thread, const UnwindPlanSP &a, const UnwindPlanSP &b) +{ + LazyBool plans_are_identical = eLazyBoolCalculate; + + RegisterNumber pc_reg (thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + uint32_t pc_reg_lldb_regnum = pc_reg.GetAsKind (eRegisterKindLLDB); + + if (a.get() && b.get()) + { + UnwindPlan::RowSP a_first_row = a->GetRowAtIndex (0); + UnwindPlan::RowSP b_first_row = b->GetRowAtIndex (0); + + if (a_first_row.get() && b_first_row.get()) + { + UnwindPlan::Row::RegisterLocation a_pc_regloc; + UnwindPlan::Row::RegisterLocation b_pc_regloc; + + a_first_row->GetRegisterInfo (pc_reg_lldb_regnum, a_pc_regloc); + b_first_row->GetRegisterInfo (pc_reg_lldb_regnum, b_pc_regloc); + + plans_are_identical = eLazyBoolYes; + + if (a_first_row->GetCFAValue() != b_first_row->GetCFAValue()) + { + plans_are_identical = eLazyBoolNo; + } + if (a_pc_regloc != b_pc_regloc) + { + plans_are_identical = eLazyBoolNo; + } + } + } + return plans_are_identical; +} UnwindPlanSP FuncUnwinders::GetUnwindPlanAtNonCallSite (Target& target, Thread& thread, int current_offset) { - UnwindPlanSP non_call_site_unwindplan_sp = GetEHFrameAugmentedUnwindPlan (target, thread, current_offset); - if (non_call_site_unwindplan_sp.get() == nullptr) + UnwindPlanSP eh_frame_sp = GetEHFrameUnwindPlan (target, current_offset); + UnwindPlanSP arch_default_at_entry_sp = GetUnwindPlanArchitectureDefaultAtFunctionEntry (thread); + UnwindPlanSP arch_default_sp = GetUnwindPlanArchitectureDefault (thread); + UnwindPlanSP assembly_sp = GetAssemblyUnwindPlan (target, thread, current_offset); + + // This point of this code is to detect when a function is using a non-standard ABI, and the eh_frame + // correctly describes that alternate ABI. This is addressing a specific situation on x86_64 linux + // systems where one function in a library pushes a value on the stack and jumps to another function. + // So using an assembly instruction based unwind will not work when you're in the second function - + // the stack has been modified in a non-ABI way. But we have eh_frame that correctly describes how to + // unwind from this location. So we're looking to see if the initial pc register save location from + // the eh_frame is different from the assembly unwind, the arch default unwind, and the arch default at + // initial function entry. + // + // We may have eh_frame that describes the entire function -- or we may have eh_frame that only describes + // the unwind after the prologue has executed -- so we need to check both the arch default (once the prologue + // has executed) and the arch default at initial function entry. And we may be running on a target where + // we have only some of the assembly/arch default unwind plans available. + + if (CompareUnwindPlansForIdenticalInitialPCLocation (thread, eh_frame_sp, arch_default_at_entry_sp) == eLazyBoolNo + && CompareUnwindPlansForIdenticalInitialPCLocation (thread, eh_frame_sp, arch_default_sp) == eLazyBoolNo + && CompareUnwindPlansForIdenticalInitialPCLocation (thread, assembly_sp, arch_default_sp) == eLazyBoolNo) { - non_call_site_unwindplan_sp = GetAssemblyUnwindPlan (target, thread, current_offset); + return eh_frame_sp; } - return non_call_site_unwindplan_sp; + + UnwindPlanSP eh_frame_augmented_sp = GetEHFrameAugmentedUnwindPlan (target, thread, current_offset); + if (eh_frame_augmented_sp) + { + return eh_frame_augmented_sp; + } + + return assembly_sp; } UnwindPlanSP @@ -242,7 +312,7 @@ FuncUnwinders::GetUnwindPlanFastUnwind (Target& target, Thread& thread) if (m_unwind_plan_fast_sp.get() || m_tried_unwind_fast) return m_unwind_plan_fast_sp; - Mutex::Locker locker (m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); m_tried_unwind_fast = true; UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler(target)); @@ -263,7 +333,7 @@ FuncUnwinders::GetUnwindPlanArchitectureDefault (Thread& thread) if (m_unwind_plan_arch_default_sp.get() || m_tried_unwind_arch_default) return m_unwind_plan_arch_default_sp; - Mutex::Locker locker (m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); m_tried_unwind_arch_default = true; Address current_pc; @@ -290,7 +360,7 @@ FuncUnwinders::GetUnwindPlanArchitectureDefaultAtFunctionEntry (Thread& thread) if (m_unwind_plan_arch_default_at_func_entry_sp.get() || m_tried_unwind_arch_default_at_func_entry) return m_unwind_plan_arch_default_at_func_entry_sp; - Mutex::Locker locker (m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); m_tried_unwind_arch_default_at_func_entry = true; Address current_pc; @@ -318,7 +388,7 @@ FuncUnwinders::GetFirstNonPrologueInsn (Target& target) if (m_first_non_prologue_insn.IsValid()) return m_first_non_prologue_insn; - Mutex::Locker locker (m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); ExecutionContext exe_ctx (target.shared_from_this(), false); UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler(target)); if (assembly_profiler_sp) |