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.benn...@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(); +} _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits