//===-- ScriptedProcessPythonInterface.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/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 "ScriptedProcessPythonInterface.h" using namespace lldb; using namespace lldb_private; using namespace lldb_private::python; using Locker = ScriptInterpreterPythonImpl::Locker; StructuredData::GenericSP ScriptedProcessPythonInterface::CreatePluginObject( const llvm::StringRef class_name, lldb::TargetSP target_sp, StructuredData::DictionarySP args_sp) { if (class_name.empty()) return {}; std::string error_string; StructuredDataImpl *args_impl = nullptr; if (args_sp) { args_impl = new StructuredDataImpl(); args_impl->SetObjectSP(args_sp); } void *ret_val; { Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); ret_val = LLDBSwigPythonCreateScriptedProcess( class_name.str().c_str(), m_interpreter.GetDictionaryName(), target_sp, args_impl, error_string); } m_object_instance_sp = StructuredData::GenericSP(new StructuredPythonObject(ret_val)); return m_object_instance_sp; } Status ScriptedProcessPythonInterface::Launch() { return GetStatusFromMethod("launch"); } Status ScriptedProcessPythonInterface::Resume() { return GetStatusFromMethod("resume"); } bool ScriptedProcessPythonInterface::ShouldStop() { llvm::Optional should_stop = GetGenericInteger("should_stop"); if (!should_stop) return false; return static_cast(*should_stop); } 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()); return status; } return Status("Returned object is null."); } llvm::Optional 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; llvm::Expected size = py_return.AsUnsignedLongLong(); // FIXME: Handle error. if (!size) return llvm::None; return *size; } lldb::MemoryRegionInfoSP ScriptedProcessPythonInterface::GetMemoryRegionContainingAddress( lldb::addr_t address) { // TODO: Implement return nullptr; } StructuredData::DictionarySP ScriptedProcessPythonInterface::GetThreadWithID(lldb::tid_t tid) { // TODO: Implement return nullptr; } StructuredData::DictionarySP ScriptedProcessPythonInterface::GetRegistersForThread(lldb::tid_t tid) { // TODO: Implement return nullptr; } 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."); } if (PyErr_Occurred()) PyErr_Clear(); PythonObject py_return(PyRefType::Owned, PyObject_CallMethod(implementor.get(), callee_name, param_format.c_str(), address, size)); if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); return error_with_message("Python method could not be called."); } if (PyObject *py_ret_ptr = py_return.get()) { lldb::SBData *sb_data = (lldb::SBData *)LLDBSWIGPython_CastPyObjectToSBData(py_ret_ptr); if (!sb_data) return error_with_message( "Couldn't cast lldb::SBData to lldb::DataExtractor."); return m_interpreter.GetDataExtractorFromSBData(*sb_data); } return error_with_message("Returned object is null."); } StructuredData::DictionarySP ScriptedProcessPythonInterface::GetLoadedImages() { // TODO: Implement return nullptr; } lldb::pid_t ScriptedProcessPythonInterface::GetProcessID() { llvm::Optional pid = GetGenericInteger("get_process_id"); return (!pid) ? LLDB_INVALID_PROCESS_ID : *pid; } bool ScriptedProcessPythonInterface::IsAlive() { llvm::Optional is_alive = GetGenericInteger("is_alive"); if (!is_alive) return false; return static_cast(*is_alive); } #endif