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:
Jim Ingham 2014-09-29 23:17:18 +00:00
parent 8b6fefb3a3
commit 2bdbfd50d2
38 changed files with 1896 additions and 322 deletions

View File

@ -117,6 +117,7 @@ protected:
friend class SBSymbolContext;
friend class SBTarget;
friend class SBThread;
friend class SBThreadPlan;
friend class SBValue;
friend class SBQueueItem;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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_

View File

@ -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,

View File

@ -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.

View File

@ -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 ()

View File

@ -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);

View File

@ -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);
};

View File

@ -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_

View File

@ -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;

View File

@ -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;
//----------------------------------------------------------------------

View File

@ -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 */,

View File

@ -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"\

View File

@ -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);

View File

@ -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_

View File

@ -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)

View File

@ -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

View File

@ -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"

View File

@ -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
}
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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();
}
}

View File

@ -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 ()

View File

@ -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;

View File

@ -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();

View File

@ -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
}

View File

@ -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

View File

@ -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);
}

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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)
{

View File

@ -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();