From 3815e702e751efb14188c0f0beeb10e343d8f053 Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Thu, 13 Sep 2018 21:35:32 +0000 Subject: Add a "scripted" breakpoint type to lldb. This change allows you to write a new breakpoint type where the logic for setting breakpoints is determined by a Python callback written using the SB API's. Differential Revision: https://reviews.llvm.org/D51830 llvm-svn: 342185 --- lldb/scripts/Python/python-wrapper.swig | 95 +++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) (limited to 'lldb/scripts/Python/python-wrapper.swig') diff --git a/lldb/scripts/Python/python-wrapper.swig b/lldb/scripts/Python/python-wrapper.swig index 96b8dda..1679d89 100644 --- a/lldb/scripts/Python/python-wrapper.swig +++ b/lldb/scripts/Python/python-wrapper.swig @@ -333,6 +333,101 @@ LLDBSWIGPythonCallThreadPlan return false; } +SWIGEXPORT void * +LLDBSwigPythonCreateScriptedBreakpointResolver +( + const char *python_class_name, + const char *session_dictionary_name, + lldb_private::StructuredDataImpl *args_impl, + lldb::BreakpointSP &breakpoint_sp +) +{ + using namespace lldb_private; + + if (python_class_name == NULL || python_class_name[0] == '\0' || !session_dictionary_name) + Py_RETURN_NONE; + + PyErr_Cleaner py_err_cleaner(true); + + auto dict = PythonModule::MainModule().ResolveName(session_dictionary_name); + auto pfunc = PythonObject::ResolveNameWithDictionary(python_class_name, dict); + + if (!pfunc.IsAllocated()) + return nullptr; + + lldb::SBBreakpoint *bkpt_value = new lldb::SBBreakpoint(breakpoint_sp); + + PythonObject bkpt_arg(PyRefType::Owned, SBTypeToSWIGWrapper(bkpt_value)); + + lldb::SBStructuredData *args_value = new lldb::SBStructuredData(args_impl); + PythonObject args_arg(PyRefType::Owned, SBTypeToSWIGWrapper(args_value)); + + PythonObject result = pfunc(bkpt_arg, args_arg, dict); + // FIXME: At this point we should check that the class we found supports all the methods + // that we need. + + if (result.IsAllocated()) + { + // Check that __callback__ is defined: + auto callback_func = result.ResolveName("__callback__"); + if (callback_func.IsAllocated()) + return result.release(); + else + result.release(); + } + Py_RETURN_NONE; +} + +SWIGEXPORT unsigned int +LLDBSwigPythonCallBreakpointResolver +( + void *implementor, + const char *method_name, + lldb_private::SymbolContext *sym_ctx +) +{ + using namespace lldb_private; + + PyErr_Cleaner py_err_cleaner(false); + PythonObject self(PyRefType::Borrowed, static_cast(implementor)); + auto pfunc = self.ResolveName(method_name); + + if (!pfunc.IsAllocated()) + return 0; + + PythonObject result; + if (sym_ctx != nullptr) { + lldb::SBSymbolContext sb_sym_ctx(sym_ctx); + PythonObject sym_ctx_arg(PyRefType::Owned, SBTypeToSWIGWrapper(sb_sym_ctx)); + result = pfunc(sym_ctx_arg); + } else + result = pfunc(); + + if (PyErr_Occurred()) + { + PyErr_Print(); + return 0; + } + + // The callback will return a bool, but we're need to also return ints + // so we're squirrelling the bool through as an int... And if you return + // nothing, we'll continue. + if (strcmp(method_name, "__callback__") == 0) { + if (result.get() == Py_False) + return 0; + else + return 1; + } + + PythonInteger int_result = result.AsType(); + if (!int_result.IsAllocated()) + return 0; + + unsigned int ret_val = int_result.GetInteger(); + + return ret_val; +} + // wrapper that calls an optional instance member of an object taking no arguments static PyObject* LLDBSwigPython_CallOptionalMember -- cgit v1.1