housel created this revision.
housel added a reviewer: clayborg.
housel requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

This change adds AllocateMemory and DeallocateMemory methods to the SBProcess 
API, so that clients can allocate and deallocate memory blocks within the 
process being debugged (for storing JIT-compiled code or other uses).

(I am developing a debugger + REPL using the API; it will need to store 
JIT-compiled code within the target.)


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D105389

Files:
  lldb/bindings/interface/SBProcess.i
  lldb/include/lldb/API/SBProcess.h
  lldb/source/API/SBProcess.cpp
  lldb/test/API/python_api/process/TestProcessAPI.py

Index: lldb/test/API/python_api/process/TestProcessAPI.py
===================================================================
--- lldb/test/API/python_api/process/TestProcessAPI.py
+++ lldb/test/API/python_api/process/TestProcessAPI.py
@@ -398,3 +398,55 @@
                 "Process effective group ID is invalid")
 
         process_info.GetParentProcessID()
+
+    def test_allocate_deallocate_memory(self):
+        """Test Python SBProcess.AllocateMemory() and SBProcess.DeallocateMemory() APIs."""
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+
+        target = self.dbg.CreateTarget(exe)
+        self.assertTrue(target, VALID_TARGET)
+
+        breakpoint = target.BreakpointCreateByLocation("main.cpp", self.line)
+        self.assertTrue(breakpoint, VALID_BREAKPOINT)
+
+        # Launch the process, and do not stop at the entry point.
+        process = target.LaunchSimple(
+            None, None, self.get_process_working_directory())
+
+        thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint)
+        self.assertTrue(
+            thread.IsValid(),
+            "There should be a thread stopped due to breakpoint")
+        frame = thread.GetFrameAtIndex(0)
+
+        # Allocate a block of memory in the target process
+        error = lldb.SBError()
+        addr = process.AllocateMemory(16384, lldb.ePermissionsWritable | lldb.ePermissionsReadable, error)
+        if not error.Success() or addr == lldb.LLDB_INVALID_ADDRESS:
+            self.fail("SBProcess.AllocateMemory() failed")
+
+        # Now use WriteMemory() API to write 'a' into the allocated memory
+        result = process.WriteMemory(addr, 'a', error)
+        if not error.Success() or result != 1:
+            self.fail("SBProcess.WriteMemory() failed")
+
+        # Read from the memory location.  This time it should be 'a'.
+        # Due to the typemap magic (see lldb.swig), we pass in 1 to ReadMemory and
+        # expect to get a Python string as the result object!
+        content = process.ReadMemory(addr, 1, error)
+        if not error.Success():
+            self.fail("SBProcess.ReadMemory() failed")
+        if self.TraceOn():
+            print("memory content:", content)
+
+        self.expect(
+            content,
+            "Result from SBProcess.ReadMemory() matches our expected output: 'a'",
+            exe=False,
+            startstr=b'a')
+
+        # Deallocate the memory
+        error = process.DeallocateMemory(addr)
+        if not error.Success():
+            self.fail("SBProcess.DeallocateMemory() failed")
Index: lldb/source/API/SBProcess.cpp
===================================================================
--- lldb/source/API/SBProcess.cpp
+++ lldb/source/API/SBProcess.cpp
@@ -1288,6 +1288,50 @@
   return LLDB_RECORD_RESULT(sb_proc_info);
 }
 
+lldb::addr_t SBProcess::AllocateMemory(size_t size, uint32_t permissions, lldb::SBError &sb_error) {
+  LLDB_RECORD_METHOD(lldb::addr_t, SBProcess, AllocateMemory,
+                     (size_t, uint32_t, lldb::SBError &), size, permissions, sb_error);
+
+  lldb::addr_t addr = LLDB_INVALID_ADDRESS;
+  ProcessSP process_sp(GetSP());
+  if (process_sp) {
+    Process::StopLocker stop_locker;
+    if (stop_locker.TryLock(&process_sp->GetRunLock())) {
+      std::lock_guard<std::recursive_mutex> guard(
+          process_sp->GetTarget().GetAPIMutex());
+      addr = process_sp->AllocateMemory(size, permissions, sb_error.ref());
+    } else {
+      sb_error.SetErrorString("process is running");
+    }
+  } else {
+    sb_error.SetErrorString("SBProcess is invalid");
+  }
+  return addr;
+}
+
+lldb::SBError SBProcess::DeallocateMemory(lldb::addr_t ptr) {
+  LLDB_RECORD_METHOD(lldb::SBError, SBProcess, DeallocateMemory, (lldb::addr_t),
+                     ptr);
+
+  lldb::SBError sb_error;
+  ProcessSP process_sp(GetSP());
+  if (process_sp) {
+    Process::StopLocker stop_locker;
+    if (stop_locker.TryLock(&process_sp->GetRunLock())) {
+      std::lock_guard<std::recursive_mutex> guard(
+          process_sp->GetTarget().GetAPIMutex());
+      Status error = process_sp->DeallocateMemory(ptr);
+      sb_error.SetError(error);
+    } else {
+      sb_error.SetErrorString("process is running");
+    }
+  } else {
+    sb_error.SetErrorString("SBProcess is invalid");
+  }
+  return sb_error;
+}
+
+
 namespace lldb_private {
 namespace repro {
 
@@ -1417,6 +1461,10 @@
   LLDB_REGISTER_METHOD(lldb::SBMemoryRegionInfoList, SBProcess,
                        GetMemoryRegions, ());
   LLDB_REGISTER_METHOD(lldb::SBProcessInfo, SBProcess, GetProcessInfo, ());
+  LLDB_REGISTER_METHOD(lldb::addr_t, SBProcess, AllocateMemory,
+                       (size_t, uint32_t, lldb::SBError &));
+  LLDB_REGISTER_METHOD(lldb::SBError, SBProcess, DeallocateMemory,
+                       (lldb::addr_t));
 
   LLDB_REGISTER_CHAR_PTR_METHOD_CONST(size_t, SBProcess, GetSTDOUT);
   LLDB_REGISTER_CHAR_PTR_METHOD_CONST(size_t, SBProcess, GetSTDERR);
Index: lldb/include/lldb/API/SBProcess.h
===================================================================
--- lldb/include/lldb/API/SBProcess.h
+++ lldb/include/lldb/API/SBProcess.h
@@ -370,6 +370,44 @@
   /// valid.
   lldb::SBProcessInfo GetProcessInfo();
 
+  /// Allocate memory within the process.
+  ///
+  /// This function will allocate memory in the process's address space.
+  ///
+  /// \param[in] size
+  ///     The size of the allocation requested.
+  ///
+  /// \param[in] permissions
+  ///     Or together any of the lldb::Permissions bits.  The
+  ///     permissions on a given memory allocation can't be changed
+  ///     after allocation.  Note that a block that isn't set writable
+  ///     can still be written from lldb, just not by the process
+  ///     itself.
+  ///
+  /// \param[out] error
+  ///     An error object that gets filled in with any errors that
+  ///     might occur when trying allocate.
+  ///
+  /// \return
+  ///     The address of the allocated buffer in the process, or
+  ///     LLDB_INVALID_ADDRESS if the allocation failed.
+  lldb::addr_t AllocateMemory(size_t size, uint32_t permissions, lldb::SBError &error);
+
+  /// Deallocate memory in the process.
+  ///
+  /// This function will deallocate memory in the process's address
+  /// space that was allocated with AllocateMemory.
+  ///
+  /// \param[in] ptr
+  ///     A return value from AllocateMemory, pointing to the memory you
+  ///     want to deallocate.
+  ///
+  /// \return
+  ///     An error object describes any errors that occurred while
+  ///     deallocating.
+  ///
+  lldb::SBError DeallocateMemory(lldb::addr_t ptr);
+
 protected:
   friend class SBAddress;
   friend class SBBreakpoint;
Index: lldb/bindings/interface/SBProcess.i
===================================================================
--- lldb/bindings/interface/SBProcess.i
+++ lldb/bindings/interface/SBProcess.i
@@ -417,6 +417,12 @@
     lldb::SBProcessInfo
     GetProcessInfo();
 
+    lldb::addr_t
+    AllocateMemory(size_t size, uint32_t permissions, lldb::SBError &error);
+
+    lldb::SBError
+    DeallocateMemory(lldb::addr_t ptr);
+
     STRING_EXTENSION(SBProcess)
 
 #ifdef SWIGPYTHON
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to