diff options
38 files changed, 1891 insertions, 317 deletions
diff --git a/lldb/include/lldb/API/SBAddress.h b/lldb/include/lldb/API/SBAddress.h index 58a7d2bfb1d..c2d07b6e9bc 100644 --- a/lldb/include/lldb/API/SBAddress.h +++ b/lldb/include/lldb/API/SBAddress.h @@ -117,6 +117,7 @@ protected: friend class SBSymbolContext; friend class SBTarget; friend class SBThread; + friend class SBThreadPlan; friend class SBValue; friend class SBQueueItem; diff --git a/lldb/include/lldb/API/SBDefines.h b/lldb/include/lldb/API/SBDefines.h index eb1d0bf4f44..9ba5da34d54 100644 --- a/lldb/include/lldb/API/SBDefines.h +++ b/lldb/include/lldb/API/SBDefines.h @@ -71,6 +71,7 @@ class LLDB_API SBSymbolContextList; class LLDB_API SBTarget; class LLDB_API SBThread; class LLDB_API SBThreadCollection; +class LLDB_API SBThreadPlan; class LLDB_API SBType; class LLDB_API SBTypeCategory; class LLDB_API SBTypeEnumMember; diff --git a/lldb/include/lldb/API/SBEvent.h b/lldb/include/lldb/API/SBEvent.h index 6cb975a1ff7..1706d0c009b 100644 --- a/lldb/include/lldb/API/SBEvent.h +++ b/lldb/include/lldb/API/SBEvent.h @@ -30,6 +30,10 @@ public: // Make an event that contains a C string. SBEvent (uint32_t event, const char *cstr, uint32_t cstr_len); + SBEvent (lldb::EventSP &event_sp); + + SBEvent (lldb_private::Event *event_sp); + ~SBEvent(); const SBEvent & @@ -77,8 +81,6 @@ protected: friend class SBThread; friend class SBWatchpoint; - SBEvent (lldb::EventSP &event_sp); - lldb::EventSP & GetSP () const; diff --git a/lldb/include/lldb/API/SBStream.h b/lldb/include/lldb/API/SBStream.h index 07b23d166e3..cd33bfda32b 100644 --- a/lldb/include/lldb/API/SBStream.h +++ b/lldb/include/lldb/API/SBStream.h @@ -85,6 +85,7 @@ protected: friend class SBSymbolContextList; friend class SBTarget; friend class SBThread; + friend class SBThreadPlan; friend class SBType; friend class SBTypeEnumMember; friend class SBTypeMemberFunction; diff --git a/lldb/include/lldb/API/SBThread.h b/lldb/include/lldb/API/SBThread.h index 07a43ebee7c..ebf38fa9290 100644 --- a/lldb/include/lldb/API/SBThread.h +++ b/lldb/include/lldb/API/SBThread.h @@ -127,6 +127,9 @@ public: uint32_t line); SBError + StepUsingScriptedThreadPlan (const char *script_class_name); + + SBError JumpToLine (lldb::SBFileSpec &file_spec, uint32_t line); void @@ -216,6 +219,15 @@ public: bool SafeToCallFunctions (); +#ifndef SWIG + lldb_private::Thread * + operator->(); + + lldb_private::Thread * + get(); + +#endif + protected: friend class SBBreakpoint; friend class SBBreakpointLocation; diff --git a/lldb/include/lldb/API/SBThreadPlan.h b/lldb/include/lldb/API/SBThreadPlan.h new file mode 100644 index 00000000000..e53942d65fa --- /dev/null +++ b/lldb/include/lldb/API/SBThreadPlan.h @@ -0,0 +1,129 @@ +//===-- SBThread.h ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBThreadPlan_h_ +#define LLDB_SBThreadPlan_h_ + +#include "lldb/API/SBDefines.h" + +#include <stdio.h> + +namespace lldb { + +class SBThreadPlan +{ + +friend class lldb_private::ThreadPlan; + +public: + SBThreadPlan (); + + SBThreadPlan (const lldb::SBThreadPlan &threadPlan); + + SBThreadPlan (const lldb::ThreadPlanSP& lldb_object_sp); + + SBThreadPlan (lldb::SBThread &thread, const char *class_name); + + ~SBThreadPlan (); + + bool + IsValid() const; + + void + Clear (); + + lldb::StopReason + GetStopReason(); + + /// Get the number of words associated with the stop reason. + /// See also GetStopReasonDataAtIndex(). + size_t + GetStopReasonDataCount(); + + //-------------------------------------------------------------------------- + /// Get information associated with a stop reason. + /// + /// Breakpoint stop reasons will have data that consists of pairs of + /// breakpoint IDs followed by the breakpoint location IDs (they always come + /// in pairs). + /// + /// Stop Reason Count Data Type + /// ======================== ===== ========================================= + /// eStopReasonNone 0 + /// eStopReasonTrace 0 + /// eStopReasonBreakpoint N duple: {breakpoint id, location id} + /// eStopReasonWatchpoint 1 watchpoint id + /// eStopReasonSignal 1 unix signal number + /// eStopReasonException N exception data + /// eStopReasonExec 0 + /// eStopReasonPlanComplete 0 + //-------------------------------------------------------------------------- + uint64_t + GetStopReasonDataAtIndex(uint32_t idx); + + SBThread + GetThread () const; + + const lldb::SBThreadPlan & + operator = (const lldb::SBThreadPlan &rhs); + + bool + GetDescription (lldb::SBStream &description) const; + + void + SetPlanComplete (bool success); + + bool + IsPlanComplete(); + + bool + IsValid(); + + // This section allows an SBThreadPlan to push another of the common types of plans... + SBThreadPlan + QueueThreadPlanForStepOverRange (SBAddress &start_address, + lldb::addr_t range_size); + + SBThreadPlan + QueueThreadPlanForStepInRange (SBAddress &start_address, + lldb::addr_t range_size); + + SBThreadPlan + QueueThreadPlanForStepOut (uint32_t frame_idx_to_step_to, bool first_insn = false); + + SBThreadPlan + QueueThreadPlanForRunToAddress (SBAddress address); + +#ifndef SWIG + lldb_private::ThreadPlan * + get(); +#endif + +protected: + friend class SBBreakpoint; + friend class SBBreakpointLocation; + friend class SBFrame; + friend class SBProcess; + friend class SBDebugger; + friend class SBValue; + friend class lldb_private::QueueImpl; + friend class SBQueueItem; + +#ifndef SWIG + void + SetThreadPlan (const lldb::ThreadPlanSP& lldb_object_sp); +#endif + +private: + lldb::ThreadPlanSP m_opaque_sp; +}; + +} // namespace lldb + +#endif // LLDB_SBThreadPlan_h_ diff --git a/lldb/include/lldb/Expression/ClangFunction.h b/lldb/include/lldb/Expression/ClangFunction.h index 61d56729f93..476bf7d92ed 100644 --- a/lldb/include/lldb/Expression/ClangFunction.h +++ b/lldb/include/lldb/Expression/ClangFunction.h @@ -285,9 +285,9 @@ public: /// True if the thread plan may simply be discarded if an error occurs. /// /// @return - /// A ThreadPlan for executing the function. + /// A ThreadPlan shared pointer for executing the function. //------------------------------------------------------------------ - ThreadPlan * + lldb::ThreadPlanSP GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, lldb::addr_t args_addr, const EvaluateExpressionOptions &options, diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h index 5a8322f8eb4..bc7c7a0e57a 100644 --- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h +++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h @@ -104,6 +104,12 @@ public: const char *session_dictionary_name, const lldb::ValueObjectSP& valobj_sp); + typedef void* (*SWIGPythonCreateScriptedThreadPlan) (const char *python_class_name, + const char *session_dictionary_name, + const lldb::ThreadPlanSP& thread_plan_sp); + + typedef bool (*SWIGPythonCallThreadPlan) (void *implementor, const char *method_name, Event *event_sp, bool &got_error); + typedef void* (*SWIGPythonCreateOSPlugin) (const char *python_class_name, const char *session_dictionary_name, const lldb::ProcessSP& process_sp); @@ -348,6 +354,39 @@ public: } virtual lldb::ScriptInterpreterObjectSP + CreateScriptedThreadPlan (const char *class_name, + lldb::ThreadPlanSP thread_plan_sp) + { + return lldb::ScriptInterpreterObjectSP(); + } + + virtual bool + ScriptedThreadPlanExplainsStop (lldb::ScriptInterpreterObjectSP implementor_sp, + Event *event, + bool &script_error) + { + script_error = true; + return true; + } + + virtual bool + ScriptedThreadPlanShouldStop (lldb::ScriptInterpreterObjectSP implementor_sp, + Event *event, + bool &script_error) + { + script_error = true; + return true; + } + + virtual lldb::StateType + ScriptedThreadPlanGetRunState (lldb::ScriptInterpreterObjectSP implementor_sp, + bool &script_error) + { + script_error = true; + return lldb::eStateStepping; + } + + virtual lldb::ScriptInterpreterObjectSP LoadPluginModule (const FileSpec& file_spec, lldb_private::Error& error) { @@ -573,7 +612,9 @@ public: SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread, SWIGPythonScriptKeyword_Target swig_run_script_keyword_target, SWIGPythonScriptKeyword_Frame swig_run_script_keyword_frame, - SWIGPython_GetDynamicSetting swig_plugin_get); + SWIGPython_GetDynamicSetting swig_plugin_get, + SWIGPythonCreateScriptedThreadPlan swig_thread_plan_script, + SWIGPythonCallThreadPlan swig_call_thread_plan); virtual void ResetOutputFileHandle (FILE *new_fh) { } //By default, do nothing. diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h b/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h index 14a62d67fde..483cb090cd5 100644 --- a/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h +++ b/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h @@ -80,6 +80,22 @@ public: lldb::ScriptInterpreterObjectSP CreateSyntheticScriptedProvider (const char *class_name, lldb::ValueObjectSP valobj); + + lldb::ScriptInterpreterObjectSP + virtual CreateScriptedThreadPlan (const char *class_name, + lldb::ThreadPlanSP thread_plan); + + virtual bool + ScriptedThreadPlanExplainsStop (lldb::ScriptInterpreterObjectSP implementor_sp, + Event *event, + bool &script_error); + virtual bool + ScriptedThreadPlanShouldStop (lldb::ScriptInterpreterObjectSP implementor_sp, + Event *event, + bool &script_error); + virtual lldb::StateType + ScriptedThreadPlanGetRunState (lldb::ScriptInterpreterObjectSP implementor_sp, + bool &script_error); virtual lldb::ScriptInterpreterObjectSP OSPlugin_CreatePluginObject (const char *class_name, @@ -275,7 +291,9 @@ public: SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread, SWIGPythonScriptKeyword_Target swig_run_script_keyword_target, SWIGPythonScriptKeyword_Frame swig_run_script_keyword_frame, - SWIGPython_GetDynamicSetting swig_plugin_get); + SWIGPython_GetDynamicSetting swig_plugin_get, + SWIGPythonCreateScriptedThreadPlan swig_thread_plan_script, + SWIGPythonCallThreadPlan swig_call_thread_plan); const char * GetDictionaryName () diff --git a/lldb/include/lldb/Target/Thread.h b/lldb/include/lldb/Target/Thread.h index cba09e16410..87373fb8f19 100644 --- a/lldb/include/lldb/Target/Thread.h +++ b/lldb/include/lldb/Target/Thread.h @@ -912,6 +912,11 @@ public: bool stop_others, uint32_t frame_idx); + virtual lldb::ThreadPlanSP + QueueThreadPlanForStepScripted (bool abort_other_plans, + const char *class_name, + bool stop_other_threads); + //------------------------------------------------------------------ // Thread Plan accessors: //------------------------------------------------------------------ @@ -1041,6 +1046,20 @@ public: 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. @@ -1050,7 +1069,10 @@ public: /// //------------------------------------------------------------------ void - DumpThreadPlans (Stream *s) const; + DumpThreadPlans (Stream *s, + lldb::DescriptionLevel desc_level = lldb::eDescriptionLevelVerbose, + bool include_internal = true, + bool ignore_boring = false) const; virtual bool CheckpointThreadState (ThreadStateCheckpoint &saved_state); diff --git a/lldb/include/lldb/Target/ThreadPlan.h b/lldb/include/lldb/Target/ThreadPlan.h index 1f20841906d..db2e7989405 100644 --- a/lldb/include/lldb/Target/ThreadPlan.h +++ b/lldb/include/lldb/Target/ThreadPlan.h @@ -223,6 +223,7 @@ namespace lldb_private { //------------------------------------------------------------------ class ThreadPlan : + public std::enable_shared_from_this<ThreadPlan>, public UserID { public: @@ -241,6 +242,7 @@ public: eKindNull, eKindBase, eKindCallFunction, + eKindPython, eKindStepInstruction, eKindStepOut, eKindStepOverBreakpoint, @@ -687,7 +689,8 @@ protected: virtual lldb::StateType GetPlanRunState (); - + + DISALLOW_COPY_AND_ASSIGN(ThreadPlanNull); }; diff --git a/lldb/include/lldb/Target/ThreadPlanPython.h b/lldb/include/lldb/Target/ThreadPlanPython.h new file mode 100644 index 00000000000..fa41af1915c --- /dev/null +++ b/lldb/include/lldb/Target/ThreadPlanPython.h @@ -0,0 +1,80 @@ +//===-- ThreadPlanPython.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_ThreadPlan_Python_h_ +#define liblldb_ThreadPlan_Python_h_ + +// C Includes +// C++ Includes +#include <string> +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Core/UserID.h" +#include "lldb/Host/Mutex.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadPlan.h" +#include "lldb/Target/ThreadPlanTracer.h" +#include "lldb/Target/StopInfo.h" + +namespace lldb_private { + +//------------------------------------------------------------------ +// ThreadPlanPython: +// +//------------------------------------------------------------------ + +class ThreadPlanPython : public ThreadPlan +{ +public: + ThreadPlanPython (Thread &thread, const char *class_name); + virtual ~ThreadPlanPython (); + + 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 + StopOthers (); + + virtual void + DidPush (); + +protected: + virtual bool + DoPlanExplainsStop (Event *event_ptr); + + virtual lldb::StateType + GetPlanRunState (); + +private: + std::string m_class_name; + lldb::ScriptInterpreterObjectSP m_implementation_sp; + + DISALLOW_COPY_AND_ASSIGN(ThreadPlanPython); +}; + + +} // namespace lldb_private + +#endif // liblldb_ThreadPlan_Python_h_ diff --git a/lldb/include/lldb/Target/ThreadPlanStepRange.h b/lldb/include/lldb/Target/ThreadPlanStepRange.h index 3487e9ad66c..43c55c2aa41 100644 --- a/lldb/include/lldb/Target/ThreadPlanStepRange.h +++ b/lldb/include/lldb/Target/ThreadPlanStepRange.h @@ -30,7 +30,8 @@ public: Thread &thread, const AddressRange &range, const SymbolContext &addr_context, - lldb::RunMode stop_others); + lldb::RunMode stop_others, + bool given_ranges_only = false); virtual ~ThreadPlanStepRange (); @@ -83,6 +84,7 @@ protected: bool m_first_run_event; // We want to broadcast only one running event, our first. lldb::BreakpointSP m_next_branch_bp_sp; bool m_use_fast_step; + bool m_given_ranges_only; private: std::vector<lldb::DisassemblerSP> m_instruction_ranges; diff --git a/lldb/include/lldb/lldb-private-enumerations.h b/lldb/include/lldb/lldb-private-enumerations.h index 9aae2a6cb25..c62863d744c 100644 --- a/lldb/include/lldb/lldb-private-enumerations.h +++ b/lldb/include/lldb/lldb-private-enumerations.h @@ -22,7 +22,8 @@ typedef enum StepType eStepTypeTraceOver, ///< Single step one instruction, stepping over. eStepTypeInto, ///< Single step into a specified context. eStepTypeOver, ///< Single step over a specified context. - eStepTypeOut ///< Single step out a specified context. + eStepTypeOut, ///< Single step out a specified context. + eStepTypeScripted ///< A step type implemented by the script interpreter. } StepType; //---------------------------------------------------------------------- diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 3a3934d51c0..c86afb02880 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -613,6 +613,10 @@ 49DCF6FE170E6B4A0092F75E /* IRMemoryMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49DCF6FD170E6B4A0092F75E /* IRMemoryMap.cpp */; }; 49DCF702170E70120092F75E /* Materializer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49DCF700170E70120092F75E /* Materializer.cpp */; }; 4C3ADCD61810D88B00357218 /* BreakpointResolverFileRegex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CAA56141422D986001FFA01 /* BreakpointResolverFileRegex.cpp */; }; + 4C56543119D1EFAA002E9C44 /* ThreadPlanPython.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C56543019D1EFAA002E9C44 /* ThreadPlanPython.cpp */; }; + 4C56543319D1EFB6002E9C44 /* ThreadPlanPython.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C56543219D1EFB5002E9C44 /* ThreadPlanPython.h */; }; + 4C56543519D2297A002E9C44 /* SBThreadPlan.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C56543419D2297A002E9C44 /* SBThreadPlan.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4C56543719D22B32002E9C44 /* SBThreadPlan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C56543619D22B32002E9C44 /* SBThreadPlan.cpp */; }; 4C6649A014EEE7F100B0316F /* StreamCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C66499F14EEE7F100B0316F /* StreamCallback.h */; }; 4C6649A314EEE81000B0316F /* StreamCallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C6649A214EEE81000B0316F /* StreamCallback.cpp */; }; 4C73152219B7D71700F865A4 /* Iterable.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C73152119B7D71700F865A4 /* Iterable.h */; }; @@ -1893,6 +1897,11 @@ 4C43DF8611069BFD00E55CBF /* ThreadPlanStepOverRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanStepOverRange.h; path = include/lldb/Target/ThreadPlanStepOverRange.h; sourceTree = "<group>"; }; 4C43DF8911069C3200E55CBF /* ThreadPlanStepInRange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanStepInRange.cpp; path = source/Target/ThreadPlanStepInRange.cpp; sourceTree = "<group>"; }; 4C43DF8A11069C3200E55CBF /* ThreadPlanStepOverRange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanStepOverRange.cpp; path = source/Target/ThreadPlanStepOverRange.cpp; sourceTree = "<group>"; }; + 4C56543019D1EFAA002E9C44 /* ThreadPlanPython.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanPython.cpp; path = source/Target/ThreadPlanPython.cpp; sourceTree = "<group>"; }; + 4C56543219D1EFB5002E9C44 /* ThreadPlanPython.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanPython.h; path = include/lldb/Target/ThreadPlanPython.h; sourceTree = "<group>"; }; + 4C56543419D2297A002E9C44 /* SBThreadPlan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBThreadPlan.h; path = include/lldb/API/SBThreadPlan.h; sourceTree = "<group>"; }; + 4C56543619D22B32002E9C44 /* SBThreadPlan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBThreadPlan.cpp; path = source/API/SBThreadPlan.cpp; sourceTree = "<group>"; }; + 4C56543819D22FD9002E9C44 /* SBThreadPlan.i */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c.preprocessed; path = SBThreadPlan.i; sourceTree = "<group>"; }; 4C5DBBC611E3FEC60035160F /* CommandObjectCommands.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectCommands.cpp; path = source/Commands/CommandObjectCommands.cpp; sourceTree = "<group>"; }; 4C5DBBC711E3FEC60035160F /* CommandObjectCommands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectCommands.h; path = source/Commands/CommandObjectCommands.h; sourceTree = "<group>"; }; 4C626533130F1B0A00C889F6 /* StreamTee.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StreamTee.h; path = include/lldb/Core/StreamTee.h; sourceTree = "<group>"; }; @@ -2669,6 +2678,7 @@ 2611FF0E142D83060017FEA3 /* SBSymbolContextList.i */, 2611FF0F142D83060017FEA3 /* SBTarget.i */, 2611FF10142D83060017FEA3 /* SBThread.i */, + 4C56543819D22FD9002E9C44 /* SBThreadPlan.i */, 8CCB018419BA54930009FD44 /* SBThreadCollection.i */, 2611FF11142D83060017FEA3 /* SBType.i */, 9475C18A14E5EA1C001BFC6D /* SBTypeCategory.i */, @@ -2786,6 +2796,8 @@ 9A9831091125FC5800A56CB0 /* SBThread.cpp */, 8CCB018119BA4E210009FD44 /* SBThreadCollection.h */, 8CCB017F19BA4DD00009FD44 /* SBThreadCollection.cpp */, + 4C56543419D2297A002E9C44 /* SBThreadPlan.h */, + 4C56543619D22B32002E9C44 /* SBThreadPlan.cpp */, 2617447911685869005ADD65 /* SBType.h */, 261744771168585B005ADD65 /* SBType.cpp */, 9475C18514E5E9C5001BFC6D /* SBTypeCategory.h */, @@ -3805,6 +3817,8 @@ 49EC3E98118F90AC00B1265E /* ThreadPlanCallFunction.cpp */, 4C7CF7E31295E10E00B4FBB5 /* ThreadPlanCallUserExpression.h */, 4C7CF7E51295E12B00B4FBB5 /* ThreadPlanCallUserExpression.cpp */, + 4C56543219D1EFB5002E9C44 /* ThreadPlanPython.h */, + 4C56543019D1EFAA002E9C44 /* ThreadPlanPython.cpp */, 4C43DEF9110641F300E55CBF /* ThreadPlanShouldStopHere.h */, 4C43DEFA110641F300E55CBF /* ThreadPlanShouldStopHere.cpp */, 260C848010F50F0A00BB2B04 /* ThreadPlanStepInstruction.h */, @@ -4403,6 +4417,7 @@ 268F9D53123AA15200B91E9B /* SBSymbolContextList.h in Headers */, 2668022C115FD13D008E1FE4 /* SBTarget.h in Headers */, 2668022E115FD13D008E1FE4 /* SBThread.h in Headers */, + 4C56543519D2297A002E9C44 /* SBThreadPlan.h in Headers */, 263C493A178B50CF0070F12D /* SBModuleSpec.h in Headers */, 2617447A11685869005ADD65 /* SBType.h in Headers */, 9475C18914E5EA08001BFC6D /* SBTypeCategory.h in Headers */, @@ -4495,6 +4510,7 @@ 26DAED6015D327A200E15819 /* OptionValuePathMappings.h in Headers */, 26ACEC2815E077AE00E94760 /* Property.h in Headers */, 26491E3B15E1DB8600CBFFC2 /* OptionValueRegex.h in Headers */, + 4C56543319D1EFB6002E9C44 /* ThreadPlanPython.h in Headers */, 2697A39515E404BA003E682C /* OptionValueArch.h in Headers */, 26474CBF18D0CB2D0073DEBA /* RegisterContextMach_i386.h in Headers */, 26474CC118D0CB2D0073DEBA /* RegisterContextMach_x86_64.h in Headers */, @@ -4899,6 +4915,7 @@ 9443B122140C18C40013457C /* SBData.cpp in Sources */, 4CF52AF8142829390051E832 /* SBFileSpecList.cpp in Sources */, 23059A101958B319007B8189 /* SBUnixSignals.cpp in Sources */, + 4C56543719D22B32002E9C44 /* SBThreadPlan.cpp in Sources */, 8CCB018319BA51BF0009FD44 /* SBThreadCollection.cpp in Sources */, 26B82840142D020F002DBC64 /* SBSection.cpp in Sources */, B2A58724143119D50092BFBA /* SBWatchpoint.cpp in Sources */, @@ -5176,6 +5193,7 @@ 268900E613353E6F00698AC0 /* Variable.cpp in Sources */, 268900E713353E6F00698AC0 /* VariableList.cpp in Sources */, 268900E813353E6F00698AC0 /* ABI.cpp in Sources */, + 4C56543119D1EFAA002E9C44 /* ThreadPlanPython.cpp in Sources */, 26AB92121819D74600E63F3E /* DWARFDataExtractor.cpp in Sources */, 268900E913353E6F00698AC0 /* CPPLanguageRuntime.cpp in Sources */, 268900EA13353E6F00698AC0 /* DynamicLoader.cpp in Sources */, diff --git a/lldb/scripts/Python/build-swig-Python.sh b/lldb/scripts/Python/build-swig-Python.sh index 88769c88856..3b610e139e2 100755 --- a/lldb/scripts/Python/build-swig-Python.sh +++ b/lldb/scripts/Python/build-swig-Python.sh @@ -114,6 +114,7 @@ HEADER_FILES="${SRC_ROOT}/include/lldb/lldb.h"\ " ${SRC_ROOT}/include/lldb/API/SBTarget.h"\ " ${SRC_ROOT}/include/lldb/API/SBThread.h"\ " ${SRC_ROOT}/include/lldb/API/SBThreadCollection.h"\ +" ${SRC_ROOT}/include/lldb/API/SBThreadPlan.h"\ " ${SRC_ROOT}/include/lldb/API/SBType.h"\ " ${SRC_ROOT}/include/lldb/API/SBTypeCategory.h"\ " ${SRC_ROOT}/include/lldb/API/SBTypeFilter.h"\ @@ -163,6 +164,7 @@ INTERFACE_FILES="${SRC_ROOT}/scripts/Python/interface/SBAddress.i"\ " ${SRC_ROOT}/scripts/Python/interface/SBTarget.i"\ " ${SRC_ROOT}/scripts/Python/interface/SBThread.i"\ " ${SRC_ROOT}/scripts/Python/interface/SBThreadCollection.i"\ +" ${SRC_ROOT}/scripts/Python/interface/SBThreadPlan.i"\ " ${SRC_ROOT}/scripts/Python/interface/SBType.i"\ " ${SRC_ROOT}/scripts/Python/interface/SBTypeCategory.i"\ " ${SRC_ROOT}/scripts/Python/interface/SBTypeFilter.i"\ diff --git a/lldb/scripts/Python/interface/SBThread.i b/lldb/scripts/Python/interface/SBThread.i index 4d69ddaf229..dac0f9bc4a7 100644 --- a/lldb/scripts/Python/interface/SBThread.i +++ b/lldb/scripts/Python/interface/SBThread.i @@ -213,6 +213,9 @@ public: uint32_t line); SBError + StepUsingScriptedThreadPlan (const char *script_class_name); + + SBError JumpToLine (lldb::SBFileSpec &file_spec, uint32_t line); void diff --git a/lldb/scripts/Python/interface/SBThreadPlan.i b/lldb/scripts/Python/interface/SBThreadPlan.i new file mode 100644 index 00000000000..785855ec5b9 --- /dev/null +++ b/lldb/scripts/Python/interface/SBThreadPlan.i @@ -0,0 +1,123 @@ +//===-- SBThread.h ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBThreadPlan_h_ +#define LLDB_SBThreadPlan_h_ + +#include "lldb/API/SBDefines.h" + +#include <stdio.h> + +namespace lldb { + +%feature("docstring", +"Represents a plan for the execution control of a given thread. + +See also SBThread and SBFrame." +) SBThread; + +class SBThreadPlan +{ + +friend class lldb_private::ThreadPlan; + +public: + SBThreadPlan (); + + SBThreadPlan (const lldb::SBThreadPlan &threadPlan); + + SBThreadPlan (const lldb::ThreadPlanSP& lldb_object_sp); + + SBThreadPlan (lldb::SBThread &thread, const char *class_name); + + ~SBThreadPlan (); + + bool + IsValid() const; + + void + Clear (); + + lldb::StopReason + GetStopReason(); + + /// Get the number of words associated with the stop reason. + /// See also GetStopReasonDataAtIndex(). + size_t + GetStopReasonDataCount(); + + //-------------------------------------------------------------------------- + /// Get information associated with a stop reason. + /// + /// Breakpoint stop reasons will have data that consists of pairs of + /// breakpoint IDs followed by the breakpoint location IDs (they always come + /// in pairs). + /// + /// Stop Reason Count Data Type + /// ======================== ===== ========================================= + /// eStopReasonNone 0 + /// eStopReasonTrace 0 + /// eStopReasonBreakpoint N duple: {breakpoint id, location id} + /// eStopReasonWatchpoint 1 watchpoint id + /// eStopReasonSignal 1 unix signal number + /// eStopReasonException N exception data + /// eStopReasonExec 0 + /// eStopReasonPlanComplete 0 + //-------------------------------------------------------------------------- + uint64_t + GetStopReasonDataAtIndex(uint32_t idx); + + SBThread + GetThread () const; + + bool + GetDescription (lldb::SBStream &description) const; + + void + SetPlanComplete (bool success); + + bool + IsPlanComplete(); + + bool + IsValid(); + + // This section allows an SBThreadPlan to push another of the common types of plans... + SBThreadPlan + QueueThreadPlanForStepOverRange (SBAddress &start_address, + lldb::addr_t range_size); + + SBThreadPlan + QueueThreadPlanForStepInRange (SBAddress &start_address, + lldb::addr_t range_size); + + SBThreadPlan + QueueThreadPlanForStepOut (uint32_t frame_idx_to_step_to, bool first_insn = false); + + SBThreadPlan + QueueThreadPlanForRunToAddress (SBAddress address); + + +protected: + friend class SBBreakpoint; + friend class SBBreakpointLocation; + friend class SBFrame; + friend class SBProcess; + friend class SBDebugger; + friend class SBValue; + friend class lldb_private::QueueImpl; + friend class SBQueueItem; + +private: + lldb::ThreadPlanSP m_opaque_sp; +}; + +} // namespace lldb + +#endif // LLDB_SBThreadPlan_h_ diff --git a/lldb/scripts/Python/python-swigsafecast.swig b/lldb/scripts/Python/python-swigsafecast.swig index 0150854d2c6..4813c4f8c4d 100644 --- a/lldb/scripts/Python/python-swigsafecast.swig +++ b/lldb/scripts/Python/python-swigsafecast.swig @@ -45,6 +45,13 @@ SBTypeToSWIGWrapper (unsigned int* c_int) template <> PyObject* +SBTypeToSWIGWrapper (lldb::SBEvent* event_sb) +{ + return SWIG_NewPointerObj((void *) event_sb, SWIGTYPE_p_lldb__SBEvent, 0); +} + +template <> +PyObject* SBTypeToSWIGWrapper (lldb::SBProcess* process_sb) { return SWIG_NewPointerObj((void *) process_sb, SWIGTYPE_p_lldb__SBProcess, 0); @@ -59,6 +66,13 @@ SBTypeToSWIGWrapper (lldb::SBThread* thread_sb) template <> PyObject* +SBTypeToSWIGWrapper (lldb::SBThreadPlan* thread_plan_sb) +{ + return SWIG_NewPointerObj((void *) thread_plan_sb, SWIGTYPE_p_lldb__SBThreadPlan, 0); +} + +template <> +PyObject* SBTypeToSWIGWrapper (lldb::SBTarget* target_sb) { return SWIG_NewPointerObj((void *) target_sb, SWIGTYPE_p_lldb__SBTarget, 0); diff --git a/lldb/scripts/Python/python-wrapper.swig b/lldb/scripts/Python/python-wrapper.swig index 646323a21cd..c3812df8110 100644 --- a/lldb/scripts/Python/python-wrapper.swig +++ b/lldb/scripts/Python/python-wrapper.swig @@ -419,6 +419,118 @@ LLDBSwigPythonCreateSyntheticProvider Py_RETURN_NONE; } +SWIGEXPORT void* +LLDBSwigPythonCreateScriptedThreadPlan +( + const char *python_class_name, + const char *session_dictionary_name, + const lldb::ThreadPlanSP& thread_plan_sp +) +{ + PyObject* retval = NULL; + + if (python_class_name == NULL || python_class_name[0] == '\0' || !session_dictionary_name) + Py_RETURN_NONE; + + // I do not want the SBThreadPlan to be deallocated when going out of scope because python + // has ownership of it and will manage memory for this object by itself + lldb::SBThreadPlan *tp_value = new lldb::SBThreadPlan(thread_plan_sp); + + PyObject *ThreadPlan_PyObj = SBTypeToSWIGWrapper(tp_value); + + if (ThreadPlan_PyObj == NULL) + Py_RETURN_NONE; + + { + PyErr_Cleaner py_err_cleaner(true); + + PyCallable pfunc = PyCallable::FindWithFunctionName(python_class_name, session_dictionary_name); + + if (!pfunc) + return retval; + + Py_INCREF(ThreadPlan_PyObj); + + PyObject* session_dict = NULL; + session_dict = FindSessionDictionary(session_dictionary_name); + retval = pfunc(tp_value, session_dict); + + // FIXME: At this point we should check that the class we found supports all the methods + // that we need. + + Py_XINCREF (session_dict); + + Py_XINCREF(retval); + } + + if (retval) + return retval; + else + Py_RETURN_NONE; +} + +SWIGEXPORT bool +LLDBSWIGPythonCallThreadPlan +( + void *implementor, + const char *method_name, + lldb_private::Event *event, + bool &got_error +) +{ + bool ret_val = false; + got_error = false; + + + PyErr_Cleaner py_err_cleaner(false); + + PyCallable pfunc = PyCallable::FindWithMemberFunction((PyObject *) implementor, method_name); + + if (!pfunc) + { + return ret_val; + } + + PyObject* py_return = Py_None; + + if (event != NULL) + { + lldb::SBEvent sb_event(event); + + PyObject *py_obj_event = SBTypeToSWIGWrapper(sb_event); + + py_return = pfunc(py_obj_event); + } + else + { + py_return = pfunc(); + } + + if (PyErr_Occurred()) + { + got_error = true; + printf ("Return value was neither false nor true for call to %s.\n", method_name); + PyErr_Print(); + } + else + { + if (py_return == Py_True) + ret_val = true; + else if (py_return == Py_False) + ret_val = false; + else + { + // Somebody returned the wrong thing... + got_error = true; + printf ("Wrong return value type for call to %s.\n", method_name); + } + } + + Py_XDECREF(py_return); + + return ret_val; +} + // wrapper that calls an optional instance member of an object taking no arguments static PyObject* LLDBSwigPython_CallOptionalMember diff --git a/lldb/scripts/lldb.swig b/lldb/scripts/lldb.swig index fc9c04249e4..fec05bb42b4 100644 --- a/lldb/scripts/lldb.swig +++ b/lldb/scripts/lldb.swig @@ -92,6 +92,7 @@ import os #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" #include "lldb/API/SBThreadCollection.h" +#include "lldb/API/SBThreadPlan.h" #include "lldb/API/SBType.h" #include "lldb/API/SBTypeCategory.h" #include "lldb/API/SBTypeEnumMember.h" @@ -164,6 +165,7 @@ import os %include "./Python/interface/SBTarget.i" %include "./Python/interface/SBThread.i" %include "./Python/interface/SBThreadCollection.i" +%include "./Python/interface/SBThreadPlan.i" %include "./Python/interface/SBType.i" %include "./Python/interface/SBTypeCategory.i" %include "./Python/interface/SBTypeEnumMember.i" diff --git a/lldb/source/API/SBCommandInterpreter.cpp b/lldb/source/API/SBCommandInterpreter.cpp index e1adea795b0..397ee61839a 100644 --- a/lldb/source/API/SBCommandInterpreter.cpp +++ b/lldb/source/API/SBCommandInterpreter.cpp @@ -442,6 +442,17 @@ LLDBSwigPythonCreateSyntheticProvider (const char *python_class_name, const lldb::ValueObjectSP& valobj_sp); +extern "C" void* +LLDBSwigPythonCreateScriptedThreadPlan (const char *python_class_name, + const char *session_dictionary_name, + const lldb::ThreadPlanSP& thread_plan_sp); + +extern "C" bool +LLDBSWIGPythonCallThreadPlan (void *implementor, + const char *method_name, + Event *event_sp, + bool &got_error); + extern "C" uint32_t LLDBSwigPython_CalculateNumChildren (void *implementor); @@ -539,7 +550,9 @@ SBCommandInterpreter::InitializeSWIG () LLDBSWIGPythonRunScriptKeywordThread, LLDBSWIGPythonRunScriptKeywordTarget, LLDBSWIGPythonRunScriptKeywordFrame, - LLDBSWIGPython_GetDynamicSetting); + LLDBSWIGPython_GetDynamicSetting, + LLDBSwigPythonCreateScriptedThreadPlan, + LLDBSWIGPythonCallThreadPlan); #endif } } diff --git a/lldb/source/API/SBEvent.cpp b/lldb/source/API/SBEvent.cpp index 57a699fd739..c62c495b87c 100644 --- a/lldb/source/API/SBEvent.cpp +++ b/lldb/source/API/SBEvent.cpp @@ -43,6 +43,12 @@ SBEvent::SBEvent (EventSP &event_sp) : { } +SBEvent::SBEvent (Event *event_ptr) : + m_event_sp (), + m_opaque_ptr (event_ptr) +{ +} + SBEvent::SBEvent (const SBEvent &rhs) : m_event_sp (rhs.m_event_sp), m_opaque_ptr (rhs.m_opaque_ptr) diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp index a0bfa431353..390fa0d4b6e 100644 --- a/lldb/source/API/SBThread.cpp +++ b/lldb/source/API/SBThread.cpp @@ -41,6 +41,7 @@ #include "lldb/API/SBEvent.h" #include "lldb/API/SBFrame.h" #include "lldb/API/SBProcess.h" +#include "lldb/API/SBThreadPlan.h" #include "lldb/API/SBValue.h" using namespace lldb; @@ -918,7 +919,9 @@ SBThread::RunToAddress (lldb::addr_t addr) Thread *thread = exe_ctx.GetThreadPtr(); - ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForRunToAddress (abort_other_plans, target_addr, stop_other_threads)); + ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForRunToAddress (abort_other_plans, + target_addr, + stop_other_threads)); // This returns an error, we should use it! ResumeNewPlan (exe_ctx, new_plan_sp.get()); @@ -1073,6 +1076,46 @@ SBThread::StepOverUntil (lldb::SBFrame &sb_frame, } SBError +SBThread::StepUsingScriptedThreadPlan (const char *script_class_name) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + SBError sb_error; + + Mutex::Locker api_locker; + ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker); + + if (log) + { + log->Printf ("SBThread(%p)::StepUsingScriptedThreadPlan: class name: %s", + static_cast<void*>(exe_ctx.GetThreadPtr()), + script_class_name); + } + + + if (!exe_ctx.HasThreadScope()) + { + sb_error.SetErrorString("this SBThread object is invalid"); + return sb_error; + } + + Thread *thread = exe_ctx.GetThreadPtr(); + ThreadPlanSP thread_plan_sp = thread->QueueThreadPlanForStepScripted(false, script_class_name, false); + + if (thread_plan_sp) + sb_error = ResumeNewPlan(exe_ctx, thread_plan_sp.get()); + else + { + sb_error.SetErrorStringWithFormat("Error queuing thread plan for class: %s.", script_class_name); + if (log) + log->Printf ("SBThread(%p)::StepUsingScriptedThreadPlan: Error queuing thread plan for class: %s", + static_cast<void*>(exe_ctx.GetThreadPtr()), + script_class_name); + } + + return sb_error; +} + +SBError SBThread::JumpToLine (lldb::SBFileSpec &file_spec, uint32_t line) { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); @@ -1473,7 +1516,8 @@ SBThread::GetExtendedBacktraceThread (const char *type) const char *queue_name = new_thread_sp->GetQueueName(); if (queue_name == NULL) queue_name = ""; - log->Printf ("SBThread(%p)::GetExtendedBacktraceThread() => new extended Thread created (%p) with queue_id 0x%" PRIx64 " queue name '%s'", + log->Printf ("SBThread(%p)::GetExtendedBacktraceThread() => new extended Thread " + "created (%p) with queue_id 0x%" PRIx64 " queue name '%s'", static_cast<void*>(exe_ctx.GetThreadPtr()), static_cast<void*>(new_thread_sp.get()), new_thread_sp->GetQueueID(), @@ -1515,3 +1559,24 @@ SBThread::SafeToCallFunctions () return thread_sp->SafeToCallFunctions(); return true; } + +lldb_private::Thread * +SBThread::operator->() +{ + ThreadSP thread_sp(m_opaque_sp->GetThreadSP()); + if (thread_sp) + return thread_sp.get(); + else + return NULL; +} + +lldb_private::Thread * +SBThread::get() +{ + ThreadSP thread_sp(m_opaque_sp->GetThreadSP()); + if (thread_sp) + return thread_sp.get(); + else + return NULL; +} + diff --git a/lldb/source/API/SBThreadPlan.cpp b/lldb/source/API/SBThreadPlan.cpp new file mode 100644 index 00000000000..02b1a8d893b --- /dev/null +++ b/lldb/source/API/SBThreadPlan.cpp @@ -0,0 +1,285 @@ +//===-- SBThread.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/lldb-python.h" + +#include "lldb/API/SBThread.h" + +#include "lldb/API/SBSymbolContext.h" +#include "lldb/API/SBFileSpec.h" +#include "lldb/API/SBStream.h" +#include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/State.h" +#include "lldb/Core/Stream.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Core/StructuredData.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Target/SystemRuntime.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadPlan.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Queue.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Target/StopInfo.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/ThreadPlan.h" +#include "lldb/Target/ThreadPlanPython.h" +#include "lldb/Target/ThreadPlanStepInstruction.h" +#include "lldb/Target/ThreadPlanStepOut.h" +#include "lldb/Target/ThreadPlanStepRange.h" +#include "lldb/Target/ThreadPlanStepInRange.h" + + +#include "lldb/API/SBAddress.h" +#include "lldb/API/SBDebugger.h" +#include "lldb/API/SBEvent.h" +#include "lldb/API/SBFrame.h" +#include "lldb/API/SBProcess.h" +#include "lldb/API/SBThreadPlan.h" +#include "lldb/API/SBValue.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// Constructors +//---------------------------------------------------------------------- +SBThreadPlan::SBThreadPlan () +{ +} + +SBThreadPlan::SBThreadPlan (const ThreadPlanSP& lldb_object_sp) : + m_opaque_sp (lldb_object_sp) +{ +} + +SBThreadPlan::SBThreadPlan (const SBThreadPlan &rhs) : + m_opaque_sp (rhs.m_opaque_sp) +{ + +} + +SBThreadPlan::SBThreadPlan (lldb::SBThread &sb_thread, const char *class_name) +{ + Thread *thread = sb_thread.get(); + if (thread) + m_opaque_sp.reset(new ThreadPlanPython(*thread, class_name)); +} + +//---------------------------------------------------------------------- +// Assignment operator +//---------------------------------------------------------------------- + +const lldb::SBThreadPlan & +SBThreadPlan::operator = (const SBThreadPlan &rhs) +{ + if (this != &rhs) + m_opaque_sp = rhs.m_opaque_sp; + return *this; +} +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +SBThreadPlan::~SBThreadPlan() +{ +} + +lldb_private::ThreadPlan * +SBThreadPlan::get() +{ + return m_opaque_sp.get(); +} + +bool +SBThreadPlan::IsValid() const +{ + return m_opaque_sp.get() != NULL; +} + +void +SBThreadPlan::Clear () +{ + m_opaque_sp.reset(); +} + +lldb::StopReason +SBThreadPlan::GetStopReason() +{ + return eStopReasonNone; +} + +size_t +SBThreadPlan::GetStopReasonDataCount() +{ + return 0; +} + +uint64_t +SBThreadPlan::GetStopReasonDataAtIndex(uint32_t idx) +{ + return 0; +} + +SBThread +SBThreadPlan::GetThread () const +{ + if (m_opaque_sp) + { + return SBThread(m_opaque_sp->GetThread().shared_from_this()); + } + else + return SBThread(); +} + +bool +SBThreadPlan::GetDescription (lldb::SBStream &description) const +{ + if (m_opaque_sp) + { + m_opaque_sp->GetDescription(description.get(), eDescriptionLevelFull); + } + else + { + description.Printf("Empty SBThreadPlan"); + } + return true; +} + +void +SBThreadPlan::SetThreadPlan (const ThreadPlanSP& lldb_object_sp) +{ + m_opaque_sp = lldb_object_sp; +} + +void +SBThreadPlan::SetPlanComplete (bool success) +{ + if (m_opaque_sp) + m_opaque_sp->SetPlanComplete (success); +} + +bool +SBThreadPlan::IsPlanComplete() +{ + if (m_opaque_sp) + return m_opaque_sp->IsPlanComplete(); + else + return true; +} + +bool +SBThreadPlan::IsValid() +{ + if (m_opaque_sp) + return m_opaque_sp->ValidatePlan(nullptr); + else + return false; +} + + // This section allows an SBThreadPlan to push another of the common types of plans... + // + // FIXME, you should only be able to queue thread plans from inside the methods of a + // Scripted Thread Plan. Need a way to enforce that. + +SBThreadPlan +SBThreadPlan::QueueThreadPlanForStepOverRange (SBAddress &sb_start_address, + lldb::addr_t size) +{ + if (m_opaque_sp) + { + Address *start_address = sb_start_address.get(); + if (!start_address) + { + return SBThreadPlan(); + } + + AddressRange range (*start_address, size); + SymbolContext sc; + start_address->CalculateSymbolContext(&sc); + return SBThreadPlan (m_opaque_sp->GetThread().QueueThreadPlanForStepOverRange (false, + range, + sc, + eAllThreads)); + } + else + { + return SBThreadPlan(); + } +} + +SBThreadPlan +SBThreadPlan::QueueThreadPlanForStepInRange (SBAddress &sb_start_address, + lldb::addr_t size) +{ + if (m_opaque_sp) + { + Address *start_address = sb_start_address.get(); + if (!start_address) + { + return SBThreadPlan(); + } + + AddressRange range (*start_address, size); + SymbolContext sc; + start_address->CalculateSymbolContext(&sc); + return SBThreadPlan (m_opaque_sp->GetThread().QueueThreadPlanForStepInRange (false, + range, + sc, + NULL, + eAllThreads)); + } + else + { + return SBThreadPlan(); + } +} + +SBThreadPlan +SBThreadPlan::QueueThreadPlanForStepOut (uint32_t frame_idx_to_step_to, bool first_insn) +{ + if (m_opaque_sp) + { + SymbolContext sc; + sc = m_opaque_sp->GetThread().GetStackFrameAtIndex(0)->GetSymbolContext(lldb::eSymbolContextEverything); + return SBThreadPlan (m_opaque_sp->GetThread().QueueThreadPlanForStepOut (false, + &sc, + first_insn, + false, + eVoteYes, + eVoteNoOpinion, + frame_idx_to_step_to)); + } + else + { + return SBThreadPlan(); + } +} + +SBThreadPlan +SBThreadPlan::QueueThreadPlanForRunToAddress (SBAddress sb_address) +{ + if (m_opaque_sp) + { + Address *address = sb_address.get(); + if (!address) + return SBThreadPlan(); + + return SBThreadPlan (m_opaque_sp->GetThread().QueueThreadPlanForRunToAddress (false, + *address, + false)); + } + else + { + return SBThreadPlan(); + } +} + + diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp index e7a8652ac89..785e8f078ee 100644 --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -46,7 +46,108 @@ using namespace lldb_private; // CommandObjectThreadBacktrace //------------------------------------------------------------------------- -class CommandObjectThreadBacktrace : public CommandObjectParsed +class CommandObjectIterateOverThreads : public CommandObjectParsed +{ +public: + CommandObjectIterateOverThreads (CommandInterpreter &interpreter, + const char *name, + const char *help, + const char *syntax, + uint32_t flags) : + CommandObjectParsed (interpreter, name, help, syntax, flags) + { + } + + virtual ~CommandObjectIterateOverThreads() {} + virtual bool + DoExecute (Args& command, CommandReturnObject &result) + { + result.SetStatus (m_success_return); + + if (command.GetArgumentCount() == 0) + { + Thread *thread = m_exe_ctx.GetThreadPtr(); + if (!HandleOneThread (*thread, result)) + return false; + } + else if (command.GetArgumentCount() == 1 && ::strcmp (command.GetArgumentAtIndex(0), "all") == 0) + { + Process *process = m_exe_ctx.GetProcessPtr(); + uint32_t idx = 0; + for (ThreadSP thread_sp : process->Threads()) + { + if (idx != 0 && m_add_return) + result.AppendMessage(""); + + if (!HandleOneThread(*(thread_sp.get()), result)) + return false; + ++idx; + } + } + else + { + const size_t num_args = command.GetArgumentCount(); + Process *process = m_exe_ctx.GetProcessPtr(); + Mutex::Locker locker (process->GetThreadList().GetMutex()); + std::vector<ThreadSP> thread_sps; + + for (size_t i = 0; i < num_args; i++) + { + bool success; + + uint32_t thread_idx = Args::StringToUInt32(command.GetArgumentAtIndex(i), 0, 0, &success); + if (!success) + { + result.AppendErrorWithFormat ("invalid thread specification: \"%s\"\n", command.GetArgumentAtIndex(i)); + result.SetStatus (eReturnStatusFailed); + return false; + } + + thread_sps.push_back(process->GetThreadList().FindThreadByIndexID(thread_idx)); + + if (!thread_sps[i]) + { + result.AppendErrorWithFormat ("no thread with index: \"%s\"\n", command.GetArgumentAtIndex(i)); + result.SetStatus (eReturnStatusFailed); + return false; + } + + } + + for (uint32_t i = 0; i < num_args; i++) + { + if (!HandleOneThread (*(thread_sps[i].get()), result)) + return false; + + if (i < num_args - 1 && m_add_return) + result.AppendMessage(""); + } + } + return result.Succeeded(); + } + +protected: + + // Override this to do whatever you need to do for one thread. + // + // If you return false, the iteration will stop, otherwise it will proceed. + // The result is set to m_success_return (defaults to eReturnStatusSuccessFinishResult) before the iteration, + // so you only need to set the return status in HandleOneThread if you want to indicate an error. + // If m_add_return is true, a blank line will be inserted between each of the listings (except the last one.) + + virtual bool + HandleOneThread (Thread &thread, CommandReturnObject &result) = 0; + + ReturnStatus m_success_return = eReturnStatusSuccessFinishResult; + bool m_add_return = true; + +}; + +//------------------------------------------------------------------------- +// CommandObjectThreadBacktrace +//------------------------------------------------------------------------- + +class CommandObjectThreadBacktrace : public CommandObjectIterateOverThreads { public: @@ -134,7 +235,7 @@ public: }; CommandObjectThreadBacktrace (CommandInterpreter &interpreter) : - CommandObjectParsed (interpreter, + CommandObjectIterateOverThreads (interpreter, "thread backtrace", "Show the stack for one or more threads. If no threads are specified, show the currently selected thread. Use the thread-index \"all\" to see all threads.", NULL, @@ -145,18 +246,6 @@ public: eFlagProcessMustBePaused ), m_options(interpreter) { - CommandArgumentEntry arg; - CommandArgumentData thread_idx_arg; - - // Define the first (and only) variant of this arg. - thread_idx_arg.arg_type = eArgTypeThreadIndex; - thread_idx_arg.arg_repetition = eArgRepeatStar; - - // There is only one variant this argument could be; put it into the argument entry. - arg.push_back (thread_idx_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back (arg); } ~CommandObjectThreadBacktrace() @@ -197,106 +286,28 @@ protected: } virtual bool - DoExecute (Args& command, CommandReturnObject &result) - { - result.SetStatus (eReturnStatusSuccessFinishResult); + HandleOneThread (Thread &thread, CommandReturnObject &result) + { Stream &strm = result.GetOutputStream(); // Don't show source context when doing backtraces. const uint32_t num_frames_with_source = 0; - if (command.GetArgumentCount() == 0) - { - Thread *thread = m_exe_ctx.GetThreadPtr(); - // Thread::GetStatus() returns the number of frames shown. - if (thread->GetStatus (strm, + + if (!thread.GetStatus (strm, m_options.m_start, m_options.m_count, num_frames_with_source)) - { - result.SetStatus (eReturnStatusSuccessFinishResult); - if (m_options.m_extended_backtrace) - { - DoExtendedBacktrace (thread, result); - } - } - } - else if (command.GetArgumentCount() == 1 && ::strcmp (command.GetArgumentAtIndex(0), "all") == 0) { - Process *process = m_exe_ctx.GetProcessPtr(); - uint32_t idx = 0; - for (ThreadSP thread_sp : process->Threads()) - { - if (idx != 0) - result.AppendMessage(""); - - if (!thread_sp->GetStatus (strm, - m_options.m_start, - m_options.m_count, - num_frames_with_source)) - { - result.AppendErrorWithFormat ("error displaying backtrace for thread: \"0x%4.4x\"\n", idx); - result.SetStatus (eReturnStatusFailed); - return false; - } - if (m_options.m_extended_backtrace) - { - DoExtendedBacktrace (thread_sp.get(), result); - } - - ++idx; - } + result.AppendErrorWithFormat ("error displaying backtrace for thread: \"0x%4.4x\"\n", thread.GetIndexID()); + result.SetStatus (eReturnStatusFailed); + return false; } - else + if (m_options.m_extended_backtrace) { - const size_t num_args = command.GetArgumentCount(); - Process *process = m_exe_ctx.GetProcessPtr(); - Mutex::Locker locker (process->GetThreadList().GetMutex()); - std::vector<ThreadSP> thread_sps; - - for (size_t i = 0; i < num_args; i++) - { - bool success; - - uint32_t thread_idx = Args::StringToUInt32(command.GetArgumentAtIndex(i), 0, 0, &success); - if (!success) - { - result.AppendErrorWithFormat ("invalid thread specification: \"%s\"\n", command.GetArgumentAtIndex(i)); - result.SetStatus (eReturnStatusFailed); - return false; - } - - thread_sps.push_back(process->GetThreadList().FindThreadByIndexID(thread_idx)); - - if (!thread_sps[i]) - { - result.AppendErrorWithFormat ("no thread with index: \"%s\"\n", command.GetArgumentAtIndex(i)); - result.SetStatus (eReturnStatusFailed); - return false; - } - - } - - for (uint32_t i = 0; i < num_args; i++) - { - if (!thread_sps[i]->GetStatus (strm, - m_options.m_start, - m_options.m_count, - num_frames_with_source)) - { - result.AppendErrorWithFormat ("error displaying backtrace for thread: \"%s\"\n", command.GetArgumentAtIndex(i)); - result.SetStatus (eReturnStatusFailed); - return false; - } - if (m_options.m_extended_backtrace) - { - DoExtendedBacktrace (thread_sps[i].get(), result); - } - - if (i < num_args - 1) - result.AppendMessage(""); - } + DoExtendedBacktrace (&thread, result); } - return result.Succeeded(); + + return true; } CommandOptions m_options; @@ -379,6 +390,12 @@ public: break; } break; + case 'C': + { + m_class_name.clear(); + m_class_name.assign(option_arg); + } + break; case 'm': { OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values; @@ -416,6 +433,7 @@ public: m_run_mode = eOnlyDuringStepping; m_avoid_regexp.clear(); m_step_in_target.clear(); + m_class_name.clear(); m_step_count = 1; } @@ -435,6 +453,7 @@ public: RunMode m_run_mode; std::string m_avoid_regexp; std::string m_step_in_target; + std::string m_class_name; int32_t m_step_count; }; @@ -520,6 +539,22 @@ protected: } } + if (m_step_type == eStepTypeScripted) + { + if (m_options.m_class_name.empty()) + { + result.AppendErrorWithFormat ("empty class name for scripted step."); + result.SetStatus(eReturnStatusFailed); + return false; + } + else if (!m_interpreter.GetScriptInterpreter()->CheckObjectExists(m_options.m_class_name.c_str())) + { + result.AppendErrorWithFormat ("class for scripted step: \"%s\" does not exist.", m_options.m_class_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + } + const bool abort_other_plans = false; const lldb::RunMode stop_other_threads = m_options.m_run_mode; @@ -530,7 +565,7 @@ protected: bool_stop_other_threads = false; else if (m_options.m_run_mode == eOnlyDuringStepping) { - if (m_step_type == eStepTypeOut) + if (m_step_type == eStepTypeOut || m_step_type == eStepTypeScripted) bool_stop_other_threads = false; else bool_stop_other_threads = true; @@ -599,6 +634,12 @@ protected: thread->GetSelectedFrameIndex(), m_options.m_step_out_avoid_no_debug); } + else if (m_step_type == eStepTypeScripted) + { + new_plan_sp = thread->QueueThreadPlanForStepScripted (abort_other_plans, + m_options.m_class_name.c_str(), + bool_stop_other_threads); + } else { result.AppendError ("step type is not supported"); @@ -686,10 +727,11 @@ CommandObjectThreadStepWithTypeAndScope::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_1, false, "step-in-avoids-no-debug", 'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "A boolean value that sets whether stepping into functions will step over functions with no debug information."}, { LLDB_OPT_SET_1, false, "step-out-avoids-no-debug", 'A', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "A boolean value, if true stepping out of functions will continue to step out till it hits a function with debug information."}, -{ LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, NULL, NULL, 1, eArgTypeCount, "How many times to perform the stepping operation - currently only supported for step-inst and next-inst."}, -{ LLDB_OPT_SET_1, false, "run-mode", 'm', OptionParser::eRequiredArgument, NULL, g_tri_running_mode, 0, eArgTypeRunMode, "Determine how to run other threads while stepping the current thread."}, -{ LLDB_OPT_SET_1, false, "step-over-regexp",'r', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeRegularExpression, "A regular expression that defines function names to not to stop at when stepping in."}, -{ LLDB_OPT_SET_1, false, "step-in-target", 't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFunctionName, "The name of the directly called function step in should stop at when stepping into."}, +{ LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, NULL, NULL, 1, eArgTypeCount, "How many times to perform the stepping operation - currently only supported for step-inst and next-inst."}, +{ LLDB_OPT_SET_1, false, "run-mode", 'm', OptionParser::eRequiredArgument, NULL, g_tri_running_mode, 0, eArgTypeRunMode, "Determine how to run other threads while stepping the current thread."}, +{ LLDB_OPT_SET_1, false, "step-over-regexp", 'r', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeRegularExpression, "A regular expression that defines function names to not to stop at when stepping in."}, +{ LLDB_OPT_SET_1, false, "step-in-target", 't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFunctionName, "The name of the directly called function step in should stop at when stepping into."}, +{ LLDB_OPT_SET_2, false, "python-class", 'C', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonClass, "The name of the class that will manage this step - only supported for Scripted Step."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; @@ -1358,32 +1400,22 @@ protected: // CommandObjectThreadInfo //------------------------------------------------------------------------- -class CommandObjectThreadInfo : public CommandObjectParsed +class CommandObjectThreadInfo : public CommandObjectIterateOverThreads { public: CommandObjectThreadInfo (CommandInterpreter &interpreter) : - CommandObjectParsed (interpreter, - "thread info", - "Show an extended summary of information about thread(s) in a process.", - "thread info", - eFlagRequiresProcess | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused), + CommandObjectIterateOverThreads (interpreter, + "thread info", + "Show an extended summary of information about thread(s) in a process.", + "thread info", + eFlagRequiresProcess | + eFlagTryTargetAPILock | + eFlagProcessMustBeLaunched | + eFlagProcessMustBePaused), m_options (interpreter) { - CommandArgumentEntry arg; - CommandArgumentData thread_idx_arg; - - thread_idx_arg.arg_type = eArgTypeThreadIndex; - thread_idx_arg.arg_repetition = eArgRepeatStar; - - // There is only one variant this argument could be; put it into the argument entry. - arg.push_back (thread_idx_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back (arg); + m_add_return = false; } class CommandOptions : public Options @@ -1451,81 +1483,16 @@ public: } virtual bool - DoExecute (Args& command, CommandReturnObject &result) + HandleOneThread (Thread &thread, CommandReturnObject &result) { - result.SetStatus (eReturnStatusSuccessFinishResult); Stream &strm = result.GetOutputStream(); - - if (command.GetArgumentCount() == 0) + if (!thread.GetDescription (strm, eDescriptionLevelFull, m_options.m_json)) { - Thread *thread = m_exe_ctx.GetThreadPtr(); - if (thread->GetDescription (strm, eDescriptionLevelFull, m_options.m_json)) - { - result.SetStatus (eReturnStatusSuccessFinishResult); - } - } - else if (command.GetArgumentCount() == 1 && ::strcmp (command.GetArgumentAtIndex(0), "all") == 0) - { - Process *process = m_exe_ctx.GetProcessPtr(); - uint32_t idx = 0; - for (ThreadSP thread_sp : process->Threads()) - { - if (idx != 0) - result.AppendMessage(""); - if (!thread_sp->GetDescription (strm, eDescriptionLevelFull, m_options.m_json)) - { - result.AppendErrorWithFormat ("error displaying info for thread: \"0x%4.4x\"\n", idx); - result.SetStatus (eReturnStatusFailed); - return false; - } - ++idx; - } - } - else - { - const size_t num_args = command.GetArgumentCount(); - Process *process = m_exe_ctx.GetProcessPtr(); - Mutex::Locker locker (process->GetThreadList().GetMutex()); - std::vector<ThreadSP> thread_sps; - - for (size_t i = 0; i < num_args; i++) - { - bool success; - - uint32_t thread_idx = Args::StringToUInt32(command.GetArgumentAtIndex(i), 0, 0, &success); - if (!success) - { - result.AppendErrorWithFormat ("invalid thread specification: \"%s\"\n", command.GetArgumentAtIndex(i)); - result.SetStatus (eReturnStatusFailed); - return false; - } - - thread_sps.push_back(process->GetThreadList().FindThreadByIndexID(thread_idx)); - - if (!thread_sps[i]) - { - result.AppendErrorWithFormat ("no thread with index: \"%s\"\n", command.GetArgumentAtIndex(i)); - result.SetStatus (eReturnStatusFailed); - return false; - } - - } - - for (uint32_t i = 0; i < num_args; i++) - { - if (!thread_sps[i]->GetDescription (strm, eDescriptionLevelFull, m_options.m_json)) - { - result.AppendErrorWithFormat ("error displaying info for thread: \"%s\"\n", command.GetArgumentAtIndex(i)); - result.SetStatus (eReturnStatusFailed); - return false; - } - - if (i < num_args - 1) - result.AppendMessage(""); - } - + result.AppendErrorWithFormat ("error displaying info for thread: \"%d\"\n", thread.GetIndexID()); + result.SetStatus (eReturnStatusFailed); + return false; } - return result.Succeeded(); + return true; } CommandOptions m_options; @@ -1958,6 +1925,228 @@ CommandObjectThreadJump::CommandOptions::g_option_table[] = }; //------------------------------------------------------------------------- +// Next are the subcommands of CommandObjectMultiwordThreadPlan +//------------------------------------------------------------------------- + + +//------------------------------------------------------------------------- +// CommandObjectThreadPlanList +//------------------------------------------------------------------------- +class CommandObjectThreadPlanList : public CommandObjectIterateOverThreads +{ +public: + + class CommandOptions : public Options + { + public: + + CommandOptions (CommandInterpreter &interpreter) : + Options(interpreter) + { + // Keep default values of all options in one place: OptionParsingStarting () + OptionParsingStarting (); + } + + virtual + ~CommandOptions () + { + } + + virtual Error + SetOptionValue (uint32_t option_idx, const char *option_arg) + { + Error error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) + { + case 'i': + { + m_internal = true; + } + break; + case 'v': + { + m_verbose = true; + } + break; + default: + error.SetErrorStringWithFormat("invalid short option character '%c'", short_option); + break; + + } + return error; + } + + void + OptionParsingStarting () + { + m_verbose = false; + m_internal = false; + } + + const OptionDefinition* + GetDefinitions () + { + return g_option_table; + } + + // Options table: Required for subclasses of Options. + + static OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + bool m_verbose; + bool m_internal; + }; + + CommandObjectThreadPlanList (CommandInterpreter &interpreter) : + CommandObjectIterateOverThreads (interpreter, + "thread plan list", + "Show thread plans for one or more threads. If no threads are specified, show the " + "currently selected thread. Use the thread-index \"all\" to see all threads.", + NULL, + eFlagRequiresProcess | + eFlagRequiresThread | + eFlagTryTargetAPILock | + eFlagProcessMustBeLaunched | + eFlagProcessMustBePaused ), + m_options(interpreter) + { + } + + ~CommandObjectThreadPlanList () + { + } + + virtual Options * + GetOptions () + { + return &m_options; + } + +protected: + virtual bool + HandleOneThread (Thread &thread, CommandReturnObject &result) + { + Stream &strm = result.GetOutputStream(); + DescriptionLevel desc_level = eDescriptionLevelFull; + if (m_options.m_verbose) + desc_level = eDescriptionLevelVerbose; + + thread.DumpThreadPlans (&strm, desc_level, m_options.m_internal, true); + return true; + } + CommandOptions m_options; +}; + +OptionDefinition +CommandObjectThreadPlanList::CommandOptions::g_option_table[] = +{ +{ LLDB_OPT_SET_1, false, "verbose", 'v', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display more information about the thread plans"}, +{ LLDB_OPT_SET_1, false, "internal", 'i', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display internal as well as user thread plans"}, +{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } +}; + +class CommandObjectThreadPlanDiscard : public CommandObjectParsed +{ +public: + CommandObjectThreadPlanDiscard (CommandInterpreter &interpreter) : + CommandObjectParsed (interpreter, + "thread plan discard", + "Discards thread plans up to and including the plan passed as the command argument." + "Only user visible plans can be discarded, use the index from \"thread plan list\"" + " without the \"-i\" argument.", + NULL, + eFlagRequiresProcess | + eFlagRequiresThread | + eFlagTryTargetAPILock | + eFlagProcessMustBeLaunched | + eFlagProcessMustBePaused ) + { + CommandArgumentEntry arg; + CommandArgumentData plan_index_arg; + + // Define the first (and only) variant of this arg. + plan_index_arg.arg_type = eArgTypeUnsignedInteger; + plan_index_arg.arg_repetition = eArgRepeatPlain; + + // There is only one variant this argument could be; put it into the argument entry. + arg.push_back (plan_index_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back (arg); + } + + virtual ~CommandObjectThreadPlanDiscard () {} + + bool + DoExecute (Args& args, CommandReturnObject &result) + { + Thread *thread = m_exe_ctx.GetThreadPtr(); + if (args.GetArgumentCount() != 1) + { + result.AppendErrorWithFormat("Too many arguments, expected one - the thread plan index - but got %zu.", + args.GetArgumentCount()); + result.SetStatus (eReturnStatusFailed); + return false; + } + + bool success; + uint32_t thread_plan_idx = Args::StringToUInt32(args.GetArgumentAtIndex(0), 0, 0, &success); + if (!success) + { + result.AppendErrorWithFormat("Invalid thread index: \"%s\" - should be unsigned int.", + args.GetArgumentAtIndex(0)); + result.SetStatus (eReturnStatusFailed); + return false; + } + + if (thread_plan_idx == 0) + { + result.AppendErrorWithFormat("You wouldn't really want me to discard the base thread plan."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + if (thread->DiscardUserThreadPlansUpToIndex(thread_plan_idx)) + { + result.SetStatus(eReturnStatusSuccessFinishNoResult); + return true; + } + else + { + result.AppendErrorWithFormat("Could not find User thread plan with index %s.", + args.GetArgumentAtIndex(0)); + result.SetStatus (eReturnStatusFailed); + return false; + } + } +}; + +//------------------------------------------------------------------------- +// CommandObjectMultiwordThreadPlan +//------------------------------------------------------------------------- + +class CommandObjectMultiwordThreadPlan : public CommandObjectMultiword +{ +public: + CommandObjectMultiwordThreadPlan(CommandInterpreter &interpreter) : + CommandObjectMultiword (interpreter, + "plan", + "A set of subcommands for accessing the thread plans controlling execution control on one or more threads.", + "thread plan <subcommand> [<subcommand objects]") + { + LoadSubCommand ("list", CommandObjectSP (new CommandObjectThreadPlanList (interpreter))); + LoadSubCommand ("discard", CommandObjectSP (new CommandObjectThreadPlanDiscard (interpreter))); + } + + virtual ~CommandObjectMultiwordThreadPlan () {} + + +}; + +//------------------------------------------------------------------------- // CommandObjectMultiwordThread //------------------------------------------------------------------------- @@ -2014,6 +2203,16 @@ CommandObjectMultiwordThread::CommandObjectMultiwordThread (CommandInterpreter & NULL, eStepTypeTraceOver, eStepScopeInstruction))); + + LoadSubCommand ("step-scripted", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ( + interpreter, + "thread step-scripted", + "Step as instructed by the script class passed in the -C option.", + NULL, + eStepTypeScripted, + eStepScopeSource))); + + LoadSubCommand ("plan", CommandObjectSP (new CommandObjectMultiwordThreadPlan(interpreter))); } CommandObjectMultiwordThread::~CommandObjectMultiwordThread () diff --git a/lldb/source/Expression/ClangFunction.cpp b/lldb/source/Expression/ClangFunction.cpp index 27afba2898a..5654e654cdb 100644 --- a/lldb/source/Expression/ClangFunction.cpp +++ b/lldb/source/Expression/ClangFunction.cpp @@ -422,7 +422,7 @@ ClangFunction::InsertFunction (ExecutionContext &exe_ctx, lldb::addr_t &args_add return true; } -ThreadPlan * +lldb::ThreadPlanSP ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, lldb::addr_t args_addr, const EvaluateExpressionOptions &options, @@ -447,14 +447,14 @@ ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, lldb::addr_t args = { args_addr }; - ThreadPlan *new_plan = new ThreadPlanCallFunction (*thread, + lldb::ThreadPlanSP new_plan_sp (new ThreadPlanCallFunction (*thread, wrapper_address, ClangASTType(), args, - options); - new_plan->SetIsMasterPlan(true); - new_plan->SetOkayToDiscard (false); - return new_plan; + options)); + new_plan_sp->SetIsMasterPlan(true); + new_plan_sp->SetOkayToDiscard (false); + return new_plan_sp; } bool @@ -541,10 +541,10 @@ ClangFunction::ExecuteFunction( if (log) log->Printf("== [ClangFunction::ExecuteFunction] Executing function \"%s\" ==", m_name.c_str()); - lldb::ThreadPlanSP call_plan_sp (GetThreadPlanToCallFunction (exe_ctx, - args_addr, - real_options, - errors)); + lldb::ThreadPlanSP call_plan_sp = GetThreadPlanToCallFunction (exe_ctx, + args_addr, + real_options, + errors); if (!call_plan_sp) return lldb::eExpressionSetupError; diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp index 52ef4d31035..dab7b556e39 100644 --- a/lldb/source/Expression/ClangUserExpression.cpp +++ b/lldb/source/Expression/ClangUserExpression.cpp @@ -885,17 +885,17 @@ ClangUserExpression::Execute (Stream &error_stream, args.push_back(struct_address); - ThreadPlanCallUserExpression *user_expression_plan = - new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(), - wrapper_address, - args, - options, - shared_ptr_to_me); - lldb::ThreadPlanSP call_plan_sp(user_expression_plan); + lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(), + wrapper_address, + args, + options, + shared_ptr_to_me)); if (!call_plan_sp || !call_plan_sp->ValidatePlan (&error_stream)) return lldb::eExpressionSetupError; + ThreadPlanCallUserExpression *user_expression_plan = static_cast<ThreadPlanCallUserExpression *>(call_plan_sp.get()); + lldb::addr_t function_stack_pointer = user_expression_plan->GetFunctionStackPointer(); function_stack_bottom = function_stack_pointer - HostInfo::GetPageSize(); diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp index b6c46f83bd9..721eedb59d7 100644 --- a/lldb/source/Interpreter/ScriptInterpreter.cpp +++ b/lldb/source/Interpreter/ScriptInterpreter.cpp @@ -131,7 +131,9 @@ ScriptInterpreter::InitializeInterpreter (SWIGInitCallback python_swig_init_call SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread, SWIGPythonScriptKeyword_Target swig_run_script_keyword_target, SWIGPythonScriptKeyword_Frame swig_run_script_keyword_frame, - SWIGPython_GetDynamicSetting swig_plugin_get) + SWIGPython_GetDynamicSetting swig_plugin_get, + SWIGPythonCreateScriptedThreadPlan swig_thread_plan_script, + SWIGPythonCallThreadPlan swig_call_thread_plan) { #ifndef LLDB_DISABLE_PYTHON ScriptInterpreterPython::InitializeInterpreter (python_swig_init_callback, @@ -153,6 +155,8 @@ ScriptInterpreter::InitializeInterpreter (SWIGInitCallback python_swig_init_call swig_run_script_keyword_thread, swig_run_script_keyword_target, swig_run_script_keyword_frame, - swig_plugin_get); + swig_plugin_get, + swig_thread_plan_script, + swig_call_thread_plan); #endif // #ifndef LLDB_DISABLE_PYTHON } diff --git a/lldb/source/Interpreter/ScriptInterpreterPython.cpp b/lldb/source/Interpreter/ScriptInterpreterPython.cpp index 1b24fea7c21..945e869a794 100644 --- a/lldb/source/Interpreter/ScriptInterpreterPython.cpp +++ b/lldb/source/Interpreter/ScriptInterpreterPython.cpp @@ -37,6 +37,7 @@ #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/PythonDataObjects.h" #include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadPlan.h" using namespace lldb; using namespace lldb_private; @@ -62,6 +63,8 @@ static ScriptInterpreter::SWIGPythonScriptKeyword_Thread g_swig_run_script_keywo static ScriptInterpreter::SWIGPythonScriptKeyword_Target g_swig_run_script_keyword_target = nullptr; static ScriptInterpreter::SWIGPythonScriptKeyword_Frame g_swig_run_script_keyword_frame = nullptr; static ScriptInterpreter::SWIGPython_GetDynamicSetting g_swig_plugin_get = nullptr; +static ScriptInterpreter::SWIGPythonCreateScriptedThreadPlan g_swig_thread_plan_script = nullptr; +static ScriptInterpreter::SWIGPythonCallThreadPlan g_swig_call_thread_plan = nullptr; static std::string ReadPythonBacktrace (PyObject* py_backtrace); @@ -1617,6 +1620,87 @@ ScriptInterpreterPython::OSPlugin_CreateThread (lldb::ScriptInterpreterObjectSP } lldb::ScriptInterpreterObjectSP +ScriptInterpreterPython::CreateScriptedThreadPlan (const char *class_name, + lldb::ThreadPlanSP thread_plan_sp) +{ + if (class_name == nullptr || class_name[0] == '\0') + return lldb::ScriptInterpreterObjectSP(); + + if (!thread_plan_sp.get()) + return lldb::ScriptInterpreterObjectSP(); + + Debugger &debugger = thread_plan_sp->GetTarget().GetDebugger(); + ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter(); + ScriptInterpreterPython *python_interpreter = static_cast<ScriptInterpreterPython *>(script_interpreter); + + if (!script_interpreter) + return lldb::ScriptInterpreterObjectSP(); + + void* ret_val; + + { + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + + ret_val = g_swig_thread_plan_script (class_name, + python_interpreter->m_dictionary_name.c_str(), + thread_plan_sp); + } + + return MakeScriptObject(ret_val); +} + +bool +ScriptInterpreterPython::ScriptedThreadPlanExplainsStop (lldb::ScriptInterpreterObjectSP implementor_sp, + Event *event, + bool &script_error) +{ + bool explains_stop = true; + if (implementor_sp) + { + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + explains_stop = g_swig_call_thread_plan (implementor_sp->GetObject(), "explains_stop", event, script_error); + if (script_error) + return true; + } + return explains_stop; +} + +bool +ScriptInterpreterPython::ScriptedThreadPlanShouldStop (lldb::ScriptInterpreterObjectSP implementor_sp, + Event *event, + bool &script_error) +{ + bool should_stop = true; + if (implementor_sp) + { + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + should_stop = g_swig_call_thread_plan (implementor_sp->GetObject(), "should_stop", event, script_error); + if (script_error) + return true; + } + return should_stop; +} + +lldb::StateType +ScriptInterpreterPython::ScriptedThreadPlanGetRunState (lldb::ScriptInterpreterObjectSP implementor_sp, + bool &script_error) +{ + bool should_step = false; + if (implementor_sp) + { + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + should_step = g_swig_call_thread_plan (implementor_sp->GetObject(), "should_step", NULL, script_error); + if (script_error) + should_step = true; + } + if (should_step) + return lldb::eStateStepping; + else + return lldb::eStateRunning; +} + + +lldb::ScriptInterpreterObjectSP ScriptInterpreterPython::LoadPluginModule (const FileSpec& file_spec, lldb_private::Error& error) { @@ -2536,7 +2620,9 @@ ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback swig_init_callb SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread, SWIGPythonScriptKeyword_Target swig_run_script_keyword_target, SWIGPythonScriptKeyword_Frame swig_run_script_keyword_frame, - SWIGPython_GetDynamicSetting swig_plugin_get) + SWIGPython_GetDynamicSetting swig_plugin_get, + SWIGPythonCreateScriptedThreadPlan swig_thread_plan_script, + SWIGPythonCallThreadPlan swig_call_thread_plan) { g_swig_init_callback = swig_init_callback; g_swig_breakpoint_callback = swig_breakpoint_callback; @@ -2558,6 +2644,8 @@ ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback swig_init_callb g_swig_run_script_keyword_target = swig_run_script_keyword_target; g_swig_run_script_keyword_frame = swig_run_script_keyword_frame; g_swig_plugin_get = swig_plugin_get; + g_swig_thread_plan_script = swig_thread_plan_script; + g_swig_call_thread_plan = swig_call_thread_plan; } void diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp index cdd5b465479..fe364faefe3 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp @@ -89,10 +89,10 @@ AppleThreadPlanStepThroughObjCTrampoline::InitializeClangFunction () options.SetIgnoreBreakpoints(true); options.SetStopOthers(m_stop_others); m_thread.CalculateExecutionContext(exc_ctx); - m_func_sp.reset(m_impl_function->GetThreadPlanToCallFunction (exc_ctx, - m_args_addr, - options, - errors)); + m_func_sp = m_impl_function->GetThreadPlanToCallFunction (exc_ctx, + m_args_addr, + options, + errors); m_func_sp->SetOkayToDiscard(true); m_thread.QueueThreadPlan (m_func_sp, false); } diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index 4a94457466b..7db83ae5467 100644 --- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -98,13 +98,11 @@ lldb_private::InferiorCallMmap (Process *process, ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext(); ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); lldb::addr_t args[] = { addr, length, prot_arg, flags_arg, fd, offset }; - ThreadPlanCallFunction *call_function_thread_plan - = new ThreadPlanCallFunction (*thread, - mmap_range.GetBaseAddress(), - clang_void_ptr_type, - args, - options); - lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan); + lldb::ThreadPlanSP call_plan_sp (new ThreadPlanCallFunction (*thread, + mmap_range.GetBaseAddress(), + clang_void_ptr_type, + args, + options)); if (call_plan_sp) { StreamFile error_strm; @@ -241,13 +239,11 @@ lldb_private::InferiorCall (Process *process, ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext(); ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); - ThreadPlanCallFunction *call_function_thread_plan - = new ThreadPlanCallFunction (*thread, - *address, - clang_void_ptr_type, - llvm::ArrayRef<addr_t>(), - options); - lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan); + lldb::ThreadPlanSP call_plan_sp (new ThreadPlanCallFunction (*thread, + *address, + clang_void_ptr_type, + llvm::ArrayRef<addr_t>(), + options)); if (call_plan_sp) { StreamString error_strm; diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index f8ea250639b..30e0ffb909b 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -32,6 +32,7 @@ #include "lldb/Target/ThreadPlan.h" #include "lldb/Target/ThreadPlanCallFunction.h" #include "lldb/Target/ThreadPlanBase.h" +#include "lldb/Target/ThreadPlanPython.h" #include "lldb/Target/ThreadPlanStepInstruction.h" #include "lldb/Target/ThreadPlanStepOut.h" #include "lldb/Target/ThreadPlanStepOverBreakpoint.h" @@ -652,17 +653,18 @@ Thread::SetupForResume () if (cur_plan->GetKind() != ThreadPlan::eKindStepOverBreakpoint) { - ThreadPlanStepOverBreakpoint *step_bp_plan = new ThreadPlanStepOverBreakpoint (*this); - if (step_bp_plan) + ThreadPlanSP step_bp_plan_sp (new ThreadPlanStepOverBreakpoint (*this)); + if (step_bp_plan_sp) { - ThreadPlanSP step_bp_plan_sp; - step_bp_plan->SetPrivate (true); + ; + step_bp_plan_sp->SetPrivate (true); if (GetCurrentPlan()->RunState() != eStateStepping) { + ThreadPlanStepOverBreakpoint *step_bp_plan + = static_cast<ThreadPlanStepOverBreakpoint *>(step_bp_plan_sp.get()); step_bp_plan->SetAutoContinue(true); } - step_bp_plan_sp.reset (step_bp_plan); QueueThreadPlan (step_bp_plan_sp, false); } } @@ -1290,6 +1292,36 @@ Thread::SetTracer (lldb::ThreadPlanTracerSP &tracer_sp) m_plan_stack[i]->SetThreadPlanTracer(tracer_sp); } +bool +Thread::DiscardUserThreadPlansUpToIndex (uint32_t thread_index) +{ + // Count the user thread plans from the back end to get the number of the one we want + // to discard: + + uint32_t idx = 0; + ThreadPlan *up_to_plan_ptr = nullptr; + + for (ThreadPlanSP plan_sp : m_plan_stack) + { + if (plan_sp->GetPrivate()) + continue; + if (idx == thread_index) + { + up_to_plan_ptr = plan_sp.get(); + break; + } + else + idx++; + } + + if (up_to_plan_ptr == nullptr) + return false; + + DiscardThreadPlansUpToPlan(up_to_plan_ptr); + return true; +} + + void Thread::DiscardThreadPlansUpToPlan (lldb::ThreadPlanSP &up_to_plan_sp) { @@ -1483,18 +1515,16 @@ Thread::QueueThreadPlanForStepInRange LazyBool step_out_avoids_code_without_debug_info ) { - ThreadPlanSP thread_plan_sp; - ThreadPlanStepInRange *plan = new ThreadPlanStepInRange (*this, + ThreadPlanSP thread_plan_sp (new ThreadPlanStepInRange (*this, range, addr_context, stop_other_threads, step_in_avoids_code_without_debug_info, - step_out_avoids_code_without_debug_info); + step_out_avoids_code_without_debug_info)); + ThreadPlanStepInRange *plan = static_cast<ThreadPlanStepInRange *>(thread_plan_sp.get()); if (step_in_target) plan->SetStepInTarget(step_in_target); - - thread_plan_sp.reset (plan); QueueThreadPlan (thread_plan_sp, abort_other_plans); return thread_plan_sp; @@ -1546,17 +1576,18 @@ Thread::QueueThreadPlanForStepOutNoShouldStop uint32_t frame_idx ) { - ThreadPlanStepOut *new_plan = new ThreadPlanStepOut (*this, + ThreadPlanSP thread_plan_sp(new ThreadPlanStepOut (*this, addr_context, first_insn, stop_other_threads, stop_vote, run_vote, frame_idx, - eLazyBoolNo); + eLazyBoolNo)); + + ThreadPlanStepOut *new_plan = static_cast<ThreadPlanStepOut *>(thread_plan_sp.get()); new_plan->ClearShouldStopHereCallbacks(); - ThreadPlanSP thread_plan_sp(new_plan); - + if (thread_plan_sp->ValidatePlan(NULL)) { QueueThreadPlan (thread_plan_sp, abort_other_plans); @@ -1602,61 +1633,105 @@ Thread::QueueThreadPlanForStepUntil (bool abort_other_plans, } +lldb::ThreadPlanSP +Thread::QueueThreadPlanForStepScripted (bool abort_other_plans, + const char *class_name, + bool stop_other_threads) +{ + ThreadPlanSP thread_plan_sp (new ThreadPlanPython (*this, class_name)); + QueueThreadPlan (thread_plan_sp, abort_other_plans); + // This seems a little funny, but I don't want to have to split up the constructor and the + // DidPush in the scripted plan, that seems annoying. + // That means the constructor has to be in DidPush. + // So I have to validate the plan AFTER pushing it, and then take it off again... + if (!thread_plan_sp->ValidatePlan(nullptr)) + { + DiscardThreadPlansUpToPlan(thread_plan_sp); + return ThreadPlanSP(); + } + else + return thread_plan_sp; + +} + uint32_t Thread::GetIndexID () const { return m_index_id; } -void -Thread::DumpThreadPlans (lldb_private::Stream *s) const +static void +PrintPlanElement (Stream *s, const ThreadPlanSP &plan, lldb::DescriptionLevel desc_level, int32_t elem_idx) { - uint32_t stack_size = m_plan_stack.size(); - int i; - s->Indent(); - s->Printf ("Plan Stack for thread #%u: tid = 0x%4.4" PRIx64 ", stack_size = %d\n", GetIndexID(), GetID(), stack_size); - for (i = stack_size - 1; i >= 0; i--) - { s->IndentMore(); s->Indent(); - s->Printf ("Element %d: ", i); - m_plan_stack[i]->GetDescription (s, eDescriptionLevelFull); + s->Printf ("Element %d: ", elem_idx); + plan->GetDescription (s, desc_level); s->EOL(); s->IndentLess(); +} + +static void +PrintPlanStack (Stream *s, const std::vector<lldb::ThreadPlanSP> &plan_stack, lldb::DescriptionLevel desc_level, bool include_internal) +{ + int32_t print_idx = 0; + for (ThreadPlanSP plan_sp : plan_stack) + { + if (include_internal || !plan_sp->GetPrivate()) + { + PrintPlanElement (s, plan_sp, desc_level, print_idx++); + } } +} - stack_size = m_completed_plan_stack.size(); - if (stack_size > 0) +void +Thread::DumpThreadPlans (Stream *s, + lldb::DescriptionLevel desc_level, + bool include_internal, + bool ignore_boring_threads) const +{ + uint32_t stack_size = m_plan_stack.size(); + + if (ignore_boring_threads) { - s->Indent(); - s->Printf ("Completed Plan Stack: %d elements.\n", stack_size); - for (i = stack_size - 1; i >= 0; i--) + uint32_t stack_size = m_plan_stack.size(); + uint32_t completed_stack_size = m_completed_plan_stack.size(); + uint32_t discarded_stack_size = m_discarded_plan_stack.size(); + if (stack_size == 1 && completed_stack_size == 0 && discarded_stack_size == 0) { + s->Printf ("thread #%u: tid = 0x%4.4" PRIx64 "\n", GetIndexID(), GetID()); s->IndentMore(); s->Indent(); - s->Printf ("Element %d: ", i); - m_completed_plan_stack[i]->GetDescription (s, eDescriptionLevelFull); - s->EOL(); + s->Printf("No active thread plans\n"); s->IndentLess(); + return; } } + s->Indent(); + s->Printf ("thread #%u: tid = 0x%4.4" PRIx64 ":\n", GetIndexID(), GetID()); + s->IndentMore(); + s->Indent(); + s->Printf ("Active plan stack:\n"); + PrintPlanStack (s, m_plan_stack, desc_level, include_internal); + + stack_size = m_completed_plan_stack.size(); + if (stack_size > 0) + { + s->Indent(); + s->Printf ("Completed Plan Stack:\n"); + PrintPlanStack (s, m_completed_plan_stack, desc_level, include_internal); + } + stack_size = m_discarded_plan_stack.size(); if (stack_size > 0) { s->Indent(); - s->Printf ("Discarded Plan Stack: %d elements.\n", stack_size); - for (i = stack_size - 1; i >= 0; i--) - { - s->IndentMore(); - s->Indent(); - s->Printf ("Element %d: ", i); - m_discarded_plan_stack[i]->GetDescription (s, eDescriptionLevelFull); - s->EOL(); - s->IndentLess(); - } + s->Printf ("Discarded Plan Stack:\n"); + PrintPlanStack (s, m_discarded_plan_stack, desc_level, include_internal); } + s->IndentLess(); } TargetSP diff --git a/lldb/source/Target/ThreadPlanPython.cpp b/lldb/source/Target/ThreadPlanPython.cpp new file mode 100644 index 00000000000..e196d81c897 --- /dev/null +++ b/lldb/source/Target/ThreadPlanPython.cpp @@ -0,0 +1,192 @@ +//===-- 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/lldb-python.h" + +#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/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/Interpreter/ScriptInterpreterPython.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadPlan.h" +#include "lldb/Target/ThreadPlanPython.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// ThreadPlanPython +//---------------------------------------------------------------------- + +ThreadPlanPython::ThreadPlanPython (Thread &thread, const char *class_name) : + ThreadPlan (ThreadPlan::eKindPython, + "Python based Thread Plan", + thread, + eVoteNoOpinion, + eVoteNoOpinion), + m_class_name (class_name) +{ + SetIsMasterPlan (true); + SetOkayToDiscard (true); + SetPrivate (false); +} + +ThreadPlanPython::~ThreadPlanPython () +{ + // FIXME, do I need to decrement the ref count on this implementation object to make it go away? +} + +bool +ThreadPlanPython::ValidatePlan (Stream *error) +{ + // I have to postpone setting up the implementation till after the constructor because I need to call + // shared_from_this, which you can't do in the constructor. So I'll do it here. + if (m_implementation_sp) + return true; + else + return false; +} + +void +ThreadPlanPython::DidPush() +{ + // We set up the script side in DidPush, so that it can push other plans in the constructor, + // and doesn't have to care about the details of DidPush. + + if (!m_class_name.empty()) + { + ScriptInterpreter *script_interp = m_thread.GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); + if (script_interp) + { + m_implementation_sp = script_interp->CreateScriptedThreadPlan (m_class_name.c_str(), this->shared_from_this()); + } + } +} + +bool +ThreadPlanPython::ShouldStop (Event *event_ptr) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); + if (log) + log->Printf ("%s called on Python Thread Plan: %s )", + __PRETTY_FUNCTION__, m_class_name.c_str()); + + bool should_stop = true; + if (m_implementation_sp) + { + ScriptInterpreter *script_interp = m_thread.GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); + if (script_interp) + { + bool script_error; + should_stop = script_interp->ScriptedThreadPlanShouldStop (m_implementation_sp, event_ptr, script_error); + if (script_error) + SetPlanComplete(false); + } + } + return should_stop; +} + +bool +ThreadPlanPython::DoPlanExplainsStop (Event *event_ptr) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); + if (log) + log->Printf ("%s called on Python Thread Plan: %s )", + __PRETTY_FUNCTION__, m_class_name.c_str()); + + bool explains_stop = true; + if (m_implementation_sp) + { + ScriptInterpreter *script_interp = m_thread.GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); + if (script_interp) + { + bool script_error; + explains_stop = script_interp->ScriptedThreadPlanExplainsStop (m_implementation_sp, event_ptr, script_error); + if (script_error) + SetPlanComplete(false); + } + } + return explains_stop; +} + +bool +ThreadPlanPython::MischiefManaged () +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); + if (log) + log->Printf ("%s called on Python Thread Plan: %s )", + __PRETTY_FUNCTION__, m_class_name.c_str()); + bool mischief_managed = true; + if (m_implementation_sp) + { + // I don't really need mischief_managed, since it's simpler to just call SetPlanComplete in should_stop. + mischief_managed = IsPlanComplete(); + if (mischief_managed) + m_implementation_sp.reset(); + } + return mischief_managed; +} + +lldb::StateType +ThreadPlanPython::GetPlanRunState () +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); + if (log) + log->Printf ("%s called on Python Thread Plan: %s )", + __PRETTY_FUNCTION__, + m_class_name.c_str()); + lldb::StateType run_state = eStateRunning; + if (m_implementation_sp) + { + ScriptInterpreter *script_interp = m_thread.GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); + if (script_interp) + { + bool script_error; + run_state = script_interp->ScriptedThreadPlanGetRunState (m_implementation_sp, script_error); + } + } + return run_state; +} + +// The ones below are not currently exported to Python. + +bool +ThreadPlanPython::StopOthers () +{ + // For now Python plans run all threads, but we should add some controls for this. + return false; +} + +void +ThreadPlanPython::GetDescription (Stream *s, + lldb::DescriptionLevel level) +{ + s->Printf ("Python thread plan implemented by class %s.", m_class_name.c_str()); +} + +bool +ThreadPlanPython::WillStop () +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); + if (log) + log->Printf ("%s called on Python Thread Plan: %s )", + __PRETTY_FUNCTION__, m_class_name.c_str()); + return true; +} diff --git a/lldb/source/Target/ThreadPlanStepInRange.cpp b/lldb/source/Target/ThreadPlanStepInRange.cpp index 3e9abef6557..1e7b0458981 100644 --- a/lldb/source/Target/ThreadPlanStepInRange.cpp +++ b/lldb/source/Target/ThreadPlanStepInRange.cpp @@ -128,17 +128,31 @@ void ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level) { if (level == lldb::eDescriptionLevelBrief) + { s->Printf("step in"); - else + return; + } + + s->Printf ("Stepping in"); + bool printed_line_info = false; + if (m_addr_context.line_entry.IsValid()) + { + s->Printf (" through line "); + m_addr_context.line_entry.DumpStopContext (s, false); + printed_line_info = true; + } + + const char *step_into_target = m_step_into_target.AsCString(); + if (step_into_target && step_into_target[0] != '\0') + s->Printf (" targeting %s", m_step_into_target.AsCString()); + + if (!printed_line_info || level == eDescriptionLevelVerbose) { - s->Printf ("Stepping through range (stepping into functions): "); + s->Printf (" using ranges:"); DumpRanges(s); - const char *step_into_target = m_step_into_target.AsCString(); - if (step_into_target && step_into_target[0] != '\0') - s->Printf (" targeting %s.", m_step_into_target.AsCString()); - else - s->PutChar('.'); } + + s->PutChar('.'); } bool @@ -303,6 +317,7 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr) else { m_no_more_plans = false; + m_sub_plan_sp->SetPrivate(true); return false; } } diff --git a/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp index b62f557319a..0ded99b3091 100644 --- a/lldb/source/Target/ThreadPlanStepOut.cpp +++ b/lldb/source/Target/ThreadPlanStepOut.cpp @@ -54,7 +54,6 @@ ThreadPlanStepOut::ThreadPlanStepOut m_return_addr (LLDB_INVALID_ADDRESS), m_stop_others (stop_others), m_immediate_step_from_function(NULL) - { SetFlagsToDefault(); SetupAvoidNoDebug(step_out_avoids_code_without_debug_info); @@ -90,6 +89,7 @@ ThreadPlanStepOut::ThreadPlanStepOut frame_idx - 1, eLazyBoolNo)); static_cast<ThreadPlanStepOut *>(m_step_out_to_inline_plan_sp.get())->SetShouldStopHereCallbacks(nullptr, nullptr); + m_step_out_to_inline_plan_sp->SetPrivate(true); } else { @@ -177,10 +177,34 @@ ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level) else if (m_step_through_inline_plan_sp) s->Printf ("Stepping out by stepping through inlined function."); else - s->Printf ("Stepping out from address 0x%" PRIx64 " to return address 0x%" PRIx64 " using breakpoint site %d", - (uint64_t)m_step_from_insn, - (uint64_t)m_return_addr, - m_return_bp_id); + { + s->Printf ("Stepping out from "); + Address tmp_address; + if (tmp_address.SetLoadAddress (m_step_from_insn, &GetTarget())) + { + tmp_address.Dump(s, &GetThread(), Address::DumpStyleResolvedDescription, Address::DumpStyleLoadAddress); + } + else + { + s->Printf ("address 0x%" PRIx64 "", (uint64_t)m_step_from_insn); + } + + // FIXME: find some useful way to present the m_return_id, since there may be multiple copies of the + // same function on the stack. + + s->Printf ("returning to frame at "); + if (tmp_address.SetLoadAddress (m_return_addr, &GetTarget())) + { + tmp_address.Dump(s, &GetThread(), Address::DumpStyleResolvedDescription, Address::DumpStyleLoadAddress); + } + else + { + s->Printf ("address 0x%" PRIx64 "", (uint64_t)m_return_addr); + } + + if (level == eDescriptionLevelVerbose) + s->Printf(" using breakpoint site %d", m_return_bp_id); + } } } @@ -474,11 +498,16 @@ ThreadPlanStepOut::QueueInlinedStepPlan (bool queue_now) inlined_sc.target_sp = GetTarget().shared_from_this(); RunMode run_mode = m_stop_others ? lldb::eOnlyThisThread : lldb::eAllThreads; const LazyBool avoid_no_debug = eLazyBoolNo; - ThreadPlanStepOverRange *step_through_inline_plan_ptr = new ThreadPlanStepOverRange(m_thread, - inline_range, - inlined_sc, - run_mode, - avoid_no_debug); + + m_step_through_inline_plan_sp.reset (new ThreadPlanStepOverRange(m_thread, + inline_range, + inlined_sc, + run_mode, + avoid_no_debug)); + ThreadPlanStepOverRange *step_through_inline_plan_ptr + = static_cast<ThreadPlanStepOverRange *>(m_step_through_inline_plan_sp.get()); + m_step_through_inline_plan_sp->SetPrivate(true); + step_through_inline_plan_ptr->SetOkayToDiscard(true); StreamString errors; if (!step_through_inline_plan_ptr->ValidatePlan(&errors)) @@ -493,7 +522,7 @@ ThreadPlanStepOut::QueueInlinedStepPlan (bool queue_now) if (inlined_block->GetRangeAtIndex (i, inline_range)) step_through_inline_plan_ptr->AddRange (inline_range); } - m_step_through_inline_plan_sp.reset (step_through_inline_plan_ptr); + if (queue_now) m_thread.QueueThreadPlan (m_step_through_inline_plan_sp, false); return true; diff --git a/lldb/source/Target/ThreadPlanStepOverRange.cpp b/lldb/source/Target/ThreadPlanStepOverRange.cpp index a4f3743346e..a6d65e4d811 100644 --- a/lldb/source/Target/ThreadPlanStepOverRange.cpp +++ b/lldb/source/Target/ThreadPlanStepOverRange.cpp @@ -62,12 +62,26 @@ void ThreadPlanStepOverRange::GetDescription (Stream *s, lldb::DescriptionLevel level) { if (level == lldb::eDescriptionLevelBrief) + { s->Printf("step over"); - else + return; + } + s->Printf ("Stepping over"); + bool printed_line_info = false; + if (m_addr_context.line_entry.IsValid()) + { + s->Printf (" line "); + m_addr_context.line_entry.DumpStopContext (s, false); + printed_line_info = true; + } + + if (!printed_line_info || level == eDescriptionLevelVerbose) { - s->Printf ("stepping through range (stepping over functions): "); - DumpRanges(s); + s->Printf (" using ranges: "); + DumpRanges(s); } + + s->PutChar('.'); } void @@ -317,11 +331,15 @@ ThreadPlanStepOverRange::ShouldStop (Event *event_ptr) { new_plan_sp = CheckShouldStopHereAndQueueStepOut (frame_order); } - + if (!new_plan_sp) m_no_more_plans = true; else + { + // Any new plan will be an implementation plan, so mark it private: + new_plan_sp->SetPrivate(true); m_no_more_plans = false; + } if (!new_plan_sp) { diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp index 82ca59fbca3..adc515cebc0 100644 --- a/lldb/source/Target/ThreadPlanStepRange.cpp +++ b/lldb/source/Target/ThreadPlanStepRange.cpp @@ -44,7 +44,8 @@ ThreadPlanStepRange::ThreadPlanStepRange (ThreadPlanKind kind, Thread &thread, const AddressRange &range, const SymbolContext &addr_context, - lldb::RunMode stop_others) : + lldb::RunMode stop_others, + bool given_ranges_only) : ThreadPlan (kind, name, thread, eVoteNoOpinion, eVoteNoOpinion), m_addr_context (addr_context), m_address_ranges (), @@ -53,7 +54,8 @@ ThreadPlanStepRange::ThreadPlanStepRange (ThreadPlanKind kind, m_parent_stack_id(), m_no_more_plans (false), m_first_run_event (true), - m_use_fast_step(false) + m_use_fast_step(false), + m_given_ranges_only (given_ranges_only) { m_use_fast_step = GetTarget().GetUseFastStepping(); AddRange(range); @@ -149,7 +151,7 @@ ThreadPlanStepRange::InRange () break; } - if (!ret_value) + if (!ret_value && !m_given_ranges_only) { // See if we've just stepped to another part of the same line number... StackFrame *frame = m_thread.GetStackFrameAtIndex(0).get(); |