forked from OSchip/llvm-project
This checkin is the first step in making the lldb thread stepping mechanism more accessible from
the user level. It adds the ability to invent new stepping modes implemented by python classes, and to view the current thread plan stack and to some extent alter it. I haven't gotten to documentation or tests yet. But this should not cause any behavior changes if you don't use it, so its safe to check it in now and work on it incrementally. llvm-svn: 218642
This commit is contained in:
parent
8b6fefb3a3
commit
2bdbfd50d2
|
@ -117,6 +117,7 @@ protected:
|
|||
friend class SBSymbolContext;
|
||||
friend class SBTarget;
|
||||
friend class SBThread;
|
||||
friend class SBThreadPlan;
|
||||
friend class SBValue;
|
||||
friend class SBQueueItem;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -126,6 +126,9 @@ public:
|
|||
lldb::SBFileSpec &file_spec,
|
||||
uint32_t line);
|
||||
|
||||
SBError
|
||||
StepUsingScriptedThreadPlan (const char *script_class_name);
|
||||
|
||||
SBError
|
||||
JumpToLine (lldb::SBFileSpec &file_spec, uint32_t line);
|
||||
|
||||
|
@ -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;
|
||||
|
|
|
@ -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_
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
@ -347,6 +353,39 @@ public:
|
|||
return lldb::ScriptInterpreterObjectSP();
|
||||
}
|
||||
|
||||
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.
|
||||
|
|
|
@ -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 ()
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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_
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
|
|
@ -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 */,
|
||||
|
|
|
@ -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"\
|
||||
|
|
|
@ -212,6 +212,9 @@ public:
|
|||
lldb::SBFileSpec &file_spec,
|
||||
uint32_t line);
|
||||
|
||||
SBError
|
||||
StepUsingScriptedThreadPlan (const char *script_class_name);
|
||||
|
||||
SBError
|
||||
JumpToLine (lldb::SBFileSpec &file_spec, uint32_t line);
|
||||
|
||||
|
|
|
@ -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_
|
|
@ -43,6 +43,13 @@ SBTypeToSWIGWrapper (unsigned int* c_int)
|
|||
return PyInt_FromLong(*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)
|
||||
|
@ -57,6 +64,13 @@ SBTypeToSWIGWrapper (lldb::SBThread* thread_sb)
|
|||
return SWIG_NewPointerObj((void *) thread_sb, SWIGTYPE_p_lldb__SBThread, 0);
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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());
|
||||
|
@ -1072,6 +1075,46 @@ SBThread::StepOverUntil (lldb::SBFrame &sb_frame,
|
|||
return sb_error;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
result.AppendErrorWithFormat ("error displaying info for thread: \"%d\"\n", thread.GetIndexID());
|
||||
result.SetStatus (eReturnStatusFailed);
|
||||
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)
|
||||
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("");
|
||||
}
|
||||
|
||||
}
|
||||
return result.Succeeded();
|
||||
return true;
|
||||
}
|
||||
|
||||
CommandOptions m_options;
|
||||
|
@ -1957,6 +1924,228 @@ CommandObjectThreadJump::CommandOptions::g_option_table[] =
|
|||
{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// 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 ()
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
@ -1616,6 +1619,87 @@ ScriptInterpreterPython::OSPlugin_CreateThread (lldb::ScriptInterpreterObjectSP
|
|||
return MakeScriptObject(py_return);
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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("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: %d elements.\n", stack_size);
|
||||
for (i = stack_size - 1; i >= 0; i--)
|
||||
{
|
||||
s->IndentMore();
|
||||
s->Indent();
|
||||
s->Printf ("Element %d: ", i);
|
||||
m_completed_plan_stack[i]->GetDescription (s, eDescriptionLevelFull);
|
||||
s->EOL();
|
||||
s->IndentLess();
|
||||
}
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -128,17 +128,31 @@ void
|
|||
ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
|
||||
{
|
||||
if (level == lldb::eDescriptionLevelBrief)
|
||||
s->Printf("step in");
|
||||
else
|
||||
{
|
||||
s->Printf ("Stepping through range (stepping into functions): ");
|
||||
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->Printf("step in");
|
||||
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 (" using ranges:");
|
||||
DumpRanges(s);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -62,12 +62,26 @@ void
|
|||
ThreadPlanStepOverRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
|
||||
{
|
||||
if (level == lldb::eDescriptionLevelBrief)
|
||||
s->Printf("step over");
|
||||
else
|
||||
{
|
||||
s->Printf ("stepping through range (stepping over functions): ");
|
||||
DumpRanges(s);
|
||||
s->Printf("step over");
|
||||
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 (" 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)
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue