llvm-project/lldb/source/Target/ThreadPlan.cpp

367 lines
10 KiB
C++
Raw Normal View History

//===-- ThreadPlan.cpp ------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Target/ThreadPlan.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/State.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/ConvertEnum.h"
using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
// ThreadPlan constructor
//----------------------------------------------------------------------
ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, Vote stop_vote, Vote run_vote) :
m_thread (thread),
m_stop_vote (stop_vote),
m_run_vote (run_vote),
m_kind (kind),
m_name (name),
m_plan_complete_mutex (Mutex::eMutexTypeRecursive),
Figure out the reply to "PlanExplainsStop" once when we stop and then use the cached value. This fixes problems, for instance, with the StepRange plans, where they know that they explained the stop because they were at their "run to here" breakpoint, then deleted that breakpoint, so when they got asked again, doh! I had done this for a couple of plans in an ad hoc fashion, this just formalizes it. Also add a "ResumeRequested" in Process so that the code in the completion handlers can tell the ShouldStop logic they want to resume rather than just directly resuming. That allows us to handle resuming in a more controlled fashion. Also, SetPublicState can take a "restarted" flag, so that it doesn't drop the run lock when the target was immediately restarted. --This line, and those below , will be ignored-- M test/lang/objc/objc-dynamic-value/TestObjCDynamicValue.py M include/lldb/Target/ThreadList.h M include/lldb/Target/ThreadPlanStepOut.h M include/lldb/Target/Thread.h M include/lldb/Target/ThreadPlanBase.h M include/lldb/Target/ThreadPlanStepThrough.h M include/lldb/Target/ThreadPlanStepInstruction.h M include/lldb/Target/ThreadPlanStepInRange.h M include/lldb/Target/ThreadPlanStepOverBreakpoint.h M include/lldb/Target/ThreadPlanStepUntil.h M include/lldb/Target/StopInfo.h M include/lldb/Target/Process.h M include/lldb/Target/ThreadPlanRunToAddress.h M include/lldb/Target/ThreadPlan.h M include/lldb/Target/ThreadPlanCallFunction.h M include/lldb/Target/ThreadPlanStepOverRange.h M source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h M source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp M source/Target/StopInfo.cpp M source/Target/Process.cpp M source/Target/ThreadPlanRunToAddress.cpp M source/Target/ThreadPlan.cpp M source/Target/ThreadPlanCallFunction.cpp M source/Target/ThreadPlanStepOverRange.cpp M source/Target/ThreadList.cpp M source/Target/ThreadPlanStepOut.cpp M source/Target/Thread.cpp M source/Target/ThreadPlanBase.cpp M source/Target/ThreadPlanStepThrough.cpp M source/Target/ThreadPlanStepInstruction.cpp M source/Target/ThreadPlanStepInRange.cpp M source/Target/ThreadPlanStepOverBreakpoint.cpp M source/Target/ThreadPlanStepUntil.cpp M lldb.xcodeproj/xcshareddata/xcschemes/Run Testsuite.xcscheme llvm-svn: 181381
2013-05-08 08:35:16 +08:00
m_cached_plan_explains_stop (eLazyBoolCalculate),
m_plan_complete (false),
m_plan_private (false),
m_okay_to_discard (true),
m_is_master_plan (false),
m_plan_succeeded(true)
{
SetID (GetNextID());
}
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
ThreadPlan::~ThreadPlan()
{
}
Figure out the reply to "PlanExplainsStop" once when we stop and then use the cached value. This fixes problems, for instance, with the StepRange plans, where they know that they explained the stop because they were at their "run to here" breakpoint, then deleted that breakpoint, so when they got asked again, doh! I had done this for a couple of plans in an ad hoc fashion, this just formalizes it. Also add a "ResumeRequested" in Process so that the code in the completion handlers can tell the ShouldStop logic they want to resume rather than just directly resuming. That allows us to handle resuming in a more controlled fashion. Also, SetPublicState can take a "restarted" flag, so that it doesn't drop the run lock when the target was immediately restarted. --This line, and those below , will be ignored-- M test/lang/objc/objc-dynamic-value/TestObjCDynamicValue.py M include/lldb/Target/ThreadList.h M include/lldb/Target/ThreadPlanStepOut.h M include/lldb/Target/Thread.h M include/lldb/Target/ThreadPlanBase.h M include/lldb/Target/ThreadPlanStepThrough.h M include/lldb/Target/ThreadPlanStepInstruction.h M include/lldb/Target/ThreadPlanStepInRange.h M include/lldb/Target/ThreadPlanStepOverBreakpoint.h M include/lldb/Target/ThreadPlanStepUntil.h M include/lldb/Target/StopInfo.h M include/lldb/Target/Process.h M include/lldb/Target/ThreadPlanRunToAddress.h M include/lldb/Target/ThreadPlan.h M include/lldb/Target/ThreadPlanCallFunction.h M include/lldb/Target/ThreadPlanStepOverRange.h M source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h M source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp M source/Target/StopInfo.cpp M source/Target/Process.cpp M source/Target/ThreadPlanRunToAddress.cpp M source/Target/ThreadPlan.cpp M source/Target/ThreadPlanCallFunction.cpp M source/Target/ThreadPlanStepOverRange.cpp M source/Target/ThreadList.cpp M source/Target/ThreadPlanStepOut.cpp M source/Target/Thread.cpp M source/Target/ThreadPlanBase.cpp M source/Target/ThreadPlanStepThrough.cpp M source/Target/ThreadPlanStepInstruction.cpp M source/Target/ThreadPlanStepInRange.cpp M source/Target/ThreadPlanStepOverBreakpoint.cpp M source/Target/ThreadPlanStepUntil.cpp M lldb.xcodeproj/xcshareddata/xcschemes/Run Testsuite.xcscheme llvm-svn: 181381
2013-05-08 08:35:16 +08:00
bool
ThreadPlan::PlanExplainsStop (Event *event_ptr)
{
if (m_cached_plan_explains_stop == eLazyBoolCalculate)
{
bool actual_value = DoPlanExplainsStop(event_ptr);
m_cached_plan_explains_stop = actual_value ? eLazyBoolYes : eLazyBoolNo;
return actual_value;
}
else
{
return m_cached_plan_explains_stop == eLazyBoolYes;
}
}
bool
ThreadPlan::IsPlanComplete ()
{
Mutex::Locker locker(m_plan_complete_mutex);
return m_plan_complete;
}
void
ThreadPlan::SetPlanComplete (bool success)
{
Mutex::Locker locker(m_plan_complete_mutex);
m_plan_complete = true;
m_plan_succeeded = success;
}
bool
ThreadPlan::MischiefManaged ()
{
Mutex::Locker locker(m_plan_complete_mutex);
// Mark the plan is complete, but don't override the success flag.
m_plan_complete = true;
return true;
}
Vote
ThreadPlan::ShouldReportStop (Event *event_ptr)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
if (m_stop_vote == eVoteNoOpinion)
{
ThreadPlan *prev_plan = GetPreviousPlan ();
if (prev_plan)
{
Vote prev_vote = prev_plan->ShouldReportStop (event_ptr);
if (log)
log->Printf ("ThreadPlan::ShouldReportStop() returning previous thread plan vote: %s",
GetVoteAsCString (prev_vote));
return prev_vote;
}
}
if (log)
log->Printf ("ThreadPlan::ShouldReportStop() returning vote: %s", GetVoteAsCString (m_stop_vote));
return m_stop_vote;
}
Vote
ThreadPlan::ShouldReportRun (Event *event_ptr)
{
if (m_run_vote == eVoteNoOpinion)
{
ThreadPlan *prev_plan = GetPreviousPlan ();
if (prev_plan)
return prev_plan->ShouldReportRun (event_ptr);
}
return m_run_vote;
}
bool
ThreadPlan::StopOthers ()
{
ThreadPlan *prev_plan;
prev_plan = GetPreviousPlan ();
if (prev_plan == NULL)
return false;
else
return prev_plan->StopOthers();
}
void
ThreadPlan::SetStopOthers (bool new_value)
{
// SetStopOthers doesn't work up the hierarchy. You have to set the
// explicit ThreadPlan you want to affect.
}
bool
ThreadPlan::WillResume (StateType resume_state, bool current_plan)
{
Figure out the reply to "PlanExplainsStop" once when we stop and then use the cached value. This fixes problems, for instance, with the StepRange plans, where they know that they explained the stop because they were at their "run to here" breakpoint, then deleted that breakpoint, so when they got asked again, doh! I had done this for a couple of plans in an ad hoc fashion, this just formalizes it. Also add a "ResumeRequested" in Process so that the code in the completion handlers can tell the ShouldStop logic they want to resume rather than just directly resuming. That allows us to handle resuming in a more controlled fashion. Also, SetPublicState can take a "restarted" flag, so that it doesn't drop the run lock when the target was immediately restarted. --This line, and those below , will be ignored-- M test/lang/objc/objc-dynamic-value/TestObjCDynamicValue.py M include/lldb/Target/ThreadList.h M include/lldb/Target/ThreadPlanStepOut.h M include/lldb/Target/Thread.h M include/lldb/Target/ThreadPlanBase.h M include/lldb/Target/ThreadPlanStepThrough.h M include/lldb/Target/ThreadPlanStepInstruction.h M include/lldb/Target/ThreadPlanStepInRange.h M include/lldb/Target/ThreadPlanStepOverBreakpoint.h M include/lldb/Target/ThreadPlanStepUntil.h M include/lldb/Target/StopInfo.h M include/lldb/Target/Process.h M include/lldb/Target/ThreadPlanRunToAddress.h M include/lldb/Target/ThreadPlan.h M include/lldb/Target/ThreadPlanCallFunction.h M include/lldb/Target/ThreadPlanStepOverRange.h M source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h M source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp M source/Target/StopInfo.cpp M source/Target/Process.cpp M source/Target/ThreadPlanRunToAddress.cpp M source/Target/ThreadPlan.cpp M source/Target/ThreadPlanCallFunction.cpp M source/Target/ThreadPlanStepOverRange.cpp M source/Target/ThreadList.cpp M source/Target/ThreadPlanStepOut.cpp M source/Target/Thread.cpp M source/Target/ThreadPlanBase.cpp M source/Target/ThreadPlanStepThrough.cpp M source/Target/ThreadPlanStepInstruction.cpp M source/Target/ThreadPlanStepInRange.cpp M source/Target/ThreadPlanStepOverBreakpoint.cpp M source/Target/ThreadPlanStepUntil.cpp M lldb.xcodeproj/xcshareddata/xcschemes/Run Testsuite.xcscheme llvm-svn: 181381
2013-05-08 08:35:16 +08:00
m_cached_plan_explains_stop = eLazyBoolCalculate;
if (current_plan)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
if (log)
{
Fixed issues with RegisterContext classes and the subclasses. There was an issue with the way the UnwindLLDB was handing out RegisterContexts: it was making shared pointers to register contexts and then handing out just the pointers (which would get put into shared pointers in the thread and stack frame classes) and cause double free issues. MallocScribble helped to find these issues after I did some other cleanup. To help avoid any RegisterContext issue in the future, all code that deals with them now returns shared pointers to the register contexts so we don't end up with multiple deletions. Also now that the RegisterContext class doesn't require a stack frame, we patched a memory leak where a StackFrame object was being created and leaked. Made the RegisterContext class not have a pointer to a StackFrame object as one register context class can be used for N inlined stack frames so there is not a 1 - 1 mapping. Updates the ExecutionContextScope part of the RegisterContext class to never return a stack frame to indicate this when it is asked to recreate the execution context. Now register contexts point to the concrete frame using a concrete frame index. Concrete frames are all of the frames that are actually formed on the stack of a thread. These concrete frames can be turned into one or more user visible frames due to inlining. Each inlined stack frame has the exact same register context (shared via shared pointers) as any parent inlined stack frames all the way up to the concrete frame itself. So now the stack frames and the register contexts should behave much better. llvm-svn: 122976
2011-01-07 06:15:06 +08:00
RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
assert (reg_ctx);
addr_t pc = reg_ctx->GetPC();
addr_t sp = reg_ctx->GetSP();
addr_t fp = reg_ctx->GetFP();
log->Printf("%s Thread #%u (0x%p): tid = 0x%4.4" PRIx64 ", pc = 0x%8.8" PRIx64 ", sp = 0x%8.8" PRIx64 ", fp = 0x%8.8" PRIx64 ", "
"plan = '%s', state = %s, stop others = %d",
__FUNCTION__, m_thread.GetIndexID(),
static_cast<void*>(&m_thread), m_thread.GetID(),
static_cast<uint64_t>(pc), static_cast<uint64_t>(sp),
static_cast<uint64_t>(fp), m_name.c_str(),
StateAsCString(resume_state), StopOthers());
}
}
Figure out the reply to "PlanExplainsStop" once when we stop and then use the cached value. This fixes problems, for instance, with the StepRange plans, where they know that they explained the stop because they were at their "run to here" breakpoint, then deleted that breakpoint, so when they got asked again, doh! I had done this for a couple of plans in an ad hoc fashion, this just formalizes it. Also add a "ResumeRequested" in Process so that the code in the completion handlers can tell the ShouldStop logic they want to resume rather than just directly resuming. That allows us to handle resuming in a more controlled fashion. Also, SetPublicState can take a "restarted" flag, so that it doesn't drop the run lock when the target was immediately restarted. --This line, and those below , will be ignored-- M test/lang/objc/objc-dynamic-value/TestObjCDynamicValue.py M include/lldb/Target/ThreadList.h M include/lldb/Target/ThreadPlanStepOut.h M include/lldb/Target/Thread.h M include/lldb/Target/ThreadPlanBase.h M include/lldb/Target/ThreadPlanStepThrough.h M include/lldb/Target/ThreadPlanStepInstruction.h M include/lldb/Target/ThreadPlanStepInRange.h M include/lldb/Target/ThreadPlanStepOverBreakpoint.h M include/lldb/Target/ThreadPlanStepUntil.h M include/lldb/Target/StopInfo.h M include/lldb/Target/Process.h M include/lldb/Target/ThreadPlanRunToAddress.h M include/lldb/Target/ThreadPlan.h M include/lldb/Target/ThreadPlanCallFunction.h M include/lldb/Target/ThreadPlanStepOverRange.h M source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h M source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp M source/Target/StopInfo.cpp M source/Target/Process.cpp M source/Target/ThreadPlanRunToAddress.cpp M source/Target/ThreadPlan.cpp M source/Target/ThreadPlanCallFunction.cpp M source/Target/ThreadPlanStepOverRange.cpp M source/Target/ThreadList.cpp M source/Target/ThreadPlanStepOut.cpp M source/Target/Thread.cpp M source/Target/ThreadPlanBase.cpp M source/Target/ThreadPlanStepThrough.cpp M source/Target/ThreadPlanStepInstruction.cpp M source/Target/ThreadPlanStepInRange.cpp M source/Target/ThreadPlanStepOverBreakpoint.cpp M source/Target/ThreadPlanStepUntil.cpp M lldb.xcodeproj/xcshareddata/xcschemes/Run Testsuite.xcscheme llvm-svn: 181381
2013-05-08 08:35:16 +08:00
return DoWillResume (resume_state, current_plan);
}
lldb::user_id_t
ThreadPlan::GetNextID()
{
static uint32_t g_nextPlanID = 0;
return ++g_nextPlanID;
}
void
ThreadPlan::DidPush()
{
}
void
ThreadPlan::WillPop()
{
}
bool
ThreadPlan::OkayToDiscard()
{
if (!IsMasterPlan())
return true;
else
return m_okay_to_discard;
}
lldb::StateType
ThreadPlan::RunState ()
{
if (m_tracer_sp && m_tracer_sp->TracingEnabled() && m_tracer_sp->SingleStepEnabled())
return eStateStepping;
else
return GetPlanRunState();
}
bool
ThreadPlan::IsUsuallyUnexplainedStopReason(lldb::StopReason reason)
{
switch (reason)
{
case eStopReasonWatchpoint:
case eStopReasonSignal:
case eStopReasonException:
case eStopReasonExec:
case eStopReasonThreadExiting:
case eStopReasonInstrumentation:
return true;
default:
return false;
}
}
//----------------------------------------------------------------------
// 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%" PRIx64 ", ptid = 0x%" PRIx64 ")",
__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%" PRIx64 ", ptid = 0x%" PRIx64 ")",
__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%" PRIx64 ", ptid = 0x%" PRIx64 ")",
__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%" PRIx64 ", ptid = 0x%" PRIx64 ")",
__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%" PRIx64 ", ptid = 0x%" PRIx64 ")",
__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%" PRIx64 ", ptid = 0x%" PRIx64 ")",
__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%" PRIx64 ", ptid = 0x%" PRIx64 ")",
__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%" PRIx64 ", ptid = 0x%" PRIx64 ")",
__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%" PRIx64 ", ptid = 0x%" PRIx64 ")",
__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%" PRIx64 ", ptid = 0x%" PRIx64 ")",
__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%" PRIx64 ", ptid = 0x%" PRIx64 ")",
__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%" PRIx64 ", ptid = 0x%" PRIx64 ")",
__PRETTY_FUNCTION__,
m_thread.GetID(),
m_thread.GetProtocolID());
#endif
return eStateRunning;
}