blob: cc5dcf89db0f77c04a1a8a3dc8664ad9b7211f57 [file] [log] [blame]
//===-- Thread.h ------------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_Thread_h_
#define liblldb_Thread_h_
#include "lldb/lldb-private.h"
#include "lldb/Host/Mutex.h"
#include "lldb/Core/UserID.h"
#include "lldb/Target/ExecutionContextScope.h"
#include "lldb/Target/StackFrameList.h"
#define LLDB_THREAD_MAX_STOP_EXC_DATA 8
// I forward declare these here so I don't have to #include ThreadPlan, so in turn I
// can use Thread.h in ThreadPlan.h.
namespace lldb_private {
class Thread :
public UserID,
public ExecutionContextScope
{
friend class ThreadPlan;
public:
//----------------------------------------------------------------------
// StopInfo
//
// Describes the reason the thread it was created with stopped.
//----------------------------------------------------------------------
class StopInfo
{
public:
StopInfo(Thread *thread = NULL);
~StopInfo();
// Clear clears the stop reason, but it does not clear the thread this
// StopInfo is tied to.
void
Clear();
lldb::StopReason
GetStopReason() const;
void
SetThread (Thread *thread);
Thread *
GetThread ();
void
SetStopReasonWithBreakpointSiteID (lldb::user_id_t break_id);
void
SetStopReasonWithWatchpointID (lldb::user_id_t watch_id);
void
SetStopReasonWithSignal (int signo);
void
SetStopReasonToTrace ();
void
SetStopReasonWithException (uint32_t exc_type, size_t exc_data_count);
void
SetStopReasonWithPlan (lldb::ThreadPlanSP &plan);
void
SetStopReasonToNone ();
const char *
GetStopDescription() const;
void
SetStopDescription(const char *desc);
lldb::user_id_t
GetBreakpointSiteID() const;
lldb::user_id_t
GetWatchpointID() const;
int
GetSignal() const;
lldb::user_id_t
GetPlanID () const;
uint32_t
GetExceptionType() const;
size_t
GetExceptionDataCount() const;
lldb::addr_t
GetExceptionDataAtIndex (uint32_t idx) const;
bool
SetExceptionDataAtIndex (uint32_t idx, lldb::addr_t data);
void
Dump (Stream *s) const;
protected:
lldb::StopReason m_reason;
//--------------------------------------------------------------
// For eStopReasonPlan the completed plan is stored in this shared pointer.
//--------------------------------------------------------------
lldb::ThreadPlanSP m_completed_plan_sp;
Thread *m_thread;
char m_description[256];
union
{
//--------------------------------------------------------------
// eStopReasonBreakpoint
//--------------------------------------------------------------
struct
{
lldb::user_id_t bp_site_id;
} breakpoint;
//--------------------------------------------------------------
// eStopReasonWatchpoint
//--------------------------------------------------------------
struct
{
lldb::user_id_t watch_id;
} watchpoint;
//--------------------------------------------------------------
// eStopReasonSignal
//--------------------------------------------------------------
struct
{
int signo;
} signal;
//--------------------------------------------------------------
// eStopReasonException
//--------------------------------------------------------------
struct
{
uint32_t type;
size_t data_count;
lldb::addr_t data[LLDB_THREAD_MAX_STOP_EXC_DATA];
} exception;
} m_details;
};
class RegisterCheckpoint
{
public:
RegisterCheckpoint() :
m_stack_id (),
m_data_sp ()
{
}
RegisterCheckpoint (const StackID &stack_id) :
m_stack_id (stack_id),
m_data_sp ()
{
}
~RegisterCheckpoint()
{
}
const StackID &
GetStackID()
{
return m_stack_id;
}
void
SetStackID (const StackID &stack_id)
{
m_stack_id = stack_id;
}
lldb::DataBufferSP &
GetData()
{
return m_data_sp;
}
const lldb::DataBufferSP &
GetData() const
{
return m_data_sp;
}
protected:
StackID m_stack_id;
lldb::DataBufferSP m_data_sp;
};
Thread (Process &process, lldb::tid_t tid);
virtual ~Thread();
Process &
GetProcess() { return m_process; }
const Process &
GetProcess() const { return m_process; }
int
GetResumeSignal () const;
void
SetResumeSignal (int signal);
lldb::StateType
GetState() const;
lldb::ThreadSP
GetSP ();
void
SetState (lldb::StateType state);
lldb::StateType
GetResumeState () const;
void
SetResumeState (lldb::StateType state);
// This function is called on all the threads before "WillResume" in case
// a thread needs to change its state before the ThreadList polls all the
// threads to figure out which ones actually will get to run and how.
void
SetupForResume ();
// Override this to do platform specific tasks before resume, but always
// call the Thread::WillResume at the end of your work.
virtual bool
WillResume (lldb::StateType resume_state);
// This clears generic thread state after a resume. If you subclass this,
// be sure to call it.
virtual void
DidResume ();
virtual void
RefreshStateAfterStop() = 0;
void
WillStop ();
bool
ShouldStop (Event *event_ptr);
lldb::Vote
ShouldReportStop (Event *event_ptr);
lldb::Vote
ShouldReportRun (Event *event_ptr);
bool
GetStopInfo (StopInfo *stop_info);
bool
ThreadStoppedForAReason ();
virtual const char *
GetInfo () = 0;
virtual const char *
GetName ()
{
return NULL;
}
virtual const char *
GetQueueName ()
{
return NULL;
}
virtual uint32_t
GetStackFrameCount() = 0;
virtual lldb::StackFrameSP
GetStackFrameAtIndex (uint32_t idx) = 0;
lldb::StackFrameSP
GetCurrentFrame ();
uint32_t
SetCurrentFrame (lldb_private::StackFrame *frame);
void
SetCurrentFrameByIndex (uint32_t frame_idx);
virtual RegisterContext *
GetRegisterContext () = 0;
virtual bool
SaveFrameZeroState (RegisterCheckpoint &checkpoint) = 0;
virtual bool
RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint) = 0;
virtual RegisterContext *
CreateRegisterContextForFrame (StackFrame *frame) = 0;
virtual void
ClearStackFrames ()
{
m_frames.Clear();
}
void
DumpInfo (Stream &strm,
bool show_stop_reason,
bool show_name,
bool show_queue,
uint32_t frame_idx);// = UINT32_MAX);
//------------------------------------------------------------------
// Thread Plan Providers:
// This section provides the basic thread plans that the Process control
// machinery uses to run the target. ThreadPlan.h provides more details on
// how this mechanism works.
// The thread provides accessors to a set of plans that perform basic operations.
// The idea is that particular Platform plugins can override these methods to
// provide the implementation of these basic operations appropriate to their
// environment.
//------------------------------------------------------------------
//------------------------------------------------------------------
/// Queues the base plan for a thread.
/// The version returned by Process does some things that are useful,
/// like handle breakpoints and signals, so if you return a plugin specific
/// one you probably want to call through to the Process one for anything
/// your plugin doesn't explicitly handle.
///
/// @param[in] abort_other_plans
/// \b true if we discard the currently queued plans and replace them with this one.
/// Otherwise this plan will go on the end of the plan stack.
///
/// @return
/// A pointer to the newly queued thread plan, or NULL if the plan could not be queued.
//------------------------------------------------------------------
virtual ThreadPlan *
QueueFundamentalPlan (bool abort_other_plans);
//------------------------------------------------------------------
/// Queues the plan used to step over a breakpoint at the current PC of \a thread.
/// The default version returned by Process handles trap based breakpoints, and
/// will disable the breakpoint, single step over it, then re-enable it.
///
/// @param[in] abort_other_plans
/// \b true if we discard the currently queued plans and replace them with this one.
/// Otherwise this plan will go on the end of the plan stack.
///
/// @return
/// A pointer to the newly queued thread plan, or NULL if the plan could not be queued.
//------------------------------------------------------------------
virtual ThreadPlan *
QueueThreadPlanForStepOverBreakpointPlan (bool abort_other_plans);
//------------------------------------------------------------------
/// Queues the plan used to step one instruction from the current PC of \a thread.
///
/// @param[in] step_over
/// \b true if we step over calls to functions, false if we step in.
///
/// @param[in] abort_other_plans
/// \b true if we discard the currently queued plans and replace them with this one.
/// Otherwise this plan will go on the end of the plan stack.
///
/// @param[in] stop_other_threads
/// \b true if we will stop other threads while we single step this one.
///
/// @return
/// A pointer to the newly queued thread plan, or NULL if the plan could not be queued.
//------------------------------------------------------------------
virtual ThreadPlan *
QueueThreadPlanForStepSingleInstruction (bool step_over,
bool abort_other_plans,
bool stop_other_threads);
//------------------------------------------------------------------
/// Queues the plan used to step through an address range, stepping into or over
/// function calls depending on the value of StepType.
///
/// @param[in] abort_other_plans
/// \b true if we discard the currently queued plans and replace them with this one.
/// Otherwise this plan will go on the end of the plan stack.
///
/// @param[in] type
/// Type of step to do, only eStepTypeInto and eStepTypeOver are supported by this plan.
///
/// @param[in] range
/// The address range to step through.
///
/// @param[in] addr_context
/// When dealing with stepping through inlined functions the current PC is not enough information to know
/// what "step" means. For instance a series of nested inline functions might start at the same address.
// The \a addr_context provides the current symbol context the step
/// is supposed to be out of.
// FIXME: Currently unused.
///
/// @param[in] stop_other_threads
/// \b true if we will stop other threads while we single step this one.
///
/// @return
/// A pointer to the newly queued thread plan, or NULL if the plan could not be queued.
//------------------------------------------------------------------
virtual ThreadPlan *
QueueThreadPlanForStepRange (bool abort_other_plans,
lldb::StepType type,
const AddressRange &range,
const SymbolContext &addr_context,
lldb::RunMode stop_other_threads);
//------------------------------------------------------------------
/// Queue the plan used to step out of the function at the current PC of
/// \a thread.
///
/// @param[in] abort_other_plans
/// \b true if we discard the currently queued plans and replace them with this one.
/// Otherwise this plan will go on the end of the plan stack.
///
/// @param[in] addr_context
/// When dealing with stepping through inlined functions the current PC is not enough information to know
/// what "step" means. For instance a series of nested inline functions might start at the same address.
// The \a addr_context provides the current symbol context the step
/// is supposed to be out of.
// FIXME: Currently unused.
///
/// @param[in] first_insn
/// \b true if this is the first instruction of a function.
///
/// @param[in] stop_other_threads
/// \b true if we will stop other threads while we single step this one.
///
/// @param[in] stop_vote
/// @param[in] run_vote
/// See standard meanings for the stop & run votes in ThreadPlan.h.
///
/// @return
/// A pointer to the newly queued thread plan, or NULL if the plan could not be queued.
//------------------------------------------------------------------
virtual ThreadPlan *
QueueThreadPlanForStepOut (bool abort_other_plans,
SymbolContext *addr_context,
bool first_insn,
bool stop_other_threads,
lldb::Vote stop_vote = lldb::eVoteYes,
lldb::Vote run_vote = lldb::eVoteNoOpinion);
//------------------------------------------------------------------
/// Gets the plan used to step through the code that steps from a function
/// call site at the current PC into the actual function call.
///
/// @param[in] abort_other_plans
/// \b true if we discard the currently queued plans and replace them with this one.
/// Otherwise this plan will go on the end of the plan stack.
///
/// @param[in] stop_other_threads
/// \b true if we will stop other threads while we single step this one.
///
/// @return
/// A pointer to the newly queued thread plan, or NULL if the plan could not be queued.
//------------------------------------------------------------------
virtual ThreadPlan *
QueueThreadPlanForStepThrough (bool abort_other_plans,
bool stop_other_threads);
//------------------------------------------------------------------
/// Gets the plan used to continue from the current PC.
/// This is a simple plan, mostly useful as a backstop when you are continuing
/// for some particular purpose.
///
/// @param[in] abort_other_plans
/// \b true if we discard the currently queued plans and replace them with this one.
/// Otherwise this plan will go on the end of the plan stack.
///
/// @param[in] stop_other_threads
/// \b true if we will stop other threads while we single step this one.
///
/// @param[in] stop_vote
/// @param[in] run_vote
/// See standard meanings for the stop & run votes in ThreadPlan.h.
///
/// @return
/// A pointer to the newly queued thread plan, or NULL if the plan could not be queued.
//------------------------------------------------------------------
virtual ThreadPlan *
QueueThreadPlanForContinue (bool abort_other_plans,
bool stop_other_threads,
lldb::Vote stop_vote,
lldb::Vote run_vote = lldb::eVoteNoOpinion,
bool immediate = false);
//------------------------------------------------------------------
/// Gets the plan used to continue from the current PC.
/// This is a simple plan, mostly useful as a backstop when you are continuing
/// for some particular purpose.
///
/// @param[in] abort_other_plans
/// \b true if we discard the currently queued plans and replace them with this one.
/// Otherwise this plan will go on the end of the plan stack.
///
/// @param[in] target_addr
/// The address to which we're running.
///
/// @param[in] stop_other_threads
/// \b true if we will stop other threads while we single step this one.
///
/// @return
/// A pointer to the newly queued thread plan, or NULL if the plan could not be queued.
//------------------------------------------------------------------
virtual ThreadPlan *
QueueThreadPlanForRunToAddress (bool abort_other_plans,
Address &target_addr,
bool stop_other_threads);
virtual ThreadPlan *
QueueThreadPlanForStepUntil (bool abort_other_plans,
lldb::addr_t *address_list,
size_t num_addresses,
bool stop_others);
virtual ThreadPlan *
QueueThreadPlanForCallFunction (bool abort_other_plans,
Address& function,
lldb::addr_t arg,
bool stop_other_threads,
bool discard_on_error = false);
virtual ThreadPlan *
QueueThreadPlanForCallFunction (bool abort_other_plans,
Address& function,
ValueList &args,
bool stop_other_threads,
bool discard_on_error = false);
//------------------------------------------------------------------
// Thread Plan accessors:
//------------------------------------------------------------------
//------------------------------------------------------------------
/// Gets the plan which will execute next on the plan stack.
///
/// @return
/// A pointer to the next executed plan.
//------------------------------------------------------------------
ThreadPlan *
GetCurrentPlan ();
//------------------------------------------------------------------
/// Gets the inner-most plan that was popped off the plan stack in the
/// most recent stop. Useful for printing the stop reason accurately.
///
/// @return
/// A pointer to the last completed plan.
//------------------------------------------------------------------
lldb::ThreadPlanSP
GetCompletedPlan ();
//------------------------------------------------------------------
/// Checks whether the given plan is in the completed plans for this
/// stop.
///
/// @param[in] plan
/// Pointer to the plan you're checking.
///
/// @return
/// Returns true if the input plan is in the completed plan stack,
/// false otherwise.
//------------------------------------------------------------------
bool
IsThreadPlanDone (ThreadPlan *plan);
//------------------------------------------------------------------
/// Checks whether the given plan is in the discarded plans for this
/// stop.
///
/// @param[in] plan
/// Pointer to the plan you're checking.
///
/// @return
/// Returns true if the input plan is in the discarded plan stack,
/// false otherwise.
//------------------------------------------------------------------
bool
WasThreadPlanDiscarded (ThreadPlan *plan);
//------------------------------------------------------------------
/// Queues a generic thread plan.
///
/// @param[in] plan_sp
/// The plan to queue.
///
/// @param[in] abort_other_plans
/// \b true if we discard the currently queued plans and replace them with this one.
/// Otherwise this plan will go on the end of the plan stack.
///
/// @return
/// A pointer to the last completed plan.
//------------------------------------------------------------------
void
QueueThreadPlan (lldb::ThreadPlanSP &plan_sp, bool abort_other_plans);
//------------------------------------------------------------------
/// Discards the plans queued on the plan stack of the current thread. This is
/// arbitrated by the "Master" ThreadPlans, using the "OkayToDiscard" call.
// But if \a force is true, all thread plans are discarded.
//------------------------------------------------------------------
void
DiscardThreadPlans (bool force);
//------------------------------------------------------------------
/// Prints the current plan stack.
///
/// @param[in] s
/// The stream to which to dump the plan stack info.
///
//------------------------------------------------------------------
void
DumpThreadPlans (Stream *s) const;
// Get the thread index ID. The index ID that is guaranteed to not be
// re-used by a process. They start at 1 and increase with each new thread.
// This allows easy command line access by a unique ID that is easier to
// type than the actual system thread ID.
uint32_t
GetIndexID () const;
//------------------------------------------------------------------
// lldb::ExecutionContextScope pure virtual functions
//------------------------------------------------------------------
virtual Target *
CalculateTarget ();
virtual Process *
CalculateProcess ();
virtual Thread *
CalculateThread ();
virtual StackFrame *
CalculateStackFrame ();
virtual void
Calculate (ExecutionContext &exe_ctx);
protected:
void
PushPlan (lldb::ThreadPlanSP &plan_sp);
void
PopPlan ();
void
DiscardPlan ();
ThreadPlan *GetPreviousPlan (ThreadPlan *plan);
virtual bool
GetRawStopReason (StopInfo *stop_info) = 0;
typedef std::vector<lldb::ThreadPlanSP> plan_stack;
//------------------------------------------------------------------
// Classes that inherit from Process can see and modify these
//------------------------------------------------------------------
Process & m_process; ///< The process that owns this thread.
const uint32_t m_index_id; ///< A unique 1 based index assigned to each thread for easy UI/command line access.
lldb::RegisterContextSP m_reg_context_sp; ///< The register context for this thread's current register state.
lldb::StateType m_state; ///< The state of our process.
plan_stack m_plan_stack; ///< The stack of plans this thread is executing.
plan_stack m_immediate_plan_stack; ///< The plans that need to get executed before any other work gets done.
plan_stack m_completed_plan_stack; ///< Plans that have been completed by this stop. They get deleted when the thread resumes.
plan_stack m_discarded_plan_stack; ///< Plans that have been discarded by this stop. They get deleted when the thread resumes.
mutable Mutex m_state_mutex; ///< Multithreaded protection for m_state.
StackFrameList m_frames; ///< The stack frames that get lazily populated after a thread stops.
uint32_t m_current_frame_idx;///< The current frame for this thread
int m_resume_signal; ///< The signal that should be used when continuing this thread.
lldb::StateType m_resume_state; ///< The state that indicates what this thread should do when the process is resumed.
private:
//------------------------------------------------------------------
// For Thread only
//------------------------------------------------------------------
DISALLOW_COPY_AND_ASSIGN (Thread);
};
} // namespace lldb_private
#endif // liblldb_Thread_h_