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:
Jason Molenda 2016-05-04 03:09:40 +00:00
parent 8195f696e4
commit 955dcf2dbc
6 changed files with 71 additions and 3 deletions

View File

@ -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().
///

View File

@ -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

View File

@ -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
//------------------------------------------------------------------

View File

@ -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_

View File

@ -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;

View File

@ -189,3 +189,9 @@ UnwindTable::GetArchitecture (lldb_private::ArchSpec &arch)
{
return m_object_file.GetArchitecture (arch);
}
bool
UnwindTable::GetAllowAssemblyEmulationUnwindPlans ()
{
return m_object_file.AllowAssemblyEmulationUnwindPlans ();
}