Add a way for an ObjectFile to indicate that assembly emulation
should not be used for this module -- for use when an ObjectFile knows that it does not have meaningful or accurate function start addresses. More commonly, it is not clear that function start addresses are missing in a module. There are certain cases on Mac OS X where we can tell that a Mach-O binary has been stripped of this essential information, and the unwinder can end up emulating many megabytes of instructions for a single "function" in the binary. When a Mach-O binary is missing both an LC_FUNCTION_STARTS load command (very unusual) and an eh_frame section, then we will assume it has also been stripped of symbols and that instruction emulation will not be useful on this module. <rdar://problem/25988067> llvm-svn: 268475
This commit is contained in:
parent
8195f696e4
commit
955dcf2dbc
|
@ -550,6 +550,35 @@ public:
|
|||
virtual lldb_private::UnwindTable&
|
||||
GetUnwindTable () { return m_unwind_table; }
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Returns if the function bounds for symbols in this symbol file
|
||||
/// are likely accurate.
|
||||
///
|
||||
/// The unwinder can emulate the instructions of functions to understand
|
||||
/// prologue/epilogue code sequences, where registers are spilled on
|
||||
/// the stack, etc. This feature relies on having the correct start
|
||||
/// addresses of all functions. If the ObjectFile has a way to tell
|
||||
/// that symbols have been stripped and there's no way to reconstruct
|
||||
/// start addresses (e.g. LC_FUNCTION_STARTS on Mach-O, or eh_frame
|
||||
/// unwind info), the ObjectFile should indicate that assembly emulation
|
||||
/// should not be used for this module.
|
||||
///
|
||||
/// It is uncommon for this to return false. An ObjectFile needs to
|
||||
/// be sure that symbol start addresses are unavailable before false
|
||||
/// is returned. If it is unclear, this should return true.
|
||||
///
|
||||
/// @return
|
||||
/// Returns true if assembly emulation should be used for this
|
||||
/// module.
|
||||
/// Only returns false if the ObjectFile is sure that symbol
|
||||
/// addresses are insufficient for accurate assembly emulation.
|
||||
//------------------------------------------------------------------
|
||||
virtual bool
|
||||
AllowAssemblyEmulationUnwindPlans ()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Similar to Process::GetImageInfoAddress().
|
||||
///
|
||||
|
|
|
@ -40,6 +40,9 @@ public:
|
|||
lldb::FuncUnwindersSP
|
||||
GetFuncUnwindersContainingAddress (const Address& addr, SymbolContext &sc);
|
||||
|
||||
bool
|
||||
GetAllowAssemblyEmulationUnwindPlans ();
|
||||
|
||||
// Normally when we create a new FuncUnwinders object we track it in this UnwindTable so it can
|
||||
// be reused later. But for the target modules show-unwind we want to create brand new
|
||||
// UnwindPlans for the function of interest - so ignore any existing FuncUnwinders for that
|
||||
|
|
|
@ -1130,7 +1130,9 @@ ObjectFileMachO::ObjectFileMachO(const lldb::ModuleSP &module_sp,
|
|||
m_mach_sections(),
|
||||
m_entry_point_address(),
|
||||
m_thread_context_offsets(),
|
||||
m_thread_context_offsets_valid(false)
|
||||
m_thread_context_offsets_valid(false),
|
||||
m_reexported_dylibs (),
|
||||
m_allow_assembly_emulation_unwind_plans (true)
|
||||
{
|
||||
::memset (&m_header, 0, sizeof(m_header));
|
||||
::memset (&m_dysymtab, 0, sizeof(m_dysymtab));
|
||||
|
@ -1145,7 +1147,9 @@ ObjectFileMachO::ObjectFileMachO (const lldb::ModuleSP &module_sp,
|
|||
m_mach_sections(),
|
||||
m_entry_point_address(),
|
||||
m_thread_context_offsets(),
|
||||
m_thread_context_offsets_valid(false)
|
||||
m_thread_context_offsets_valid(false),
|
||||
m_reexported_dylibs (),
|
||||
m_allow_assembly_emulation_unwind_plans (true)
|
||||
{
|
||||
::memset (&m_header, 0, sizeof(m_header));
|
||||
::memset (&m_dysymtab, 0, sizeof(m_dysymtab));
|
||||
|
@ -2603,6 +2607,18 @@ ObjectFileMachO::ParseSymtab ()
|
|||
|
||||
const size_t function_starts_count = function_starts.GetSize();
|
||||
|
||||
if (function_starts_count == 0)
|
||||
{
|
||||
// No LC_FUNCTION_STARTS/eh_frame section in this binary, we're going to assume the binary
|
||||
// has been stripped. Don't allow assembly language instruction emulation because we don't
|
||||
// know proper function start boundaries.
|
||||
m_allow_assembly_emulation_unwind_plans = false;
|
||||
Log *unwind_or_symbol_log (lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_SYMBOLS | LIBLLDB_LOG_UNWIND));
|
||||
|
||||
if (unwind_or_symbol_log)
|
||||
module_sp->LogMessage(unwind_or_symbol_log, "no LC_FUNCTION_STARTS, will not allow assembly profiled unwinds");
|
||||
}
|
||||
|
||||
const user_id_t TEXT_eh_frame_sectID =
|
||||
eh_frame_section_sp.get() ? eh_frame_section_sp->GetID()
|
||||
: static_cast<user_id_t>(NO_SECT);
|
||||
|
@ -5624,6 +5640,12 @@ ObjectFileMachO::GetIsDynamicLinkEditor()
|
|||
return m_header.filetype == llvm::MachO::MH_DYLINKER;
|
||||
}
|
||||
|
||||
bool
|
||||
ObjectFileMachO::AllowAssemblyEmulationUnwindPlans ()
|
||||
{
|
||||
return m_allow_assembly_emulation_unwind_plans;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// PluginInterface protocol
|
||||
//------------------------------------------------------------------
|
||||
|
|
|
@ -176,6 +176,9 @@ public:
|
|||
lldb::offset_t *data_offset_ptr,
|
||||
llvm::MachO::mach_header &header);
|
||||
|
||||
bool
|
||||
AllowAssemblyEmulationUnwindPlans () override;
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// PluginInterface protocol
|
||||
//------------------------------------------------------------------
|
||||
|
@ -247,6 +250,7 @@ protected:
|
|||
FileRangeArray m_thread_context_offsets;
|
||||
bool m_thread_context_offsets_valid;
|
||||
lldb_private::FileSpecList m_reexported_dylibs;
|
||||
bool m_allow_assembly_emulation_unwind_plans;
|
||||
};
|
||||
|
||||
#endif // liblldb_ObjectFileMachO_h_
|
||||
|
|
|
@ -206,8 +206,12 @@ 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);
|
||||
m_tried_unwind_plan_assembly = true;
|
||||
|
|
|
@ -189,3 +189,9 @@ UnwindTable::GetArchitecture (lldb_private::ArchSpec &arch)
|
|||
{
|
||||
return m_object_file.GetArchitecture (arch);
|
||||
}
|
||||
|
||||
bool
|
||||
UnwindTable::GetAllowAssemblyEmulationUnwindPlans ()
|
||||
{
|
||||
return m_object_file.AllowAssemblyEmulationUnwindPlans ();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue