mib updated this revision to Diff 515902.
mib marked 2 inline comments as done.
mib added a comment.

Re-format python code with `black`


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D148548/new/

https://reviews.llvm.org/D148548

Files:
  lldb/bindings/interface/SBTargetExtensions.i
  lldb/bindings/python/python-wrapper.swig
  lldb/examples/python/scripted_process/scripted_process.py
  lldb/include/lldb/API/SBBreakpoint.h
  lldb/include/lldb/Interpreter/ScriptInterpreter.h
  lldb/include/lldb/Interpreter/ScriptedProcessInterface.h
  lldb/source/Interpreter/ScriptInterpreter.cpp
  lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
  lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
  
lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
  lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h
  lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp
  lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
  
lldb/test/API/functionalities/interactive_scripted_process/TestInteractiveScriptedProcess.py
  
lldb/test/API/functionalities/interactive_scripted_process/interactive_scripted_process.py
  lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp

Index: lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
===================================================================
--- lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
+++ lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
@@ -139,6 +139,10 @@
   return nullptr;
 }
 
+void *lldb_private::LLDBSWIGPython_CastPyObjectToSBBreakpoint(PyObject *data) {
+  return nullptr;
+}
+
 void *lldb_private::LLDBSWIGPython_CastPyObjectToSBAttachInfo(PyObject *data) {
   return nullptr;
 }
Index: lldb/test/API/functionalities/interactive_scripted_process/interactive_scripted_process.py
===================================================================
--- lldb/test/API/functionalities/interactive_scripted_process/interactive_scripted_process.py
+++ lldb/test/API/functionalities/interactive_scripted_process/interactive_scripted_process.py
@@ -6,7 +6,7 @@
 #   -o "create_sub" \
 #   -o "br set -p 'also break here'" -o 'continue'
 
-import os, json, struct, signal
+import os, json, struct, signal, tempfile
 
 from threading import Thread
 from typing import Any, Dict
@@ -152,6 +152,11 @@
             )
         )
 
+    def create_breakpoint(self, addr, error, pid=None):
+        if not self.multiplexer:
+            error.SetErrorString("Multiplexer is not set.")
+        return self.multiplexer.create_breakpoint(addr, error, self.get_process_id())
+
     def get_scripted_thread_plugin(self) -> str:
         return f"{MultiplexedScriptedThread.__module__}.{MultiplexedScriptedThread.__name__}"
 
@@ -300,6 +305,40 @@
             )
             self.multiplexed_processes = {}
 
+            # Copy breakpoints from real target to passthrough
+            with tempfile.NamedTemporaryFile() as tf:
+                bkpt_file = lldb.SBFileSpec(tf.name)
+                error = self.driving_target.BreakpointsWriteToFile(bkpt_file)
+                if error.Fail():
+                    log(
+                        "Failed to save breakpoints from driving target (%s)"
+                        % error.GetCString()
+                    )
+                bkpts_list = lldb.SBBreakpointList(self.target)
+                error = self.target.BreakpointsCreateFromFile(bkpt_file, bkpts_list)
+                if error.Fail():
+                    log(
+                        "Failed create breakpoints from driving target \
+                        (bkpt file: %s)"
+                        % tf.name
+                    )
+
+            # Copy breakpoint from passthrough to real target
+            if error.Success():
+                self.driving_target.DeleteAllBreakpoints()
+                for bkpt in self.target.breakpoints:
+                    if bkpt.IsValid():
+                        for bl in bkpt:
+                            real_bpkt = self.driving_target.BreakpointCreateBySBAddress(
+                                bl.GetAddress()
+                            )
+                            if not real_bpkt.IsValid():
+                                log(
+                                    "Failed to set breakpoint at address %s in \
+                                    driving target"
+                                    % hex(bl.GetLoadAddress())
+                                )
+
             self.listener_thread = Thread(
                 target=self.wait_for_driving_process_to_stop, daemon=True
             )
@@ -364,6 +403,47 @@
         parity = pid % 2
         return dict(filter(lambda pair: pair[0] % 2 == parity, self.threads.items()))
 
+    def create_breakpoint(self, addr, error, pid=None):
+        if not self.driving_target:
+            error.SetErrorString("%s has no driving target." % self.__class__.__name__)
+            return False
+
+        def create_breakpoint_with_name(target, load_addr, name, error):
+            addr = lldb.SBAddress(load_addr, target)
+            if not addr.IsValid():
+                error.SetErrorString("Invalid breakpoint address %s" % hex(load_addr))
+                return False
+            bkpt = target.BreakpointCreateBySBAddress(addr)
+            if not bkpt.IsValid():
+                error.SetErrorString(
+                    "Failed to create breakpoint at address %s"
+                    % hex(addr.GetLoadAddress())
+                )
+                return False
+            error = bkpt.AddNameWithErrorHandling(name)
+            return error.Success()
+
+        name = (
+            "multiplexer scripted process"
+            if not pid
+            else "multiplexed scripted process (%d)" % pid
+        )
+
+        if pid is not None:
+            # This means that this method has been called from one of the
+            # multiplexed scripted process. That also means that the multiplexer
+            # target doesn't have this breakpoint created.
+            mux_error = lldb.SBError()
+            bkpt = create_breakpoint_with_name(self.target, addr, name, mux_error)
+            if mux_error.Fail():
+                error.SetError(
+                    "Failed to create breakpoint in multiplexer \
+                               target: %s"
+                    % mux_error.GetCString()
+                )
+                return False
+        return create_breakpoint_with_name(self.driving_target, addr, name, error)
+
 
 def multiplex(mux_process, muxed_process):
     muxed_process.GetScriptedImplementation().multiplexer = (
Index: lldb/test/API/functionalities/interactive_scripted_process/TestInteractiveScriptedProcess.py
===================================================================
--- lldb/test/API/functionalities/interactive_scripted_process/TestInteractiveScriptedProcess.py
+++ lldb/test/API/functionalities/interactive_scripted_process/TestInteractiveScriptedProcess.py
@@ -107,7 +107,7 @@
             self.assertEqual(real_pc, mux_pc, f"PC's equal for {id}")
 
         lldbutil.run_break_set_by_source_regexp(self, "also break here")
-        self.assertEqual(mux_target.GetNumBreakpoints(), 1)
+        self.assertEqual(mux_target.GetNumBreakpoints(), 2)
         error = mux_process.Continue()
         self.assertSuccess(error, "Resuming multiplexer scripted process")
         self.assertTrue(mux_process.IsValid(), "Got a valid process")
Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
+++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
@@ -228,6 +228,11 @@
 Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>(
     python::PythonObject &p, Status &error);
 
+template <>
+lldb::BreakpointSP
+ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>(
+    python::PythonObject &p, Status &error);
+
 template <>
 lldb::ProcessAttachInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject<
     lldb::ProcessAttachInfoSP>(python::PythonObject &p, Status &error);
Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp
+++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp
@@ -70,6 +70,22 @@
   return m_interpreter.GetDataExtractorFromSBData(*sb_data);
 }
 
+template <>
+lldb::BreakpointSP
+ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>(
+    python::PythonObject &p, Status &error) {
+  lldb::SBBreakpoint *sb_breakpoint = reinterpret_cast<lldb::SBBreakpoint *>(
+      LLDBSWIGPython_CastPyObjectToSBBreakpoint(p.get()));
+
+  if (!sb_breakpoint) {
+    error.SetErrorString(
+        "Couldn't cast lldb::SBBreakpoint to lldb::BreakpointSP.");
+    return nullptr;
+  }
+
+  return m_interpreter.GetOpaqueTypeFromSBBreakpoint(*sb_breakpoint);
+}
+
 template <>
 lldb::ProcessAttachInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject<
     lldb::ProcessAttachInfoSP>(python::PythonObject &p, Status &error) {
Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h
+++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h
@@ -43,6 +43,8 @@
 
   StructuredData::DictionarySP GetThreadsInfo() override;
 
+  bool CreateBreakpoint(lldb::addr_t addr, Status &error) override;
+
   lldb::DataExtractorSP ReadMemoryAtAddress(lldb::addr_t address, size_t size,
                                             Status &error) override;
 
Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
+++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
@@ -110,6 +110,22 @@
   return dict;
 }
 
+bool ScriptedProcessPythonInterface::CreateBreakpoint(lldb::addr_t addr,
+                                                      Status &error) {
+  Status py_error;
+  StructuredData::ObjectSP obj =
+      Dispatch("create_breakpoint", py_error, addr, error);
+
+  // If there was an error on the python call, surface it to the user.
+  if (py_error.Fail())
+    error = py_error;
+
+  if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error))
+    return {};
+
+  return obj->GetBooleanValue();
+}
+
 lldb::DataExtractorSP ScriptedProcessPythonInterface::ReadMemoryAtAddress(
     lldb::addr_t address, size_t size, Status &error) {
   Status py_error;
Index: lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
+++ lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
@@ -92,6 +92,7 @@
 } // namespace python
 
 void *LLDBSWIGPython_CastPyObjectToSBData(PyObject *data);
+void *LLDBSWIGPython_CastPyObjectToSBBreakpoint(PyObject *data);
 void *LLDBSWIGPython_CastPyObjectToSBAttachInfo(PyObject *data);
 void *LLDBSWIGPython_CastPyObjectToSBLaunchInfo(PyObject *data);
 void *LLDBSWIGPython_CastPyObjectToSBError(PyObject *data);
Index: lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
===================================================================
--- lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
+++ lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
@@ -260,7 +260,10 @@
     return Status("Scripted Processes don't support hardware breakpoints");
   }
 
-  return EnableSoftwareBreakpoint(bp_site);
+  Status error;
+  GetInterface().CreateBreakpoint(bp_site->GetLoadAddress(), error);
+
+  return error;
 }
 
 ArchSpec ScriptedProcess::GetArchitecture() {
Index: lldb/source/Interpreter/ScriptInterpreter.cpp
===================================================================
--- lldb/source/Interpreter/ScriptInterpreter.cpp
+++ lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -80,6 +80,11 @@
   return data.m_opaque_sp;
 }
 
+lldb::BreakpointSP ScriptInterpreter::GetOpaqueTypeFromSBBreakpoint(
+    const lldb::SBBreakpoint &breakpoint) const {
+  return breakpoint.m_opaque_wp.lock();
+}
+
 lldb::ProcessAttachInfoSP ScriptInterpreter::GetOpaqueTypeFromSBAttachInfo(
     const lldb::SBAttachInfo &attach_info) const {
   return attach_info.m_opaque_sp;
Index: lldb/include/lldb/Interpreter/ScriptedProcessInterface.h
===================================================================
--- lldb/include/lldb/Interpreter/ScriptedProcessInterface.h
+++ lldb/include/lldb/Interpreter/ScriptedProcessInterface.h
@@ -46,6 +46,11 @@
 
   virtual StructuredData::DictionarySP GetThreadsInfo() { return {}; }
 
+  virtual bool CreateBreakpoint(lldb::addr_t addr, Status &error) {
+    error.SetErrorString("ScriptedProcess don't support creating breakpoints.");
+    return {};
+  }
+
   virtual lldb::DataExtractorSP
   ReadMemoryAtAddress(lldb::addr_t address, size_t size, Status &error) {
     return {};
Index: lldb/include/lldb/Interpreter/ScriptInterpreter.h
===================================================================
--- lldb/include/lldb/Interpreter/ScriptInterpreter.h
+++ lldb/include/lldb/Interpreter/ScriptInterpreter.h
@@ -10,6 +10,7 @@
 #define LLDB_INTERPRETER_SCRIPTINTERPRETER_H
 
 #include "lldb/API/SBAttachInfo.h"
+#include "lldb/API/SBBreakpoint.h"
 #include "lldb/API/SBData.h"
 #include "lldb/API/SBError.h"
 #include "lldb/API/SBLaunchInfo.h"
@@ -587,6 +588,9 @@
 
   Status GetStatusFromSBError(const lldb::SBError &error) const;
 
+  lldb::BreakpointSP
+  GetOpaqueTypeFromSBBreakpoint(const lldb::SBBreakpoint &breakpoint) const;
+
   lldb::ProcessAttachInfoSP
   GetOpaqueTypeFromSBAttachInfo(const lldb::SBAttachInfo &attach_info) const;
 
Index: lldb/include/lldb/API/SBBreakpoint.h
===================================================================
--- lldb/include/lldb/API/SBBreakpoint.h
+++ lldb/include/lldb/API/SBBreakpoint.h
@@ -13,6 +13,10 @@
 
 class SBBreakpointListImpl;
 
+namespace lldb_private {
+class ScriptInterpreter;
+}
+
 namespace lldb {
 
 class LLDB_API SBBreakpoint {
@@ -155,6 +159,8 @@
   friend class SBBreakpointName;
   friend class SBTarget;
 
+  friend class lldb_private::ScriptInterpreter;
+
   lldb::BreakpointSP GetSP() const;
 
   lldb::BreakpointWP m_opaque_wp;
Index: lldb/examples/python/scripted_process/scripted_process.py
===================================================================
--- lldb/examples/python/scripted_process/scripted_process.py
+++ lldb/examples/python/scripted_process/scripted_process.py
@@ -209,6 +209,23 @@
         """
         return self.metadata
 
+    def create_breakpoint(self, addr, error):
+        """ Create a breakpoint in the scripted process from an address.
+            This is mainly used with interactive scripted process debugging.
+
+        Args:
+            addr (int): Address at which the breakpoint should be set.
+            error (lldb.SBError): Error object.
+
+        Returns:
+            SBBreakpoint: A valid breakpoint object that was created a the specified
+                          address. None if the breakpoint creation failed.
+        """
+        error.SetErrorString("%s doesn't support creating breakpoints."
+                             % self.__class__.__name__)
+        return False
+
+
 class ScriptedThread(metaclass=ABCMeta):
 
     """
Index: lldb/bindings/python/python-wrapper.swig
===================================================================
--- lldb/bindings/python/python-wrapper.swig
+++ lldb/bindings/python/python-wrapper.swig
@@ -716,6 +716,18 @@
   return sb_ptr;
 }
 
+void *lldb_private::LLDBSWIGPython_CastPyObjectToSBBreakpoint(PyObject * data) {
+  lldb::SBBreakpoint *sb_ptr = nullptr;
+
+  int valid_cast =
+      SWIG_ConvertPtr(data, (void **)&sb_ptr, SWIGTYPE_p_lldb__SBBreakpoint, 0);
+
+  if (valid_cast == -1)
+    return NULL;
+
+  return sb_ptr;
+}
+
 void *lldb_private::LLDBSWIGPython_CastPyObjectToSBAttachInfo(PyObject * data) {
   lldb::SBAttachInfo *sb_ptr = nullptr;
 
Index: lldb/bindings/interface/SBTargetExtensions.i
===================================================================
--- lldb/bindings/interface/SBTargetExtensions.i
+++ lldb/bindings/interface/SBTargetExtensions.i
@@ -88,7 +88,7 @@
 
         def get_modules_access_object(self):
             '''An accessor function that returns a modules_access() object which allows lazy module access from a lldb.SBTarget object.'''
-            return self.modules_access (self)
+            return self.modules_access(self)
 
         def get_modules_array(self):
             '''An accessor function that returns a list() that contains all modules in a lldb.SBTarget object.'''
@@ -107,18 +107,80 @@
             object.'''
             return lldb_iter(self, 'GetNumBreakpoints', 'GetBreakpointAtIndex')
 
+        class bkpts_access(object):
+            '''A helper object that will lazily hand out bkpts for a target when supplied an index.'''
+            def __init__(self, sbtarget):
+                self.sbtarget = sbtarget
+
+            def __len__(self):
+                if self.sbtarget:
+                    return int(self.sbtarget.GetNumBreakpoints())
+                return 0
+
+            def __getitem__(self, key):
+                if isinstance(key, int):
+                    count = len(self)
+                    if -count <= key < count:
+                        key %= count
+                        return self.sbtarget.GetBreakpointAtIndex(key)
+                return None
+
+        def get_bkpts_access_object(self):
+            '''An accessor function that returns a bkpts_access() object which allows lazy bkpt access from a lldb.SBtarget object.'''
+            return self.bkpts_access(self)
+
+        def get_target_bkpts(self):
+            '''An accessor function that returns a list() that contains all bkpts in a lldb.SBtarget object.'''
+            bkpts = []
+            for idx in range(self.GetNumBreakpoints()):
+                bkpts.append(self.GetBreakpointAtIndex(idx))
+            return bkpts
+
         def watchpoint_iter(self):
             '''Returns an iterator over all watchpoints in a lldb.SBTarget
             object.'''
             return lldb_iter(self, 'GetNumWatchpoints', 'GetWatchpointAtIndex')
 
+        class watchpoints_access(object):
+            '''A helper object that will lazily hand out watchpoints for a target when supplied an index.'''
+            def __init__(self, sbtarget):
+                self.sbtarget = sbtarget
+
+            def __len__(self):
+                if self.sbtarget:
+                    return int(self.sbtarget.GetNumWatchpoints())
+                return 0
+
+            def __getitem__(self, key):
+                if isinstance(key, int):
+                    count = len(self)
+                    if -count <= key < count:
+                        key %= count
+                        return self.sbtarget.GetWatchpointAtIndex(key)
+                return None
+
+        def get_watchpoints_access_object(self):
+            '''An accessor function that returns a watchpoints_access() object which allows lazy watchpoint access from a lldb.SBtarget object.'''
+            return self.watchpoints_access(self)
+
+        def get_target_watchpoints(self):
+            '''An accessor function that returns a list() that contains all watchpoints in a lldb.SBtarget object.'''
+            watchpoints = []
+            for idx in range(self.GetNumWatchpoints()):
+                bkpts.append(self.GetWatchpointAtIndex(idx))
+            return watchpoints
+
         modules = property(get_modules_array, None, doc='''A read only property that returns a list() of lldb.SBModule objects contained in this target. This list is a list all modules that the target currently is tracking (the main executable and all dependent shared libraries).''')
         module = property(get_modules_access_object, None, doc=r'''A read only property that returns an object that implements python operator overloading with the square brackets().\n    target.module[<int>] allows array access to any modules.\n    target.module[<str>] allows access to modules by basename, full path, or uuid string value.\n    target.module[uuid.UUID()] allows module access by UUID.\n    target.module[re] allows module access using a regular expression that matches the module full path.''')
         process = property(GetProcess, None, doc='''A read only property that returns an lldb object that represents the process (lldb.SBProcess) that this target owns.''')
         executable = property(GetExecutable, None, doc='''A read only property that returns an lldb object that represents the main executable module (lldb.SBModule) for this target.''')
         debugger = property(GetDebugger, None, doc='''A read only property that returns an lldb object that represents the debugger (lldb.SBDebugger) that owns this target.''')
         num_breakpoints = property(GetNumBreakpoints, None, doc='''A read only property that returns the number of breakpoints that this target has as an integer.''')
+        breakpoints = property(get_target_bkpts, None, doc='''A read only property that returns a list() of lldb.SBBreakpoint objects for all breakpoints in this target.''')
+        breakpoint = property(get_bkpts_access_object, None, doc='''A read only property that returns an object that can be used to access breakpoints as an array ("bkpt_12 = lldb.target.bkpt[12]").''')
         num_watchpoints = property(GetNumWatchpoints, None, doc='''A read only property that returns the number of watchpoints that this target has as an integer.''')
+        watchpoints = property(get_target_watchpoints, None, doc='''A read only property that returns a list() of lldb.SBwatchpoint objects for all watchpoints in this target.''')
+        watchpoint = property(get_watchpoints_access_object, None, doc='''A read only property that returns an object that can be used to access watchpoints as an array ("watchpoint_12 = lldb.target.watchpoint[12]").''')
         broadcaster = property(GetBroadcaster, None, doc='''A read only property that an lldb object that represents the broadcaster (lldb.SBBroadcaster) for this target.''')
         byte_order = property(GetByteOrder, None, doc='''A read only property that returns an lldb enumeration value (lldb.eByteOrderLittle, lldb.eByteOrderBig, lldb.eByteOrderInvalid) that represents the byte order for this target.''')
         addr_size = property(GetAddressByteSize, None, doc='''A read only property that returns the size in bytes of an address for this target.''')
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to