From 2bdbfd50d2c9a80c6132a3f83d1c097b0b0c6ca5 Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Mon, 29 Sep 2014 23:17:18 +0000 Subject: 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 --- lldb/scripts/Python/build-swig-Python.sh | 2 + lldb/scripts/Python/interface/SBThread.i | 3 + lldb/scripts/Python/interface/SBThreadPlan.i | 123 +++++++++++++++++++++++++++ lldb/scripts/Python/python-swigsafecast.swig | 14 +++ lldb/scripts/Python/python-wrapper.swig | 112 ++++++++++++++++++++++++ 5 files changed, 254 insertions(+) create mode 100644 lldb/scripts/Python/interface/SBThreadPlan.i (limited to 'lldb/scripts/Python') diff --git a/lldb/scripts/Python/build-swig-Python.sh b/lldb/scripts/Python/build-swig-Python.sh index 88769c88856..3b610e139e2 100755 --- a/lldb/scripts/Python/build-swig-Python.sh +++ b/lldb/scripts/Python/build-swig-Python.sh @@ -114,6 +114,7 @@ HEADER_FILES="${SRC_ROOT}/include/lldb/lldb.h"\ " ${SRC_ROOT}/include/lldb/API/SBTarget.h"\ " ${SRC_ROOT}/include/lldb/API/SBThread.h"\ " ${SRC_ROOT}/include/lldb/API/SBThreadCollection.h"\ +" ${SRC_ROOT}/include/lldb/API/SBThreadPlan.h"\ " ${SRC_ROOT}/include/lldb/API/SBType.h"\ " ${SRC_ROOT}/include/lldb/API/SBTypeCategory.h"\ " ${SRC_ROOT}/include/lldb/API/SBTypeFilter.h"\ @@ -163,6 +164,7 @@ INTERFACE_FILES="${SRC_ROOT}/scripts/Python/interface/SBAddress.i"\ " ${SRC_ROOT}/scripts/Python/interface/SBTarget.i"\ " ${SRC_ROOT}/scripts/Python/interface/SBThread.i"\ " ${SRC_ROOT}/scripts/Python/interface/SBThreadCollection.i"\ +" ${SRC_ROOT}/scripts/Python/interface/SBThreadPlan.i"\ " ${SRC_ROOT}/scripts/Python/interface/SBType.i"\ " ${SRC_ROOT}/scripts/Python/interface/SBTypeCategory.i"\ " ${SRC_ROOT}/scripts/Python/interface/SBTypeFilter.i"\ diff --git a/lldb/scripts/Python/interface/SBThread.i b/lldb/scripts/Python/interface/SBThread.i index 4d69ddaf229..dac0f9bc4a7 100644 --- a/lldb/scripts/Python/interface/SBThread.i +++ b/lldb/scripts/Python/interface/SBThread.i @@ -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); diff --git a/lldb/scripts/Python/interface/SBThreadPlan.i b/lldb/scripts/Python/interface/SBThreadPlan.i new file mode 100644 index 00000000000..785855ec5b9 --- /dev/null +++ b/lldb/scripts/Python/interface/SBThreadPlan.i @@ -0,0 +1,123 @@ +//===-- SBThread.h ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBThreadPlan_h_ +#define LLDB_SBThreadPlan_h_ + +#include "lldb/API/SBDefines.h" + +#include + +namespace lldb { + +%feature("docstring", +"Represents a plan for the execution control of a given thread. + +See also SBThread and SBFrame." +) SBThread; + +class SBThreadPlan +{ + +friend class lldb_private::ThreadPlan; + +public: + SBThreadPlan (); + + SBThreadPlan (const lldb::SBThreadPlan &threadPlan); + + SBThreadPlan (const lldb::ThreadPlanSP& lldb_object_sp); + + SBThreadPlan (lldb::SBThread &thread, const char *class_name); + + ~SBThreadPlan (); + + bool + IsValid() const; + + void + Clear (); + + lldb::StopReason + GetStopReason(); + + /// Get the number of words associated with the stop reason. + /// See also GetStopReasonDataAtIndex(). + size_t + GetStopReasonDataCount(); + + //-------------------------------------------------------------------------- + /// Get information associated with a stop reason. + /// + /// Breakpoint stop reasons will have data that consists of pairs of + /// breakpoint IDs followed by the breakpoint location IDs (they always come + /// in pairs). + /// + /// Stop Reason Count Data Type + /// ======================== ===== ========================================= + /// eStopReasonNone 0 + /// eStopReasonTrace 0 + /// eStopReasonBreakpoint N duple: {breakpoint id, location id} + /// eStopReasonWatchpoint 1 watchpoint id + /// eStopReasonSignal 1 unix signal number + /// eStopReasonException N exception data + /// eStopReasonExec 0 + /// eStopReasonPlanComplete 0 + //-------------------------------------------------------------------------- + uint64_t + GetStopReasonDataAtIndex(uint32_t idx); + + SBThread + GetThread () const; + + bool + GetDescription (lldb::SBStream &description) const; + + void + SetPlanComplete (bool success); + + bool + IsPlanComplete(); + + bool + IsValid(); + + // This section allows an SBThreadPlan to push another of the common types of plans... + SBThreadPlan + QueueThreadPlanForStepOverRange (SBAddress &start_address, + lldb::addr_t range_size); + + SBThreadPlan + QueueThreadPlanForStepInRange (SBAddress &start_address, + lldb::addr_t range_size); + + SBThreadPlan + QueueThreadPlanForStepOut (uint32_t frame_idx_to_step_to, bool first_insn = false); + + SBThreadPlan + QueueThreadPlanForRunToAddress (SBAddress address); + + +protected: + friend class SBBreakpoint; + friend class SBBreakpointLocation; + friend class SBFrame; + friend class SBProcess; + friend class SBDebugger; + friend class SBValue; + friend class lldb_private::QueueImpl; + friend class SBQueueItem; + +private: + lldb::ThreadPlanSP m_opaque_sp; +}; + +} // namespace lldb + +#endif // LLDB_SBThreadPlan_h_ diff --git a/lldb/scripts/Python/python-swigsafecast.swig b/lldb/scripts/Python/python-swigsafecast.swig index 0150854d2c6..4813c4f8c4d 100644 --- a/lldb/scripts/Python/python-swigsafecast.swig +++ b/lldb/scripts/Python/python-swigsafecast.swig @@ -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) diff --git a/lldb/scripts/Python/python-wrapper.swig b/lldb/scripts/Python/python-wrapper.swig index 646323a21cd..c3812df8110 100644 --- a/lldb/scripts/Python/python-wrapper.swig +++ b/lldb/scripts/Python/python-wrapper.swig @@ -419,6 +419,118 @@ LLDBSwigPythonCreateSyntheticProvider Py_RETURN_NONE; } +SWIGEXPORT void* +LLDBSwigPythonCreateScriptedThreadPlan +( + const char *python_class_name, + const char *session_dictionary_name, + const lldb::ThreadPlanSP& thread_plan_sp +) +{ + PyObject* retval = NULL; + + if (python_class_name == NULL || python_class_name[0] == '\0' || !session_dictionary_name) + Py_RETURN_NONE; + + // I do not want the SBThreadPlan to be deallocated when going out of scope because python + // has ownership of it and will manage memory for this object by itself + lldb::SBThreadPlan *tp_value = new lldb::SBThreadPlan(thread_plan_sp); + + PyObject *ThreadPlan_PyObj = SBTypeToSWIGWrapper(tp_value); + + if (ThreadPlan_PyObj == NULL) + Py_RETURN_NONE; + + { + PyErr_Cleaner py_err_cleaner(true); + + PyCallable pfunc = PyCallable::FindWithFunctionName(python_class_name, session_dictionary_name); + + if (!pfunc) + return retval; + + Py_INCREF(ThreadPlan_PyObj); + + PyObject* session_dict = NULL; + session_dict = FindSessionDictionary(session_dictionary_name); + retval = pfunc(tp_value, session_dict); + + // FIXME: At this point we should check that the class we found supports all the methods + // that we need. + + Py_XINCREF (session_dict); + + Py_XINCREF(retval); + } + + if (retval) + return retval; + else + Py_RETURN_NONE; +} + +SWIGEXPORT bool +LLDBSWIGPythonCallThreadPlan +( + void *implementor, + const char *method_name, + lldb_private::Event *event, + bool &got_error +) +{ + bool ret_val = false; + got_error = false; + + + PyErr_Cleaner py_err_cleaner(false); + + PyCallable pfunc = PyCallable::FindWithMemberFunction((PyObject *) implementor, method_name); + + if (!pfunc) + { + return ret_val; + } + + PyObject* py_return = Py_None; + + if (event != NULL) + { + lldb::SBEvent sb_event(event); + + PyObject *py_obj_event = SBTypeToSWIGWrapper(sb_event); + + py_return = pfunc(py_obj_event); + } + else + { + py_return = pfunc(); + } + + if (PyErr_Occurred()) + { + got_error = true; + printf ("Return value was neither false nor true for call to %s.\n", method_name); + PyErr_Print(); + } + else + { + if (py_return == Py_True) + ret_val = true; + else if (py_return == Py_False) + ret_val = false; + else + { + // Somebody returned the wrong thing... + got_error = true; + printf ("Wrong return value type for call to %s.\n", method_name); + } + } + + Py_XDECREF(py_return); + + return ret_val; +} + // wrapper that calls an optional instance member of an object taking no arguments static PyObject* LLDBSwigPython_CallOptionalMember -- cgit v1.2.3