[Lldb-commits] [lldb] r342185 - Add a "scripted" breakpoint type to lldb.

Jim Ingham via lldb-commits lldb-commits at lists.llvm.org
Thu Sep 13 14:35:33 PDT 2018


Modified: lldb/trunk/packages/Python/lldbsuite/test/lldbutil.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/lldbutil.py?rev=342185&r1=342184&r2=342185&view=diff
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/lldbutil.py (original)
+++ lldb/trunk/packages/Python/lldbsuite/test/lldbutil.py Thu Sep 13 14:35:32 2018
@@ -330,6 +330,20 @@ def sort_stopped_threads(process,
 # Utility functions for setting breakpoints
 # ==================================================
 
+def run_break_set_by_script(
+        test,
+        class_name,
+        extra_options=None,
+        num_expected_locations=1):
+    """Set a scripted breakpoint.  Check that it got the right number of locations."""
+    test.assertTrue(class_name is not None, "Must pass in a class name.")
+    command = "breakpoint set -P " + class_name
+    if extra_options is not None:
+        command += " " + extra_options
+
+    break_results = run_break_set_command(test, command)
+    check_breakpoint_result(test, break_results, num_locations=num_expected_locations)
+    return get_bpno_from_match(break_results)
 
 def run_break_set_by_file_and_line(
         test,
@@ -737,7 +751,7 @@ def get_crashed_threads(test, process):
 
 # Helper functions for run_to_{source,name}_breakpoint:
 
-def run_to_breakpoint_make_target(test, exe_name, in_cwd):
+def run_to_breakpoint_make_target(test, exe_name = "a.out", in_cwd = True):
     if in_cwd:
         exe = test.getBuildArtifact(exe_name)
 
@@ -746,7 +760,7 @@ def run_to_breakpoint_make_target(test,
     test.assertTrue(target, "Target: %s is not valid."%(exe_name))
     return target
 
-def run_to_breakpoint_do_run(test, target, bkpt, launch_info):
+def run_to_breakpoint_do_run(test, target, bkpt, launch_info = None):
 
     # Launch the process, and do not stop at the entry point.
     if not launch_info:

Modified: lldb/trunk/scripts/Python/python-swigsafecast.swig
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/Python/python-swigsafecast.swig?rev=342185&r1=342184&r2=342185&view=diff
==============================================================================
--- lldb/trunk/scripts/Python/python-swigsafecast.swig (original)
+++ lldb/trunk/scripts/Python/python-swigsafecast.swig Thu Sep 13 14:35:32 2018
@@ -147,3 +147,17 @@ SBTypeToSWIGWrapper (lldb::SBTypeSummary
 {
     return SWIG_NewPointerObj((void *) summary_options_sb, SWIGTYPE_p_lldb__SBTypeSummaryOptions, 0);
 }
+
+template <>
+PyObject*
+SBTypeToSWIGWrapper (lldb::SBStructuredData* structured_data_sb)
+{
+    return SWIG_NewPointerObj((void *) structured_data_sb, SWIGTYPE_p_lldb__SBStructuredData, 0);
+}
+
+template <>
+PyObject*
+SBTypeToSWIGWrapper (lldb::SBSymbolContext* sym_ctx_sb)
+{
+    return SWIG_NewPointerObj((void *) sym_ctx_sb, SWIGTYPE_p_lldb__SBSymbolContext, 0);
+}

Modified: lldb/trunk/scripts/Python/python-wrapper.swig
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/Python/python-wrapper.swig?rev=342185&r1=342184&r2=342185&view=diff
==============================================================================
--- lldb/trunk/scripts/Python/python-wrapper.swig (original)
+++ lldb/trunk/scripts/Python/python-wrapper.swig Thu Sep 13 14:35:32 2018
@@ -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<PythonDictionary>(session_dictionary_name);
+    auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>(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<PythonCallable>("__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<PyObject*>(implementor));
+    auto pfunc = self.ResolveName<PythonCallable>(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<PythonInteger>();
+    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

Modified: lldb/trunk/scripts/interface/SBBreakpoint.i
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/interface/SBBreakpoint.i?rev=342185&r1=342184&r2=342185&view=diff
==============================================================================
--- lldb/trunk/scripts/interface/SBBreakpoint.i (original)
+++ lldb/trunk/scripts/interface/SBBreakpoint.i Thu Sep 13 14:35:32 2018
@@ -226,6 +226,10 @@ public:
     bool 
     GetDescription(lldb::SBStream &description, bool include_locations);
 
+    // Can only be called from a ScriptedBreakpointResolver...
+    SBError
+    AddLocation(SBAddress &address);
+
     bool
     operator == (const lldb::SBBreakpoint& rhs);
            

Modified: lldb/trunk/scripts/interface/SBStructuredData.i
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/interface/SBStructuredData.i?rev=342185&r1=342184&r2=342185&view=diff
==============================================================================
--- lldb/trunk/scripts/interface/SBStructuredData.i (original)
+++ lldb/trunk/scripts/interface/SBStructuredData.i Thu Sep 13 14:35:32 2018
@@ -38,6 +38,8 @@ namespace lldb {
 
         size_t GetSize() const;
 
+        bool GetKeys(lldb::SBStringList &keys) const;
+
         lldb::SBStructuredData GetValueForKey(const char *key) const;
 
         lldb::SBStructuredData GetItemAtIndex(size_t idx) const;

Modified: lldb/trunk/scripts/interface/SBTarget.i
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/interface/SBTarget.i?rev=342185&r1=342184&r2=342185&view=diff
==============================================================================
--- lldb/trunk/scripts/interface/SBTarget.i (original)
+++ lldb/trunk/scripts/interface/SBTarget.i Thu Sep 13 14:35:32 2018
@@ -731,6 +731,74 @@ public:
 
     lldb::SBBreakpoint
     BreakpointCreateBySBAddress (SBAddress &sb_address);
+    
+    %feature("docstring", "
+  //------------------------------------------------------------------
+  /// Create a breakpoint using a scripted resolver.
+  ///
+  /// @param[in] class_name
+  ///    This is the name of the class that implements a scripted resolver.
+  ///    The class should have the following signature:
+  ///    class Resolver:
+  ///        def __init__(self, bkpt, extra_args):
+  ///            # bkpt - the breakpoint for which this is the resolver.  When
+  ///            # the resolver finds an interesting address, call AddLocation
+  ///            # on this breakpoint to add it.
+  ///            #
+  ///            # extra_args - an SBStructuredData that can be used to 
+  ///            # parametrize this instance.  Same as the extra_args passed
+  ///            # to BreakpointCreateFromScript.
+  ///
+  ///        def __get_depth__ (self):
+  ///            # This is optional, but if defined, you should return the
+  ///            # depth at which you want the callback to be called.  The
+  ///            # available options are:
+  ///            #    lldb.eSearchDepthModule
+  ///            #    lldb.eSearchDepthCompUnit
+  ///            # The default if you don't implement this method is
+  ///            # eSearchDepthModule.
+  ///            
+  ///        def __callback__(self, sym_ctx):
+  ///            # sym_ctx - an SBSymbolContext that is the cursor in the 
+  ///            # search through the program to resolve breakpoints.  
+  ///            # The sym_ctx will be filled out to the depth requested in
+  ///            # __get_depth__.
+  ///            # Look in this sym_ctx for new breakpoint locations,
+  ///            # and if found use bkpt.AddLocation to add them.
+  ///            # Note, you will only get called for modules/compile_units that
+  ///            # pass the SearchFilter provided by the module_list & file_list
+  ///            # passed into BreakpointCreateFromScript.
+  ///
+  ///        def get_short_help(self):
+  ///            # Optional, but if implemented return a short string that will
+  ///            # be printed at the beginning of the break list output for the
+  ///            # breakpoint.
+  ///
+  /// @param[in] extra_args
+  ///    This is an SBStructuredData object that will get passed to the
+  ///    constructor of the class in class_name.  You can use this to 
+  ///    reuse the same class, parametrizing it with entries from this 
+  ///    dictionary.
+  ///
+  /// @param module_list
+  ///    If this is non-empty, this will be used as the module filter in the 
+  ///    SearchFilter created for this breakpoint.
+  ///
+  /// @param file_list
+  ///    If this is non-empty, this will be used as the comp unit filter in the 
+  ///    SearchFilter created for this breakpoint.
+  ///
+  /// @return
+  ///     An SBBreakpoint that will set locations based on the logic in the
+  ///     resolver's search callback.
+  //------------------------------------------------------------------
+    ") BreakpointCreateFromScript;
+    lldb::SBBreakpoint BreakpointCreateFromScript(
+      const char *class_name,
+      SBStructuredData &extra_args,
+      const SBFileSpecList &module_list,
+      const SBFileSpecList &file_list,
+      bool request_hardware = false);
 
     uint32_t
     GetNumBreakpoints () const;

Modified: lldb/trunk/source/API/SBBreakpoint.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBBreakpoint.cpp?rev=342185&r1=342184&r2=342185&view=diff
==============================================================================
--- lldb/trunk/source/API/SBBreakpoint.cpp (original)
+++ lldb/trunk/source/API/SBBreakpoint.cpp Thu Sep 13 14:35:32 2018
@@ -23,6 +23,8 @@
 #include "lldb/Breakpoint/Breakpoint.h"
 #include "lldb/Breakpoint/BreakpointIDList.h"
 #include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/BreakpointResolver.h"
+#include "lldb/Breakpoint/BreakpointResolverScripted.h"
 #include "lldb/Breakpoint/StoppointCallbackContext.h"
 #include "lldb/Core/Address.h"
 #include "lldb/Core/Debugger.h"
@@ -487,6 +489,40 @@ bool SBBreakpoint::GetDescription(SBStre
   return false;
 }
 
+SBError
+SBBreakpoint::AddLocation(SBAddress &address) {
+    BreakpointSP bkpt_sp = GetSP();
+    SBError error;
+  
+    if (!address.IsValid()) {
+      error.SetErrorString("Can't add an invalid address.");
+      return error;
+    }
+  
+    if (!bkpt_sp) {
+      error.SetErrorString("No breakpoint to add a location to.");
+      return error;
+    }
+  
+    if (!llvm::isa<BreakpointResolverScripted>(bkpt_sp->GetResolver().get())) {
+      error.SetErrorString("Only a scripted resolver can add locations.");
+      return error;
+    }
+  
+    if (bkpt_sp->GetSearchFilter()->AddressPasses(address.ref()))
+      bkpt_sp->AddLocation(address.ref());
+    else
+    {
+      StreamString s;
+      address.get()->Dump(&s, &bkpt_sp->GetTarget(),
+                          Address::DumpStyleModuleWithFileAddress);
+      error.SetErrorStringWithFormat("Address: %s didn't pass the filter.",
+                                     s.GetData());
+    }
+    return error;
+}
+
+
 void SBBreakpoint
   ::SetCallback(SBBreakpointHitCallback callback,
   void *baton) {

Modified: lldb/trunk/source/API/SBStructuredData.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBStructuredData.cpp?rev=342185&r1=342184&r2=342185&view=diff
==============================================================================
--- lldb/trunk/source/API/SBStructuredData.cpp (original)
+++ lldb/trunk/source/API/SBStructuredData.cpp Thu Sep 13 14:35:32 2018
@@ -10,6 +10,7 @@
 #include "lldb/API/SBStructuredData.h"
 
 #include "lldb/API/SBStream.h"
+#include "lldb/API/SBStringList.h"
 #include "lldb/Core/Event.h"
 #include "lldb/Core/StructuredDataImpl.h"
 #include "lldb/Target/StructuredDataPlugin.h"
@@ -31,6 +32,9 @@ SBStructuredData::SBStructuredData(const
 SBStructuredData::SBStructuredData(const lldb::EventSP &event_sp)
     : m_impl_up(new StructuredDataImpl(event_sp)) {}
 
+SBStructuredData::SBStructuredData(lldb_private::StructuredDataImpl *impl)
+    : m_impl_up(impl) {}
+
 SBStructuredData::~SBStructuredData() {}
 
 SBStructuredData &SBStructuredData::
@@ -76,6 +80,33 @@ size_t SBStructuredData::GetSize() const
   return (m_impl_up ? m_impl_up->GetSize() : 0);
 }
 
+bool SBStructuredData::GetKeys(lldb::SBStringList &keys) const {
+  if (!m_impl_up)
+    return false;
+  
+  if (GetType() != eStructuredDataTypeDictionary)
+    return false;
+  
+  StructuredData::ObjectSP obj_sp = m_impl_up->GetObjectSP();
+  if (!obj_sp)
+    return false;
+
+  StructuredData::Dictionary *dict = obj_sp->GetAsDictionary();
+  // We claimed we were a dictionary, so this can't be null.
+  assert(dict);
+  // The return kind of GetKeys is an Array:
+  StructuredData::ObjectSP array_sp = dict->GetKeys();
+  StructuredData::Array *key_arr = array_sp->GetAsArray();
+  assert(key_arr);
+  
+  key_arr->ForEach([&keys] (StructuredData::Object *object) -> bool {
+    llvm::StringRef key = object->GetStringValue("");
+    keys.AppendString(key.str().c_str());
+    return true;
+  });
+  return true;
+}
+
 lldb::SBStructuredData SBStructuredData::GetValueForKey(const char *key) const {
   if (!m_impl_up)
     return SBStructuredData();

Modified: lldb/trunk/source/API/SBTarget.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBTarget.cpp?rev=342185&r1=342184&r2=342185&view=diff
==============================================================================
--- lldb/trunk/source/API/SBTarget.cpp (original)
+++ lldb/trunk/source/API/SBTarget.cpp Thu Sep 13 14:35:32 2018
@@ -1044,7 +1044,7 @@ SBTarget::BreakpointCreateForException(l
   }
 
   if (log)
-    log->Printf("SBTarget(%p)::BreakpointCreateByRegex (Language: %s, catch: "
+    log->Printf("SBTarget(%p)::BreakpointCreateForException (Language: %s, catch: "
                 "%s throw: %s) => SBBreakpoint(%p)",
                 static_cast<void *>(target_sp.get()),
                 Language::GetNameForLanguageType(language),
@@ -1054,6 +1054,42 @@ SBTarget::BreakpointCreateForException(l
   return sb_bp;
 }
 
+lldb::SBBreakpoint
+SBTarget::BreakpointCreateFromScript(const char *class_name,
+                                     SBStructuredData &extra_args,
+                                     const SBFileSpecList &module_list,
+                                     const SBFileSpecList &file_list,
+                                     bool request_hardware)
+{
+  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
+
+  SBBreakpoint sb_bp;
+  TargetSP target_sp(GetSP());
+  if (target_sp) {
+    std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex());
+    Status error;
+    
+    StructuredData::ObjectSP obj_sp = extra_args.m_impl_up->GetObjectSP();
+    sb_bp =
+        target_sp->CreateScriptedBreakpoint(class_name,
+                                            module_list.get(),
+                                            file_list.get(),
+                                            false, /* internal */
+                                            request_hardware,
+                                            obj_sp,
+                                            &error);
+  }
+  if (log)
+    log->Printf("SBTarget(%p)::BreakpointCreateFromScript (class name: %s) "
+                " => SBBreakpoint(%p)",
+                static_cast<void *>(target_sp.get()),
+                class_name,
+                static_cast<void *>(sb_bp.GetSP().get()));
+
+  return sb_bp;
+}
+
+
 uint32_t SBTarget::GetNumBreakpoints() const {
   TargetSP target_sp(GetSP());
   if (target_sp) {

Modified: lldb/trunk/source/API/SystemInitializerFull.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SystemInitializerFull.cpp?rev=342185&r1=342184&r2=342185&view=diff
==============================================================================
--- lldb/trunk/source/API/SystemInitializerFull.cpp (original)
+++ lldb/trunk/source/API/SystemInitializerFull.cpp Thu Sep 13 14:35:32 2018
@@ -176,6 +176,18 @@ extern "C" void *LLDBSwigPythonCreateScr
 extern "C" bool LLDBSWIGPythonCallThreadPlan(void *implementor,
                                              const char *method_name,
                                              Event *event_sp, bool &got_error);
+                                             
+extern "C" void *LLDBSwigPythonCreateScriptedBreakpointResolver(
+    const char *python_class_name,
+    const char *session_dictionary_name,
+    lldb_private::StructuredDataImpl *args,
+    lldb::BreakpointSP &bkpt_sp);
+
+extern "C" unsigned int LLDBSwigPythonCallBreakpointResolver(
+    void *implementor,
+    const char *method_name,
+    lldb_private::SymbolContext *sym_ctx
+);
 
 extern "C" size_t LLDBSwigPython_CalculateNumChildren(void *implementor,
                                                       uint32_t max);
@@ -413,7 +425,8 @@ void SystemInitializerFull::InitializeSW
       LLDBSWIGPythonRunScriptKeywordThread,
       LLDBSWIGPythonRunScriptKeywordTarget, LLDBSWIGPythonRunScriptKeywordFrame,
       LLDBSWIGPythonRunScriptKeywordValue, LLDBSWIGPython_GetDynamicSetting,
-      LLDBSwigPythonCreateScriptedThreadPlan, LLDBSWIGPythonCallThreadPlan);
+      LLDBSwigPythonCreateScriptedThreadPlan, LLDBSWIGPythonCallThreadPlan,
+      LLDBSwigPythonCreateScriptedBreakpointResolver, LLDBSwigPythonCallBreakpointResolver);
 #endif
 }
 

Modified: lldb/trunk/source/Breakpoint/BreakpointResolver.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Breakpoint/BreakpointResolver.cpp?rev=342185&r1=342184&r2=342185&view=diff
==============================================================================
--- lldb/trunk/source/Breakpoint/BreakpointResolver.cpp (original)
+++ lldb/trunk/source/Breakpoint/BreakpointResolver.cpp Thu Sep 13 14:35:32 2018
@@ -21,6 +21,7 @@
 #include "lldb/Breakpoint/BreakpointResolverFileLine.h"
 #include "lldb/Breakpoint/BreakpointResolverFileRegex.h"
 #include "lldb/Breakpoint/BreakpointResolverName.h"
+#include "lldb/Breakpoint/BreakpointResolverScripted.h"
 #include "lldb/Core/Address.h"
 #include "lldb/Core/ModuleList.h"
 #include "lldb/Core/SearchFilter.h"
@@ -44,9 +45,10 @@ const char *BreakpointResolver::g_ty_to_
 
 const char *BreakpointResolver::g_option_names[static_cast<uint32_t>(
     BreakpointResolver::OptionNames::LastOptionName)] = {
-    "AddressOffset", "Exact",       "FileName",     "Inlines",    "Language",
-    "LineNumber",    "Column",      "ModuleName",   "NameMask",   "Offset",
-    "Regex",         "SectionName", "SkipPrologue", "SymbolNames"};
+    "AddressOffset", "Exact",     "FileName",     "Inlines",     "Language",
+    "LineNumber",    "Column",    "ModuleName",   "NameMask",    "Offset",
+    "PythonClass",   "Regex",     "ScriptArgs",   "SectionName", "SearchDepth",
+    "SkipPrologue",  "SymbolNames"};
 
 const char *BreakpointResolver::ResolverTyToName(enum ResolverTy type) {
   if (type > LastKnownResolverType)
@@ -132,6 +134,10 @@ BreakpointResolverSP BreakpointResolver:
     resolver = BreakpointResolverFileRegex::CreateFromStructuredData(
         nullptr, *subclass_options, error);
     break;
+  case PythonResolver:
+    resolver = BreakpointResolverScripted::CreateFromStructuredData(
+        nullptr, *subclass_options, error);
+    break;
   case ExceptionResolver:
     error.SetErrorString("Exception resolvers are hard.");
     break;
@@ -165,6 +171,7 @@ StructuredData::DictionarySP BreakpointR
 
 void BreakpointResolver::SetBreakpoint(Breakpoint *bkpt) {
   m_breakpoint = bkpt;
+  NotifyBreakpointSet();
 }
 
 void BreakpointResolver::ResolveBreakpointInModules(SearchFilter &filter,

Modified: lldb/trunk/source/Commands/CommandObjectBreakpoint.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectBreakpoint.cpp?rev=342185&r1=342184&r2=342185&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectBreakpoint.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectBreakpoint.cpp Thu Sep 13 14:35:32 2018
@@ -245,10 +245,10 @@ public:
 
 // If an additional option set beyond LLDB_OPTION_SET_10 is added, make sure to
 // update the numbers passed to LLDB_OPT_SET_FROM_TO(...) appropriately.
-#define LLDB_OPT_FILE (LLDB_OPT_SET_FROM_TO(1, 9) & ~LLDB_OPT_SET_2)
-#define LLDB_OPT_NOT_10 (LLDB_OPT_SET_FROM_TO(1, 10) & ~LLDB_OPT_SET_10)
+#define LLDB_OPT_NOT_10 (LLDB_OPT_SET_FROM_TO(1, 11) & ~LLDB_OPT_SET_10)
 #define LLDB_OPT_SKIP_PROLOGUE (LLDB_OPT_SET_1 | LLDB_OPT_SET_FROM_TO(3, 8))
-#define LLDB_OPT_OFFSET_APPLIES (LLDB_OPT_SET_1 | LLDB_OPT_SET_FROM_TO(3, 8))
+#define LLDB_OPT_FILE (LLDB_OPT_SET_FROM_TO(1, 11) & ~LLDB_OPT_SET_2 & ~LLDB_OPT_SET_10)
+#define LLDB_OPT_OFFSET_APPLIES (LLDB_OPT_SET_FROM_TO(1, 8) & ~LLDB_OPT_SET_2)
 #define LLDB_OPT_MOVE_TO_NEAREST_CODE (LLDB_OPT_SET_1 | LLDB_OPT_SET_9)
 #define LLDB_OPT_EXPR_LANGUAGE (LLDB_OPT_SET_FROM_TO(3, 8))
 
@@ -301,6 +301,9 @@ static OptionDefinition g_breakpoint_set
   "are specified, uses the current \"default source file\".  If you want to "
   "match against all source files, pass the \"--all-files\" option." },
   { LLDB_OPT_SET_9,                false, "all-files",              'A', OptionParser::eNoArgument,       nullptr, nullptr, 0,                                         eArgTypeNone,                "All files are searched for source pattern matches." },
+  { LLDB_OPT_SET_11,               true, "python-class",           'P', OptionParser::eRequiredArgument, nullptr, nullptr,            0,                              eArgTypePythonClass,       "The name of the class that implement a scripted breakpoint." },
+  { LLDB_OPT_SET_11,               false, "python-class-key",       'k', OptionParser::eRequiredArgument, nullptr, nullptr,            0,                              eArgTypeNone,                "The key for a key/value pair passed to the class that implements a scripted breakpoint.  Can be specified more than once." },
+  { LLDB_OPT_SET_11,               false, "python-class-value",     'v', OptionParser::eRequiredArgument, nullptr, nullptr,            0,                              eArgTypeNone,                "The value for the previous key in the pair passed to the class that implements a scripted breakpoint.    Can be specified more than once." },
   { LLDB_OPT_SET_10,               true,  "language-exception",     'E', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeLanguage,            "Set the breakpoint on exceptions thrown by the specified language (without "
   "options, on throw but not catch.)" },
   { LLDB_OPT_SET_10,               false, "on-throw",               'w', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeBoolean,             "Set the breakpoint on exception throW." },
@@ -336,7 +339,8 @@ public:
     eSetTypeFunctionName,
     eSetTypeFunctionRegexp,
     eSetTypeSourceRegexp,
-    eSetTypeException
+    eSetTypeException,
+    eSetTypeScripted,
   } BreakpointSetType;
 
   CommandObjectBreakpointSet(CommandInterpreter &interpreter)
@@ -454,7 +458,15 @@ public:
       case 'H':
         m_hardware = true;
         break;
-
+        
+      case 'k': {
+          if (m_current_key.empty())
+            m_current_key.assign(option_arg);
+          else
+            error.SetErrorStringWithFormat("Key: %s missing value.",
+                                            m_current_key.c_str());
+        
+      } break;
       case 'K': {
         bool success;
         bool value;
@@ -535,6 +547,10 @@ public:
       case 'p':
         m_source_text_regexp.assign(option_arg);
         break;
+        
+      case 'P':
+        m_python_class.assign(option_arg);
+        break;
 
       case 'r':
         m_func_regexp.assign(option_arg);
@@ -549,6 +565,16 @@ public:
         m_func_name_type_mask |= eFunctionNameTypeSelector;
         break;
 
+      case 'v': {
+          if (!m_current_key.empty()) {
+              m_extra_args_sp->AddStringItem(m_current_key, option_arg);
+              m_current_key.clear();
+          }
+          else
+            error.SetErrorStringWithFormat("Value \"%s\" missing matching key.",
+                                           option_arg.str().c_str());
+      } break;
+        
       case 'w': {
         bool success;
         m_throw_bp = OptionArgParser::ToBoolean(option_arg, true, &success);
@@ -593,6 +619,9 @@ public:
       m_exception_extra_args.Clear();
       m_move_to_nearest_code = eLazyBoolCalculate;
       m_source_regex_func_names.clear();
+      m_python_class.clear();
+      m_extra_args_sp.reset(new StructuredData::Dictionary());
+      m_current_key.clear();
     }
 
     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
@@ -623,6 +652,9 @@ public:
     Args m_exception_extra_args;
     LazyBool m_move_to_nearest_code;
     std::unordered_set<std::string> m_source_regex_func_names;
+    std::string m_python_class;
+    StructuredData::DictionarySP m_extra_args_sp;
+    std::string m_current_key;
   };
 
 protected:
@@ -649,7 +681,9 @@ protected:
 
     BreakpointSetType break_type = eSetTypeInvalid;
 
-    if (m_options.m_line_num != 0)
+    if (!m_options.m_python_class.empty())
+      break_type = eSetTypeScripted;
+    else if (m_options.m_line_num != 0)
       break_type = eSetTypeFileAndLine;
     else if (m_options.m_load_addr != LLDB_INVALID_ADDRESS)
       break_type = eSetTypeAddress;
@@ -822,6 +856,25 @@ protected:
         target->RemoveBreakpointByID(bp_sp->GetID());
         result.SetStatus(eReturnStatusFailed);
         return false;
+      }
+    } break;
+    case eSetTypeScripted: {
+
+      Status error;
+      bp_sp = target->CreateScriptedBreakpoint(m_options.m_python_class,
+                                               &(m_options.m_modules), 
+                                               &(m_options.m_filenames),
+                                               false,
+                                               m_options.m_hardware,
+                                               m_options.m_extra_args_sp,
+                                               &error);
+      if (error.Fail()) {
+        result.AppendErrorWithFormat(
+            "Error setting extra exception arguments: %s",
+            error.AsCString());
+        target->RemoveBreakpointByID(bp_sp->GetID());
+        result.SetStatus(eReturnStatusFailed);
+        return false;
       }
     } break;
     default:

Modified: lldb/trunk/source/Core/SearchFilter.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/SearchFilter.cpp?rev=342185&r1=342184&r2=342185&view=diff
==============================================================================
--- lldb/trunk/source/Core/SearchFilter.cpp (original)
+++ lldb/trunk/source/Core/SearchFilter.cpp Thu Sep 13 14:35:32 2018
@@ -311,7 +311,7 @@ SearchFilter::DoCUIteration(const Module
             return Searcher::eCallbackReturnContinue;
           else if (shouldContinue == Searcher::eCallbackReturnStop)
             return shouldContinue;
-        } else {
+        } else if (searcher.GetDepth() == lldb::eSearchDepthFunction) {
           // FIXME Descend to block.
         }
       }
@@ -748,7 +748,15 @@ SearchFilterByModuleListAndCU::Serialize
 }
 
 bool SearchFilterByModuleListAndCU::AddressPasses(Address &address) {
-  return true;
+  SymbolContext sym_ctx;
+  address.CalculateSymbolContext(&sym_ctx, eSymbolContextEverything);
+  if (!sym_ctx.comp_unit) {
+    if (m_cu_spec_list.GetSize() != 0)
+      return false; // Has no comp_unit so can't pass the file check.
+  }
+  if (m_cu_spec_list.FindFileIndex(0, sym_ctx.comp_unit, false) == UINT32_MAX)
+        return false; // Fails the file check
+  return SearchFilterByModuleList::ModulePasses(sym_ctx.module_sp); 
 }
 
 bool SearchFilterByModuleListAndCU::CompUnitPasses(FileSpec &fileSpec) {

Modified: lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp?rev=342185&r1=342184&r2=342185&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp (original)
+++ lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp Thu Sep 13 14:35:32 2018
@@ -107,6 +107,10 @@ static ScriptInterpreterPython::SWIGPyth
     g_swig_thread_plan_script = nullptr;
 static ScriptInterpreterPython::SWIGPythonCallThreadPlan
     g_swig_call_thread_plan = nullptr;
+static ScriptInterpreterPython::SWIGPythonCreateScriptedBreakpointResolver
+    g_swig_bkpt_resolver_script = nullptr;
+static ScriptInterpreterPython::SWIGPythonCallBreakpointResolver
+    g_swig_call_bkpt_resolver = nullptr;
 
 static bool g_initialized = false;
 
@@ -1868,6 +1872,84 @@ lldb::StateType ScriptInterpreterPython:
     return lldb::eStateRunning;
 }
 
+StructuredData::GenericSP
+ScriptInterpreterPython::CreateScriptedBreakpointResolver(
+    const char *class_name,
+    StructuredDataImpl *args_data,
+    lldb::BreakpointSP &bkpt_sp) {
+    
+  if (class_name == nullptr || class_name[0] == '\0')
+    return StructuredData::GenericSP();
+
+  if (!bkpt_sp.get())
+    return StructuredData::GenericSP();
+
+  Debugger &debugger = bkpt_sp->GetTarget().GetDebugger();
+  ScriptInterpreter *script_interpreter =
+      debugger.GetCommandInterpreter().GetScriptInterpreter();
+  ScriptInterpreterPython *python_interpreter =
+      static_cast<ScriptInterpreterPython *>(script_interpreter);
+
+  if (!script_interpreter)
+    return StructuredData::GenericSP();
+
+  void *ret_val;
+
+  {
+    Locker py_lock(this,
+                   Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
+
+    ret_val = g_swig_bkpt_resolver_script(
+        class_name, python_interpreter->m_dictionary_name.c_str(),
+        args_data, bkpt_sp);
+  }
+
+  return StructuredData::GenericSP(new StructuredPythonObject(ret_val));
+}
+
+bool
+ScriptInterpreterPython::ScriptedBreakpointResolverSearchCallback(
+    StructuredData::GenericSP implementor_sp,
+    SymbolContext *sym_ctx) {
+  bool should_continue = false;
+  
+  if (implementor_sp) {
+    Locker py_lock(this,
+                   Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
+    should_continue
+        = g_swig_call_bkpt_resolver(implementor_sp->GetValue(), "__callback__",
+                                    sym_ctx);
+    if (PyErr_Occurred()) {
+      PyErr_Print();
+      PyErr_Clear();
+    }
+  }
+  return should_continue;
+}
+
+lldb::SearchDepth
+ScriptInterpreterPython::ScriptedBreakpointResolverSearchDepth(
+    StructuredData::GenericSP implementor_sp) {
+  int depth_as_int = lldb::eSearchDepthModule;
+  if (implementor_sp) {
+    Locker py_lock(this,
+                   Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN);
+    depth_as_int
+        = g_swig_call_bkpt_resolver(implementor_sp->GetValue(), "__get_depth__", nullptr);
+    if (PyErr_Occurred()) {
+      PyErr_Print();
+      PyErr_Clear();
+    }
+  }
+  if (depth_as_int == lldb::eSearchDepthInvalid)
+    return lldb::eSearchDepthModule;
+
+  if (depth_as_int <= lldb::kLastSearchDepthKind)
+    return (lldb::SearchDepth) depth_as_int;
+  else
+    return lldb::eSearchDepthModule;
+}
+
 StructuredData::ObjectSP
 ScriptInterpreterPython::LoadPluginModule(const FileSpec &file_spec,
                                           lldb_private::Status &error) {
@@ -3107,7 +3189,9 @@ void ScriptInterpreterPython::Initialize
     SWIGPythonScriptKeyword_Value swig_run_script_keyword_value,
     SWIGPython_GetDynamicSetting swig_plugin_get,
     SWIGPythonCreateScriptedThreadPlan swig_thread_plan_script,
-    SWIGPythonCallThreadPlan swig_call_thread_plan) {
+    SWIGPythonCallThreadPlan swig_call_thread_plan,
+    SWIGPythonCreateScriptedBreakpointResolver swig_bkpt_resolver_script,
+    SWIGPythonCallBreakpointResolver swig_call_bkpt_resolver) {
   g_swig_init_callback = swig_init_callback;
   g_swig_breakpoint_callback = swig_breakpoint_callback;
   g_swig_watchpoint_callback = swig_watchpoint_callback;
@@ -3134,6 +3218,8 @@ void ScriptInterpreterPython::Initialize
   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;
+  g_swig_bkpt_resolver_script = swig_bkpt_resolver_script;
+  g_swig_call_bkpt_resolver = swig_call_bkpt_resolver;
 }
 
 void ScriptInterpreterPython::InitializePrivate() {

Modified: lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h?rev=342185&r1=342184&r2=342185&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h (original)
+++ lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h Thu Sep 13 14:35:32 2018
@@ -81,6 +81,15 @@ public:
                                            const char *method_name,
                                            Event *event_sp, bool &got_error);
 
+  typedef void *(*SWIGPythonCreateScriptedBreakpointResolver)(
+      const char *python_class_name, const char *session_dictionary_name,
+      lldb_private::StructuredDataImpl *args_impl,
+      lldb::BreakpointSP &bkpt_sp);
+
+  typedef unsigned int (*SWIGPythonCallBreakpointResolver)(void *implementor,
+                                          const char *method_name,
+                                          lldb_private::SymbolContext *sym_ctx);
+
   typedef void *(*SWIGPythonCreateOSPlugin)(const char *python_class_name,
                                             const char *session_dictionary_name,
                                             const lldb::ProcessSP &process_sp);
@@ -208,6 +217,19 @@ public:
   lldb::StateType
   ScriptedThreadPlanGetRunState(StructuredData::ObjectSP implementor_sp,
                                 bool &script_error) override;
+                                
+  StructuredData::GenericSP
+  CreateScriptedBreakpointResolver(const char *class_name,
+                                   StructuredDataImpl *args_data,
+                                   lldb::BreakpointSP &bkpt_sp) override;
+  bool
+  ScriptedBreakpointResolverSearchCallback(StructuredData::GenericSP
+                                               implementor_sp,
+                                           SymbolContext *sym_ctx) override;
+
+  lldb::SearchDepth
+  ScriptedBreakpointResolverSearchDepth(StructuredData::GenericSP
+                                            implementor_sp) override;
 
   StructuredData::GenericSP
   OSPlugin_CreatePluginObject(const char *class_name,
@@ -411,7 +433,9 @@ public:
       SWIGPythonScriptKeyword_Value swig_run_script_keyword_value,
       SWIGPython_GetDynamicSetting swig_plugin_get,
       SWIGPythonCreateScriptedThreadPlan swig_thread_plan_script,
-      SWIGPythonCallThreadPlan swig_call_thread_plan);
+      SWIGPythonCallThreadPlan swig_call_thread_plan,
+      SWIGPythonCreateScriptedBreakpointResolver swig_bkpt_resolver_script,
+      SWIGPythonCallBreakpointResolver swig_call_breakpoint_resolver);
 
   const char *GetDictionaryName() { return m_dictionary_name.c_str(); }
 

Modified: lldb/trunk/source/Target/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Target.cpp?rev=342185&r1=342184&r2=342185&view=diff
==============================================================================
--- lldb/trunk/source/Target/Target.cpp (original)
+++ lldb/trunk/source/Target/Target.cpp Thu Sep 13 14:35:32 2018
@@ -21,6 +21,7 @@
 #include "lldb/Breakpoint/BreakpointResolverFileLine.h"
 #include "lldb/Breakpoint/BreakpointResolverFileRegex.h"
 #include "lldb/Breakpoint/BreakpointResolverName.h"
+#include "lldb/Breakpoint/BreakpointResolverScripted.h"
 #include "lldb/Breakpoint/Watchpoint.h"
 #include "lldb/Core/Debugger.h"
 #include "lldb/Core/Event.h"
@@ -28,8 +29,10 @@
 #include "lldb/Core/ModuleSpec.h"
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Core/Section.h"
+#include "lldb/Core/SearchFilter.h"
 #include "lldb/Core/SourceManager.h"
 #include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StructuredDataImpl.h"
 #include "lldb/Core/ValueObject.h"
 #include "lldb/Expression/REPL.h"
 #include "lldb/Expression/UserExpression.h"
@@ -579,6 +582,48 @@ Target::CreateExceptionBreakpoint(enum l
   return exc_bkpt_sp;
 }
 
+lldb::BreakpointSP
+Target::CreateScriptedBreakpoint(const llvm::StringRef class_name,
+                                 const FileSpecList *containingModules,
+                                 const FileSpecList *containingSourceFiles,
+                                 bool internal,
+                                 bool request_hardware,
+                                 StructuredData::ObjectSP extra_args_sp,
+                                 Status *creation_error)
+{
+  SearchFilterSP filter_sp;
+  
+  lldb::SearchDepth depth = lldb::eSearchDepthTarget;
+  bool has_files = containingSourceFiles && containingSourceFiles->GetSize() > 0;
+  bool has_modules = containingModules && containingModules->GetSize() > 0;
+  
+  if (has_files && has_modules) {
+    filter_sp = GetSearchFilterForModuleAndCUList(
+      containingModules, containingSourceFiles);
+  } else if (has_files) {
+    filter_sp = GetSearchFilterForModuleAndCUList(
+      nullptr, containingSourceFiles);
+  } else if (has_modules) {
+    filter_sp = GetSearchFilterForModuleList(containingModules);
+  } else {
+    filter_sp.reset(new SearchFilterForUnconstrainedSearches(shared_from_this()));
+  }
+  
+  StructuredDataImpl *extra_args_impl = new StructuredDataImpl();
+  if (extra_args_sp)
+    extra_args_impl->SetObjectSP(extra_args_sp);
+  
+  BreakpointResolverSP resolver_sp(new 
+                                   BreakpointResolverScripted(nullptr, class_name,
+                                   depth,
+                                   extra_args_impl,
+                                   *GetDebugger().GetCommandInterpreter()
+                                       .GetScriptInterpreter()));
+  return CreateBreakpoint(filter_sp, resolver_sp, internal, false, true);
+
+}
+
+
 BreakpointSP Target::CreateBreakpoint(SearchFilterSP &filter_sp,
                                       BreakpointResolverSP &resolver_sp,
                                       bool internal, bool request_hardware,




More information about the lldb-commits mailing list