aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Clayton <gclayton@apple.com>2013-07-30 00:23:06 +0000
committerGreg Clayton <gclayton@apple.com>2013-07-30 00:23:06 +0000
commite4923ddaa18bf003e339e6ab33bfd137a632fc0f (patch)
tree16c5945b76cc002ce58f6af66a20eab29ac92802
parent21f98a38a0cfa10b9935248f1b3628b5ba914402 (diff)
downloadlldb-e4923ddaa18bf003e339e6ab33bfd137a632fc0f.tar.gz
<rdar://problem/14526890>
Fixed a crasher when using memory threads where a thread is sticking around too long and was causing problems when it didn't have a thread plan. git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@187395 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/lldb/Target/ThreadPlan.h54
-rw-r--r--source/Target/Thread.cpp13
-rw-r--r--source/Target/ThreadPlan.cpp141
3 files changed, 207 insertions, 1 deletions
diff --git a/include/lldb/Target/ThreadPlan.h b/include/lldb/Target/ThreadPlan.h
index 3d95a0924..3c83fd1b9 100644
--- a/include/lldb/Target/ThreadPlan.h
+++ b/include/lldb/Target/ThreadPlan.h
@@ -238,6 +238,7 @@ public:
typedef enum
{
eKindGeneric,
+ eKindNull,
eKindBase,
eKindCallFunction,
eKindStepInstruction,
@@ -435,7 +436,7 @@ public:
virtual void
WillPop();
- // This pushes \a plan onto the plan stack of the current plan's thread.
+ // This pushes a plan onto the plan stack of the current plan's thread.
void
PushPlan (lldb::ThreadPlanSP &thread_plan_sp)
{
@@ -600,6 +601,57 @@ private:
DISALLOW_COPY_AND_ASSIGN(ThreadPlan);
};
+//----------------------------------------------------------------------
+// ThreadPlanNull:
+// Threads are assumed to always have at least one plan on the plan stack.
+// This is put on the plan stack when a thread is destroyed so that if you
+// accidentally access a thread after it is destroyed you won't crash.
+// But asking questions of the ThreadPlanNull is definitely an error.
+//----------------------------------------------------------------------
+
+class ThreadPlanNull : public ThreadPlan
+{
+public:
+ ThreadPlanNull (Thread &thread);
+ virtual ~ThreadPlanNull ();
+
+ virtual void
+ GetDescription (Stream *s,
+ lldb::DescriptionLevel level);
+
+ virtual bool
+ ValidatePlan (Stream *error);
+
+ virtual bool
+ ShouldStop (Event *event_ptr);
+
+ virtual bool
+ MischiefManaged ();
+
+ virtual bool
+ WillStop ();
+
+ virtual bool
+ IsBasePlan()
+ {
+ return true;
+ }
+
+ virtual bool
+ OkayToDiscard ()
+ {
+ return false;
+ }
+
+protected:
+ virtual bool
+ DoPlanExplainsStop (Event *event_ptr);
+
+ virtual lldb::StateType
+ GetPlanRunState ();
+
+};
+
} // namespace lldb_private
diff --git a/source/Target/Thread.cpp b/source/Target/Thread.cpp
index 401eac2b2..b65434bf9 100644
--- a/source/Target/Thread.cpp
+++ b/source/Target/Thread.cpp
@@ -292,6 +292,13 @@ Thread::DestroyThread ()
m_plan_stack.clear();
m_discarded_plan_stack.clear();
m_completed_plan_stack.clear();
+
+ // Push a ThreadPlanNull on the plan stack. That way we can continue assuming that the
+ // plan stack is never empty, but if somebody errantly asks questions of a destroyed thread
+ // without checking first whether it is destroyed, they won't crash.
+ ThreadPlanSP null_plan_sp(new ThreadPlanNull (*this));
+ m_plan_stack.push_back (null_plan_sp);
+
m_stop_info_sp.reset();
m_reg_context_sp.reset();
m_unwinder_ap.reset();
@@ -362,6 +369,9 @@ Thread::SetSelectedFrameByIndexNoisily (uint32_t frame_idx, Stream &output_strea
lldb::StopInfoSP
Thread::GetStopInfo ()
{
+ if (m_destroy_called)
+ return m_stop_info_sp;
+
ThreadPlanSP plan_sp (GetCompletedPlan());
ProcessSP process_sp (GetProcess());
const uint32_t stop_id = process_sp ? process_sp->GetStopID() : UINT32_MAX;
@@ -387,6 +397,9 @@ Thread::GetStopInfo ()
lldb::StopInfoSP
Thread::GetPrivateStopInfo ()
{
+ if (m_destroy_called)
+ return m_stop_info_sp;
+
ProcessSP process_sp (GetProcess());
if (process_sp)
{
diff --git a/source/Target/ThreadPlan.cpp b/source/Target/ThreadPlan.cpp
index ba35db19c..11240dbe2 100644
--- a/source/Target/ThreadPlan.cpp
+++ b/source/Target/ThreadPlan.cpp
@@ -210,3 +210,144 @@ ThreadPlan::RunState ()
else
return GetPlanRunState();
}
+
+//----------------------------------------------------------------------
+// ThreadPlanNull
+//----------------------------------------------------------------------
+
+ThreadPlanNull::ThreadPlanNull (Thread &thread) :
+ ThreadPlan (ThreadPlan::eKindNull,
+ "Null Thread Plan",
+ thread,
+ eVoteNoOpinion,
+ eVoteNoOpinion)
+{
+}
+
+ThreadPlanNull::~ThreadPlanNull ()
+{
+}
+
+void
+ThreadPlanNull::GetDescription (Stream *s,
+ lldb::DescriptionLevel level)
+{
+ s->PutCString("Null thread plan - thread has been destroyed.");
+}
+
+bool
+ThreadPlanNull::ValidatePlan (Stream *error)
+{
+#ifdef LLDB_CONFIGURATION_DEBUG
+ fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%llx, ptid = 0x%llx)",
+ __PRETTY_FUNCTION__,
+ m_thread.GetID(),
+ m_thread.GetProtocolID());
+#else
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Error("%s called on thread that has been destroyed (tid = 0x%llx, ptid = 0x%llx)",
+ __PRETTY_FUNCTION__,
+ m_thread.GetID(),
+ m_thread.GetProtocolID());
+#endif
+ return true;
+}
+
+bool
+ThreadPlanNull::ShouldStop (Event *event_ptr)
+{
+#ifdef LLDB_CONFIGURATION_DEBUG
+ fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%llx, ptid = 0x%llx)",
+ __PRETTY_FUNCTION__,
+ m_thread.GetID(),
+ m_thread.GetProtocolID());
+#else
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Error("%s called on thread that has been destroyed (tid = 0x%llx, ptid = 0x%llx)",
+ __PRETTY_FUNCTION__,
+ m_thread.GetID(),
+ m_thread.GetProtocolID());
+#endif
+ return true;
+}
+
+bool
+ThreadPlanNull::WillStop ()
+{
+#ifdef LLDB_CONFIGURATION_DEBUG
+ fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%llx, ptid = 0x%llx)",
+ __PRETTY_FUNCTION__,
+ m_thread.GetID(),
+ m_thread.GetProtocolID());
+#else
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Error("%s called on thread that has been destroyed (tid = 0x%llx, ptid = 0x%llx)",
+ __PRETTY_FUNCTION__,
+ m_thread.GetID(),
+ m_thread.GetProtocolID());
+#endif
+ return true;
+}
+
+bool
+ThreadPlanNull::DoPlanExplainsStop (Event *event_ptr)
+{
+#ifdef LLDB_CONFIGURATION_DEBUG
+ fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%llx, ptid = 0x%llx)",
+ __PRETTY_FUNCTION__,
+ m_thread.GetID(),
+ m_thread.GetProtocolID());
+#else
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Error("%s called on thread that has been destroyed (tid = 0x%llx, ptid = 0x%llx)",
+ __PRETTY_FUNCTION__,
+ m_thread.GetID(),
+ m_thread.GetProtocolID());
+#endif
+ return true;
+}
+
+// The null plan is never done.
+bool
+ThreadPlanNull::MischiefManaged ()
+{
+ // The null plan is never done.
+#ifdef LLDB_CONFIGURATION_DEBUG
+ fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%llx, ptid = 0x%llx)",
+ __PRETTY_FUNCTION__,
+ m_thread.GetID(),
+ m_thread.GetProtocolID());
+#else
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Error("%s called on thread that has been destroyed (tid = 0x%llx, ptid = 0x%llx)",
+ __PRETTY_FUNCTION__,
+ m_thread.GetID(),
+ m_thread.GetProtocolID());
+#endif
+ return false;
+}
+
+lldb::StateType
+ThreadPlanNull::GetPlanRunState ()
+{
+ // Not sure what to return here. This is a dead thread.
+#ifdef LLDB_CONFIGURATION_DEBUG
+ fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%llx, ptid = 0x%llx)",
+ __PRETTY_FUNCTION__,
+ m_thread.GetID(),
+ m_thread.GetProtocolID());
+#else
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Error("%s called on thread that has been destroyed (tid = 0x%llx, ptid = 0x%llx)",
+ __PRETTY_FUNCTION__,
+ m_thread.GetID(),
+ m_thread.GetProtocolID());
+#endif
+ return eStateRunning;
+}