diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2022-03-20 11:40:34 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2022-05-14 11:43:05 +0000 |
| commit | 349cc55c9796c4596a5b9904cd3281af295f878f (patch) | |
| tree | 410c5a785075730a35f1272ca6a7adf72222ad03 /contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python | |
| parent | cb2ae6163174b90e999326ecec3699ee093a5d43 (diff) | |
| parent | c0981da47d5696fe36474fcf86b4ce03ae3ff818 (diff) | |
Diffstat (limited to 'contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python')
12 files changed, 584 insertions, 273 deletions
diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp index f51d9b3a796c..7c71c9329e57 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp @@ -998,20 +998,6 @@ bool PythonFile::Check(PyObject *py_obj) { #endif } -namespace { -class GIL { -public: - GIL() { - m_state = PyGILState_Ensure(); - assert(!PyErr_Occurred()); - } - ~GIL() { PyGILState_Release(m_state); } - -protected: - PyGILState_STATE m_state; -}; -} // namespace - const char *PythonException::toCString() const { if (!m_repr_bytes) return "unknown exception"; @@ -1114,10 +1100,12 @@ GetOptionsForPyObject(const PythonObject &obj) { auto writable = As<bool>(obj.CallMethod("writable")); if (!writable) return writable.takeError(); - if (readable.get()) - options |= File::eOpenOptionRead; - if (writable.get()) - options |= File::eOpenOptionWrite; + if (readable.get() && writable.get()) + options |= File::eOpenOptionReadWrite; + else if (writable.get()) + options |= File::eOpenOptionWriteOnly; + else if (readable.get()) + options |= File::eOpenOptionReadOnly; return options; #else PythonString py_mode = obj.GetAttributeValue("mode").AsType<PythonString>(); @@ -1413,7 +1401,10 @@ llvm::Expected<FileSP> PythonFile::ConvertToFile(bool borrowed) { if (!options) return options.takeError(); - if (options.get() & File::eOpenOptionWrite) { + File::OpenOptions rw = + options.get() & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly | + File::eOpenOptionReadWrite); + if (rw == File::eOpenOptionWriteOnly || rw == File::eOpenOptionReadWrite) { // LLDB and python will not share I/O buffers. We should probably // flush the python buffers now. auto r = CallMethod("flush"); diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h index 4577253227cd..56bc55d239d1 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h @@ -71,6 +71,18 @@ class PythonDictionary; class PythonInteger; class PythonException; +class GIL { +public: + GIL() { + m_state = PyGILState_Ensure(); + assert(!PyErr_Occurred()); + } + ~GIL() { PyGILState_Release(m_state); } + +protected: + PyGILState_STATE m_state; +}; + class StructuredPythonObject : public StructuredData::Generic { public: StructuredPythonObject() : StructuredData::Generic() {} diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h index 1ef792bcf303..798d947a0a7d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h @@ -46,9 +46,15 @@ extern "C" void *LLDBSwigPythonCreateScriptedProcess( const lldb::TargetSP &target_sp, StructuredDataImpl *args_impl, std::string &error_string); +extern "C" void *LLDBSwigPythonCreateScriptedThread( + const char *python_class_name, const char *session_dictionary_name, + const lldb::ProcessSP &process_sp, StructuredDataImpl *args_impl, + std::string &error_string); + extern "C" void *LLDBSWIGPython_CastPyObjectToSBData(void *data); extern "C" void *LLDBSWIGPython_CastPyObjectToSBError(void *data); extern "C" void *LLDBSWIGPython_CastPyObjectToSBValue(void *data); +extern "C" void *LLDBSWIGPython_CastPyObjectToSBMemoryRegionInfo(void *data); } // namespace lldb_private diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index 7ad63722c31c..c1f4c2d3b4d3 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -355,7 +355,6 @@ private: PyEval_InitThreads(); } - TerminalState m_stdin_tty_state; PyGILState_STATE m_gil_state = PyGILState_UNLOCKED; bool m_was_already_initialized = false; }; @@ -411,6 +410,36 @@ FileSpec ScriptInterpreterPython::GetPythonDir() { return g_spec; } +static const char GetInterpreterInfoScript[] = R"( +import os +import sys + +def main(lldb_python_dir, python_exe_relative_path): + info = { + "lldb-pythonpath": lldb_python_dir, + "language": "python", + "prefix": sys.prefix, + "executable": os.path.join(sys.prefix, python_exe_relative_path) + } + return info +)"; + +static const char python_exe_relative_path[] = LLDB_PYTHON_EXE_RELATIVE_PATH; + +StructuredData::DictionarySP ScriptInterpreterPython::GetInterpreterInfo() { + GIL gil; + FileSpec python_dir_spec = GetPythonDir(); + if (!python_dir_spec) + return nullptr; + PythonScript get_info(GetInterpreterInfoScript); + auto info_json = unwrapIgnoringErrors( + As<PythonDictionary>(get_info(PythonString(python_dir_spec.GetPath()), + PythonString(python_exe_relative_path)))); + if (!info_json) + return nullptr; + return info_json.CreateStructuredDictionary(); +} + void ScriptInterpreterPython::SharedLibraryDirectoryHelper( FileSpec &this_file) { // When we're loaded from python, this_file will point to the file inside the @@ -437,12 +466,7 @@ void ScriptInterpreterPython::SharedLibraryDirectoryHelper( #endif } -lldb_private::ConstString ScriptInterpreterPython::GetPluginNameStatic() { - static ConstString g_name("script-python"); - return g_name; -} - -const char *ScriptInterpreterPython::GetPluginDescriptionStatic() { +llvm::StringRef ScriptInterpreterPython::GetPluginDescriptionStatic() { return "Embedded Python interpreter"; } @@ -591,12 +615,6 @@ ScriptInterpreterPythonImpl::~ScriptInterpreterPythonImpl() { PyGILState_Release(gil_state); } -lldb_private::ConstString ScriptInterpreterPythonImpl::GetPluginName() { - return GetPluginNameStatic(); -} - -uint32_t ScriptInterpreterPythonImpl::GetPluginVersion() { return 1; } - void ScriptInterpreterPythonImpl::IOHandlerActivated(IOHandler &io_handler, bool interactive) { const char *instructions = nullptr; diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h index b8b978118218..8cfc24e71283 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h @@ -13,8 +13,6 @@ #if LLDB_ENABLE_PYTHON -#include "ScriptedProcessPythonInterface.h" - #include "lldb/Breakpoint/BreakpointOptions.h" #include "lldb/Core/IOHandler.h" #include "lldb/Core/StructuredDataImpl.h" @@ -48,10 +46,11 @@ public: : ScriptInterpreter(debugger, lldb::eScriptLanguagePython), IOHandlerDelegateMultiline("DONE") {} + StructuredData::DictionarySP GetInterpreterInfo() override; static void Initialize(); static void Terminate(); - static lldb_private::ConstString GetPluginNameStatic(); - static const char *GetPluginDescriptionStatic(); + static llvm::StringRef GetPluginNameStatic() { return "script-python"; } + static llvm::StringRef GetPluginDescriptionStatic(); static FileSpec GetPythonDir(); static void SharedLibraryDirectoryHelper(FileSpec &this_file); diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h index d1b0b3fda1ef..a3f83b696ed4 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h @@ -292,9 +292,7 @@ public: static lldb::ScriptInterpreterSP CreateInstance(Debugger &debugger); // PluginInterface protocol - lldb_private::ConstString GetPluginName() override; - - uint32_t GetPluginVersion() override; + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } class Locker : public ScriptInterpreterLocker { public: @@ -432,13 +430,12 @@ public: int stdin_fd = GetInputFD(); if (stdin_fd >= 0) { Terminal terminal(stdin_fd); - TerminalState terminal_state; - const bool is_a_tty = terminal.IsATerminal(); + TerminalState terminal_state(terminal); - if (is_a_tty) { - terminal_state.Save(stdin_fd, false); - terminal.SetCanonical(false); - terminal.SetEcho(true); + if (terminal.IsATerminal()) { + // FIXME: error handling? + llvm::consumeError(terminal.SetCanonical(false)); + llvm::consumeError(terminal.SetEcho(true)); } ScriptInterpreterPythonImpl::Locker locker( @@ -466,9 +463,6 @@ public: run_string.Printf("run_python_interpreter (%s)", m_python->GetDictionaryName()); PyRun_SimpleString(run_string.GetData()); - - if (is_a_tty) - terminal_state.Restore(); } } SetIsDone(true); diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp index ce262c930f8b..29680dab5a14 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/Config.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Logging.h" #include "lldb/lldb-enumerations.h" #if LLDB_ENABLE_PYTHON @@ -17,36 +19,40 @@ #include "SWIGPythonBridge.h" #include "ScriptInterpreterPythonImpl.h" #include "ScriptedProcessPythonInterface.h" +#include "ScriptedThreadPythonInterface.h" using namespace lldb; using namespace lldb_private; using namespace lldb_private::python; using Locker = ScriptInterpreterPythonImpl::Locker; +ScriptedProcessPythonInterface::ScriptedProcessPythonInterface( + ScriptInterpreterPythonImpl &interpreter) + : ScriptedProcessInterface(), ScriptedPythonInterface(interpreter) {} + StructuredData::GenericSP ScriptedProcessPythonInterface::CreatePluginObject( - const llvm::StringRef class_name, lldb::TargetSP target_sp, + llvm::StringRef class_name, ExecutionContext &exe_ctx, StructuredData::DictionarySP args_sp) { if (class_name.empty()) return {}; - std::string error_string; + TargetSP target_sp = exe_ctx.GetTargetSP(); StructuredDataImpl *args_impl = nullptr; if (args_sp) { args_impl = new StructuredDataImpl(); args_impl->SetObjectSP(args_sp); } + std::string error_string; - void *ret_val; - - { + Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); - Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, - Locker::FreeLock); + void *ret_val = LLDBSwigPythonCreateScriptedProcess( + class_name.str().c_str(), m_interpreter.GetDictionaryName(), target_sp, + args_impl, error_string); - ret_val = LLDBSwigPythonCreateScriptedProcess( - class_name.str().c_str(), m_interpreter.GetDictionaryName(), target_sp, - args_impl, error_string); - } + if (!ret_val) + return {}; m_object_instance_sp = StructuredData::GenericSP(new StructuredPythonObject(ret_val)); @@ -63,244 +69,101 @@ Status ScriptedProcessPythonInterface::Resume() { } bool ScriptedProcessPythonInterface::ShouldStop() { - llvm::Optional<unsigned long long> should_stop = - GetGenericInteger("should_stop"); + Status error; + StructuredData::ObjectSP obj = Dispatch("is_alive", error); - if (!should_stop) - return false; + if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error)) + return {}; - return static_cast<bool>(*should_stop); + return obj->GetBooleanValue(); } Status ScriptedProcessPythonInterface::Stop() { return GetStatusFromMethod("stop"); } -Status ScriptedProcessPythonInterface::GetStatusFromMethod( - llvm::StringRef method_name) { - Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, - Locker::FreeLock); - - if (!m_object_instance_sp) - return Status("Python object ill-formed."); - - if (!m_object_instance_sp) - return Status("Cannot convert Python object to StructuredData::Generic."); - PythonObject implementor(PyRefType::Borrowed, - (PyObject *)m_object_instance_sp->GetValue()); - - if (!implementor.IsAllocated()) - return Status("Python implementor not allocated."); - - PythonObject pmeth( - PyRefType::Owned, - PyObject_GetAttrString(implementor.get(), method_name.str().c_str())); - - if (PyErr_Occurred()) - PyErr_Clear(); - - if (!pmeth.IsAllocated()) - return Status("Python method not allocated."); - - if (PyCallable_Check(pmeth.get()) == 0) { - if (PyErr_Occurred()) - PyErr_Clear(); - return Status("Python method not callable."); - } - - if (PyErr_Occurred()) - PyErr_Clear(); - - PythonObject py_return(PyRefType::Owned, - PyObject_CallMethod(implementor.get(), - method_name.str().c_str(), - nullptr)); - - if (PyErr_Occurred()) { - PyErr_Print(); - PyErr_Clear(); - return Status("Python method could not be called."); - } - - if (PyObject *py_ret_ptr = py_return.get()) { - lldb::SBError *sb_error = - (lldb::SBError *)LLDBSWIGPython_CastPyObjectToSBError(py_ret_ptr); - - if (!sb_error) - return Status("Couldn't cast lldb::SBError to lldb::Status."); - - Status status = m_interpreter.GetStatusFromSBError(*sb_error); - - if (status.Fail()) - return Status("error: %s", status.AsCString()); +llvm::Optional<MemoryRegionInfo> +ScriptedProcessPythonInterface::GetMemoryRegionContainingAddress( + lldb::addr_t address, Status &error) { + auto mem_region = Dispatch<llvm::Optional<MemoryRegionInfo>>( + "get_memory_region_containing_address", error, address); - return status; + if (error.Fail()) { + return ErrorWithMessage<MemoryRegionInfo>(LLVM_PRETTY_FUNCTION, + error.AsCString(), error); } - return Status("Returned object is null."); + return mem_region; } -llvm::Optional<unsigned long long> -ScriptedProcessPythonInterface::GetGenericInteger(llvm::StringRef method_name) { - Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, - Locker::FreeLock); - - if (!m_object_instance_sp) - return llvm::None; - - if (!m_object_instance_sp) - return llvm::None; - PythonObject implementor(PyRefType::Borrowed, - (PyObject *)m_object_instance_sp->GetValue()); - - if (!implementor.IsAllocated()) - return llvm::None; - - PythonObject pmeth( - PyRefType::Owned, - PyObject_GetAttrString(implementor.get(), method_name.str().c_str())); - - if (PyErr_Occurred()) - PyErr_Clear(); - - if (!pmeth.IsAllocated()) - return llvm::None; - - if (PyCallable_Check(pmeth.get()) == 0) { - if (PyErr_Occurred()) - PyErr_Clear(); - return llvm::None; - } - - if (PyErr_Occurred()) - PyErr_Clear(); - - PythonObject py_return(PyRefType::Owned, - PyObject_CallMethod(implementor.get(), - method_name.str().c_str(), - nullptr)); - - if (PyErr_Occurred()) { - PyErr_Print(); - PyErr_Clear(); - } - - if (!py_return.get()) - return llvm::None; +StructuredData::DictionarySP +ScriptedProcessPythonInterface::GetThreadWithID(lldb::tid_t tid) { + Status error; + StructuredData::ObjectSP obj = Dispatch("get_thread_with_id", error, tid); - llvm::Expected<unsigned long long> size = py_return.AsUnsignedLongLong(); - // FIXME: Handle error. - if (!size) - return llvm::None; + if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error)) + return {}; - return *size; -} + StructuredData::DictionarySP dict{obj->GetAsDictionary()}; -lldb::MemoryRegionInfoSP -ScriptedProcessPythonInterface::GetMemoryRegionContainingAddress( - lldb::addr_t address) { - // TODO: Implement - return nullptr; -} - -StructuredData::DictionarySP -ScriptedProcessPythonInterface::GetThreadWithID(lldb::tid_t tid) { - // TODO: Implement - return nullptr; + return dict; } StructuredData::DictionarySP ScriptedProcessPythonInterface::GetRegistersForThread(lldb::tid_t tid) { // TODO: Implement - return nullptr; + return {}; } lldb::DataExtractorSP ScriptedProcessPythonInterface::ReadMemoryAtAddress( lldb::addr_t address, size_t size, Status &error) { - Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, - Locker::FreeLock); - - auto error_with_message = [&error](llvm::StringRef message) { - error.SetErrorString(message); - return nullptr; - }; - - static char callee_name[] = "read_memory_at_address"; - std::string param_format = GetPythonValueFormatString(address); - param_format += GetPythonValueFormatString(size); - - if (!m_object_instance_sp) - return error_with_message("Python object ill-formed."); - - if (!m_object_instance_sp) - return error_with_message("Python method not callable."); - - PythonObject implementor(PyRefType::Borrowed, - (PyObject *)m_object_instance_sp->GetValue()); - - if (!implementor.IsAllocated()) - return error_with_message("Python implementor not allocated."); - - PythonObject pmeth(PyRefType::Owned, - PyObject_GetAttrString(implementor.get(), callee_name)); - - if (PyErr_Occurred()) - PyErr_Clear(); - - if (!pmeth.IsAllocated()) - return error_with_message("Python method not allocated."); - - if (PyCallable_Check(pmeth.get()) == 0) { - if (PyErr_Occurred()) - PyErr_Clear(); - return error_with_message("Python method not callable."); - } + return Dispatch<lldb::DataExtractorSP>("read_memory_at_address", error, + address, size); +} - if (PyErr_Occurred()) - PyErr_Clear(); +StructuredData::DictionarySP ScriptedProcessPythonInterface::GetLoadedImages() { + // TODO: Implement + return {}; +} - PythonObject py_return(PyRefType::Owned, - PyObject_CallMethod(implementor.get(), callee_name, - param_format.c_str(), address, - size)); +lldb::pid_t ScriptedProcessPythonInterface::GetProcessID() { + Status error; + StructuredData::ObjectSP obj = Dispatch("get_process_id", error); - if (PyErr_Occurred()) { - PyErr_Print(); - PyErr_Clear(); - return error_with_message("Python method could not be called."); - } + if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error)) + return LLDB_INVALID_PROCESS_ID; - if (PyObject *py_ret_ptr = py_return.get()) { - lldb::SBData *sb_data = - (lldb::SBData *)LLDBSWIGPython_CastPyObjectToSBData(py_ret_ptr); + return obj->GetIntegerValue(LLDB_INVALID_PROCESS_ID); +} - if (!sb_data) - return error_with_message( - "Couldn't cast lldb::SBData to lldb::DataExtractor."); +bool ScriptedProcessPythonInterface::IsAlive() { + Status error; + StructuredData::ObjectSP obj = Dispatch("is_alive", error); - return m_interpreter.GetDataExtractorFromSBData(*sb_data); - } + if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error)) + return {}; - return error_with_message("Returned object is null."); + return obj->GetBooleanValue(); } -StructuredData::DictionarySP ScriptedProcessPythonInterface::GetLoadedImages() { - // TODO: Implement - return nullptr; -} +llvm::Optional<std::string> +ScriptedProcessPythonInterface::GetScriptedThreadPluginName() { + Status error; + StructuredData::ObjectSP obj = Dispatch("get_scripted_thread_plugin", error); -lldb::pid_t ScriptedProcessPythonInterface::GetProcessID() { - llvm::Optional<unsigned long long> pid = GetGenericInteger("get_process_id"); - return (!pid) ? LLDB_INVALID_PROCESS_ID : *pid; -} + if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error)) + return {}; -bool ScriptedProcessPythonInterface::IsAlive() { - llvm::Optional<unsigned long long> is_alive = GetGenericInteger("is_alive"); + return obj->GetStringValue().str(); +} - if (!is_alive) - return false; +lldb::ScriptedThreadInterfaceSP +ScriptedProcessPythonInterface::GetScriptedThreadInterface() { + if (!m_scripted_thread_interface_sp) + m_scripted_thread_interface_sp = + std::make_shared<ScriptedThreadPythonInterface>(m_interpreter); - return static_cast<bool>(*is_alive); + return m_scripted_thread_interface_sp; } #endif diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h index 30cb5a882af2..421bdd59887c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h @@ -13,17 +13,18 @@ #if LLDB_ENABLE_PYTHON +#include "ScriptedPythonInterface.h" #include "lldb/Interpreter/ScriptedProcessInterface.h" namespace lldb_private { -class ScriptInterpreterPythonImpl; -class ScriptedProcessPythonInterface : public ScriptedProcessInterface { +class ScriptedProcessPythonInterface : public ScriptedProcessInterface, + public ScriptedPythonInterface { public: - ScriptedProcessPythonInterface(ScriptInterpreterPythonImpl &interpreter) - : ScriptedProcessInterface(), m_interpreter(interpreter) {} + ScriptedProcessPythonInterface(ScriptInterpreterPythonImpl &interpreter); StructuredData::GenericSP - CreatePluginObject(const llvm::StringRef class_name, lldb::TargetSP target_sp, + CreatePluginObject(const llvm::StringRef class_name, + ExecutionContext &exe_ctx, StructuredData::DictionarySP args_sp) override; Status Launch() override; @@ -34,8 +35,9 @@ public: Status Stop() override; - lldb::MemoryRegionInfoSP - GetMemoryRegionContainingAddress(lldb::addr_t address) override; + llvm::Optional<MemoryRegionInfo> + GetMemoryRegionContainingAddress(lldb::addr_t address, + Status &error) override; StructuredData::DictionarySP GetThreadWithID(lldb::tid_t tid) override; @@ -50,15 +52,10 @@ public: bool IsAlive() override; -protected: - llvm::Optional<unsigned long long> - GetGenericInteger(llvm::StringRef method_name); - Status GetStatusFromMethod(llvm::StringRef method_name); + llvm::Optional<std::string> GetScriptedThreadPluginName() override; private: - // The lifetime is managed by the ScriptInterpreter - ScriptInterpreterPythonImpl &m_interpreter; - StructuredData::GenericSP m_object_instance_sp; + lldb::ScriptedThreadInterfaceSP GetScriptedThreadInterface() override; }; } // namespace lldb_private diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp new file mode 100644 index 000000000000..07bf952bf840 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.cpp @@ -0,0 +1,92 @@ +//===-- ScriptedPythonInterface.cpp ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/Config.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Logging.h" +#include "lldb/lldb-enumerations.h" + +#if LLDB_ENABLE_PYTHON + +// LLDB Python header must be included first +#include "lldb-python.h" + +#include "SWIGPythonBridge.h" +#include "ScriptInterpreterPythonImpl.h" +#include "ScriptedPythonInterface.h" + +using namespace lldb; +using namespace lldb_private; + +ScriptedPythonInterface::ScriptedPythonInterface( + ScriptInterpreterPythonImpl &interpreter) + : ScriptedInterface(), m_interpreter(interpreter) {} + +Status +ScriptedPythonInterface::GetStatusFromMethod(llvm::StringRef method_name) { + Status error; + Dispatch<Status>(method_name, error); + + return error; +} + +template <> +StructuredData::DictionarySP +ScriptedPythonInterface::ExtractValueFromPythonObject< + StructuredData::DictionarySP>(python::PythonObject &p, Status &error) { + python::PythonDictionary result_dict(python::PyRefType::Borrowed, p.get()); + return result_dict.CreateStructuredDictionary(); +} + +template <> +Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>( + python::PythonObject &p, Status &error) { + if (lldb::SBError *sb_error = reinterpret_cast<lldb::SBError *>( + LLDBSWIGPython_CastPyObjectToSBError(p.get()))) + error = m_interpreter.GetStatusFromSBError(*sb_error); + else + error.SetErrorString("Couldn't cast lldb::SBError to lldb::Status."); + + return error; +} + +template <> +lldb::DataExtractorSP +ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>( + python::PythonObject &p, Status &error) { + lldb::SBData *sb_data = reinterpret_cast<lldb::SBData *>( + LLDBSWIGPython_CastPyObjectToSBData(p.get())); + + if (!sb_data) { + error.SetErrorString( + "Couldn't cast lldb::SBData to lldb::DataExtractorSP."); + return nullptr; + } + + return m_interpreter.GetDataExtractorFromSBData(*sb_data); +} + +template <> +llvm::Optional<MemoryRegionInfo> +ScriptedPythonInterface::ExtractValueFromPythonObject< + llvm::Optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error) { + + lldb::SBMemoryRegionInfo *sb_mem_reg_info = + reinterpret_cast<lldb::SBMemoryRegionInfo *>( + LLDBSWIGPython_CastPyObjectToSBMemoryRegionInfo(p.get())); + + if (!sb_mem_reg_info) { + error.SetErrorString( + "Couldn't cast lldb::SBMemoryRegionInfo to lldb::MemoryRegionInfoSP."); + return {}; + } + + return m_interpreter.GetOpaqueTypeFromSBMemoryRegionInfo(*sb_mem_reg_info); +} + +#endif diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h new file mode 100644 index 000000000000..da112eb72022 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedPythonInterface.h @@ -0,0 +1,151 @@ +//===-- ScriptedPythonInterface.h -------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H +#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H + +#include "lldb/Host/Config.h" + +#if LLDB_ENABLE_PYTHON + +#include "lldb/Interpreter/ScriptedInterface.h" +#include "lldb/Utility/DataBufferHeap.h" + +#include "PythonDataObjects.h" +#include "SWIGPythonBridge.h" +#include "ScriptInterpreterPythonImpl.h" + +namespace lldb_private { +class ScriptInterpreterPythonImpl; +class ScriptedPythonInterface : virtual public ScriptedInterface { +public: + ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter); + virtual ~ScriptedPythonInterface() = default; + +protected: + template <typename T = StructuredData::ObjectSP> + T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) { + return p.CreateStructuredObject(); + } + + template <typename T = StructuredData::ObjectSP, typename... Args> + T Dispatch(llvm::StringRef method_name, Status &error, Args... args) { + using namespace python; + using Locker = ScriptInterpreterPythonImpl::Locker; + + std::string caller_signature = + llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(" (") + + llvm::Twine(method_name) + llvm::Twine(")")) + .str(); + if (!m_object_instance_sp) + return ErrorWithMessage<T>(caller_signature, "Python object ill-formed", + error); + + Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); + + PythonObject implementor(PyRefType::Borrowed, + (PyObject *)m_object_instance_sp->GetValue()); + + if (!implementor.IsAllocated()) + return ErrorWithMessage<T>(caller_signature, + "Python implementor not allocated.", error); + + PythonObject pmeth( + PyRefType::Owned, + PyObject_GetAttrString(implementor.get(), method_name.str().c_str())); + + if (PyErr_Occurred()) + PyErr_Clear(); + + if (!pmeth.IsAllocated()) + return ErrorWithMessage<T>(caller_signature, + "Python method not allocated.", error); + + if (PyCallable_Check(pmeth.get()) == 0) { + if (PyErr_Occurred()) + PyErr_Clear(); + return ErrorWithMessage<T>(caller_signature, + "Python method not callable.", error); + } + + if (PyErr_Occurred()) + PyErr_Clear(); + + // TODO: make `const char *` when removing support for Python 2. + char *format = nullptr; + std::string format_buffer; + + if (sizeof...(Args) > 0) { + FormatArgs(format_buffer, args...); + // TODO: make `const char *` when removing support for Python 2. + format = const_cast<char *>(format_buffer.c_str()); + } + + // TODO: make `const char *` when removing support for Python 2. + PythonObject py_return( + PyRefType::Owned, + PyObject_CallMethod(implementor.get(), + const_cast<char *>(method_name.data()), format, + args...)); + + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + return ErrorWithMessage<T>(caller_signature, + "Python method could not be called.", error); + } + + if (!py_return.IsAllocated()) + return ErrorWithMessage<T>(caller_signature, "Returned object is null.", + error); + + return ExtractValueFromPythonObject<T>(py_return, error); + } + + Status GetStatusFromMethod(llvm::StringRef method_name); + + template <typename T, typename... Args> + void FormatArgs(std::string &fmt, T arg, Args... args) const { + FormatArgs(fmt, arg); + FormatArgs(fmt, args...); + } + + template <typename T> void FormatArgs(std::string &fmt, T arg) const { + fmt += GetPythonValueFormatString(arg); + } + + void FormatArgs(std::string &fmt) const {} + + // The lifetime is managed by the ScriptInterpreter + ScriptInterpreterPythonImpl &m_interpreter; +}; + +template <> +StructuredData::DictionarySP +ScriptedPythonInterface::ExtractValueFromPythonObject< + StructuredData::DictionarySP>(python::PythonObject &p, Status &error); + +template <> +Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>( + python::PythonObject &p, Status &error); + +template <> +lldb::DataExtractorSP +ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>( + python::PythonObject &p, Status &error); + +template <> +llvm::Optional<MemoryRegionInfo> +ScriptedPythonInterface::ExtractValueFromPythonObject< + llvm::Optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error); + +} // namespace lldb_private + +#endif // LLDB_ENABLE_PYTHON +#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp new file mode 100644 index 000000000000..d2c28bc426ee --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.cpp @@ -0,0 +1,140 @@ +//===-- ScriptedThreadPythonInterface.cpp ---------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/Config.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Logging.h" +#include "lldb/lldb-enumerations.h" + +#if LLDB_ENABLE_PYTHON + +// LLDB Python header must be included first +#include "lldb-python.h" + +#include "SWIGPythonBridge.h" +#include "ScriptInterpreterPythonImpl.h" +#include "ScriptedThreadPythonInterface.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::python; +using Locker = ScriptInterpreterPythonImpl::Locker; + +ScriptedThreadPythonInterface::ScriptedThreadPythonInterface( + ScriptInterpreterPythonImpl &interpreter) + : ScriptedThreadInterface(), ScriptedPythonInterface(interpreter) {} + +StructuredData::GenericSP ScriptedThreadPythonInterface::CreatePluginObject( + const llvm::StringRef class_name, ExecutionContext &exe_ctx, + StructuredData::DictionarySP args_sp) { + + if (class_name.empty()) + return {}; + + ProcessSP process_sp = exe_ctx.GetProcessSP(); + StructuredDataImpl *args_impl = nullptr; + if (args_sp) { + args_impl = new StructuredDataImpl(); + args_impl->SetObjectSP(args_sp); + } + std::string error_string; + + Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); + + void *ret_val = LLDBSwigPythonCreateScriptedThread( + class_name.str().c_str(), m_interpreter.GetDictionaryName(), process_sp, + args_impl, error_string); + + if (!ret_val) + return {}; + + m_object_instance_sp = + StructuredData::GenericSP(new StructuredPythonObject(ret_val)); + + return m_object_instance_sp; +} + +lldb::tid_t ScriptedThreadPythonInterface::GetThreadID() { + Status error; + StructuredData::ObjectSP obj = Dispatch("get_thread_id", error); + + if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error)) + return LLDB_INVALID_THREAD_ID; + + return obj->GetIntegerValue(LLDB_INVALID_THREAD_ID); +} + +llvm::Optional<std::string> ScriptedThreadPythonInterface::GetName() { + Status error; + StructuredData::ObjectSP obj = Dispatch("get_name", error); + + if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error)) + return {}; + + return obj->GetStringValue().str(); +} + +lldb::StateType ScriptedThreadPythonInterface::GetState() { + Status error; + StructuredData::ObjectSP obj = Dispatch("get_state", error); + + if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error)) + return eStateInvalid; + + return static_cast<StateType>(obj->GetIntegerValue(eStateInvalid)); +} + +llvm::Optional<std::string> ScriptedThreadPythonInterface::GetQueue() { + Status error; + StructuredData::ObjectSP obj = Dispatch("get_queue", error); + + if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error)) + return {}; + + return obj->GetStringValue().str(); +} + +StructuredData::DictionarySP ScriptedThreadPythonInterface::GetStopReason() { + Status error; + StructuredData::DictionarySP dict = + Dispatch<StructuredData::DictionarySP>("get_stop_reason", error); + + if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict, error)) + return {}; + + return dict; +} + +StructuredData::ArraySP ScriptedThreadPythonInterface::GetStackFrames() { + return nullptr; +} + +StructuredData::DictionarySP ScriptedThreadPythonInterface::GetRegisterInfo() { + Status error; + StructuredData::DictionarySP dict = + Dispatch<StructuredData::DictionarySP>("get_register_info", error); + + if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict, error)) + return {}; + + return dict; +} + +llvm::Optional<std::string> +ScriptedThreadPythonInterface::GetRegisterContext() { + Status error; + StructuredData::ObjectSP obj = Dispatch("get_register_context", error); + + if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error)) + return {}; + + return obj->GetAsString()->GetValue().str(); +} + +#endif diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.h b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.h new file mode 100644 index 000000000000..996b8d43136b --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedThreadPythonInterface.h @@ -0,0 +1,48 @@ +//===-- ScriptedThreadPythonInterface.h ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDTHREADPYTHONINTERFACE_H +#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDTHREADPYTHONINTERFACE_H + +#include "lldb/Host/Config.h" + +#if LLDB_ENABLE_PYTHON + +#include "ScriptedPythonInterface.h" +#include "lldb/Interpreter/ScriptedProcessInterface.h" + +namespace lldb_private { +class ScriptedThreadPythonInterface : public ScriptedThreadInterface, + public ScriptedPythonInterface { +public: + ScriptedThreadPythonInterface(ScriptInterpreterPythonImpl &interpreter); + + StructuredData::GenericSP + CreatePluginObject(llvm::StringRef class_name, ExecutionContext &exe_ctx, + StructuredData::DictionarySP args_sp) override; + + lldb::tid_t GetThreadID() override; + + llvm::Optional<std::string> GetName() override; + + lldb::StateType GetState() override; + + llvm::Optional<std::string> GetQueue() override; + + StructuredData::DictionarySP GetStopReason() override; + + StructuredData::ArraySP GetStackFrames() override; + + StructuredData::DictionarySP GetRegisterInfo() override; + + llvm::Optional<std::string> GetRegisterContext() override; +}; +} // namespace lldb_private + +#endif // LLDB_ENABLE_PYTHON +#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPROCESSTHREADINTERFACE_H |
