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 @@ -98,6 +98,21 @@ """ 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 writting." % self.__class__.__name__) + return 0 + def get_loaded_images(self): """ Get the list of loaded images for the scripted process. Index: lldb/include/lldb/Interpreter/ScriptedProcessInterface.h =================================================================== --- lldb/include/lldb/Interpreter/ScriptedProcessInterface.h +++ lldb/include/lldb/Interpreter/ScriptedProcessInterface.h @@ -52,6 +52,11 @@ ReadMemoryAtAddress(lldb::addr_t address, size_t size, Status &error) { return {}; } + + virtual size_t + WriteMemoryAtAddress(lldb::addr_t addr, lldb::DataExtractorSP data_sp, Status &error) { + return LLDB_INVALID_OFFSET; + }; virtual StructuredData::ArraySP GetLoadedImages() { return {}; } Index: lldb/source/Plugins/Process/scripted/ScriptedProcess.h =================================================================== --- lldb/source/Plugins/Process/scripted/ScriptedProcess.h +++ lldb/source/Plugins/Process/scripted/ScriptedProcess.h @@ -68,6 +68,9 @@ 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(); Index: lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp =================================================================== --- lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp +++ lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp @@ -307,6 +307,22 @@ return size; } +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(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( + LLVM_PRETTY_FUNCTION, "Failed to copy write buffer to memory.", error); + + return size; +} + ArchSpec ScriptedProcess::GetArchitecture() { return GetTarget().GetArchitecture(); } Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h +++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h @@ -50,6 +50,7 @@ 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; Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp +++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp @@ -131,6 +131,20 @@ 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 = Index: lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py =================================================================== --- lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py +++ lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py @@ -150,7 +150,6 @@ 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 @@ # ... 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.WriteCStringToMemory(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) Index: lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py =================================================================== --- lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py +++ 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]) + def get_loaded_images(self): return self.loaded_images