Index: include/lldb/Symbol/FuncUnwinders.h =================================================================== --- include/lldb/Symbol/FuncUnwinders.h +++ include/lldb/Symbol/FuncUnwinders.h @@ -112,31 +112,32 @@ std::recursive_mutex m_mutex; - lldb::UnwindPlanSP m_unwind_plan_assembly_sp; - lldb::UnwindPlanSP m_unwind_plan_eh_frame_sp; - lldb::UnwindPlanSP m_unwind_plan_debug_frame_sp; + /// A helper class encapsulating the lazy construction of an unwind plan. + class LazyPlan { + lldb::UnwindPlanSP m_plan_sp; + + public: + LazyPlan(); + + /// Return the cached unwind plan or call the provided function to compute + /// it if we don't have a cached plan yet (and then return it). + lldb::UnwindPlanSP Get(llvm::function_ref compute); + }; + + LazyPlan m_unwind_plan_assembly; + LazyPlan m_unwind_plan_eh_frame; + LazyPlan m_unwind_plan_debug_frame; // augmented by assembly inspection so it's valid everywhere - lldb::UnwindPlanSP m_unwind_plan_eh_frame_augmented_sp; - lldb::UnwindPlanSP m_unwind_plan_debug_frame_augmented_sp; - - std::vector m_unwind_plan_compact_unwind; - lldb::UnwindPlanSP m_unwind_plan_arm_unwind_sp; - lldb::UnwindPlanSP m_unwind_plan_symbol_file_sp; - lldb::UnwindPlanSP m_unwind_plan_fast_sp; - lldb::UnwindPlanSP m_unwind_plan_arch_default_sp; - lldb::UnwindPlanSP m_unwind_plan_arch_default_at_func_entry_sp; - - // Fetching the UnwindPlans can be expensive - if we've already attempted to - // get one & failed, don't try again. - bool m_tried_unwind_plan_assembly : 1, m_tried_unwind_plan_eh_frame : 1, - m_tried_unwind_plan_debug_frame : 1, - m_tried_unwind_plan_eh_frame_augmented : 1, - m_tried_unwind_plan_debug_frame_augmented : 1, - m_tried_unwind_plan_compact_unwind : 1, - m_tried_unwind_plan_arm_unwind : 1, m_tried_unwind_plan_symbol_file : 1, - m_tried_unwind_fast : 1, m_tried_unwind_arch_default : 1, - m_tried_unwind_arch_default_at_func_entry : 1; + LazyPlan m_unwind_plan_eh_frame_augmented; + LazyPlan m_unwind_plan_debug_frame_augmented; + + LazyPlan m_unwind_plan_compact_unwind; + LazyPlan m_unwind_plan_arm_unwind; + LazyPlan m_unwind_plan_symbol_file; + LazyPlan m_unwind_plan_fast; + LazyPlan m_unwind_plan_arch_default; + LazyPlan m_unwind_plan_arch_default_at_func_entry; Address m_first_non_prologue_insn; Index: source/Symbol/FuncUnwinders.cpp =================================================================== --- source/Symbol/FuncUnwinders.cpp +++ source/Symbol/FuncUnwinders.cpp @@ -30,25 +30,25 @@ using namespace lldb; using namespace lldb_private; +/// Return a special value meaning the unwind plan hasn't been computed yet. +static lldb::UnwindPlanSP GetUncomputedMarkerValue() { + static auto value_sp = std::make_shared(eRegisterKindGeneric); + return value_sp; +} + +FuncUnwinders::LazyPlan::LazyPlan() : m_plan_sp(GetUncomputedMarkerValue()) {} + +lldb::UnwindPlanSP +FuncUnwinders::LazyPlan::Get(llvm::function_ref compute) { + if (m_plan_sp == GetUncomputedMarkerValue()) + m_plan_sp = compute(); + return m_plan_sp; +} + /// constructor 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_debug_frame(false), - m_tried_unwind_plan_eh_frame_augmented(false), - m_tried_unwind_plan_debug_frame_augmented(false), - m_tried_unwind_plan_compact_unwind(false), - m_tried_unwind_plan_arm_unwind(false), - m_tried_unwind_plan_symbol_file(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() {} + : m_unwind_table(unwind_table), m_range(range) {} /// destructor @@ -71,83 +71,66 @@ UnwindPlanSP FuncUnwinders::GetCompactUnwindUnwindPlan(Target &target) { std::lock_guard guard(m_mutex); - if (m_unwind_plan_compact_unwind.size() > 0) - return m_unwind_plan_compact_unwind[0]; // FIXME support multiple compact - // unwind plans for one func - if (m_tried_unwind_plan_compact_unwind) - return UnwindPlanSP(); - m_tried_unwind_plan_compact_unwind = true; - if (m_range.GetBaseAddress().IsValid()) { - Address current_pc(m_range.GetBaseAddress()); - CompactUnwindInfo *compact_unwind = m_unwind_table.GetCompactUnwindInfo(); - if (compact_unwind) { - UnwindPlanSP unwind_plan_sp(new UnwindPlan(lldb::eRegisterKindGeneric)); - if (compact_unwind->GetUnwindPlan(target, current_pc, *unwind_plan_sp)) { - m_unwind_plan_compact_unwind.push_back(unwind_plan_sp); - return m_unwind_plan_compact_unwind[0]; // FIXME support multiple - // compact unwind plans for one - // func + // FIXME support multiple compact unwind plans for one func + return m_unwind_plan_compact_unwind.Get([&] { + if (m_range.GetBaseAddress().IsValid()) { + Address current_pc(m_range.GetBaseAddress()); + CompactUnwindInfo *compact_unwind = m_unwind_table.GetCompactUnwindInfo(); + if (compact_unwind) { + UnwindPlanSP unwind_plan_sp(new UnwindPlan(lldb::eRegisterKindGeneric)); + if (compact_unwind->GetUnwindPlan(target, current_pc, + *unwind_plan_sp)) { + return unwind_plan_sp; + } } } - } - return UnwindPlanSP(); + return UnwindPlanSP(); + }); } UnwindPlanSP FuncUnwinders::GetEHFrameUnwindPlan(Target &target) { std::lock_guard guard(m_mutex); - if (m_unwind_plan_eh_frame_sp.get() || m_tried_unwind_plan_eh_frame) - return m_unwind_plan_eh_frame_sp; - - m_tried_unwind_plan_eh_frame = true; - if (m_range.GetBaseAddress().IsValid()) { - DWARFCallFrameInfo *eh_frame = m_unwind_table.GetEHFrameInfo(); - if (eh_frame) { - m_unwind_plan_eh_frame_sp = - std::make_shared(lldb::eRegisterKindGeneric); - if (!eh_frame->GetUnwindPlan(m_range, *m_unwind_plan_eh_frame_sp)) - m_unwind_plan_eh_frame_sp.reset(); + return m_unwind_plan_eh_frame.Get([&] { + if (m_range.GetBaseAddress().IsValid()) { + if (DWARFCallFrameInfo *eh_frame = m_unwind_table.GetEHFrameInfo()) { + auto plan_sp = std::make_shared(lldb::eRegisterKindGeneric); + if (eh_frame->GetUnwindPlan(m_range, *plan_sp)) + return plan_sp; + } } - } - return m_unwind_plan_eh_frame_sp; + return UnwindPlanSP(); + }); } UnwindPlanSP FuncUnwinders::GetDebugFrameUnwindPlan(Target &target) { std::lock_guard guard(m_mutex); - if (m_unwind_plan_debug_frame_sp || m_tried_unwind_plan_debug_frame) - return m_unwind_plan_debug_frame_sp; - - m_tried_unwind_plan_debug_frame = true; - if (m_range.GetBaseAddress().IsValid()) { - DWARFCallFrameInfo *debug_frame = m_unwind_table.GetDebugFrameInfo(); - if (debug_frame) { - m_unwind_plan_debug_frame_sp = - std::make_shared(lldb::eRegisterKindGeneric); - if (!debug_frame->GetUnwindPlan(m_range, *m_unwind_plan_debug_frame_sp)) - m_unwind_plan_debug_frame_sp.reset(); + return m_unwind_plan_debug_frame.Get([&] { + if (m_range.GetBaseAddress().IsValid()) { + if (DWARFCallFrameInfo *debug_frame = + m_unwind_table.GetDebugFrameInfo()) { + auto plan_sp = std::make_shared(lldb::eRegisterKindGeneric); + if (debug_frame->GetUnwindPlan(m_range, *plan_sp)) + return plan_sp; + } } - } - return m_unwind_plan_debug_frame_sp; + return UnwindPlanSP(); + }); } UnwindPlanSP FuncUnwinders::GetArmUnwindUnwindPlan(Target &target) { std::lock_guard guard(m_mutex); - if (m_unwind_plan_arm_unwind_sp.get() || m_tried_unwind_plan_arm_unwind) - return m_unwind_plan_arm_unwind_sp; - - m_tried_unwind_plan_arm_unwind = true; - if (m_range.GetBaseAddress().IsValid()) { - Address current_pc(m_range.GetBaseAddress()); - ArmUnwindInfo *arm_unwind_info = m_unwind_table.GetArmUnwindInfo(); - if (arm_unwind_info) { - m_unwind_plan_arm_unwind_sp = - std::make_shared(lldb::eRegisterKindGeneric); - if (!arm_unwind_info->GetUnwindPlan(target, current_pc, - *m_unwind_plan_arm_unwind_sp)) - m_unwind_plan_arm_unwind_sp.reset(); + return m_unwind_plan_arm_unwind.Get([&] { + if (m_range.GetBaseAddress().IsValid()) { + Address current_pc(m_range.GetBaseAddress()); + if (ArmUnwindInfo *arm_unwind_info = m_unwind_table.GetArmUnwindInfo()) { + auto plan_sp = std::make_shared(lldb::eRegisterKindGeneric); + if (arm_unwind_info->GetUnwindPlan(target, current_pc, *plan_sp)) + return plan_sp; + } } - } - return m_unwind_plan_arm_unwind_sp; + return UnwindPlanSP(); + }); } namespace { @@ -170,120 +153,98 @@ UnwindPlanSP FuncUnwinders::GetSymbolFileUnwindPlan(Thread &thread) { std::lock_guard guard(m_mutex); - if (m_unwind_plan_symbol_file_sp.get() || m_tried_unwind_plan_symbol_file) - return m_unwind_plan_symbol_file_sp; - - m_tried_unwind_plan_symbol_file = true; - if (SymbolFile *symfile = m_unwind_table.GetSymbolFile()) { - m_unwind_plan_symbol_file_sp = symfile->GetUnwindPlan( - m_range.GetBaseAddress(), - RegisterContextToInfo(*thread.GetRegisterContext())); - } - return m_unwind_plan_symbol_file_sp; + return m_unwind_plan_symbol_file.Get([&] { + if (SymbolFile *symfile = m_unwind_table.GetSymbolFile()) { + return symfile->GetUnwindPlan( + m_range.GetBaseAddress(), + RegisterContextToInfo(*thread.GetRegisterContext())); + } + return UnwindPlanSP(); + }); } UnwindPlanSP FuncUnwinders::GetEHFrameAugmentedUnwindPlan(Target &target, Thread &thread) { std::lock_guard guard(m_mutex); - if (m_unwind_plan_eh_frame_augmented_sp.get() || - m_tried_unwind_plan_eh_frame_augmented) - return m_unwind_plan_eh_frame_augmented_sp; - - // Only supported on x86 architectures where we get eh_frame from the - // compiler that describes the prologue instructions perfectly, and sometimes - // the epilogue instructions too. - if (target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_32_i386 && - target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64 && - target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h) { - m_tried_unwind_plan_eh_frame_augmented = true; - return m_unwind_plan_eh_frame_augmented_sp; - } - - m_tried_unwind_plan_eh_frame_augmented = true; - - UnwindPlanSP eh_frame_plan = GetEHFrameUnwindPlan(target); - if (!eh_frame_plan) - return m_unwind_plan_eh_frame_augmented_sp; + return m_unwind_plan_eh_frame_augmented.Get([&] { + // Only supported on x86 architectures where we get eh_frame from the + // compiler that describes the prologue instructions perfectly, and + // sometimes the epilogue instructions too. + if (target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_32_i386 && + target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64 && + target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h) { + return UnwindPlanSP(); + } - m_unwind_plan_eh_frame_augmented_sp = - std::make_shared(*eh_frame_plan); + UnwindPlanSP eh_frame_plan = GetEHFrameUnwindPlan(target); + if (!eh_frame_plan) + return UnwindPlanSP(); - // Augment the eh_frame instructions with epilogue descriptions if necessary - // so the UnwindPlan can be used at any instruction in the function. + // Augment the eh_frame instructions with epilogue descriptions if necessary + // so the UnwindPlan can be used at any instruction in the function. - UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target)); - if (assembly_profiler_sp) { - if (!assembly_profiler_sp->AugmentUnwindPlanFromCallSite( - m_range, thread, *m_unwind_plan_eh_frame_augmented_sp)) { - m_unwind_plan_eh_frame_augmented_sp.reset(); + UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target)); + if (assembly_profiler_sp) { + auto plan_sp = std::make_shared(*eh_frame_plan); + if (assembly_profiler_sp->AugmentUnwindPlanFromCallSite(m_range, thread, + *plan_sp)) { + return plan_sp; + } } - } else { - m_unwind_plan_eh_frame_augmented_sp.reset(); - } - return m_unwind_plan_eh_frame_augmented_sp; + return UnwindPlanSP(); + }); } UnwindPlanSP FuncUnwinders::GetDebugFrameAugmentedUnwindPlan(Target &target, Thread &thread) { std::lock_guard guard(m_mutex); - if (m_unwind_plan_debug_frame_augmented_sp.get() || - m_tried_unwind_plan_debug_frame_augmented) - return m_unwind_plan_debug_frame_augmented_sp; - - // Only supported on x86 architectures where we get debug_frame from the - // compiler that describes the prologue instructions perfectly, and sometimes - // the epilogue instructions too. - if (target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_32_i386 && - target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64 && - target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h) { - m_tried_unwind_plan_debug_frame_augmented = true; - return m_unwind_plan_debug_frame_augmented_sp; - } - - m_tried_unwind_plan_debug_frame_augmented = true; - - UnwindPlanSP debug_frame_plan = GetDebugFrameUnwindPlan(target); - if (!debug_frame_plan) - return m_unwind_plan_debug_frame_augmented_sp; + return m_unwind_plan_debug_frame.Get([&] { + // Only supported on x86 architectures where we get debug_frame from the + // compiler that describes the prologue instructions perfectly, and + // sometimes the epilogue instructions too. + if (target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_32_i386 && + target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64 && + target.GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h) { + return UnwindPlanSP(); + } - m_unwind_plan_debug_frame_augmented_sp = - std::make_shared(*debug_frame_plan); + UnwindPlanSP debug_frame_plan = GetDebugFrameUnwindPlan(target); + if (!debug_frame_plan) + return UnwindPlanSP(); - // Augment the debug_frame instructions with epilogue descriptions if - // necessary so the UnwindPlan can be used at any instruction in the - // function. + // Augment the debug_frame instructions with epilogue descriptions if + // necessary so the UnwindPlan can be used at any instruction in the + // function. - UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target)); - if (assembly_profiler_sp) { - if (!assembly_profiler_sp->AugmentUnwindPlanFromCallSite( - m_range, thread, *m_unwind_plan_debug_frame_augmented_sp)) { - m_unwind_plan_debug_frame_augmented_sp.reset(); + UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target)); + if (assembly_profiler_sp) { + auto plan_sp = std::make_shared(*debug_frame_plan); + if (assembly_profiler_sp->AugmentUnwindPlanFromCallSite(m_range, thread, + *plan_sp)) { + return plan_sp; + } } - } else - m_unwind_plan_debug_frame_augmented_sp.reset(); - return m_unwind_plan_debug_frame_augmented_sp; + return UnwindPlanSP(); + }); } UnwindPlanSP FuncUnwinders::GetAssemblyUnwindPlan(Target &target, Thread &thread) { std::lock_guard guard(m_mutex); - if (m_unwind_plan_assembly_sp.get() || m_tried_unwind_plan_assembly || - !m_unwind_table.GetAllowAssemblyEmulationUnwindPlans()) { - return m_unwind_plan_assembly_sp; - } - - m_tried_unwind_plan_assembly = true; - - UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target)); - if (assembly_profiler_sp) { - m_unwind_plan_assembly_sp = - std::make_shared(lldb::eRegisterKindGeneric); - if (!assembly_profiler_sp->GetNonCallSiteUnwindPlanFromAssembly( - m_range, thread, *m_unwind_plan_assembly_sp)) { - m_unwind_plan_assembly_sp.reset(); + return m_unwind_plan_assembly.Get([&] { + if (!m_unwind_table.GetAllowAssemblyEmulationUnwindPlans()) + return UnwindPlanSP(); + + UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target)); + if (assembly_profiler_sp) { + auto plan_sp = std::make_shared(lldb::eRegisterKindGeneric); + if (assembly_profiler_sp->GetNonCallSiteUnwindPlanFromAssembly( + m_range, thread, *plan_sp)) { + return plan_sp; + } } - } - return m_unwind_plan_assembly_sp; + return lldb::UnwindPlanSP(); + }); } // This method compares the pc unwind rule in the first row of two UnwindPlans. @@ -368,70 +329,44 @@ UnwindPlanSP FuncUnwinders::GetUnwindPlanFastUnwind(Target &target, Thread &thread) { std::lock_guard guard(m_mutex); - if (m_unwind_plan_fast_sp.get() || m_tried_unwind_fast) - return m_unwind_plan_fast_sp; - - m_tried_unwind_fast = true; - - UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target)); - if (assembly_profiler_sp) { - m_unwind_plan_fast_sp = - std::make_shared(lldb::eRegisterKindGeneric); - if (!assembly_profiler_sp->GetFastUnwindPlan(m_range, thread, - *m_unwind_plan_fast_sp)) { - m_unwind_plan_fast_sp.reset(); + return m_unwind_plan_fast.Get([&] { + UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target)); + if (assembly_profiler_sp) { + auto plan_sp = std::make_shared(lldb::eRegisterKindGeneric); + if (assembly_profiler_sp->GetFastUnwindPlan(m_range, thread, *plan_sp)) + return plan_sp; } - } - return m_unwind_plan_fast_sp; + return UnwindPlanSP(); + }); } UnwindPlanSP FuncUnwinders::GetUnwindPlanArchitectureDefault(Thread &thread) { std::lock_guard guard(m_mutex); - if (m_unwind_plan_arch_default_sp.get() || m_tried_unwind_arch_default) - return m_unwind_plan_arch_default_sp; - - m_tried_unwind_arch_default = true; - - Address current_pc; - ProcessSP process_sp(thread.CalculateProcess()); - if (process_sp) { - ABI *abi = process_sp->GetABI().get(); - if (abi) { - m_unwind_plan_arch_default_sp = - std::make_shared(lldb::eRegisterKindGeneric); - if (!abi->CreateDefaultUnwindPlan(*m_unwind_plan_arch_default_sp)) { - m_unwind_plan_arch_default_sp.reset(); + return m_unwind_plan_arch_default.Get([&] { + if (ProcessSP process_sp = thread.CalculateProcess()) { + if (ABI *abi = process_sp->GetABI().get()) { + auto plan_sp = std::make_shared(lldb::eRegisterKindGeneric); + if (abi->CreateDefaultUnwindPlan(*plan_sp)) + return plan_sp; } } - } - - return m_unwind_plan_arch_default_sp; + return UnwindPlanSP(); + }); } UnwindPlanSP FuncUnwinders::GetUnwindPlanArchitectureDefaultAtFunctionEntry(Thread &thread) { std::lock_guard guard(m_mutex); - 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; - - m_tried_unwind_arch_default_at_func_entry = true; - - Address current_pc; - ProcessSP process_sp(thread.CalculateProcess()); - if (process_sp) { - ABI *abi = process_sp->GetABI().get(); - if (abi) { - m_unwind_plan_arch_default_at_func_entry_sp = - std::make_shared(lldb::eRegisterKindGeneric); - if (!abi->CreateFunctionEntryUnwindPlan( - *m_unwind_plan_arch_default_at_func_entry_sp)) { - m_unwind_plan_arch_default_at_func_entry_sp.reset(); + return m_unwind_plan_arch_default_at_func_entry.Get([&] { + if (ProcessSP process_sp = thread.CalculateProcess()) { + if (ABI *abi = process_sp->GetABI().get()) { + auto plan_sp = std::make_shared(lldb::eRegisterKindGeneric); + if (abi->CreateFunctionEntryUnwindPlan(*plan_sp)) + return plan_sp; } } - } - - return m_unwind_plan_arch_default_at_func_entry_sp; + return UnwindPlanSP(); + }); } Address &FuncUnwinders::GetFirstNonPrologueInsn(Target &target) {