[Lldb-commits] [lldb] 2e7ec44 - [lldb] Add AllocateMemory/DeallocateMemory to the SBProcess API

Raphael Isemann via lldb-commits lldb-commits at lists.llvm.org
Thu Jul 15 15:45:48 PDT 2021


Author: Peter S. Housel
Date: 2021-07-16T00:45:22+02:00
New Revision: 2e7ec447cc7eab89a72413ad91a897049f551c56

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

LOG: [lldb] Add AllocateMemory/DeallocateMemory to the SBProcess API

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.)

Reviewed By: clayborg, jingham

Differential Revision: https://reviews.llvm.org/D105389

Added: 
    

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

Removed: 
    


################################################################################
diff  --git a/lldb/bindings/interface/SBProcess.i b/lldb/bindings/interface/SBProcess.i
index 27c015df85cda..14566a2942d04 100644
--- a/lldb/bindings/interface/SBProcess.i
+++ b/lldb/bindings/interface/SBProcess.i
@@ -417,6 +417,25 @@ public:
     lldb::SBProcessInfo
     GetProcessInfo();
 
+    %feature("autodoc", "
+    Allocates a block of memory within the process, with size and
+    access permissions specified in the arguments. The permisssions
+    argument is an or-combination of zero or more of
+    lldb.ePermissionsWritable, lldb.ePermissionsReadable, and
+    lldb.ePermissionsExecutable. Returns the address
+    of the allocated buffer in the process, or
+    lldb.LLDB_INVALID_ADDRESS if the allocation failed.") AllocateMemory;
+
+    lldb::addr_t
+    AllocateMemory(size_t size, uint32_t permissions, lldb::SBError &error);
+
+    %feature("autodoc", "
+    Deallocates the block of memory (previously allocated using
+    AllocateMemory) given in the argument.") DeallocateMemory;
+
+    lldb::SBError
+    DeallocateMemory(lldb::addr_t ptr);
+
     STRING_EXTENSION(SBProcess)
 
 #ifdef SWIGPYTHON

diff  --git a/lldb/include/lldb/API/SBProcess.h b/lldb/include/lldb/API/SBProcess.h
index a5676c2cab9a8..73a8d918f4d65 100644
--- a/lldb/include/lldb/API/SBProcess.h
+++ b/lldb/include/lldb/API/SBProcess.h
@@ -370,6 +370,45 @@ class LLDB_API SBProcess {
   /// 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;

diff  --git a/lldb/source/API/SBProcess.cpp b/lldb/source/API/SBProcess.cpp
index f0c7c5f75a2e5..47c35a23b0781 100644
--- a/lldb/source/API/SBProcess.cpp
+++ b/lldb/source/API/SBProcess.cpp
@@ -1288,6 +1288,51 @@ lldb::SBProcessInfo SBProcess::GetProcessInfo() {
   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 +1462,10 @@ void RegisterMethods<SBProcess>(Registry &R) {
   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);

diff  --git a/lldb/test/API/python_api/process/TestProcessAPI.py b/lldb/test/API/python_api/process/TestProcessAPI.py
index b7efc7e4affa6..790d794890d60 100644
--- a/lldb/test/API/python_api/process/TestProcessAPI.py
+++ b/lldb/test/API/python_api/process/TestProcessAPI.py
@@ -398,3 +398,58 @@ def test_get_process_info(self):
                 "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()
+        (target, process, main_thread, main_breakpoint) = lldbutil.run_to_source_breakpoint(
+            self, "// Set break point at this line", lldb.SBFileSpec("main.cpp"))
+
+        # Allocate a block of memory in the target process
+        error = lldb.SBError()
+        addr = process.AllocateMemory(16384, 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. Note that the debugger can do this even though the
+        # block is not set writable.
+        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')
+
+        # Verify that the process itself can read the allocated memory
+        frame = main_thread.GetFrameAtIndex(0)
+        val = frame.EvaluateExpression(
+            "test_read(reinterpret_cast<char *>({:#x}))".format(addr))
+        self.expect(val.GetValue(),
+                    "Result of test_read() matches expected output 'a'",
+                    exe=False,
+                    startstr="'a'")
+
+        # Verify that the process cannot write into the block
+        val = frame.EvaluateExpression(
+            "test_write(reinterpret_cast<char *>({:#x}), 'b')".format(addr))
+        if val.GetError().Success():
+            self.fail(
+                "test_write() to allocated memory without write permission unexpectedly succeeded")
+
+        # Deallocate the memory
+        error = process.DeallocateMemory(addr)
+        if not error.Success():
+            self.fail("SBProcess.DeallocateMemory() failed")

diff  --git a/lldb/test/API/python_api/process/main.cpp b/lldb/test/API/python_api/process/main.cpp
index f3cc7e12d3357..07cde05e2a054 100644
--- a/lldb/test/API/python_api/process/main.cpp
+++ b/lldb/test/API/python_api/process/main.cpp
@@ -21,3 +21,13 @@ int main (int argc, char const *argv[])
     return 0; // Set break point at this line and check variable 'my_char'.
               // Use lldb Python API to set memory content for my_int and check the result.
 }
+
+char test_read (char *ptr)
+{
+    return *ptr;
+}
+
+void test_write (char *ptr, char c)
+{
+    *ptr = c;
+}


        


More information about the lldb-commits mailing list