forked from OSchip/llvm-project
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:
parent
23a55f1eee
commit
5c45c541a2
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue