| //===-- Thread.h ------------------------------------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef liblldb_Thread_h_ |
| #define liblldb_Thread_h_ |
| |
| #include <memory> |
| #include <mutex> |
| #include <string> |
| #include <vector> |
| |
| #include "lldb/Core/UserSettingsController.h" |
| #include "lldb/Target/ExecutionContextScope.h" |
| #include "lldb/Target/RegisterCheckpoint.h" |
| #include "lldb/Target/StackFrameList.h" |
| #include "lldb/Utility/Broadcaster.h" |
| #include "lldb/Utility/Event.h" |
| #include "lldb/Utility/StructuredData.h" |
| #include "lldb/Utility/UserID.h" |
| #include "lldb/lldb-private.h" |
| |
| #define LLDB_THREAD_MAX_STOP_EXC_DATA 8 |
| |
| namespace lldb_private { |
| |
| class ThreadProperties : public Properties { |
| public: |
| ThreadProperties(bool is_global); |
| |
| ~ThreadProperties() override; |
| |
| /// The regular expression returned determines symbols that this |
| /// thread won't stop in during "step-in" operations. |
| /// |
| /// \return |
| /// A pointer to a regular expression to compare against symbols, |
| /// or nullptr if all symbols are allowed. |
| /// |
| const RegularExpression *GetSymbolsToAvoidRegexp(); |
| |
| FileSpecList GetLibrariesToAvoid() const; |
| |
| bool GetTraceEnabledState() const; |
| |
| bool GetStepInAvoidsNoDebug() const; |
| |
| bool GetStepOutAvoidsNoDebug() const; |
| |
| uint64_t GetMaxBacktraceDepth() const; |
| }; |
| |
| typedef std::shared_ptr<ThreadProperties> ThreadPropertiesSP; |
| |
| class Thread : public std::enable_shared_from_this<Thread>, |
| public ThreadProperties, |
| public UserID, |
| public ExecutionContextScope, |
| public Broadcaster { |
| public: |
| /// Broadcaster event bits definitions. |
| enum { |
| eBroadcastBitStackChanged = (1 << 0), |
| eBroadcastBitThreadSuspended = (1 << 1), |
| eBroadcastBitThreadResumed = (1 << 2), |
| eBroadcastBitSelectedFrameChanged = (1 << 3), |
| eBroadcastBitThreadSelected = (1 << 4) |
| }; |
| |
| static ConstString &GetStaticBroadcasterClass(); |
| |
| ConstString &GetBroadcasterClass() const override { |
| return GetStaticBroadcasterClass(); |
| } |
| |
| class ThreadEventData : public EventData { |
| public: |
| ThreadEventData(const lldb::ThreadSP thread_sp); |
| |
| ThreadEventData(const lldb::ThreadSP thread_sp, const StackID &stack_id); |
| |
| ThreadEventData(); |
| |
| ~ThreadEventData() override; |
| |
| static ConstString GetFlavorString(); |
| |
| ConstString GetFlavor() const override { |
| return ThreadEventData::GetFlavorString(); |
| } |
| |
| void Dump(Stream *s) const override; |
| |
| static const ThreadEventData *GetEventDataFromEvent(const Event *event_ptr); |
| |
| static lldb::ThreadSP GetThreadFromEvent(const Event *event_ptr); |
| |
| static StackID GetStackIDFromEvent(const Event *event_ptr); |
| |
| static lldb::StackFrameSP GetStackFrameFromEvent(const Event *event_ptr); |
| |
| lldb::ThreadSP GetThread() const { return m_thread_sp; } |
| |
| StackID GetStackID() const { return m_stack_id; } |
| |
| private: |
| lldb::ThreadSP m_thread_sp; |
| StackID m_stack_id; |
| |
| DISALLOW_COPY_AND_ASSIGN(ThreadEventData); |
| }; |
| |
| struct ThreadStateCheckpoint { |
| uint32_t orig_stop_id; // Dunno if I need this yet but it is an interesting |
| // bit of data. |
| lldb::StopInfoSP stop_info_sp; // You have to restore the stop info or you |
| // might continue with the wrong signals. |
| std::vector<lldb::ThreadPlanSP> m_completed_plan_stack; |
| lldb::RegisterCheckpointSP |
| register_backup_sp; // You need to restore the registers, of course... |
| uint32_t current_inlined_depth; |
| lldb::addr_t current_inlined_pc; |
| }; |
| |
| /// Constructor |
| /// |
| /// \param [in] process |
| /// |
| /// \param [in] tid |
| /// |
| /// \param [in] use_invalid_index_id |
| /// Optional parameter, defaults to false. The only subclass that |
| /// is likely to set use_invalid_index_id == true is the HistoryThread |
| /// class. In that case, the Thread we are constructing represents |
| /// a thread from earlier in the program execution. We may have the |
| /// tid of the original thread that they represent but we don't want |
| /// to reuse the IndexID of that thread, or create a new one. If a |
| /// client wants to know the original thread's IndexID, they should use |
| /// Thread::GetExtendedBacktraceOriginatingIndexID(). |
| Thread(Process &process, lldb::tid_t tid, bool use_invalid_index_id = false); |
| |
| ~Thread() override; |
| |
| static void SettingsInitialize(); |
| |
| static void SettingsTerminate(); |
| |
| static const ThreadPropertiesSP &GetGlobalProperties(); |
| |
| lldb::ProcessSP GetProcess() const { return m_process_wp.lock(); } |
| |
| int GetResumeSignal() const { return m_resume_signal; } |
| |
| void SetResumeSignal(int signal) { m_resume_signal = signal; } |
| |
| lldb::StateType GetState() const; |
| |
| void SetState(lldb::StateType state); |
| |
| /// Sets the USER resume state for this thread. If you set a thread to |
| /// suspended with |
| /// this API, it won't take part in any of the arbitration for ShouldResume, |
| /// and will stay |
| /// suspended even when other threads do get to run. |
| /// |
| /// N.B. This is not the state that is used internally by thread plans to |
| /// implement |
| /// staying on one thread while stepping over a breakpoint, etc. The is the |
| /// TemporaryResume state, and if you are implementing some bit of strategy in |
| /// the stepping |
| /// machinery you should be using that state and not the user resume state. |
| /// |
| /// If you are just preparing all threads to run, you should not override the |
| /// threads that are |
| /// marked as suspended by the debugger. In that case, pass override_suspend |
| /// = false. If you want |
| /// to force the thread to run (e.g. the "thread continue" command, or are |
| /// resetting the state |
| /// (e.g. in SBThread::Resume()), then pass true to override_suspend. |
| /// \return |
| /// The User resume state for this thread. |
| void SetResumeState(lldb::StateType state, bool override_suspend = false) { |
| if (m_resume_state == lldb::eStateSuspended && !override_suspend) |
| return; |
| m_resume_state = state; |
| } |
| |
| /// Gets the USER resume state for this thread. This is not the same as what |
| /// this thread is going to do for any particular step, however if this thread |
| /// returns eStateSuspended, then the process control logic will never allow |
| /// this |
| /// thread to run. |
| /// |
| /// \return |
| /// The User resume state for this thread. |
| lldb::StateType GetResumeState() const { return m_resume_state; } |
| |
| // This function is called on all the threads before "ShouldResume" and |
| // "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(); |
| |
| // Do not override this function, it is for thread plan logic only |
| bool ShouldResume(lldb::StateType resume_state); |
| |
| // Override this to do platform specific tasks before resume. |
| virtual void 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(); |
| |
| // This notifies the thread when a private stop occurs. |
| virtual void DidStop(); |
| |
| virtual void RefreshStateAfterStop() = 0; |
| |
| void WillStop(); |
| |
| bool ShouldStop(Event *event_ptr); |
| |
| Vote ShouldReportStop(Event *event_ptr); |
| |
| Vote ShouldReportRun(Event *event_ptr); |
| |
| void Flush(); |
| |
| // Return whether this thread matches the specification in ThreadSpec. This |
| // is a virtual method because at some point we may extend the thread spec |
| // with a platform specific dictionary of attributes, which then only the |
| // platform specific Thread implementation would know how to match. For now, |
| // this just calls through to the ThreadSpec's ThreadPassesBasicTests method. |
| virtual bool MatchesSpec(const ThreadSpec *spec); |
| |
| lldb::StopInfoSP GetStopInfo(); |
| |
| lldb::StopReason GetStopReason(); |
| |
| bool StopInfoIsUpToDate() const; |
| |
| // This sets the stop reason to a "blank" stop reason, so you can call |
| // functions on the thread without having the called function run with |
| // whatever stop reason you stopped with. |
| void SetStopInfoToNothing(); |
| |
| bool ThreadStoppedForAReason(); |
| |
| static const char *RunModeAsCString(lldb::RunMode mode); |
| |
| static const char *StopReasonAsCString(lldb::StopReason reason); |
| |
| virtual const char *GetInfo() { return nullptr; } |
| |
| /// Retrieve a dictionary of information about this thread |
| /// |
| /// On Mac OS X systems there may be voucher information. |
| /// The top level dictionary returned will have an "activity" key and the |
| /// value of the activity is a dictionary. Keys in that dictionary will |
| /// be "name" and "id", among others. |
| /// There may also be "trace_messages" (an array) with each entry in that |
| /// array |
| /// being a dictionary (keys include "message" with the text of the trace |
| /// message). |
| StructuredData::ObjectSP GetExtendedInfo() { |
| if (!m_extended_info_fetched) { |
| m_extended_info = FetchThreadExtendedInfo(); |
| m_extended_info_fetched = true; |
| } |
| return m_extended_info; |
| } |
| |
| virtual const char *GetName() { return nullptr; } |
| |
| virtual void SetName(const char *name) {} |
| |
| /// Whether this thread can be associated with a libdispatch queue |
| /// |
| /// The Thread may know if it is associated with a libdispatch queue, |
| /// it may know definitively that it is NOT associated with a libdispatch |
| /// queue, or it may be unknown whether it is associated with a libdispatch |
| /// queue. |
| /// |
| /// \return |
| /// eLazyBoolNo if this thread is definitely not associated with a |
| /// libdispatch queue (e.g. on a non-Darwin system where GCD aka |
| /// libdispatch is not available). |
| /// |
| /// eLazyBoolYes this thread is associated with a libdispatch queue. |
| /// |
| /// eLazyBoolCalculate this thread may be associated with a libdispatch |
| /// queue but the thread doesn't know one way or the other. |
| virtual lldb_private::LazyBool GetAssociatedWithLibdispatchQueue() { |
| return eLazyBoolNo; |
| } |
| |
| virtual void SetAssociatedWithLibdispatchQueue( |
| lldb_private::LazyBool associated_with_libdispatch_queue) {} |
| |
| /// Retrieve the Queue ID for the queue currently using this Thread |
| /// |
| /// If this Thread is doing work on behalf of a libdispatch/GCD queue, |
| /// retrieve the QueueID. |
| /// |
| /// This is a unique identifier for the libdispatch/GCD queue in a |
| /// process. Often starting at 1 for the initial system-created |
| /// queues and incrementing, a QueueID will not be reused for a |
| /// different queue during the lifetime of a process. |
| /// |
| /// \return |
| /// A QueueID if the Thread subclass implements this, else |
| /// LLDB_INVALID_QUEUE_ID. |
| virtual lldb::queue_id_t GetQueueID() { return LLDB_INVALID_QUEUE_ID; } |
| |
| virtual void SetQueueID(lldb::queue_id_t new_val) {} |
| |
| /// Retrieve the Queue name for the queue currently using this Thread |
| /// |
| /// If this Thread is doing work on behalf of a libdispatch/GCD queue, |
| /// retrieve the Queue name. |
| /// |
| /// \return |
| /// The Queue name, if the Thread subclass implements this, else |
| /// nullptr. |
| virtual const char *GetQueueName() { return nullptr; } |
| |
| virtual void SetQueueName(const char *name) {} |
| |
| /// Retrieve the Queue kind for the queue currently using this Thread |
| /// |
| /// If this Thread is doing work on behalf of a libdispatch/GCD queue, |
| /// retrieve the Queue kind - either eQueueKindSerial or |
| /// eQueueKindConcurrent, indicating that this queue processes work |
| /// items serially or concurrently. |
| /// |
| /// \return |
| /// The Queue kind, if the Thread subclass implements this, else |
| /// eQueueKindUnknown. |
| virtual lldb::QueueKind GetQueueKind() { return lldb::eQueueKindUnknown; } |
| |
| virtual void SetQueueKind(lldb::QueueKind kind) {} |
| |
| /// Retrieve the Queue for this thread, if any. |
| /// |
| /// \return |
| /// A QueueSP for the queue that is currently associated with this |
| /// thread. |
| /// An empty shared pointer indicates that this thread is not |
| /// associated with a queue, or libdispatch queues are not |
| /// supported on this target. |
| virtual lldb::QueueSP GetQueue() { return lldb::QueueSP(); } |
| |
| /// Retrieve the address of the libdispatch_queue_t struct for queue |
| /// currently using this Thread |
| /// |
| /// If this Thread is doing work on behalf of a libdispatch/GCD queue, |
| /// retrieve the address of the libdispatch_queue_t structure describing |
| /// the queue. |
| /// |
| /// This address may be reused for different queues later in the Process |
| /// lifetime and should not be used to identify a queue uniquely. Use |
| /// the GetQueueID() call for that. |
| /// |
| /// \return |
| /// The Queue's libdispatch_queue_t address if the Thread subclass |
| /// implements this, else LLDB_INVALID_ADDRESS. |
| virtual lldb::addr_t GetQueueLibdispatchQueueAddress() { |
| return LLDB_INVALID_ADDRESS; |
| } |
| |
| virtual void SetQueueLibdispatchQueueAddress(lldb::addr_t dispatch_queue_t) {} |
| |
| /// Whether this Thread already has all the Queue information cached or not |
| /// |
| /// A Thread may be associated with a libdispatch work Queue at a given |
| /// public stop event. If so, the thread can satisify requests like |
| /// GetQueueLibdispatchQueueAddress, GetQueueKind, GetQueueName, and |
| /// GetQueueID |
| /// either from information from the remote debug stub when it is initially |
| /// created, or it can query the SystemRuntime for that information. |
| /// |
| /// This method allows the SystemRuntime to discover if a thread has this |
| /// information already, instead of calling the thread to get the information |
| /// and having the thread call the SystemRuntime again. |
| virtual bool ThreadHasQueueInformation() const { return false; } |
| |
| virtual uint32_t GetStackFrameCount() { |
| return GetStackFrameList()->GetNumFrames(); |
| } |
| |
| virtual lldb::StackFrameSP GetStackFrameAtIndex(uint32_t idx) { |
| return GetStackFrameList()->GetFrameAtIndex(idx); |
| } |
| |
| virtual lldb::StackFrameSP |
| GetFrameWithConcreteFrameIndex(uint32_t unwind_idx); |
| |
| bool DecrementCurrentInlinedDepth() { |
| return GetStackFrameList()->DecrementCurrentInlinedDepth(); |
| } |
| |
| uint32_t GetCurrentInlinedDepth() { |
| return GetStackFrameList()->GetCurrentInlinedDepth(); |
| } |
| |
| Status ReturnFromFrameWithIndex(uint32_t frame_idx, |
| lldb::ValueObjectSP return_value_sp, |
| bool broadcast = false); |
| |
| Status ReturnFromFrame(lldb::StackFrameSP frame_sp, |
| lldb::ValueObjectSP return_value_sp, |
| bool broadcast = false); |
| |
| Status JumpToLine(const FileSpec &file, uint32_t line, |
| bool can_leave_function, std::string *warnings = nullptr); |
| |
| virtual lldb::StackFrameSP GetFrameWithStackID(const StackID &stack_id) { |
| if (stack_id.IsValid()) |
| return GetStackFrameList()->GetFrameWithStackID(stack_id); |
| return lldb::StackFrameSP(); |
| } |
| |
| uint32_t GetSelectedFrameIndex() { |
| return GetStackFrameList()->GetSelectedFrameIndex(); |
| } |
| |
| lldb::StackFrameSP GetSelectedFrame(); |
| |
| uint32_t SetSelectedFrame(lldb_private::StackFrame *frame, |
| bool broadcast = false); |
| |
| bool SetSelectedFrameByIndex(uint32_t frame_idx, bool broadcast = false); |
| |
| bool SetSelectedFrameByIndexNoisily(uint32_t frame_idx, |
| Stream &output_stream); |
| |
| void SetDefaultFileAndLineToSelectedFrame() { |
| GetStackFrameList()->SetDefaultFileAndLineToSelectedFrame(); |
| } |
| |
| virtual lldb::RegisterContextSP GetRegisterContext() = 0; |
| |
| virtual lldb::RegisterContextSP |
| CreateRegisterContextForFrame(StackFrame *frame) = 0; |
| |
| virtual void ClearStackFrames(); |
| |
| virtual bool SetBackingThread(const lldb::ThreadSP &thread_sp) { |
| return false; |
| } |
| |
| virtual lldb::ThreadSP GetBackingThread() const { return lldb::ThreadSP(); } |
| |
| virtual void ClearBackingThread() { |
| // Subclasses can use this function if a thread is actually backed by |
| // another thread. This is currently used for the OperatingSystem plug-ins |
| // where they might have a thread that is in memory, yet its registers are |
| // available through the lldb_private::Thread subclass for the current |
| // lldb_private::Process class. Since each time the process stops the |
| // backing threads for memory threads can change, we need a way to clear |
| // the backing thread for all memory threads each time we stop. |
| } |
| |
| // If stop_format is true, this will be the form used when we print stop |
| // info. If false, it will be the form we use for thread list and co. |
| void DumpUsingSettingsFormat(Stream &strm, uint32_t frame_idx, |
| bool stop_format); |
| |
| bool GetDescription(Stream &s, lldb::DescriptionLevel level, |
| bool print_json_thread, bool print_json_stopinfo); |
| |
| /// Default implementation for stepping into. |
| /// |
| /// This function is designed to be used by commands where the |
| /// process is publicly stopped. |
| /// |
| /// \param[in] source_step |
| /// If true and the frame has debug info, then do a source level |
| /// step in, else do a single instruction step in. |
| /// |
| /// \param[in] step_in_avoids_code_without_debug_info |
| /// If \a true, then avoid stepping into code that doesn't have |
| /// debug info, else step into any code regardless of whether it |
| /// has debug info. |
| /// |
| /// \param[in] step_out_avoids_code_without_debug_info |
| /// If \a true, then if you step out to code with no debug info, keep |
| /// stepping out till you get to code with debug info. |
| /// |
| /// \return |
| /// An error that describes anything that went wrong |
| virtual Status |
| StepIn(bool source_step, |
| LazyBool step_in_avoids_code_without_debug_info = eLazyBoolCalculate, |
| LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate); |
| |
| /// Default implementation for stepping over. |
| /// |
| /// This function is designed to be used by commands where the |
| /// process is publicly stopped. |
| /// |
| /// \param[in] source_step |
| /// If true and the frame has debug info, then do a source level |
| /// step over, else do a single instruction step over. |
| /// |
| /// \return |
| /// An error that describes anything that went wrong |
| virtual Status StepOver( |
| bool source_step, |
| LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate); |
| |
| /// Default implementation for stepping out. |
| /// |
| /// This function is designed to be used by commands where the |
| /// process is publicly stopped. |
| /// |
| /// \return |
| /// An error that describes anything that went wrong |
| virtual Status StepOut(); |
| |
| /// Retrieves the per-thread data area. |
| /// Most OSs maintain a per-thread pointer (e.g. the FS register on |
| /// x64), which we return the value of here. |
| /// |
| /// \return |
| /// LLDB_INVALID_ADDRESS if not supported, otherwise the thread |
| /// pointer value. |
| virtual lldb::addr_t GetThreadPointer(); |
| |
| /// Retrieves the per-module TLS block for a thread. |
| /// |
| /// \param[in] module |
| /// The module to query TLS data for. |
| /// |
| /// \param[in] tls_file_addr |
| /// The thread local address in module |
| /// \return |
| /// If the thread has TLS data allocated for the |
| /// module, the address of the TLS block. Otherwise |
| /// LLDB_INVALID_ADDRESS is returned. |
| virtual lldb::addr_t GetThreadLocalData(const lldb::ModuleSP module, |
| lldb::addr_t tls_file_addr); |
| |
| /// Check whether this thread is safe to run functions |
| /// |
| /// The SystemRuntime may know of certain thread states (functions in |
| /// process of execution, for instance) which can make it unsafe for |
| /// functions to be called. |
| /// |
| /// \return |
| /// True if it is safe to call functions on this thread. |
| /// False if function calls should be avoided on this thread. |
| virtual bool SafeToCallFunctions(); |
| |
| // 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. |
| // |
| // NB: All the QueueThreadPlanXXX providers return Shared Pointers to |
| // Thread plans. This is useful so that you can modify the plans after |
| // creation in ways specific to that plan type. Also, it is often necessary |
| // for ThreadPlans that utilize other ThreadPlans to implement their task to |
| // keep a shared pointer to the sub-plan. But besides that, the shared |
| // pointers should only be held onto by entities who live no longer than the |
| // thread containing the ThreadPlan. |
| // FIXME: If this becomes a problem, we can make a version that just returns a |
| // pointer, |
| // which it is clearly unsafe to hold onto, and a shared pointer version, and |
| // only allow ThreadPlan and Co. to use the latter. That is made more |
| // annoying to do because there's no elegant way to friend a method to all |
| // sub-classes of a given class. |
| // |
| |
| /// 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 shared pointer to the newly queued thread plan, or nullptr if the |
| /// plan could not be queued. |
| virtual lldb::ThreadPlanSP QueueFundamentalPlan(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. |
| /// |
| /// \param[out] status |
| /// A status with an error if queuing failed. |
| /// |
| /// \return |
| /// A shared pointer to the newly queued thread plan, or nullptr if the |
| /// plan could not be queued. |
| virtual lldb::ThreadPlanSP QueueThreadPlanForStepSingleInstruction( |
| bool step_over, bool abort_other_plans, bool stop_other_threads, |
| Status &status); |
| |
| /// Queues the plan used to step through an address range, stepping over |
| /// function calls. |
| /// |
| /// \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. |
| /// |
| /// \param[out] status |
| /// A status with an error if queuing failed. |
| /// |
| /// \param[in] step_out_avoids_code_without_debug_info |
| /// If eLazyBoolYes, if the step over steps out it will continue to step |
| /// out till it comes to a frame with debug info. |
| /// If eLazyBoolCalculate, we will consult the default set in the thread. |
| /// |
| /// \return |
| /// A shared pointer to the newly queued thread plan, or nullptr if the |
| /// plan could not be queued. |
| virtual lldb::ThreadPlanSP QueueThreadPlanForStepOverRange( |
| bool abort_other_plans, const AddressRange &range, |
| const SymbolContext &addr_context, lldb::RunMode stop_other_threads, |
| Status &status, |
| LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate); |
| |
| // Helper function that takes a LineEntry to step, insted of an AddressRange. |
| // This may combine multiple LineEntries of the same source line number to |
| // step over a longer address range in a single operation. |
| virtual lldb::ThreadPlanSP QueueThreadPlanForStepOverRange( |
| bool abort_other_plans, const LineEntry &line_entry, |
| const SymbolContext &addr_context, lldb::RunMode stop_other_threads, |
| Status &status, |
| LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate); |
| |
| /// Queues the plan used to step through an address range, stepping into |
| /// functions. |
| /// |
| /// \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] step_in_target |
| /// Name if function we are trying to step into. We will step out if we |
| /// don't land in that function. |
| /// |
| /// \param[in] stop_other_threads |
| /// \b true if we will stop other threads while we single step this one. |
| /// |
| /// \param[out] status |
| /// A status with an error if queuing failed. |
| /// |
| /// \param[in] step_in_avoids_code_without_debug_info |
| /// If eLazyBoolYes we will step out if we step into code with no debug |
| /// info. |
| /// If eLazyBoolCalculate we will consult the default set in the thread. |
| /// |
| /// \param[in] step_out_avoids_code_without_debug_info |
| /// If eLazyBoolYes, if the step over steps out it will continue to step |
| /// out till it comes to a frame with debug info. |
| /// If eLazyBoolCalculate, it will consult the default set in the thread. |
| /// |
| /// \return |
| /// A shared pointer to the newly queued thread plan, or nullptr if the |
| /// plan could not be queued. |
| virtual lldb::ThreadPlanSP QueueThreadPlanForStepInRange( |
| bool abort_other_plans, const AddressRange &range, |
| const SymbolContext &addr_context, const char *step_in_target, |
| lldb::RunMode stop_other_threads, Status &status, |
| LazyBool step_in_avoids_code_without_debug_info = eLazyBoolCalculate, |
| LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate); |
| |
| // Helper function that takes a LineEntry to step, insted of an AddressRange. |
| // This may combine multiple LineEntries of the same source line number to |
| // step over a longer address range in a single operation. |
| virtual lldb::ThreadPlanSP QueueThreadPlanForStepInRange( |
| bool abort_other_plans, const LineEntry &line_entry, |
| const SymbolContext &addr_context, const char *step_in_target, |
| lldb::RunMode stop_other_threads, Status &status, |
| LazyBool step_in_avoids_code_without_debug_info = eLazyBoolCalculate, |
| LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate); |
| |
| /// 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. |
| /// |
| /// \param[out] status |
| /// A status with an error if queuing failed. |
| /// |
| /// \param[in] step_out_avoids_code_without_debug_info |
| /// If eLazyBoolYes, if the step over steps out it will continue to step |
| /// out till it comes to a frame with debug info. |
| /// If eLazyBoolCalculate, it will consult the default set in the thread. |
| /// |
| /// \return |
| /// A shared pointer to the newly queued thread plan, or nullptr if the |
| /// plan could not be queued. |
| virtual lldb::ThreadPlanSP QueueThreadPlanForStepOut( |
| bool abort_other_plans, SymbolContext *addr_context, bool first_insn, |
| bool stop_other_threads, Vote stop_vote, Vote run_vote, |
| uint32_t frame_idx, Status &status, |
| LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate); |
| |
| /// Queue the plan used to step out of the function at the current PC of |
| /// a thread. This version does not consult the should stop here callback, |
| /// and should only |
| /// be used by other thread plans when they need to retain control of the step |
| /// out. |
| /// |
| /// \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. |
| /// |
| /// \param[in] frame_idx |
| /// |
| /// \param[out] status |
| /// A status with an error if queuing failed. |
| /// |
| /// \param[in] continue_to_next_branch |
| /// Normally this will enqueue a plan that will put a breakpoint on the |
| /// return address and continue |
| /// to there. If continue_to_next_branch is true, this is an operation not |
| /// involving the user -- |
| /// e.g. stepping "next" in a source line and we instruction stepped into |
| /// another function -- |
| /// so instead of putting a breakpoint on the return address, advance the |
| /// breakpoint to the |
| /// end of the source line that is doing the call, or until the next flow |
| /// control instruction. |
| /// If the return value from the function call is to be retrieved / |
| /// displayed to the user, you must stop |
| /// on the return address. The return value may be stored in volatile |
| /// registers which are overwritten |
| /// before the next branch instruction. |
| /// |
| /// \return |
| /// A shared pointer to the newly queued thread plan, or nullptr if the |
| /// plan could not be queued. |
| virtual lldb::ThreadPlanSP QueueThreadPlanForStepOutNoShouldStop( |
| bool abort_other_plans, SymbolContext *addr_context, bool first_insn, |
| bool stop_other_threads, Vote stop_vote, Vote run_vote, |
| uint32_t frame_idx, Status &status, bool continue_to_next_branch = false); |
| |
| /// 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] return_stack_id |
| /// The stack id that we will return to (by setting backstop breakpoints on |
| /// the return |
| /// address to that frame) if we fail to step through. |
| /// |
| /// \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[out] status |
| /// A status with an error if queuing failed. |
| /// |
| /// \return |
| /// A shared pointer to the newly queued thread plan, or nullptr if the |
| /// plan could not be queued. |
| virtual lldb::ThreadPlanSP |
| QueueThreadPlanForStepThrough(StackID &return_stack_id, |
| bool abort_other_plans, bool stop_other_threads, |
| Status &status); |
| |
| /// 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. |
| /// |
| /// \param[out] status |
| /// A status with an error if queuing failed. |
| /// |
| /// \return |
| /// A shared pointer to the newly queued thread plan, or nullptr if the |
| /// plan could not be queued. |
| virtual lldb::ThreadPlanSP |
| QueueThreadPlanForRunToAddress(bool abort_other_plans, Address &target_addr, |
| bool stop_other_threads, Status &status); |
| |
| virtual lldb::ThreadPlanSP QueueThreadPlanForStepUntil( |
| bool abort_other_plans, lldb::addr_t *address_list, size_t num_addresses, |
| bool stop_others, uint32_t frame_idx, Status &status); |
| |
| virtual lldb::ThreadPlanSP |
| QueueThreadPlanForStepScripted(bool abort_other_plans, const char *class_name, |
| bool stop_other_threads, Status &status); |
| |
| // Thread Plan accessors: |
| |
| /// Gets the plan which will execute next on the plan stack. |
| /// |
| /// \return |
| /// A pointer to the next executed plan. |
| ThreadPlan *GetCurrentPlan(); |
| |
| /// Unwinds the thread stack for the innermost expression plan currently |
| /// on the thread plan stack. |
| /// |
| /// \return |
| /// An error if the thread plan could not be unwound. |
| |
| Status UnwindInnermostExpression(); |
| |
| /// Gets the outer-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(); |
| |
| /// Gets the outer-most return value from the completed plans |
| /// |
| /// \return |
| /// A ValueObjectSP, either empty if there is no return value, |
| /// or containing the return value. |
| lldb::ValueObjectSP GetReturnValueObject(); |
| |
| /// Gets the outer-most expression variable from the completed plans |
| /// |
| /// \return |
| /// A ExpressionVariableSP, either empty if there is no |
| /// plan completed an expression during the current stop |
| /// or the expression variable that was made for the completed expression. |
| lldb::ExpressionVariableSP GetExpressionVariable(); |
| |
| /// 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); |
| |
| /// Check if we have completed plan to override breakpoint stop reason |
| /// |
| /// \return |
| /// Returns true if completed plan stack is not empty |
| /// false otherwise. |
| bool CompletedPlanOverridesBreakpoint(); |
| |
| /// 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. |
| Status 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); |
| |
| /// Discards the plans queued on the plan stack of the current thread up to |
| /// and |
| /// including up_to_plan_sp. |
| // |
| // \param[in] up_to_plan_sp |
| // Discard all plans up to and including this one. |
| void DiscardThreadPlansUpToPlan(lldb::ThreadPlanSP &up_to_plan_sp); |
| |
| void DiscardThreadPlansUpToPlan(ThreadPlan *up_to_plan_ptr); |
| |
| /// Discards the plans queued on the plan stack of the current thread up to |
| /// and |
| /// including the plan in that matches \a thread_index counting only |
| /// the non-Private plans. |
| /// |
| /// \param[in] up_to_plan_sp |
| /// Discard all plans up to and including this user plan given by this |
| /// index. |
| /// |
| /// \return |
| /// \b true if there was a thread plan with that user index, \b false |
| /// otherwise. |
| bool DiscardUserThreadPlansUpToIndex(uint32_t thread_index); |
| |
| /// Prints the current plan stack. |
| /// |
| /// \param[in] s |
| /// The stream to which to dump the plan stack info. |
| /// |
| void DumpThreadPlans( |
| Stream *s, |
| lldb::DescriptionLevel desc_level = lldb::eDescriptionLevelVerbose, |
| bool include_internal = true, bool ignore_boring = false) const; |
| |
| virtual bool CheckpointThreadState(ThreadStateCheckpoint &saved_state); |
| |
| virtual bool |
| RestoreRegisterStateFromCheckpoint(ThreadStateCheckpoint &saved_state); |
| |
| virtual bool |
| RestoreThreadStateFromCheckpoint(ThreadStateCheckpoint &saved_state); |
| |
| void EnableTracer(bool value, bool single_step); |
| |
| void SetTracer(lldb::ThreadPlanTracerSP &tracer_sp); |
| |
| // 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; |
| |
| // Get the originating thread's index ID. |
| // In the case of an "extended" thread -- a thread which represents the stack |
| // that enqueued/spawned work that is currently executing -- we need to |
| // provide the IndexID of the thread that actually did this work. We don't |
| // want to just masquerade as that thread's IndexID by using it in our own |
| // IndexID because that way leads to madness - but the driver program which |
| // is iterating over extended threads may ask for the OriginatingThreadID to |
| // display that information to the user. |
| // Normal threads will return the same thing as GetIndexID(); |
| virtual uint32_t GetExtendedBacktraceOriginatingIndexID() { |
| return GetIndexID(); |
| } |
| |
| // The API ID is often the same as the Thread::GetID(), but not in all cases. |
| // Thread::GetID() is the user visible thread ID that clients would want to |
| // see. The API thread ID is the thread ID that is used when sending data |
| // to/from the debugging protocol. |
| virtual lldb::user_id_t GetProtocolID() const { return GetID(); } |
| |
| // lldb::ExecutionContextScope pure virtual functions |
| lldb::TargetSP CalculateTarget() override; |
| |
| lldb::ProcessSP CalculateProcess() override; |
| |
| lldb::ThreadSP CalculateThread() override; |
| |
| lldb::StackFrameSP CalculateStackFrame() override; |
| |
| void CalculateExecutionContext(ExecutionContext &exe_ctx) override; |
| |
| lldb::StackFrameSP |
| GetStackFrameSPForStackFramePtr(StackFrame *stack_frame_ptr); |
| |
| size_t GetStatus(Stream &strm, uint32_t start_frame, uint32_t num_frames, |
| uint32_t num_frames_with_source, bool stop_format, |
| bool only_stacks = false); |
| |
| size_t GetStackFrameStatus(Stream &strm, uint32_t first_frame, |
| uint32_t num_frames, bool show_frame_info, |
| uint32_t num_frames_with_source); |
| |
| // We need a way to verify that even though we have a thread in a shared |
| // pointer that the object itself is still valid. Currently this won't be the |
| // case if DestroyThread() was called. DestroyThread is called when a thread |
| // has been removed from the Process' thread list. |
| bool IsValid() const { return !m_destroy_called; } |
| |
| // Sets and returns a valid stop info based on the process stop ID and the |
| // current thread plan. If the thread stop ID does not match the process' |
| // stop ID, the private stop reason is not set and an invalid StopInfoSP may |
| // be returned. |
| // |
| // NOTE: This function must be called before the current thread plan is |
| // moved to the completed plan stack (in Thread::ShouldStop()). |
| // |
| // NOTE: If subclasses override this function, ensure they do not overwrite |
| // the m_actual_stop_info if it is valid. The stop info may be a |
| // "checkpointed and restored" stop info, so if it is still around it is |
| // right even if you have not calculated this yourself, or if it disagrees |
| // with what you might have calculated. |
| virtual lldb::StopInfoSP GetPrivateStopInfo(); |
| |
| // Ask the thread subclass to set its stop info. |
| // |
| // Thread subclasses should call Thread::SetStopInfo(...) with the reason the |
| // thread stopped. |
| // |
| // \return |
| // True if Thread::SetStopInfo(...) was called, false otherwise. |
| virtual bool CalculateStopInfo() = 0; |
| |
| // Gets the temporary resume state for a thread. |
| // |
| // This value gets set in each thread by complex debugger logic in |
| // Thread::ShouldResume() and an appropriate thread resume state will get set |
| // in each thread every time the process is resumed prior to calling |
| // Process::DoResume(). The lldb_private::Process subclass should adhere to |
| // the thread resume state request which will be one of: |
| // |
| // eStateRunning - thread will resume when process is resumed |
| // eStateStepping - thread should step 1 instruction and stop when process |
| // is resumed |
| // eStateSuspended - thread should not execute any instructions when |
| // process is resumed |
| lldb::StateType GetTemporaryResumeState() const { |
| return m_temporary_resume_state; |
| } |
| |
| void SetStopInfo(const lldb::StopInfoSP &stop_info_sp); |
| |
| void ResetStopInfo(); |
| |
| void SetShouldReportStop(Vote vote); |
| |
| /// Sets the extended backtrace token for this thread |
| /// |
| /// Some Thread subclasses may maintain a token to help with providing |
| /// an extended backtrace. The SystemRuntime plugin will set/request this. |
| /// |
| /// \param [in] token |
| virtual void SetExtendedBacktraceToken(uint64_t token) {} |
| |
| /// Gets the extended backtrace token for this thread |
| /// |
| /// Some Thread subclasses may maintain a token to help with providing |
| /// an extended backtrace. The SystemRuntime plugin will set/request this. |
| /// |
| /// \return |
| /// The token needed by the SystemRuntime to create an extended backtrace. |
| /// LLDB_INVALID_ADDRESS is returned if no token is available. |
| virtual uint64_t GetExtendedBacktraceToken() { return LLDB_INVALID_ADDRESS; } |
| |
| lldb::ValueObjectSP GetCurrentException(); |
| |
| lldb::ThreadSP GetCurrentExceptionBacktrace(); |
| |
| protected: |
| friend class ThreadPlan; |
| friend class ThreadList; |
| friend class ThreadEventData; |
| friend class StackFrameList; |
| friend class StackFrame; |
| friend class OperatingSystem; |
| |
| // This is necessary to make sure thread assets get destroyed while the |
| // thread is still in good shape to call virtual thread methods. This must |
| // be called by classes that derive from Thread in their destructor. |
| virtual void DestroyThread(); |
| |
| void PushPlan(lldb::ThreadPlanSP &plan_sp); |
| |
| void PopPlan(); |
| |
| void DiscardPlan(); |
| |
| ThreadPlan *GetPreviousPlan(ThreadPlan *plan); |
| |
| typedef std::vector<lldb::ThreadPlanSP> plan_stack; |
| |
| virtual lldb_private::Unwind *GetUnwinder(); |
| |
| // Check to see whether the thread is still at the last breakpoint hit that |
| // stopped it. |
| virtual bool IsStillAtLastBreakpointHit(); |
| |
| // Some threads are threads that are made up by OperatingSystem plugins that |
| // are threads that exist and are context switched out into memory. The |
| // OperatingSystem plug-in need a ways to know if a thread is "real" or made |
| // up. |
| virtual bool IsOperatingSystemPluginThread() const { return false; } |
| |
| // Subclasses that have a way to get an extended info dictionary for this |
| // thread should fill |
| virtual lldb_private::StructuredData::ObjectSP FetchThreadExtendedInfo() { |
| return StructuredData::ObjectSP(); |
| } |
| |
| lldb::StackFrameListSP GetStackFrameList(); |
| |
| void SetTemporaryResumeState(lldb::StateType new_state) { |
| m_temporary_resume_state = new_state; |
| } |
| |
| void FunctionOptimizationWarning(lldb_private::StackFrame *frame); |
| |
| // Classes that inherit from Process can see and modify these |
| lldb::ProcessWP m_process_wp; ///< The process that owns this thread. |
| lldb::StopInfoSP m_stop_info_sp; ///< The private stop reason for this thread |
| uint32_t m_stop_info_stop_id; // This is the stop id for which the StopInfo is |
| // valid. Can use this so you know that |
| // the thread's m_stop_info_sp is current and you don't have to fetch it |
| // again |
| uint32_t m_stop_info_override_stop_id; // The stop ID containing the last time |
| // the stop info was checked against |
| // the stop info override |
| 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. |
| mutable std::recursive_mutex |
| m_state_mutex; ///< Multithreaded protection for m_state. |
| plan_stack m_plan_stack; ///< The stack of plans this thread is executing. |
| 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 std::recursive_mutex |
| m_frame_mutex; ///< Multithreaded protection for m_state. |
| lldb::StackFrameListSP m_curr_frames_sp; ///< The stack frames that get lazily |
| ///populated after a thread stops. |
| lldb::StackFrameListSP m_prev_frames_sp; ///< The previous stack frames from |
| ///the last time this thread stopped. |
| int m_resume_signal; ///< The signal that should be used when continuing this |
| ///thread. |
| lldb::StateType m_resume_state; ///< This state is used to force a thread to |
| ///be suspended from outside the ThreadPlan |
| ///logic. |
| lldb::StateType m_temporary_resume_state; ///< This state records what the |
| ///thread was told to do by the |
| ///thread plan logic for the current |
| ///resume. |
| /// It gets set in Thread::ShouldResume. |
| std::unique_ptr<lldb_private::Unwind> m_unwinder_up; |
| bool m_destroy_called; // This is used internally to make sure derived Thread |
| // classes call DestroyThread. |
| LazyBool m_override_should_notify; |
| |
| private: |
| bool m_extended_info_fetched; // Have we tried to retrieve the m_extended_info |
| // for this thread? |
| StructuredData::ObjectSP m_extended_info; // The extended info for this thread |
| |
| private: |
| bool PlanIsBasePlan(ThreadPlan *plan_ptr); |
| |
| void BroadcastSelectedFrameChange(StackID &new_frame_id); |
| |
| DISALLOW_COPY_AND_ASSIGN(Thread); |
| }; |
| |
| } // namespace lldb_private |
| |
| #endif // liblldb_Thread_h_ |