Made FuncUnwinders threadsafe.

Other small cleanups as well.

llvm-svn: 123088
This commit is contained in:
Greg Clayton 2011-01-08 21:19:00 +00:00
parent 5120ebf184
commit 877aaa589b
5 changed files with 121 additions and 61 deletions

View File

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

View File

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

View File

@ -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());
}
}

View File

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

View File

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