Index: lldb/bindings/python/python-swigsafecast.swig =================================================================== --- lldb/bindings/python/python-swigsafecast.swig +++ lldb/bindings/python/python-swigsafecast.swig @@ -5,28 +5,6 @@ return {PyRefType::Owned, SWIG_NewPointerObj(obj, info, SWIG_POINTER_OWN)}; } -/// A class that automatically clears an SB object when it goes out of scope. -/// Use for cases where the SB object points to a temporary/unowned entity. -template class ScopedPythonObject : PythonObject { -public: - ScopedPythonObject(T *sb, swig_type_info *info) - : PythonObject(ToSWIGHelper(sb, info)), m_sb(sb) {} - ~ScopedPythonObject() { - if (m_sb) - *m_sb = T(); - } - ScopedPythonObject(ScopedPythonObject &&rhs) - : PythonObject(std::move(rhs)), m_sb(std::exchange(rhs.m_sb, nullptr)) {} - ScopedPythonObject(const ScopedPythonObject &) = delete; - ScopedPythonObject &operator=(const ScopedPythonObject &) = delete; - ScopedPythonObject &operator=(ScopedPythonObject &&) = delete; - - const PythonObject &obj() const { return *this; } - -private: - T *m_sb; -}; - PythonObject ToSWIGWrapper(std::unique_ptr value_sb) { return ToSWIGHelper(value_sb.release(), SWIGTYPE_p_lldb__SBValue); } @@ -55,6 +33,11 @@ SWIGTYPE_p_lldb__SBBreakpoint); } +PythonObject ToSWIGWrapper(lldb::StatusSP status_sp) { + return ToSWIGHelper(new lldb::SBError(std::move(status_sp)), + SWIGTYPE_p_lldb__SBError); +} + PythonObject ToSWIGWrapper(std::unique_ptr stream_sb) { return ToSWIGHelper(stream_sb.release(), SWIGTYPE_p_lldb__SBStream); } 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 @@ -167,6 +167,19 @@ """ pass + def write_memory_at_address(self, addr, buf, size): + """ Write a buffer at a certain address in the scripted process memory. + + Args: + addr (int): Address from which we should start reading. + buf (bytes): The buffer storing the data to be written. + size (int): Size of the data to be written. + + Returns: + int: Size of the data written. + """ + return 0 + def get_loaded_images(self): """ Get the list of loaded images for the scripted process. Index: lldb/include/lldb/API/SBError.h =================================================================== --- lldb/include/lldb/API/SBError.h +++ lldb/include/lldb/API/SBError.h @@ -22,6 +22,8 @@ SBError(); SBError(const lldb::SBError &rhs); + + SBError(const lldb::StatusSP &status_sp); ~SBError(); @@ -90,7 +92,7 @@ void SetError(const lldb_private::Status &lldb_error); private: - std::unique_ptr m_opaque_up; + std::shared_ptr m_opaque_sp; void CreateIfNeeded(); }; Index: lldb/include/lldb/Interpreter/ScriptedProcessInterface.h =================================================================== --- lldb/include/lldb/Interpreter/ScriptedProcessInterface.h +++ lldb/include/lldb/Interpreter/ScriptedProcessInterface.h @@ -69,6 +69,11 @@ ReadMemoryAtAddress(lldb::addr_t address, size_t size, Status &error) { return nullptr; } + + virtual size_t + WriteMemoryAtAddress(lldb::addr_t address, const void* buf, size_t size, Status &error) { + return 0; + } virtual StructuredData::ArraySP GetLoadedImages() { return nullptr; } Index: lldb/include/lldb/lldb-forward.h =================================================================== --- lldb/include/lldb/lldb-forward.h +++ lldb/include/lldb/lldb-forward.h @@ -393,6 +393,7 @@ StackFrameRecognizerSP; typedef std::unique_ptr StackFrameRecognizerManagerUP; +typedef std::shared_ptr StatusSP; typedef std::shared_ptr StopInfoSP; typedef std::shared_ptr StreamSP; typedef std::shared_ptr StreamFileSP; Index: lldb/source/API/SBError.cpp =================================================================== --- lldb/source/API/SBError.cpp +++ lldb/source/API/SBError.cpp @@ -22,7 +22,11 @@ SBError::SBError(const SBError &rhs) { LLDB_INSTRUMENT_VA(this, rhs); - m_opaque_up = clone(rhs.m_opaque_up); + m_opaque_sp = clone(rhs.m_opaque_sp); +} + +SBError::SBError(const lldb::StatusSP &status_sp) : m_opaque_sp(status_sp) { + LLDB_INSTRUMENT_VA(this, status_sp); } SBError::~SBError() = default; @@ -31,31 +35,31 @@ LLDB_INSTRUMENT_VA(this, rhs); if (this != &rhs) - m_opaque_up = clone(rhs.m_opaque_up); + m_opaque_sp = clone(rhs.m_opaque_sp); return *this; } const char *SBError::GetCString() const { LLDB_INSTRUMENT_VA(this); - if (m_opaque_up) - return m_opaque_up->AsCString(); + if (m_opaque_sp) + return m_opaque_sp->AsCString(); return nullptr; } void SBError::Clear() { LLDB_INSTRUMENT_VA(this); - if (m_opaque_up) - m_opaque_up->Clear(); + if (m_opaque_sp) + m_opaque_sp->Clear(); } bool SBError::Fail() const { LLDB_INSTRUMENT_VA(this); bool ret_value = false; - if (m_opaque_up) - ret_value = m_opaque_up->Fail(); + if (m_opaque_sp) + ret_value = m_opaque_sp->Fail(); return ret_value; @@ -65,8 +69,8 @@ LLDB_INSTRUMENT_VA(this); bool ret_value = true; - if (m_opaque_up) - ret_value = m_opaque_up->Success(); + if (m_opaque_sp) + ret_value = m_opaque_sp->Success(); return ret_value; } @@ -75,8 +79,8 @@ LLDB_INSTRUMENT_VA(this); uint32_t err = 0; - if (m_opaque_up) - err = m_opaque_up->GetError(); + if (m_opaque_sp) + err = m_opaque_sp->GetError(); return err; @@ -86,8 +90,8 @@ LLDB_INSTRUMENT_VA(this); ErrorType err_type = eErrorTypeInvalid; - if (m_opaque_up) - err_type = m_opaque_up->GetType(); + if (m_opaque_sp) + err_type = m_opaque_sp->GetType(); return err_type; } @@ -96,40 +100,40 @@ LLDB_INSTRUMENT_VA(this, err, type); CreateIfNeeded(); - m_opaque_up->SetError(err, type); + m_opaque_sp->SetError(err, type); } void SBError::SetError(const Status &lldb_error) { CreateIfNeeded(); - *m_opaque_up = lldb_error; + *m_opaque_sp = lldb_error; } void SBError::SetErrorToErrno() { LLDB_INSTRUMENT_VA(this); CreateIfNeeded(); - m_opaque_up->SetErrorToErrno(); + m_opaque_sp->SetErrorToErrno(); } void SBError::SetErrorToGenericError() { LLDB_INSTRUMENT_VA(this); CreateIfNeeded(); - m_opaque_up->SetErrorToGenericError(); + m_opaque_sp->SetErrorToGenericError(); } void SBError::SetErrorString(const char *err_str) { LLDB_INSTRUMENT_VA(this, err_str); CreateIfNeeded(); - m_opaque_up->SetErrorString(err_str); + m_opaque_sp->SetErrorString(err_str); } int SBError::SetErrorStringWithFormat(const char *format, ...) { CreateIfNeeded(); va_list args; va_start(args, format); - int num_chars = m_opaque_up->SetErrorStringWithVarArg(format, args); + int num_chars = m_opaque_sp->SetErrorStringWithVarArg(format, args); va_end(args); return num_chars; } @@ -141,33 +145,33 @@ SBError::operator bool() const { LLDB_INSTRUMENT_VA(this); - return m_opaque_up != nullptr; + return m_opaque_sp != nullptr; } void SBError::CreateIfNeeded() { - if (m_opaque_up == nullptr) - m_opaque_up = std::make_unique(); + if (m_opaque_sp == nullptr) + m_opaque_sp = std::make_unique(); } -lldb_private::Status *SBError::operator->() { return m_opaque_up.get(); } +lldb_private::Status *SBError::operator->() { return m_opaque_sp.get(); } -lldb_private::Status *SBError::get() { return m_opaque_up.get(); } +lldb_private::Status *SBError::get() { return m_opaque_sp.get(); } lldb_private::Status &SBError::ref() { CreateIfNeeded(); - return *m_opaque_up; + return *m_opaque_sp; } const lldb_private::Status &SBError::operator*() const { // Be sure to call "IsValid()" before calling this function or it will crash - return *m_opaque_up; + return *m_opaque_sp; } bool SBError::GetDescription(SBStream &description) { LLDB_INSTRUMENT_VA(this, description); - if (m_opaque_up) { - if (m_opaque_up->Success()) + if (m_opaque_sp) { + if (m_opaque_sp->Success()) description.Printf("success"); else { const char *err_string = GetCString(); Index: lldb/source/Interpreter/ScriptInterpreter.cpp =================================================================== --- lldb/source/Interpreter/ScriptInterpreter.cpp +++ lldb/source/Interpreter/ScriptInterpreter.cpp @@ -81,8 +81,8 @@ Status ScriptInterpreter::GetStatusFromSBError(const lldb::SBError &error) const { - if (error.m_opaque_up) - return *error.m_opaque_up.get(); + if (error.m_opaque_sp) + return *error.m_opaque_sp; return Status(); } Index: lldb/source/Plugins/Process/scripted/ScriptedProcess.h =================================================================== --- lldb/source/Plugins/Process/scripted/ScriptedProcess.h +++ lldb/source/Plugins/Process/scripted/ScriptedProcess.h @@ -83,6 +83,9 @@ size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, Status &error) override; + + size_t DoWriteMemory(lldb::addr_t 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 @@ -338,6 +338,21 @@ return size; } +size_t ScriptedProcess::DoWriteMemory(lldb::addr_t addr, const void *buf, + size_t size, Status &error) { + if (!m_interpreter) + return ScriptedInterface::ErrorWithMessage( + LLVM_PRETTY_FUNCTION, "No interpreter.", error); + + size_t bytes_written = GetInterface().WriteMemoryAtAddress(addr, buf, size, error); + + if (!bytes_written || error.Fail()) + return ScriptedInterface::ErrorWithMessage( + LLVM_PRETTY_FUNCTION, "Failed to write buffer to memory.", error); + + return size; +} + ArchSpec ScriptedProcess::GetArchitecture() { return GetTarget().GetArchitecture(); } Index: lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h +++ lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h @@ -23,7 +23,66 @@ #include "lldb/lldb-types.h" #include "llvm/Support/Error.h" +namespace lldb { +class SBEvent; +class SBCommandReturnObject; +class SBValue; +class SBStream; +class SBStructuredData; +} + namespace lldb_private { + namespace python { + typedef struct swig_type_info swig_type_info; + + python::PythonObject ToSWIGHelper(void *obj, swig_type_info *info); + + /// A class that automatically clears an SB object when it goes out of scope. + /// Use for cases where the SB object points to a temporary/unowned entity. + template class ScopedPythonObject : PythonObject { + public: + ScopedPythonObject(T *sb, swig_type_info *info) + : PythonObject(ToSWIGHelper(sb, info)), m_sb(sb) {} + ~ScopedPythonObject() { + if (m_sb) + *m_sb = T(); + } + ScopedPythonObject(ScopedPythonObject &&rhs) + : PythonObject(std::move(rhs)), m_sb(std::exchange(rhs.m_sb, nullptr)) {} + ScopedPythonObject(const ScopedPythonObject &) = delete; + ScopedPythonObject &operator=(const ScopedPythonObject &) = delete; + ScopedPythonObject &operator=(ScopedPythonObject &&) = delete; + + const PythonObject &obj() const { return *this; } + + private: + T *m_sb; + }; + + python::PythonObject ToSWIGWrapper(lldb::ValueObjectSP value_sp); + python::PythonObject ToSWIGWrapper(lldb::TargetSP target_sp); + python::PythonObject ToSWIGWrapper(lldb::ProcessSP process_sp); + python::PythonObject ToSWIGWrapper(lldb::ThreadPlanSP thread_plan_sp); + python::PythonObject ToSWIGWrapper(lldb::BreakpointSP breakpoint_sp); + python::PythonObject ToSWIGWrapper(lldb::StatusSP status_sp); + python::PythonObject ToSWIGWrapper(const StructuredDataImpl &data_impl); + python::PythonObject ToSWIGWrapper(lldb::ThreadSP thread_sp); + python::PythonObject ToSWIGWrapper(lldb::StackFrameSP frame_sp); + python::PythonObject ToSWIGWrapper(lldb::DebuggerSP debugger_sp); + python::PythonObject ToSWIGWrapper(lldb::WatchpointSP watchpoint_sp); + python::PythonObject ToSWIGWrapper(lldb::BreakpointLocationSP bp_loc_sp); + python::PythonObject ToSWIGWrapper(lldb::ExecutionContextRefSP ctx_sp); + python::PythonObject ToSWIGWrapper(const TypeSummaryOptions &summary_options); + python::PythonObject ToSWIGWrapper(const SymbolContext &sym_ctx); + + python::PythonObject ToSWIGWrapper(std::unique_ptr value_sb); + python::PythonObject ToSWIGWrapper(std::unique_ptr stream_sb); + python::PythonObject ToSWIGWrapper(std::unique_ptr data_sb); + + python::ScopedPythonObject ToSWIGWrapper(CommandReturnObject &cmd_retobj); + python::ScopedPythonObject ToSWIGWrapper(Event *event); + + } // GetPythonValueFormatString provides a system independent type safe way to // convert a variable's type into a python value format. Python value formats @@ -32,6 +91,8 @@ // change. template const char *GetPythonValueFormatString(T t); +template <> const char *GetPythonValueFormatString(python::PythonObject*); +template <> const char *GetPythonValueFormatString(const void *); template <> const char *GetPythonValueFormatString(char *); template <> const char *GetPythonValueFormatString(char); template <> const char *GetPythonValueFormatString(unsigned char); Index: lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.cpp =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.cpp +++ lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.cpp @@ -14,13 +14,19 @@ // LLDB Python header must be included first #include "lldb-python.h" +#include "PythonDataObjects.h" #include "SWIGPythonBridge.h" +// DOC: https://docs.python.org/3/c-api/arg.html#building-values + using namespace lldb; namespace lldb_private { template const char *GetPythonValueFormatString(T t); +// FIXME: This should probably be a PyObject * instead of PythonObject +template <> const char *GetPythonValueFormatString(python::PythonObject*) { return "O"; } +template <> const char *GetPythonValueFormatString(const void *) { return "y"; } template <> const char *GetPythonValueFormatString(char *) { return "s"; } template <> const char *GetPythonValueFormatString(char) { return "b"; } template <> const char *GetPythonValueFormatString(unsigned char) { Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h +++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h @@ -56,6 +56,9 @@ lldb::DataExtractorSP ReadMemoryAtAddress(lldb::addr_t address, size_t size, Status &error) override; + + size_t WriteMemoryAtAddress(lldb::addr_t address, const void* buf, + size_t size, 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 @@ -155,8 +155,52 @@ lldb::DataExtractorSP ScriptedProcessPythonInterface::ReadMemoryAtAddress( lldb::addr_t address, size_t size, Status &error) { - return Dispatch("read_memory_at_address", error, - address, size); + + // Turn the `Status` arguement into an `SBError` to pass it down to the Python call. + StatusSP status_sp = std::make_shared(error); + PythonObject* sb_error = new PythonObject(ToSWIGWrapper(status_sp)); + + Status caller_status; + DataExtractorSP data_sp = Dispatch("read_memory_at_address", caller_status, + address, size, sb_error); + // Convert the `SBError` back to a `Status` object and assign it to the original `error` reference. + Status sb_extractor_status; + error = ExtractValueFromPythonObject(*sb_error, sb_extractor_status); + +// if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error)) +// return ScriptedInterface::ErrorWithMessage( +// LLVM_PRETTY_FUNCTION, +// llvm::Twine("Null or invalid object (" + +// llvm::Twine(error.AsCString()) + llvm::Twine(").")) +// .str(), +// error); + + return data_sp; +} + +size_t ScriptedProcessPythonInterface::WriteMemoryAtAddress( + lldb::addr_t address, const void* buf, size_t size, Status &error) { + + // Turn the `Status` arguement into an `SBError` to pass it down to the Python call. + StatusSP status_sp = std::make_shared(error); + PythonObject* sb_error = new PythonObject(ToSWIGWrapper(status_sp)); + + Status caller_status; + StructuredData::ObjectSP obj = Dispatch("write_memory_at_address", caller_status, address, buf, size, sb_error); + + // Convert the `SBError` back to a `Status` object and assign it to the original `error` reference. + Status sb_extractor_status; + error = ExtractValueFromPythonObject(*sb_error, sb_extractor_status); + + if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error)) + return ScriptedInterface::ErrorWithMessage( + LLVM_PRETTY_FUNCTION, + llvm::Twine("Null or invalid object (" + + llvm::Twine(error.AsCString()) + llvm::Twine(").")) + .str(), + error); + + return obj->GetIntegerValue(); } StructuredData::ArraySP ScriptedProcessPythonInterface::GetLoadedImages() { Index: lldb/test/API/functionalities/scripted_process_passthru/scripted_process_passthru.py =================================================================== --- lldb/test/API/functionalities/scripted_process_passthru/scripted_process_passthru.py +++ lldb/test/API/functionalities/scripted_process_passthru/scripted_process_passthru.py @@ -46,11 +46,20 @@ return data + def write_memory_at_address(self, addr: int, buf : bytes, size: int) -> lldb.SBData: + error = lldb.SBError() + bytes_written = self.parent_process.WriteMemory(addr, size, error) + + if error.Fail(): + return 0 + + return bytes_written + def get_loaded_images(self): return self.loaded_images def get_process_id(self) -> int: - return 42 + return self.parent_process.GetProcessID() def should_stop(self) -> bool: return True Index: lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp =================================================================== --- lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp +++ lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp @@ -193,6 +193,52 @@ return python::PythonObject(); } +python::PythonObject lldb_private::ToSWIGWrapper(lldb::ValueObjectSP value_sp) { + return python::PythonObject(); +} +python::PythonObject lldb_private::ToSWIGWrapper(lldb::TargetSP target_sp) { + return python::PythonObject(); +} +python::PythonObject lldb_private::ToSWIGWrapper(lldb::ProcessSP process_sp) { + return python::PythonObject(); +} +python::PythonObject lldb_private::ToSWIGWrapper(lldb::ThreadPlanSP thread_plan_sp) { + return python::PythonObject(); +} +python::PythonObject lldb_private::ToSWIGWrapper(lldb::BreakpointSP breakpoint_sp) { + return python::PythonObject(); +} +python::PythonObject lldb_private::ToSWIGWrapper(lldb::StatusSP status_sp) { + return python::PythonObject(); +} +python::PythonObject lldb_private::ToSWIGWrapper(const StructuredDataImpl &data_impl) { + return python::PythonObject(); +} +python::PythonObject lldb_private::ToSWIGWrapper(lldb::ThreadSP thread_sp) { + return python::PythonObject(); +} +python::PythonObject lldb_private::ToSWIGWrapper(lldb::StackFrameSP frame_sp) { + return python::PythonObject(); +} +python::PythonObject lldb_private::ToSWIGWrapper(lldb::DebuggerSP debugger_sp) { + return python::PythonObject(); +} +python::PythonObject lldb_private::ToSWIGWrapper(lldb::WatchpointSP watchpoint_sp) { + return python::PythonObject(); +} +python::PythonObject lldb_private::ToSWIGWrapper(lldb::BreakpointLocationSP bp_loc_sp) { + return python::PythonObject(); +} +python::PythonObject lldb_private::ToSWIGWrapper(lldb::ExecutionContextRefSP ctx_sp) { + return python::PythonObject(); +} +python::PythonObject lldb_private::ToSWIGWrapper(const TypeSummaryOptions &summary_options) { + return python::PythonObject(); +} +python::PythonObject lldb_private::ToSWIGWrapper(const SymbolContext &sym_ctx) { + return python::PythonObject(); +} + python::PythonObject lldb_private::LLDBSwigPythonCreateScriptedProcess( const char *python_class_name, const char *session_dictionary_name, const lldb::TargetSP &target_sp, const StructuredDataImpl &args_impl,