summaryrefslogtreecommitdiff
path: root/source/Symbol/FuncUnwinders.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Symbol/FuncUnwinders.cpp')
-rw-r--r--source/Symbol/FuncUnwinders.cpp142
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)