[Lldb-commits] [lldb] f190ec6 - [lldb/Plugins] Add memory writing capabilities to Scripted Process

Med Ismail Bennani via lldb-commits lldb-commits at lists.llvm.org
Fri Mar 3 19:33:24 PST 2023


Author: Med Ismail Bennani
Date: 2023-03-03T19:33:02-08:00
New Revision: f190ec6882706d30c606e62986512371925288a9

URL: https://github.com/llvm/llvm-project/commit/f190ec6882706d30c606e62986512371925288a9
DIFF: https://github.com/llvm/llvm-project/commit/f190ec6882706d30c606e62986512371925288a9.diff

LOG: [lldb/Plugins] Add memory writing capabilities to Scripted Process

This patch adds memory writing capabilities to the Scripted Process plugin.

This allows to user to get a target address and a memory buffer on the
python scripted process implementation that the user can make processing
on before performing the actual write.

This will also be used to write trap instruction to a real process
memory to set a breakpoint.

Signed-off-by: Med Ismail Bennani <medismail.bennani at gmail.com>

Added: 
    

Modified: 
    lldb/bindings/python/python-swigsafecast.swig
    lldb/examples/python/scripted_process/scripted_process.py
    lldb/include/lldb/Interpreter/ScriptedProcessInterface.h
    lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
    lldb/source/Plugins/Process/scripted/ScriptedProcess.h
    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.h
    lldb/source/Target/Memory.cpp
    lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py
    lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py
    lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/bindings/python/python-swigsafecast.swig b/lldb/bindings/python/python-swigsafecast.swig
index ae562c26518c..f7e78bb419bd 100644
--- a/lldb/bindings/python/python-swigsafecast.swig
+++ b/lldb/bindings/python/python-swigsafecast.swig
@@ -103,6 +103,11 @@ PythonObject ToSWIGWrapper(lldb::ProcessLaunchInfoSP launch_info_sp) {
                        SWIGTYPE_p_lldb__SBAttachInfo);
  }
 
+PythonObject ToSWIGWrapper(lldb::DataExtractorSP data_sp) {
+  return ToSWIGHelper(new lldb::DataExtractorSP(std::move(data_sp)),
+                      SWIGTYPE_p_lldb__SBData);
+}
+
 ScopedPythonObject<lldb::SBCommandReturnObject>
 ToSWIGWrapper(CommandReturnObject &cmd_retobj) {
   return ScopedPythonObject<lldb::SBCommandReturnObject>(

diff  --git a/lldb/examples/python/scripted_process/scripted_process.py b/lldb/examples/python/scripted_process/scripted_process.py
index 60b65fc4b4c9..044aee133880 100644
--- a/lldb/examples/python/scripted_process/scripted_process.py
+++ b/lldb/examples/python/scripted_process/scripted_process.py
@@ -98,6 +98,21 @@ def read_memory_at_address(self, addr, size, error):
         """
         pass
 
+    def write_memory_at_address(self, addr, data, error):
+        """ Write a buffer to the scripted process memory.
+
+        Args:
+            addr (int): Address from which we should start reading.
+            data (lldb.SBData): An `lldb.SBData` buffer to write to the
+                process memory.
+            error (lldb.SBError): Error object.
+
+        Returns:
+            size (int): Size of the memory to read.
+        """
+        error.SetErrorString("%s doesn't support memory writes." % self.__class__.__name__)
+        return 0
+
     def get_loaded_images(self):
         """ Get the list of loaded images for the scripted process.
 

diff  --git a/lldb/include/lldb/Interpreter/ScriptedProcessInterface.h b/lldb/include/lldb/Interpreter/ScriptedProcessInterface.h
index ec0d7deac01b..ba4743077e02 100644
--- a/lldb/include/lldb/Interpreter/ScriptedProcessInterface.h
+++ b/lldb/include/lldb/Interpreter/ScriptedProcessInterface.h
@@ -55,6 +55,12 @@ class ScriptedProcessInterface : virtual public ScriptedInterface {
     return {};
   }
 
+  virtual size_t WriteMemoryAtAddress(lldb::addr_t addr,
+                                      lldb::DataExtractorSP data_sp,
+                                      Status &error) {
+    return LLDB_INVALID_OFFSET;
+  };
+
   virtual StructuredData::ArraySP GetLoadedImages() { return {}; }
 
   virtual lldb::pid_t GetProcessID() { return LLDB_INVALID_PROCESS_ID; }

diff  --git a/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp b/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
index 84e9dea4b7be..948ee691ecbe 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
+++ b/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
@@ -255,7 +255,31 @@ size_t ScriptedProcess::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
     return ScriptedInterface::ErrorWithMessage<size_t>(
         LLVM_PRETTY_FUNCTION, "Failed to copy read memory to buffer.", error);
 
-  return size;
+  // FIXME: We should use the diagnostic system to report a warning if the
+  // `bytes_copied` is 
diff erent from `size`.
+
+  return bytes_copied;
+}
+
+size_t ScriptedProcess::DoWriteMemory(lldb::addr_t vm_addr, const void *buf,
+                                      size_t size, Status &error) {
+  lldb::DataExtractorSP data_extractor_sp = std::make_shared<DataExtractor>(
+      buf, size, GetByteOrder(), GetAddressByteSize());
+
+  if (!data_extractor_sp || !data_extractor_sp->GetByteSize())
+    return 0;
+
+  size_t bytes_written =
+      GetInterface().WriteMemoryAtAddress(vm_addr, data_extractor_sp, error);
+
+  if (!bytes_written || bytes_written == LLDB_INVALID_OFFSET)
+    return ScriptedInterface::ErrorWithMessage<size_t>(
+        LLVM_PRETTY_FUNCTION, "Failed to copy write buffer to memory.", error);
+
+  // FIXME: We should use the diagnostic system to report a warning if the
+  // `bytes_written` is 
diff erent from `size`.
+
+  return bytes_written;
 }
 
 ArchSpec ScriptedProcess::GetArchitecture() {

diff  --git a/lldb/source/Plugins/Process/scripted/ScriptedProcess.h b/lldb/source/Plugins/Process/scripted/ScriptedProcess.h
index 004ee7c12742..3601173e99cf 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedProcess.h
+++ b/lldb/source/Plugins/Process/scripted/ScriptedProcess.h
@@ -69,6 +69,9 @@ class ScriptedProcess : public Process {
   size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
                       Status &error) override;
 
+  size_t DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
+                       Status &error) override;
+
   ArchSpec GetArchitecture();
 
   Status

diff  --git a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
index 7b7ceff30b65..2812cc78189d 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
@@ -79,6 +79,7 @@ PythonObject ToSWIGWrapper(const SymbolContext &sym_ctx);
 
 PythonObject ToSWIGWrapper(lldb::ProcessAttachInfoSP attach_info_sp);
 PythonObject ToSWIGWrapper(lldb::ProcessLaunchInfoSP launch_info_sp);
+PythonObject ToSWIGWrapper(lldb::DataExtractorSP data_extractor_sp);
 
 PythonObject ToSWIGWrapper(std::unique_ptr<lldb::SBValue> value_sb);
 PythonObject ToSWIGWrapper(std::unique_ptr<lldb::SBStream> stream_sb);

diff  --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
index 3ca4664587df..cffa3bda3ab0 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp
@@ -135,6 +135,22 @@ lldb::DataExtractorSP ScriptedProcessPythonInterface::ReadMemoryAtAddress(
   return data_sp;
 }
 
+size_t ScriptedProcessPythonInterface::WriteMemoryAtAddress(
+    lldb::addr_t addr, lldb::DataExtractorSP data_sp, Status &error) {
+  Status py_error;
+  StructuredData::ObjectSP obj =
+      Dispatch("write_memory_at_address", py_error, addr, data_sp, error);
+
+  if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error))
+    return LLDB_INVALID_OFFSET;
+
+  // If there was an error on the python call, surface it to the user.
+  if (py_error.Fail())
+    error = py_error;
+
+  return obj->GetIntegerValue(LLDB_INVALID_OFFSET);
+}
+
 StructuredData::ArraySP ScriptedProcessPythonInterface::GetLoadedImages() {
   Status error;
   StructuredData::ArraySP array =

diff  --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h
index 44273f1d0d0c..b7b12b93a002 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h
@@ -49,7 +49,9 @@ class ScriptedProcessPythonInterface : public ScriptedProcessInterface,
 
   lldb::DataExtractorSP ReadMemoryAtAddress(lldb::addr_t address, size_t size,
                                             Status &error) override;
-                                         
+
+  size_t WriteMemoryAtAddress(lldb::addr_t addr, lldb::DataExtractorSP data_sp,
+                              Status &error) override;
 
   StructuredData::ArraySP GetLoadedImages() override;
 

diff  --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
index aa09be79086a..a015bd106b5c 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h
@@ -125,6 +125,10 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
     return python::ToSWIGWrapper(arg);
   }
 
+  python::PythonObject Transform(lldb::DataExtractorSP arg) {
+    return python::ToSWIGWrapper(arg);
+  }
+
   template <typename T, typename U>
   void ReverseTransform(T &original_arg, U transformed_arg, Status &error) {
     // If U is not a PythonObject, don't touch it!

diff  --git a/lldb/source/Target/Memory.cpp b/lldb/source/Target/Memory.cpp
index d4dedeea7c2c..fdc01389721e 100644
--- a/lldb/source/Target/Memory.cpp
+++ b/lldb/source/Target/Memory.cpp
@@ -234,11 +234,11 @@ size_t MemoryCache::Read(addr_t addr, void *dst, size_t dst_len,
           return dst_len - bytes_left;
 
         if (process_bytes_read != cache_line_byte_size) {
+          data_buffer_heap_up->SetByteSize(process_bytes_read);
           if (process_bytes_read < data_buffer_heap_up->GetByteSize()) {
             dst_len -= data_buffer_heap_up->GetByteSize() - process_bytes_read;
             bytes_left = process_bytes_read;
           }
-          data_buffer_heap_up->SetByteSize(process_bytes_read);
         }
         m_L2_cache[curr_addr] = DataBufferSP(data_buffer_heap_up.release());
         // We have read data and put it into the cache, continue through the

diff  --git a/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py b/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py
index 053654c14421..5a198cc95704 100644
--- a/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py
+++ b/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py
@@ -150,7 +150,6 @@ def cleanup():
         self.assertEqual(process_1.GetNumThreads(), 1)
 
         # ... then try reading from target #1 process ...
-        addr = 0x500000000
         message = "Hello, target 1"
         buff = process_1.ReadCStringFromMemory(addr, len(message) + 1, error)
         self.assertSuccess(error)
@@ -158,12 +157,22 @@ def cleanup():
 
         # ... now, reading again from target #0 process to make sure the call
         # gets dispatched to the right target.
-        addr = 0x500000000
         message = "Hello, target 0"
         buff = process_0.ReadCStringFromMemory(addr, len(message) + 1, error)
         self.assertSuccess(error)
         self.assertEqual(buff, message)
 
+        # Let's write some memory.
+        message = "Hello, world!"
+        bytes_written = process_0.WriteMemoryAsCString(addr, message, error)
+        self.assertSuccess(error)
+        self.assertEqual(bytes_written, len(message) + 1)
+
+        # ... and check if that memory was saved properly.
+        buff = process_0.ReadCStringFromMemory(addr, len(message) + 1, error)
+        self.assertSuccess(error)
+        self.assertEqual(buff, message)
+
         thread = process_0.GetSelectedThread()
         self.assertTrue(thread, "Invalid thread.")
         self.assertEqual(thread.GetThreadID(), 0x19)

diff  --git a/lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py b/lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py
index 47038144bb08..3f6ce6c1f9fe 100644
--- a/lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py
+++ b/lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py
@@ -7,20 +7,29 @@
 from lldb.plugins.scripted_process import ScriptedThread
 
 class DummyScriptedProcess(ScriptedProcess):
+    memory = None
+
     def __init__(self, exe_ctx: lldb.SBExecutionContext, args : lldb.SBStructuredData):
         super().__init__(exe_ctx, args)
         self.threads[0] = DummyScriptedThread(self, None)
-
-    def read_memory_at_address(self, addr: int, size: int, error: lldb.SBError) -> lldb.SBData:
+        self.memory = {}
+        addr = 0x500000000
         debugger = self.target.GetDebugger()
         index = debugger.GetIndexOfTarget(self.target)
+        self.memory[addr] = "Hello, target " + str(index)
+
+    def read_memory_at_address(self, addr: int, size: int, error: lldb.SBError) -> lldb.SBData:
         data = lldb.SBData().CreateDataFromCString(
                                     self.target.GetByteOrder(),
                                     self.target.GetCodeByteSize(),
-                                    "Hello, target " + str(index))
+                                    self.memory[addr])
 
         return data
 
+    def write_memory_at_address(self, addr, data, error):
+        self.memory[addr] = data.GetString(error, 0)
+        return len(self.memory[addr]) + 1
+
     def get_loaded_images(self):
         return self.loaded_images
 

diff  --git a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
index 1a8ad866e66c..59ba0b7b6aea 100644
--- a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
+++ b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
@@ -286,3 +286,8 @@ python::PythonObject
 lldb_private::python::ToSWIGWrapper(lldb::ProcessLaunchInfoSP) {
   return python::PythonObject();
 }
+
+python::PythonObject
+lldb_private::python::ToSWIGWrapper(lldb::DataExtractorSP) {
+  return python::PythonObject();
+}


        


More information about the lldb-commits mailing list