Various unwinder work.

Most of the changes are to the FuncUnwinders class -- as we've added
more types of unwind information, the way this class was written was
making it a mess to maintain.  Instead of trying to keep one
"non-call site" unwind plan and one "call site" unwind plan, track
all the different types of unwind plans we can possibly retrieve for
each function and have the call-site/non-call-site accessor methods
retrieve those.

Add a real "fast unwind plan" for x86_64 / i386 -- when doing an
unwind through a function, this only has to read the first 4 bytes 
to tell if the function has a standard prologue sequence.  If so, 
we can use the architecture default unwind plan to backtrace 
through this function.  If we try to retrieve the save location for
other registers later on, a real unwind plan will be used.  This
one is just for doing fast backtraces.

Change the compact unwind plan importer to fill in the valid address
range it is valid for. 

Compact unwind, in theory, may have multiple entries for a single
function.  The FuncUnwinders rewrite includes the start of supporting
this correctly.  In practice compact unwind encodings are used for
the entire range of the function today -- in fact, sometimes the same
encoding is used for multiple functions that have the same unwind
rules.  But I want to handle a single function that has multiple
different compact unwind UnwindPlans eventually.

llvm-svn: 224689
This commit is contained in:
Jason Molenda 2014-12-21 10:44:54 +00:00
parent 23a55f1eee
commit 5c45c541a2
5 changed files with 331 additions and 125 deletions

View File

@ -29,6 +29,11 @@ namespace lldb_private {
// i386/x86_64 for instance. When a function is too complex to be represented in
// the compact unwind format, it calls out to eh_frame unwind instructions.
// On Mac OS X / iOS, a function will have either a compact unwind representation
// or an eh_frame representation. If lldb is going to benefit from the compiler's
// description about saved register locations, it must be able to read both
// sources of information.
class CompactUnwindInfo
{
public:
@ -83,13 +88,17 @@ private:
};
// An internal object used to store the information we retrieve about a function --
// the encoding bits and possibly the LSDA/personality function.
struct FunctionInfo
{
uint32_t encoding; // compact encoding 32-bit value for this function
Address lsda_address; // the address of the LSDA data for this function
Address personality_ptr_address; // the address where the personality routine addr can be found
FunctionInfo () : encoding(0), lsda_address(), personality_ptr_address() { }
uint32_t valid_range_offset_start; // first offset that this encoding is valid for (start of the function)
uint32_t valid_range_offset_end; // the offset of the start of the next function
FunctionInfo () : encoding(0), lsda_address(), personality_ptr_address(), valid_range_offset_start(0), valid_range_offset_end(0) { }
};
struct UnwindHeader
@ -110,10 +119,10 @@ private:
GetCompactUnwindInfoForFunction (Target &target, Address address, FunctionInfo &unwind_info);
lldb::offset_t
BinarySearchRegularSecondPage (uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset);
BinarySearchRegularSecondPage (uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset, uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset);
uint32_t
BinarySearchCompressedSecondPage (uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset_to_find, uint32_t function_offset_base);
BinarySearchCompressedSecondPage (uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset_to_find, uint32_t function_offset_base, uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset);
uint32_t
GetLSDAForFunctionOffset (uint32_t lsda_offset, uint32_t lsda_count, uint32_t function_offset);

View File

@ -1,6 +1,8 @@
#ifndef liblldb_FuncUnwinders_h
#define liblldb_FuncUnwinders_h
#include <vector>
#include "lldb/Core/AddressRange.h"
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/AddressRange.h"
@ -87,25 +89,50 @@ private:
lldb::UnwindAssemblySP
GetUnwindAssemblyProfiler ();
lldb::UnwindPlanSP
GetAssemblyUnwindPlan (Target &target, Thread &thread, int current_offset);
lldb::UnwindPlanSP
GetEHFrameUnwindPlan (Target &target, int current_offset);
lldb::UnwindPlanSP
GetEHFrameAugmentedUnwindPlan (Target &target, Thread &thread, int current_offset);
lldb::UnwindPlanSP
GetCompactUnwindUnwindPlan (Target &target, int current_offset);
lldb::UnwindPlanSP
GetFastUnwindPlan (Target &target, int current_offset);
lldb::UnwindPlanSP
GetArchDefaultUnwindPlan (Target &target, int current_offset);
lldb::UnwindPlanSP
GetArchDefaultAtFuncEntryUnwindPlan (Target &target, int current_offset);
UnwindTable& m_unwind_table;
AddressRange m_range;
Mutex m_mutex;
lldb::UnwindPlanSP m_unwind_plan_call_site_sp;
lldb::UnwindPlanSP m_unwind_plan_non_call_site_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;
lldb::UnwindPlanSP m_unwind_plan_assembly_sp;
lldb::UnwindPlanSP m_unwind_plan_eh_frame_sp;
lldb::UnwindPlanSP m_unwind_plan_eh_frame_augmented_sp; // augmented by assembly inspection so it's valid everywhere
std::vector<lldb::UnwindPlanSP> m_unwind_plan_compact_unwind;
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_at_call_site:1,
m_tried_unwind_at_non_call_site:1,
bool m_tried_unwind_plan_assembly:1,
m_tried_unwind_plan_eh_frame:1,
m_tried_unwind_plan_eh_frame_augmented:1,
m_tried_unwind_plan_compact_unwind:1,
m_tried_unwind_fast:1,
m_tried_unwind_arch_default:1,
m_tried_unwind_arch_default_at_func_entry:1;
Address m_first_non_prologue_insn;
DISALLOW_COPY_AND_ASSIGN (FuncUnwinders);

View File

@ -1259,9 +1259,41 @@ UnwindAssembly_x86::AugmentUnwindPlanFromCallSite (AddressRange& func, Thread& t
bool
UnwindAssembly_x86::GetFastUnwindPlan (AddressRange& func, Thread& thread, UnwindPlan &unwind_plan)
{
ExecutionContext exe_ctx (thread.shared_from_this());
AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func);
return asm_parse.get_fast_unwind_plan (func, unwind_plan);
// if prologue is
// 55 pushl %ebp
// 89 e5 movl %esp, %ebp
// or
// 55 pushq %rbp
// 48 89 e5 movq %rsp, %rbp
// We should pull in the ABI architecture default unwind plan and return that
llvm::SmallVector <uint8_t, 4> opcode_data;
ProcessSP process_sp = thread.GetProcess();
if (process_sp)
{
Target &target (process_sp->GetTarget());
const bool prefer_file_cache = true;
Error error;
if (target.ReadMemory (func.GetBaseAddress (), prefer_file_cache, opcode_data.data(),
4, error) == 4)
{
uint8_t i386_push_mov[] = {0x55, 0x89, 0xe5};
uint8_t x86_64_push_mov[] = {0x55, 0x48, 0x89, 0xe5};
if (memcmp (opcode_data.data(), i386_push_mov, sizeof (i386_push_mov)) == 0
|| memcmp (opcode_data.data(), x86_64_push_mov, sizeof (x86_64_push_mov)) == 0)
{
ABISP abi_sp = process_sp->GetABI();
if (abi_sp)
{
return abi_sp->CreateDefaultUnwindPlan (unwind_plan);
}
}
}
}
return false;
}
bool

View File

@ -17,6 +17,7 @@
#include "lldb/Core/Module.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Symbol/CompactUnwindInfo.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/UnwindPlan.h"
@ -162,6 +163,29 @@ CompactUnwindInfo::GetUnwindPlan (Target &target, Address addr, UnwindPlan& unwi
ArchSpec arch;
if (m_objfile.GetArchitecture (arch))
{
Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
if (log && log->GetVerbose())
{
StreamString strm;
addr.Dump (&strm, NULL, Address::DumpStyle::DumpStyleResolvedDescriptionNoFunctionArguments, Address::DumpStyle::DumpStyleFileAddress, arch.GetAddressByteSize());
log->Printf ("Got compact unwind encoding 0x%x for function %s", function_info.encoding, strm.GetData());
}
if (function_info.valid_range_offset_start != 0 && function_info.valid_range_offset_end != 0)
{
SectionList *sl = m_objfile.GetSectionList ();
if (sl)
{
addr_t func_range_start_file_addr =
function_info.valid_range_offset_start + m_objfile.GetHeaderAddress().GetFileAddress();
AddressRange func_range (func_range_start_file_addr,
function_info.valid_range_offset_end - function_info.valid_range_offset_start,
sl);
unwind_plan.SetPlanValidAddressRange (func_range);
}
}
if (arch.GetTriple().getArch() == llvm::Triple::x86_64)
{
return CreateUnwindPlan_x86_64 (target, function_info, unwind_plan, addr);
@ -202,6 +226,10 @@ CompactUnwindInfo::ScanIndex (const ProcessSP &process_sp)
return;
}
Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
if (log)
m_objfile.GetModule()->LogMessage(log, "Reading compact unwind first-level indexes");
if (m_unwindinfo_data_computed == false)
{
if (m_section_sp->IsEncrypted())
@ -341,7 +369,7 @@ CompactUnwindInfo::GetLSDAForFunctionOffset (uint32_t lsda_offset, uint32_t lsda
}
lldb::offset_t
CompactUnwindInfo::BinarySearchRegularSecondPage (uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset)
CompactUnwindInfo::BinarySearchRegularSecondPage (uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset, uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset)
{
// typedef uint32_t compact_unwind_encoding_t;
// struct unwind_info_regular_second_level_entry
@ -369,6 +397,10 @@ CompactUnwindInfo::BinarySearchRegularSecondPage (uint32_t entry_page_offset, ui
{
if (mid == last || (next_func_offset > function_offset))
{
if (entry_func_start_offset)
*entry_func_start_offset = mid_func_offset;
if (mid != last && entry_func_end_offset)
*entry_func_end_offset = next_func_offset;
return first_entry + (mid * 8);
}
else
@ -385,7 +417,7 @@ CompactUnwindInfo::BinarySearchRegularSecondPage (uint32_t entry_page_offset, ui
}
uint32_t
CompactUnwindInfo::BinarySearchCompressedSecondPage (uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset_to_find, uint32_t function_offset_base)
CompactUnwindInfo::BinarySearchCompressedSecondPage (uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset_to_find, uint32_t function_offset_base, uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset)
{
offset_t first_entry = entry_page_offset;
@ -411,6 +443,10 @@ CompactUnwindInfo::BinarySearchCompressedSecondPage (uint32_t entry_page_offset,
{
if (mid == last || (next_func_offset > function_offset_to_find))
{
if (entry_func_start_offset)
*entry_func_start_offset = mid_func_offset;
if (mid != last && entry_func_end_offset)
*entry_func_end_offset = next_func_offset;
return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX (entry);
}
else
@ -427,7 +463,6 @@ CompactUnwindInfo::BinarySearchCompressedSecondPage (uint32_t entry_page_offset,
return UINT32_MAX;
}
bool
CompactUnwindInfo::GetCompactUnwindInfoForFunction (Target &target, Address address, FunctionInfo &unwind_info)
{
@ -474,6 +509,15 @@ CompactUnwindInfo::GetCompactUnwindInfoForFunction (Target &target, Address addr
return false;
}
auto next_it = it + 1;
if (next_it != m_indexes.begin())
{
// initialize the function offset end range to be the start of the
// next index offset. If we find an entry which is at the end of
// the index table, this will establish the range end.
unwind_info.valid_range_offset_end = next_it->function_offset;
}
offset_t second_page_offset = it->second_level;
offset_t lsda_array_start = it->lsda_array_start;
offset_t lsda_array_count = (it->lsda_array_end - it->lsda_array_start) / 8;
@ -498,7 +542,7 @@ CompactUnwindInfo::GetCompactUnwindInfoForFunction (Target &target, Address addr
uint16_t entry_page_offset = m_unwindinfo_data.GetU16(&offset); // entryPageOffset
uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount
offset_t entry_offset = BinarySearchRegularSecondPage (second_page_offset + entry_page_offset, entry_count, function_offset);
offset_t entry_offset = BinarySearchRegularSecondPage (second_page_offset + entry_page_offset, entry_count, function_offset, &unwind_info.valid_range_offset_start, &unwind_info.valid_range_offset_end);
if (entry_offset == LLDB_INVALID_OFFSET)
{
return false;
@ -556,7 +600,7 @@ CompactUnwindInfo::GetCompactUnwindInfoForFunction (Target &target, Address addr
uint16_t encodings_page_offset = m_unwindinfo_data.GetU16(&offset); // encodingsPageOffset
uint16_t encodings_count = m_unwindinfo_data.GetU16(&offset); // encodingsCount
uint32_t encoding_index = BinarySearchCompressedSecondPage (second_page_offset + entry_page_offset, entry_count, function_offset, it->function_offset);
uint32_t encoding_index = BinarySearchCompressedSecondPage (second_page_offset + entry_page_offset, entry_count, function_offset, it->function_offset, &unwind_info.valid_range_offset_start, &unwind_info.valid_range_offset_end);
if (encoding_index == UINT32_MAX || encoding_index >= encodings_count + m_unwind_header.common_encodings_array_count)
{
return false;
@ -575,7 +619,6 @@ CompactUnwindInfo::GetCompactUnwindInfoForFunction (Target &target, Address addr
}
if (encoding == 0)
return false;
unwind_info.encoding = encoding;
unwind_info.encoding = encoding;
if (unwind_info.encoding & UNWIND_HAS_LSDA)

View File

@ -25,17 +25,25 @@
using namespace lldb;
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_call_site_sp (),
m_unwind_plan_non_call_site_sp (),
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_fast_sp (),
m_unwind_plan_arch_default_sp (),
m_tried_unwind_at_call_site (false),
m_tried_unwind_at_non_call_site (false),
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_fast (false),
m_tried_unwind_arch_default (false),
m_tried_unwind_arch_default_at_func_entry (false),
@ -43,6 +51,10 @@ FuncUnwinders::FuncUnwinders (UnwindTable& unwind_table, AddressRange range) :
{
}
//------------------------------------------------
/// destructor
//------------------------------------------------
FuncUnwinders::~FuncUnwinders ()
{
}
@ -51,101 +63,174 @@ UnwindPlanSP
FuncUnwinders::GetUnwindPlanAtCallSite (Target &target, int current_offset)
{
Mutex::Locker locker (m_mutex);
if (m_tried_unwind_at_call_site == false && m_unwind_plan_call_site_sp.get() == nullptr)
UnwindPlanSP unwind_plan_sp = GetEHFrameUnwindPlan (target, current_offset);
if (unwind_plan_sp.get() == nullptr)
{
m_tried_unwind_at_call_site = true;
unwind_plan_sp = GetCompactUnwindUnwindPlan (target, current_offset);
}
// We have cases (e.g. with _sigtramp on Mac OS X) where the hand-written eh_frame unwind info for a
// function does not cover the entire range of the function and so the FDE only lists a subset of the
// address range. If we try to look up the unwind info by the starting address of the function
// (i.e. m_range.GetBaseAddress()) we may not find the eh_frame FDE. We need to use the actual byte offset
// into the function when looking it up.
return unwind_plan_sp;
}
if (m_range.GetBaseAddress().IsValid())
UnwindPlanSP
FuncUnwinders::GetCompactUnwindUnwindPlan (Target &target, int current_offset)
{
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();
Mutex::Locker lock (m_mutex);
m_tried_unwind_plan_compact_unwind = true;
if (m_range.GetBaseAddress().IsValid())
{
Address current_pc (m_range.GetBaseAddress ());
if (current_offset != -1)
current_pc.SetOffset (current_pc.GetOffset() + current_offset);
CompactUnwindInfo *compact_unwind = m_unwind_table.GetCompactUnwindInfo();
if (compact_unwind)
{
Address current_pc (m_range.GetBaseAddress ());
if (current_offset != -1)
current_pc.SetOffset (current_pc.GetOffset() + current_offset);
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_call_site_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
if (!compact_unwind->GetUnwindPlan (target, current_pc, *m_unwind_plan_call_site_sp))
m_unwind_plan_call_site_sp.reset();
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
}
if (m_unwind_plan_call_site_sp.get() == nullptr)
}
}
return UnwindPlanSP();
}
UnwindPlanSP
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);
m_tried_unwind_plan_eh_frame = true;
if (m_range.GetBaseAddress().IsValid())
{
Address current_pc (m_range.GetBaseAddress ());
if (current_offset != -1)
current_pc.SetOffset (current_pc.GetOffset() + current_offset);
DWARFCallFrameInfo *eh_frame = m_unwind_table.GetEHFrameInfo();
if (eh_frame)
{
m_unwind_plan_eh_frame_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
if (!eh_frame->GetUnwindPlan (current_pc, *m_unwind_plan_eh_frame_sp))
m_unwind_plan_eh_frame_sp.reset();
}
}
return m_unwind_plan_eh_frame_sp;
}
UnwindPlanSP
FuncUnwinders::GetEHFrameAugmentedUnwindPlan (Target &target, Thread &thread, int current_offset)
{
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;
}
Mutex::Locker lock (m_mutex);
m_tried_unwind_plan_eh_frame_augmented = true;
if (m_range.GetBaseAddress().IsValid())
{
Address current_pc (m_range.GetBaseAddress ());
if (current_offset != -1)
current_pc.SetOffset (current_pc.GetOffset() + current_offset);
DWARFCallFrameInfo *eh_frame = m_unwind_table.GetEHFrameInfo();
if (eh_frame)
{
m_unwind_plan_eh_frame_augmented_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
if (!eh_frame->GetUnwindPlan (current_pc, *m_unwind_plan_eh_frame_augmented_sp))
{
DWARFCallFrameInfo *eh_frame = m_unwind_table.GetEHFrameInfo();
if (eh_frame)
m_unwind_plan_eh_frame_augmented_sp.reset();
}
else
{
// 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());
if (assembly_profiler_sp)
{
m_unwind_plan_call_site_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
if (!eh_frame->GetUnwindPlan (current_pc, *m_unwind_plan_call_site_sp))
m_unwind_plan_call_site_sp.reset();
if (!assembly_profiler_sp->AugmentUnwindPlanFromCallSite (m_range, thread, *m_unwind_plan_eh_frame_augmented_sp))
{
m_unwind_plan_eh_frame_augmented_sp.reset();
}
}
else
{
m_unwind_plan_eh_frame_augmented_sp.reset();
}
}
}
}
return m_unwind_plan_call_site_sp;
return m_unwind_plan_eh_frame_augmented_sp;
}
UnwindPlanSP
FuncUnwinders::GetAssemblyUnwindPlan (Target &target, Thread &thread, int current_offset)
{
if (m_unwind_plan_assembly_sp.get() || m_tried_unwind_plan_assembly)
return m_unwind_plan_assembly_sp;
Mutex::Locker lock (m_mutex);
m_tried_unwind_plan_assembly = true;
UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
if (assembly_profiler_sp)
{
m_unwind_plan_assembly_sp.reset (new UnwindPlan (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_sp;
}
UnwindPlanSP
FuncUnwinders::GetUnwindPlanAtNonCallSite (Target& target, Thread& thread, int current_offset)
{
Mutex::Locker locker (m_mutex);
if (m_tried_unwind_at_non_call_site == false && m_unwind_plan_non_call_site_sp.get() == nullptr)
UnwindPlanSP non_call_site_unwindplan_sp = GetEHFrameAugmentedUnwindPlan (target, thread, current_offset);
if (non_call_site_unwindplan_sp.get() == nullptr)
{
UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
if (assembly_profiler_sp)
{
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)
{
// For 0th frame on i386 & x86_64, we fetch eh_frame and try using assembly profiler
// to augment it into asynchronous unwind table.
DWARFCallFrameInfo *eh_frame = m_unwind_table.GetEHFrameInfo();
if (eh_frame)
{
UnwindPlanSP unwind_plan (new UnwindPlan (lldb::eRegisterKindGeneric));
if (m_range.GetBaseAddress().IsValid())
{
Address current_pc (m_range.GetBaseAddress ());
if (current_offset != -1)
current_pc.SetOffset (current_pc.GetOffset() + current_offset);
if (eh_frame->GetUnwindPlan (current_pc, *unwind_plan))
{
if (assembly_profiler_sp->AugmentUnwindPlanFromCallSite (m_range, thread, *unwind_plan))
{
m_unwind_plan_non_call_site_sp = unwind_plan;
return m_unwind_plan_non_call_site_sp;
}
}
}
}
}
m_unwind_plan_non_call_site_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
if (!assembly_profiler_sp->GetNonCallSiteUnwindPlanFromAssembly (m_range, thread, *m_unwind_plan_non_call_site_sp))
m_unwind_plan_non_call_site_sp.reset();
}
non_call_site_unwindplan_sp = GetAssemblyUnwindPlan (target, thread, current_offset);
}
return m_unwind_plan_non_call_site_sp;
return non_call_site_unwindplan_sp;
}
UnwindPlanSP
FuncUnwinders::GetUnwindPlanFastUnwind (Thread& thread)
{
if (m_unwind_plan_fast_sp.get() || m_tried_unwind_fast)
return m_unwind_plan_fast_sp;
Mutex::Locker locker (m_mutex);
if (m_tried_unwind_fast == false && m_unwind_plan_fast_sp.get() == nullptr)
m_tried_unwind_fast = true;
UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
if (assembly_profiler_sp)
{
m_tried_unwind_fast = true;
UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
if (assembly_profiler_sp)
m_unwind_plan_fast_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
if (!assembly_profiler_sp->GetFastUnwindPlan (m_range, thread, *m_unwind_plan_fast_sp))
{
m_unwind_plan_fast_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
if (!assembly_profiler_sp->GetFastUnwindPlan (m_range, thread, *m_unwind_plan_fast_sp))
m_unwind_plan_fast_sp.reset();
m_unwind_plan_fast_sp.reset();
}
}
return m_unwind_plan_fast_sp;
@ -154,20 +239,23 @@ FuncUnwinders::GetUnwindPlanFastUnwind (Thread& thread)
UnwindPlanSP
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);
if (m_tried_unwind_arch_default == false && m_unwind_plan_arch_default_sp.get() == nullptr)
m_tried_unwind_arch_default = true;
Address current_pc;
ProcessSP process_sp (thread.CalculateProcess());
if (process_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)
{
ABI *abi = process_sp->GetABI().get();
if (abi)
m_unwind_plan_arch_default_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
if (!abi->CreateDefaultUnwindPlan(*m_unwind_plan_arch_default_sp))
{
m_unwind_plan_arch_default_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
if (m_unwind_plan_arch_default_sp)
abi->CreateDefaultUnwindPlan(*m_unwind_plan_arch_default_sp);
m_unwind_plan_arch_default_sp.reset();
}
}
}
@ -178,21 +266,23 @@ FuncUnwinders::GetUnwindPlanArchitectureDefault (Thread& thread)
UnwindPlanSP
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);
if (m_tried_unwind_arch_default_at_func_entry == false
&& m_unwind_plan_arch_default_at_func_entry_sp.get() == nullptr)
m_tried_unwind_arch_default_at_func_entry = true;
Address current_pc;
ProcessSP process_sp (thread.CalculateProcess());
if (process_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)
{
ABI *abi = process_sp->GetABI().get();
if (abi)
m_unwind_plan_arch_default_at_func_entry_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
if (!abi->CreateFunctionEntryUnwindPlan(*m_unwind_plan_arch_default_at_func_entry_sp))
{
m_unwind_plan_arch_default_at_func_entry_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
if (m_unwind_plan_arch_default_at_func_entry_sp)
abi->CreateFunctionEntryUnwindPlan(*m_unwind_plan_arch_default_at_func_entry_sp);
m_unwind_plan_arch_default_at_func_entry_sp.reset();
}
}
}
@ -206,6 +296,8 @@ FuncUnwinders::GetFirstNonPrologueInsn (Target& target)
{
if (m_first_non_prologue_insn.IsValid())
return m_first_non_prologue_insn;
Mutex::Locker locker (m_mutex);
ExecutionContext exe_ctx (target.shared_from_this(), false);
UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
if (assembly_profiler_sp)
@ -235,15 +327,16 @@ Address
FuncUnwinders::GetLSDAAddress (Target &target)
{
Address lsda_addr;
Mutex::Locker locker (m_mutex);
GetUnwindPlanAtCallSite (target, -1);
if (m_unwind_plan_call_site_sp && m_unwind_plan_call_site_sp->GetLSDAAddress().IsValid())
UnwindPlanSP unwind_plan_sp = GetEHFrameUnwindPlan (target, -1);
if (unwind_plan_sp.get() == nullptr)
{
lsda_addr = m_unwind_plan_call_site_sp->GetLSDAAddress().IsValid();
unwind_plan_sp = GetCompactUnwindUnwindPlan (target, -1);
}
if (unwind_plan_sp.get() && unwind_plan_sp->GetLSDAAddress().IsValid())
{
lsda_addr = unwind_plan_sp->GetLSDAAddress();
}
return lsda_addr;
}
@ -252,13 +345,15 @@ Address
FuncUnwinders::GetPersonalityRoutinePtrAddress (Target &target)
{
Address personality_addr;
Mutex::Locker locker (m_mutex);
GetUnwindPlanAtCallSite (target, -1);
if (m_unwind_plan_call_site_sp && m_unwind_plan_call_site_sp->GetPersonalityFunctionPtr().IsValid())
UnwindPlanSP unwind_plan_sp = GetEHFrameUnwindPlan (target, -1);
if (unwind_plan_sp.get() == nullptr)
{
personality_addr = m_unwind_plan_call_site_sp->GetPersonalityFunctionPtr().IsValid();
unwind_plan_sp = GetCompactUnwindUnwindPlan (target, -1);
}
if (unwind_plan_sp.get() && unwind_plan_sp->GetPersonalityFunctionPtr().IsValid())
{
personality_addr = unwind_plan_sp->GetPersonalityFunctionPtr();
}
return personality_addr;