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 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/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 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 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/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")