forked from OSchip/llvm-project
Made FuncUnwinders threadsafe.
Other small cleanups as well. llvm-svn: 123088
This commit is contained in:
parent
5120ebf184
commit
877aaa589b
|
@ -1,12 +1,13 @@
|
|||
#ifndef liblldb_FuncUnwinders_h
|
||||
#define liblldb_FuncUnwinders_h
|
||||
|
||||
#include "lldb/lldb-private.h"
|
||||
#include "lldb/lldb-forward.h"
|
||||
#include "lldb/lldb-forward-rtti.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "lldb/Core/AddressRange.h"
|
||||
#include "lldb/Core/ArchSpec.h"
|
||||
#include <memory>
|
||||
#include "lldb/Core/AddressRange.h"
|
||||
#include "lldb/Host/Mutex.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
|
@ -72,15 +73,16 @@ private:
|
|||
UnwindAssemblyProfiler *m_assembly_profiler;
|
||||
AddressRange m_range;
|
||||
|
||||
Mutex m_mutex;
|
||||
std::auto_ptr<UnwindPlan> m_unwind_at_call_site_ap;
|
||||
std::auto_ptr<UnwindPlan> m_unwind_at_non_call_site_ap;
|
||||
std::auto_ptr<UnwindPlan> m_fast_unwind_ap;
|
||||
UnwindPlan *m_arch_default_unwind;
|
||||
std::auto_ptr<UnwindPlan> m_unwind_fast_ap;
|
||||
UnwindPlan *m_unwind_arch_default;
|
||||
|
||||
bool m_tried_unwind_at_call_site:1,
|
||||
m_tried_unwind_at_non_call_site:1,
|
||||
m_tried_fast_unwind:1,
|
||||
m_tried_arch_default_unwind:1;
|
||||
m_tried_unwind_fast:1,
|
||||
m_tried_unwind_arch_default:1;
|
||||
|
||||
Address m_first_non_prologue_insn;
|
||||
|
||||
|
|
|
@ -204,7 +204,11 @@ public:
|
|||
|
||||
public:
|
||||
|
||||
UnwindPlan () : m_register_kind(-1), m_row_list(), m_plan_valid_address_range(), m_source_name()
|
||||
UnwindPlan () :
|
||||
m_register_kind(-1),
|
||||
m_row_list(),
|
||||
m_plan_valid_address_range(),
|
||||
m_source_name()
|
||||
{
|
||||
m_plan_valid_address_range.SetByteSize (0);
|
||||
}
|
||||
|
|
|
@ -107,9 +107,9 @@ RegisterContextLLDB::InitializeZerothFrame()
|
|||
|
||||
m_current_pc = frame_sp->GetFrameCodeAddress();
|
||||
|
||||
static ConstString sigtramp_name ("_sigtramp");
|
||||
if ((m_sym_ctx.function && m_sym_ctx.function->GetMangled().GetMangledName() == sigtramp_name)
|
||||
|| (m_sym_ctx.symbol && m_sym_ctx.symbol->GetMangled().GetMangledName() == sigtramp_name))
|
||||
static ConstString g_sigtramp_name ("_sigtramp");
|
||||
if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == g_sigtramp_name) ||
|
||||
(m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == g_sigtramp_name))
|
||||
{
|
||||
m_frame_type = eSigtrampFrame;
|
||||
}
|
||||
|
@ -184,8 +184,11 @@ RegisterContextLLDB::InitializeZerothFrame()
|
|||
if (log)
|
||||
{
|
||||
log->Printf("%*sThread %d Frame %u initialized frame current pc is 0x%llx cfa is 0x%llx using %s UnwindPlan",
|
||||
m_frame_number < 100 ? m_frame_number : 100, "", m_thread.GetIndexID(), m_frame_number,
|
||||
(uint64_t) m_current_pc.GetLoadAddress (&m_thread.GetProcess().GetTarget()), (uint64_t) m_cfa,
|
||||
m_frame_number < 100 ? m_frame_number : 100, "",
|
||||
m_thread.GetIndexID(),
|
||||
m_frame_number,
|
||||
(uint64_t) m_current_pc.GetLoadAddress (&m_thread.GetProcess().GetTarget()),
|
||||
(uint64_t) m_cfa,
|
||||
m_full_unwind_plan->GetSourceName().GetCString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,14 +33,15 @@ FuncUnwinders::FuncUnwinders
|
|||
m_unwind_table(unwind_table),
|
||||
m_assembly_profiler(assembly_profiler),
|
||||
m_range(range),
|
||||
m_mutex (Mutex::eMutexTypeNormal),
|
||||
m_unwind_at_call_site_ap (),
|
||||
m_unwind_at_non_call_site_ap (),
|
||||
m_fast_unwind_ap (),
|
||||
m_arch_default_unwind (NULL),
|
||||
m_unwind_fast_ap (),
|
||||
m_unwind_arch_default (NULL),
|
||||
m_tried_unwind_at_call_site (false),
|
||||
m_tried_unwind_at_non_call_site (false),
|
||||
m_tried_fast_unwind (false),
|
||||
m_tried_arch_default_unwind (false),
|
||||
m_tried_unwind_fast (false),
|
||||
m_tried_unwind_arch_default (false),
|
||||
m_first_non_prologue_insn()
|
||||
{
|
||||
}
|
||||
|
@ -52,6 +53,19 @@ FuncUnwinders::~FuncUnwinders ()
|
|||
UnwindPlan*
|
||||
FuncUnwinders::GetUnwindPlanAtCallSite (int current_offset)
|
||||
{
|
||||
// Lock the mutex to ensure we can always give out the most appropriate
|
||||
// information. We want to make sure if someone requests a call site unwind
|
||||
// plan, that they get one and don't run into a race condition where one
|
||||
// thread has started to create the unwind plan and has put it into
|
||||
// m_unwind_at_call_site_ap, and have another thread enter this function
|
||||
// and return the partially filled in m_unwind_at_call_site_ap pointer.
|
||||
// We also want to make sure that we lock out other unwind plans from
|
||||
// being accessed until this one is done creating itself in case someone
|
||||
// had some code like:
|
||||
// UnwindPlan *best_unwind_plan = ...GetUnwindPlanAtCallSite (...)
|
||||
// if (best_unwind_plan == NULL)
|
||||
// best_unwind_plan = GetUnwindPlanAtNonCallSite (...)
|
||||
Mutex::Locker locker (m_mutex);
|
||||
if (m_tried_unwind_at_call_site == false && m_unwind_at_call_site_ap.get() == NULL)
|
||||
{
|
||||
m_tried_unwind_at_call_site = true;
|
||||
|
@ -82,6 +96,19 @@ FuncUnwinders::GetUnwindPlanAtCallSite (int current_offset)
|
|||
UnwindPlan*
|
||||
FuncUnwinders::GetUnwindPlanAtNonCallSite (Thread& thread)
|
||||
{
|
||||
// Lock the mutex to ensure we can always give out the most appropriate
|
||||
// information. We want to make sure if someone requests an unwind
|
||||
// plan, that they get one and don't run into a race condition where one
|
||||
// thread has started to create the unwind plan and has put it into
|
||||
// the auto_ptr member variable, and have another thread enter this function
|
||||
// and return the partially filled pointer contained in the auto_ptr.
|
||||
// We also want to make sure that we lock out other unwind plans from
|
||||
// being accessed until this one is done creating itself in case someone
|
||||
// had some code like:
|
||||
// UnwindPlan *best_unwind_plan = ...GetUnwindPlanAtCallSite (...)
|
||||
// if (best_unwind_plan == NULL)
|
||||
// best_unwind_plan = GetUnwindPlanAtNonCallSite (...)
|
||||
Mutex::Locker locker (m_mutex);
|
||||
if (m_tried_unwind_at_non_call_site == false && m_unwind_at_non_call_site_ap.get() == NULL)
|
||||
{
|
||||
m_tried_unwind_at_non_call_site = true;
|
||||
|
@ -95,22 +122,48 @@ FuncUnwinders::GetUnwindPlanAtNonCallSite (Thread& thread)
|
|||
UnwindPlan*
|
||||
FuncUnwinders::GetUnwindPlanFastUnwind (Thread& thread)
|
||||
{
|
||||
if (m_tried_fast_unwind == false && m_fast_unwind_ap.get() == NULL)
|
||||
// Lock the mutex to ensure we can always give out the most appropriate
|
||||
// information. We want to make sure if someone requests an unwind
|
||||
// plan, that they get one and don't run into a race condition where one
|
||||
// thread has started to create the unwind plan and has put it into
|
||||
// the auto_ptr member variable, and have another thread enter this function
|
||||
// and return the partially filled pointer contained in the auto_ptr.
|
||||
// We also want to make sure that we lock out other unwind plans from
|
||||
// being accessed until this one is done creating itself in case someone
|
||||
// had some code like:
|
||||
// UnwindPlan *best_unwind_plan = ...GetUnwindPlanAtCallSite (...)
|
||||
// if (best_unwind_plan == NULL)
|
||||
// best_unwind_plan = GetUnwindPlanAtNonCallSite (...)
|
||||
Mutex::Locker locker (m_mutex);
|
||||
if (m_tried_unwind_fast == false && m_unwind_fast_ap.get() == NULL)
|
||||
{
|
||||
m_tried_fast_unwind = true;
|
||||
m_fast_unwind_ap.reset (new UnwindPlan);
|
||||
if (!m_assembly_profiler->GetFastUnwindPlan (m_range, thread, *m_fast_unwind_ap))
|
||||
m_fast_unwind_ap.reset();
|
||||
m_tried_unwind_fast = true;
|
||||
m_unwind_fast_ap.reset (new UnwindPlan);
|
||||
if (!m_assembly_profiler->GetFastUnwindPlan (m_range, thread, *m_unwind_fast_ap))
|
||||
m_unwind_fast_ap.reset();
|
||||
}
|
||||
return m_fast_unwind_ap.get();
|
||||
return m_unwind_fast_ap.get();
|
||||
}
|
||||
|
||||
UnwindPlan*
|
||||
FuncUnwinders::GetUnwindPlanArchitectureDefault (Thread& thread)
|
||||
{
|
||||
if (m_tried_arch_default_unwind == false && m_arch_default_unwind == NULL)
|
||||
// Lock the mutex to ensure we can always give out the most appropriate
|
||||
// information. We want to make sure if someone requests an unwind
|
||||
// plan, that they get one and don't run into a race condition where one
|
||||
// thread has started to create the unwind plan and has put it into
|
||||
// the auto_ptr member variable, and have another thread enter this function
|
||||
// and return the partially filled pointer contained in the auto_ptr.
|
||||
// We also want to make sure that we lock out other unwind plans from
|
||||
// being accessed until this one is done creating itself in case someone
|
||||
// had some code like:
|
||||
// UnwindPlan *best_unwind_plan = ...GetUnwindPlanAtCallSite (...)
|
||||
// if (best_unwind_plan == NULL)
|
||||
// best_unwind_plan = GetUnwindPlanAtNonCallSite (...)
|
||||
Mutex::Locker locker (m_mutex);
|
||||
if (m_tried_unwind_arch_default == false && m_unwind_arch_default == NULL)
|
||||
{
|
||||
m_tried_arch_default_unwind = true;
|
||||
m_tried_unwind_arch_default = true;
|
||||
Address current_pc;
|
||||
Target *target = thread.CalculateTarget();
|
||||
if (target)
|
||||
|
@ -118,11 +171,11 @@ FuncUnwinders::GetUnwindPlanArchitectureDefault (Thread& thread)
|
|||
ArchSpec arch = target->GetArchitecture ();
|
||||
ArchDefaultUnwindPlan *arch_default = ArchDefaultUnwindPlan::FindPlugin (arch);
|
||||
if (arch_default)
|
||||
m_arch_default_unwind = arch_default->GetArchDefaultUnwindPlan (thread, current_pc);
|
||||
m_unwind_arch_default = arch_default->GetArchDefaultUnwindPlan (thread, current_pc);
|
||||
}
|
||||
}
|
||||
|
||||
return m_arch_default_unwind;
|
||||
return m_unwind_arch_default;
|
||||
}
|
||||
|
||||
Address&
|
||||
|
|
|
@ -97,13 +97,13 @@ UnwindPlan::Row::RegisterLocation::Dump (Stream &s) const
|
|||
switch (m_type)
|
||||
{
|
||||
case unspecified:
|
||||
s.Printf ("unspecified");
|
||||
s.PutCString ("unspecified");
|
||||
break;
|
||||
case isUndefined:
|
||||
s.Printf ("isUndefined");
|
||||
s.PutCString ("isUndefined");
|
||||
break;
|
||||
case isSame:
|
||||
s.Printf ("isSame");
|
||||
s.PutCString ("isSame");
|
||||
break;
|
||||
case atCFAPlusOffset:
|
||||
s.Printf ("atCFAPlusOffset %d", m_location.offset);
|
||||
|
@ -115,10 +115,10 @@ UnwindPlan::Row::RegisterLocation::Dump (Stream &s) const
|
|||
s.Printf ("inOtherRegister %d", m_location.reg_num);
|
||||
break;
|
||||
case atDWARFExpression:
|
||||
s.Printf ("atDWARFExpression");
|
||||
s.PutCString ("atDWARFExpression");
|
||||
break;
|
||||
case isDWARFExpression:
|
||||
s.Printf ("isDWARFExpression");
|
||||
s.PutCString ("isDWARFExpression");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ UnwindPlan::Row::Dump (Stream& s, int register_kind, Thread* thread) const
|
|||
s.Printf ("CFA offset %d", (int) GetCFAOffset ());
|
||||
for (collection::const_iterator idx = m_register_locations.begin (); idx != m_register_locations.end (); ++idx)
|
||||
{
|
||||
s.Printf (" [");
|
||||
s.PutCString (" [");
|
||||
bool printed_name = false;
|
||||
if (reg_ctx)
|
||||
{
|
||||
|
@ -174,9 +174,9 @@ UnwindPlan::Row::Dump (Stream& s, int register_kind, Thread* thread) const
|
|||
s.Printf ("reg %d ", idx->first);
|
||||
}
|
||||
idx->second.Dump(s);
|
||||
s.Printf ("]");
|
||||
s.PutCString ("]");
|
||||
}
|
||||
s.Printf ("\n");
|
||||
s.EOL();
|
||||
}
|
||||
|
||||
UnwindPlan::Row::Row() :
|
||||
|
@ -218,23 +218,24 @@ UnwindPlan::AppendRow (const UnwindPlan::Row &row)
|
|||
const UnwindPlan::Row *
|
||||
UnwindPlan::GetRowForFunctionOffset (int offset) const
|
||||
{
|
||||
const UnwindPlan::Row *rowp = NULL;
|
||||
if (offset == -1 && m_row_list.size() > 0)
|
||||
const UnwindPlan::Row *row_ptr = NULL;
|
||||
if (!m_row_list.empty())
|
||||
{
|
||||
return &m_row_list[m_row_list.size() - 1];
|
||||
}
|
||||
for (int i = 0; i < m_row_list.size(); ++i)
|
||||
{
|
||||
if (m_row_list[i].GetOffset() <= offset)
|
||||
{
|
||||
rowp = &m_row_list[i];
|
||||
}
|
||||
if (offset == -1)
|
||||
row_ptr = &m_row_list.back();
|
||||
else
|
||||
{
|
||||
break;
|
||||
collection::const_iterator pos, end = m_row_list.end();
|
||||
for (pos = m_row_list.begin(); pos != end; ++pos)
|
||||
{
|
||||
if (pos->GetOffset() <= offset)
|
||||
row_ptr = &*pos;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rowp;
|
||||
return row_ptr;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -247,6 +248,7 @@ const UnwindPlan::Row&
|
|||
UnwindPlan::GetRowAtIndex (uint32_t idx) const
|
||||
{
|
||||
// You must call IsValidRowIndex(idx) first before calling this!!!
|
||||
assert (idx < m_row_list.size());
|
||||
return m_row_list[idx];
|
||||
}
|
||||
|
||||
|
@ -272,11 +274,7 @@ void
|
|||
UnwindPlan::SetPlanValidAddressRange (const AddressRange& range)
|
||||
{
|
||||
if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
|
||||
{
|
||||
m_plan_valid_address_range = range;
|
||||
}
|
||||
// .GetBaseAddress() = addr;
|
||||
// m_plan_valid_address_range.SetByteSize (range.GetByteSize());
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -303,25 +301,25 @@ UnwindPlan::Dump (Stream& s, Thread *thread) const
|
|||
}
|
||||
if (m_plan_valid_address_range.GetBaseAddress().IsValid() && m_plan_valid_address_range.GetByteSize() > 0)
|
||||
{
|
||||
s.Printf ("Address range of this UnwindPlan: ");
|
||||
s.PutCString ("Address range of this UnwindPlan: ");
|
||||
m_plan_valid_address_range.Dump (&s, &thread->GetProcess().GetTarget(), Address::DumpStyleSectionNameOffset);
|
||||
s.Printf ("\n");
|
||||
s.EOL();
|
||||
}
|
||||
else
|
||||
{
|
||||
s.Printf ("No valid address range recorded for this UnwindPlan.\n");
|
||||
s.PutCString ("No valid address range recorded for this UnwindPlan.\n");
|
||||
}
|
||||
s.Printf ("UnwindPlan register kind %d", m_register_kind);
|
||||
switch (m_register_kind)
|
||||
{
|
||||
case eRegisterKindGCC: s.Printf (" [eRegisterKindGCC]"); break;
|
||||
case eRegisterKindDWARF: s.Printf (" [eRegisterKindDWARF]"); break;
|
||||
case eRegisterKindGeneric: s.Printf (" [eRegisterKindGeneric]"); break;
|
||||
case eRegisterKindGDB: s.Printf (" [eRegisterKindGDB]"); break;
|
||||
case eRegisterKindLLDB: s.Printf (" [eRegisterKindLLDB]"); break;
|
||||
case eRegisterKindGCC: s.PutCString (" [eRegisterKindGCC]"); break;
|
||||
case eRegisterKindDWARF: s.PutCString (" [eRegisterKindDWARF]"); break;
|
||||
case eRegisterKindGeneric: s.PutCString (" [eRegisterKindGeneric]"); break;
|
||||
case eRegisterKindGDB: s.PutCString (" [eRegisterKindGDB]"); break;
|
||||
case eRegisterKindLLDB: s.PutCString (" [eRegisterKindLLDB]"); break;
|
||||
default: break;
|
||||
}
|
||||
s.Printf ("\n");
|
||||
s.EOL();
|
||||
for (int i = 0; IsValidRowIndex (i); i++)
|
||||
{
|
||||
s.Printf ("UnwindPlan row at index %d: ", i);
|
||||
|
|
Loading…
Reference in New Issue