80 changes: 80 additions & 0 deletions lldb/include/lldb/Target/ThreadPlanPython.h
Original file line number Diff line number Diff line change
@@ -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_
4 changes: 3 additions & 1 deletion lldb/include/lldb/Target/ThreadPlanStepRange.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ class ThreadPlanStepRange : public ThreadPlan
Thread &thread,
const AddressRange &range,
const SymbolContext &addr_context,
lldb::RunMode stop_others);
lldb::RunMode stop_others,
bool given_ranges_only = false);

virtual ~ThreadPlanStepRange ();

Expand Down Expand Up @@ -83,6 +84,7 @@ class ThreadPlanStepRange : public ThreadPlan
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;
Expand Down
3 changes: 2 additions & 1 deletion lldb/include/lldb/lldb-private-enumerations.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

//----------------------------------------------------------------------
Expand Down
18 changes: 18 additions & 0 deletions lldb/lldb.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */; };
Expand Down Expand Up @@ -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>"; };
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -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 */,
Expand Down
2 changes: 2 additions & 0 deletions lldb/scripts/Python/build-swig-Python.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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"\
Expand Down Expand Up @@ -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"\
Expand Down
3 changes: 3 additions & 0 deletions lldb/scripts/Python/interface/SBThread.i
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
123 changes: 123 additions & 0 deletions lldb/scripts/Python/interface/SBThreadPlan.i
Original file line number Diff line number Diff line change
@@ -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_
14 changes: 14 additions & 0 deletions lldb/scripts/Python/python-swigsafecast.swig
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down
112 changes: 112 additions & 0 deletions lldb/scripts/Python/python-wrapper.swig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions lldb/scripts/lldb.swig
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down
15 changes: 14 additions & 1 deletion lldb/source/API/SBCommandInterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -539,7 +550,9 @@ SBCommandInterpreter::InitializeSWIG ()
LLDBSWIGPythonRunScriptKeywordThread,
LLDBSWIGPythonRunScriptKeywordTarget,
LLDBSWIGPythonRunScriptKeywordFrame,
LLDBSWIGPython_GetDynamicSetting);
LLDBSWIGPython_GetDynamicSetting,
LLDBSwigPythonCreateScriptedThreadPlan,
LLDBSWIGPythonCallThreadPlan);
#endif
}
}
Expand Down
6 changes: 6 additions & 0 deletions lldb/source/API/SBEvent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
69 changes: 67 additions & 2 deletions lldb/source/API/SBThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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;
}

285 changes: 285 additions & 0 deletions lldb/source/API/SBThreadPlan.cpp
Original file line number Diff line number Diff line change
@@ -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();
}
}


597 changes: 398 additions & 199 deletions lldb/source/Commands/CommandObjectThread.cpp

Large diffs are not rendered by default.

20 changes: 10 additions & 10 deletions lldb/source/Expression/ClangFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -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;

Expand Down
14 changes: 7 additions & 7 deletions lldb/source/Expression/ClangUserExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
8 changes: 6 additions & 2 deletions lldb/source/Interpreter/ScriptInterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
}
90 changes: 89 additions & 1 deletion lldb/source/Interpreter/ScriptInterpreterPython.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
24 changes: 10 additions & 14 deletions lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
159 changes: 117 additions & 42 deletions lldb/source/Target/Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -1602,61 +1633,105 @@ Thread::QueueThreadPlanForStepUntil (bool abort_other_plans,

}

lldb::ThreadPlanSP
Thread::QueueThreadPlanForStepScripted (bool abort_other_plans,
const char *class_name,
bool stop_other_threads)
{
ThreadPlanSP thread_plan_sp (new ThreadPlanPython (*this, class_name));
QueueThreadPlan (thread_plan_sp, abort_other_plans);
// This seems a little funny, but I don't want to have to split up the constructor and the
// DidPush in the scripted plan, that seems annoying.
// That means the constructor has to be in DidPush.
// So I have to validate the plan AFTER pushing it, and then take it off again...
if (!thread_plan_sp->ValidatePlan(nullptr))
{
DiscardThreadPlansUpToPlan(thread_plan_sp);
return ThreadPlanSP();
}
else
return thread_plan_sp;

}

uint32_t
Thread::GetIndexID () const
{
return m_index_id;
}

void
Thread::DumpThreadPlans (lldb_private::Stream *s) const
static void
PrintPlanElement (Stream *s, const ThreadPlanSP &plan, lldb::DescriptionLevel desc_level, int32_t elem_idx)
{
uint32_t stack_size = m_plan_stack.size();
int i;
s->Indent();
s->Printf ("Plan Stack for thread #%u: tid = 0x%4.4" PRIx64 ", stack_size = %d\n", GetIndexID(), GetID(), stack_size);
for (i = stack_size - 1; i >= 0; i--)
{
s->IndentMore();
s->Indent();
s->Printf ("Element %d: ", i);
m_plan_stack[i]->GetDescription (s, eDescriptionLevelFull);
s->Printf ("Element %d: ", elem_idx);
plan->GetDescription (s, desc_level);
s->EOL();
s->IndentLess();
}

static void
PrintPlanStack (Stream *s, const std::vector<lldb::ThreadPlanSP> &plan_stack, lldb::DescriptionLevel desc_level, bool include_internal)
{
int32_t print_idx = 0;
for (ThreadPlanSP plan_sp : plan_stack)
{
if (include_internal || !plan_sp->GetPrivate())
{
PrintPlanElement (s, plan_sp, desc_level, print_idx++);
}
}
}

stack_size = m_completed_plan_stack.size();
if (stack_size > 0)
void
Thread::DumpThreadPlans (Stream *s,
lldb::DescriptionLevel desc_level,
bool include_internal,
bool ignore_boring_threads) const
{
uint32_t stack_size = m_plan_stack.size();

if (ignore_boring_threads)
{
s->Indent();
s->Printf ("Completed Plan Stack: %d elements.\n", stack_size);
for (i = stack_size - 1; i >= 0; i--)
uint32_t stack_size = m_plan_stack.size();
uint32_t completed_stack_size = m_completed_plan_stack.size();
uint32_t discarded_stack_size = m_discarded_plan_stack.size();
if (stack_size == 1 && completed_stack_size == 0 && discarded_stack_size == 0)
{
s->Printf ("thread #%u: tid = 0x%4.4" PRIx64 "\n", GetIndexID(), GetID());
s->IndentMore();
s->Indent();
s->Printf ("Element %d: ", i);
m_completed_plan_stack[i]->GetDescription (s, eDescriptionLevelFull);
s->EOL();
s->Printf("No active thread plans\n");
s->IndentLess();
return;
}
}

s->Indent();
s->Printf ("thread #%u: tid = 0x%4.4" PRIx64 ":\n", GetIndexID(), GetID());
s->IndentMore();
s->Indent();
s->Printf ("Active plan stack:\n");
PrintPlanStack (s, m_plan_stack, desc_level, include_internal);

stack_size = m_completed_plan_stack.size();
if (stack_size > 0)
{
s->Indent();
s->Printf ("Completed Plan Stack:\n");
PrintPlanStack (s, m_completed_plan_stack, desc_level, include_internal);
}

stack_size = m_discarded_plan_stack.size();
if (stack_size > 0)
{
s->Indent();
s->Printf ("Discarded Plan Stack: %d elements.\n", stack_size);
for (i = stack_size - 1; i >= 0; i--)
{
s->IndentMore();
s->Indent();
s->Printf ("Element %d: ", i);
m_discarded_plan_stack[i]->GetDescription (s, eDescriptionLevelFull);
s->EOL();
s->IndentLess();
}
s->Printf ("Discarded Plan Stack:\n");
PrintPlanStack (s, m_discarded_plan_stack, desc_level, include_internal);
}

s->IndentLess();
}

TargetSP
Expand Down
192 changes: 192 additions & 0 deletions lldb/source/Target/ThreadPlanPython.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
29 changes: 22 additions & 7 deletions lldb/source/Target/ThreadPlanStepInRange.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,17 +128,31 @@ void
ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
{
if (level == lldb::eDescriptionLevelBrief)
{
s->Printf("step in");
else
return;
}

s->Printf ("Stepping in");
bool printed_line_info = false;
if (m_addr_context.line_entry.IsValid())
{
s->Printf (" through line ");
m_addr_context.line_entry.DumpStopContext (s, false);
printed_line_info = true;
}

const char *step_into_target = m_step_into_target.AsCString();
if (step_into_target && step_into_target[0] != '\0')
s->Printf (" targeting %s", m_step_into_target.AsCString());

if (!printed_line_info || level == eDescriptionLevelVerbose)
{
s->Printf ("Stepping through range (stepping into functions): ");
s->Printf (" using ranges:");
DumpRanges(s);
const char *step_into_target = m_step_into_target.AsCString();
if (step_into_target && step_into_target[0] != '\0')
s->Printf (" targeting %s.", m_step_into_target.AsCString());
else
s->PutChar('.');
}

s->PutChar('.');
}

bool
Expand Down Expand Up @@ -303,6 +317,7 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
else
{
m_no_more_plans = false;
m_sub_plan_sp->SetPrivate(true);
return false;
}
}
Expand Down
51 changes: 40 additions & 11 deletions lldb/source/Target/ThreadPlanStepOut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -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);
}
}
}

Expand Down Expand Up @@ -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))
Expand All @@ -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;
Expand Down
26 changes: 22 additions & 4 deletions lldb/source/Target/ThreadPlanStepOverRange.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,26 @@ void
ThreadPlanStepOverRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
{
if (level == lldb::eDescriptionLevelBrief)
{
s->Printf("step over");
else
return;
}
s->Printf ("Stepping over");
bool printed_line_info = false;
if (m_addr_context.line_entry.IsValid())
{
s->Printf (" line ");
m_addr_context.line_entry.DumpStopContext (s, false);
printed_line_info = true;
}

if (!printed_line_info || level == eDescriptionLevelVerbose)
{
s->Printf ("stepping through range (stepping over functions): ");
DumpRanges(s);
s->Printf (" using ranges: ");
DumpRanges(s);
}

s->PutChar('.');
}

void
Expand Down Expand Up @@ -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)
{
Expand Down
8 changes: 5 additions & 3 deletions lldb/source/Target/ThreadPlanStepRange.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 (),
Expand All @@ -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);
Expand Down Expand Up @@ -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();
Expand Down