[Lldb-commits] [lldb] f190ec6 - [lldb/Plugins] Add memory writing capabilities to Scripted Process
Med Ismail Bennani via lldb-commits
lldb-commits at lists.llvm.org
Fri Mar 3 19:33:24 PST 2023
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.bennani at 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();
+}
More information about the lldb-commits
mailing list