1*3925204cSMed Ismail Bennani //===-- ScriptedPythonInterface.h -------------------------------*- C++ -*-===// 2*3925204cSMed Ismail Bennani // 3*3925204cSMed Ismail Bennani // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*3925204cSMed Ismail Bennani // See https://llvm.org/LICENSE.txt for license information. 5*3925204cSMed Ismail Bennani // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*3925204cSMed Ismail Bennani // 7*3925204cSMed Ismail Bennani //===----------------------------------------------------------------------===// 8*3925204cSMed Ismail Bennani 9*3925204cSMed Ismail Bennani #ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H 10*3925204cSMed Ismail Bennani #define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H 11*3925204cSMed Ismail Bennani 12*3925204cSMed Ismail Bennani #include "lldb/Host/Config.h" 13*3925204cSMed Ismail Bennani 14*3925204cSMed Ismail Bennani #if LLDB_ENABLE_PYTHON 15*3925204cSMed Ismail Bennani 16*3925204cSMed Ismail Bennani #include "lldb/Interpreter/ScriptedInterface.h" 17*3925204cSMed Ismail Bennani #include "lldb/Utility/DataBufferHeap.h" 18*3925204cSMed Ismail Bennani 19*3925204cSMed Ismail Bennani #include "PythonDataObjects.h" 20*3925204cSMed Ismail Bennani #include "SWIGPythonBridge.h" 21*3925204cSMed Ismail Bennani #include "ScriptInterpreterPythonImpl.h" 22*3925204cSMed Ismail Bennani 23*3925204cSMed Ismail Bennani namespace lldb_private { 24*3925204cSMed Ismail Bennani class ScriptInterpreterPythonImpl; 25*3925204cSMed Ismail Bennani class ScriptedPythonInterface : virtual public ScriptedInterface { 26*3925204cSMed Ismail Bennani public: 27*3925204cSMed Ismail Bennani ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter); 28*3925204cSMed Ismail Bennani virtual ~ScriptedPythonInterface() = default; 29*3925204cSMed Ismail Bennani 30*3925204cSMed Ismail Bennani protected: 31*3925204cSMed Ismail Bennani template <typename T = StructuredData::ObjectSP> 32*3925204cSMed Ismail Bennani T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) { 33*3925204cSMed Ismail Bennani return p.CreateStructuredObject(); 34*3925204cSMed Ismail Bennani } 35*3925204cSMed Ismail Bennani 36*3925204cSMed Ismail Bennani template <> 37*3925204cSMed Ismail Bennani Status ExtractValueFromPythonObject<Status>(python::PythonObject &p, 38*3925204cSMed Ismail Bennani Status &error) { 39*3925204cSMed Ismail Bennani if (lldb::SBError *sb_error = reinterpret_cast<lldb::SBError *>( 40*3925204cSMed Ismail Bennani LLDBSWIGPython_CastPyObjectToSBError(p.get()))) 41*3925204cSMed Ismail Bennani error = m_interpreter.GetStatusFromSBError(*sb_error); 42*3925204cSMed Ismail Bennani else 43*3925204cSMed Ismail Bennani error.SetErrorString("Couldn't cast lldb::SBError to lldb::Status."); 44*3925204cSMed Ismail Bennani 45*3925204cSMed Ismail Bennani return error; 46*3925204cSMed Ismail Bennani } 47*3925204cSMed Ismail Bennani 48*3925204cSMed Ismail Bennani template <> 49*3925204cSMed Ismail Bennani lldb::DataExtractorSP 50*3925204cSMed Ismail Bennani ExtractValueFromPythonObject<lldb::DataExtractorSP>(python::PythonObject &p, 51*3925204cSMed Ismail Bennani Status &error) { 52*3925204cSMed Ismail Bennani lldb::SBData *sb_data = reinterpret_cast<lldb::SBData *>( 53*3925204cSMed Ismail Bennani LLDBSWIGPython_CastPyObjectToSBData(p.get())); 54*3925204cSMed Ismail Bennani 55*3925204cSMed Ismail Bennani if (!sb_data) { 56*3925204cSMed Ismail Bennani error.SetErrorString("Couldn't cast lldb::SBError to lldb::Status."); 57*3925204cSMed Ismail Bennani return nullptr; 58*3925204cSMed Ismail Bennani } 59*3925204cSMed Ismail Bennani 60*3925204cSMed Ismail Bennani return m_interpreter.GetDataExtractorFromSBData(*sb_data); 61*3925204cSMed Ismail Bennani } 62*3925204cSMed Ismail Bennani 63*3925204cSMed Ismail Bennani template <typename T = StructuredData::ObjectSP, typename... Args> 64*3925204cSMed Ismail Bennani T Dispatch(llvm::StringRef method_name, Status &error, Args... args) { 65*3925204cSMed Ismail Bennani using namespace python; 66*3925204cSMed Ismail Bennani using Locker = ScriptInterpreterPythonImpl::Locker; 67*3925204cSMed Ismail Bennani 68*3925204cSMed Ismail Bennani auto error_with_message = [&method_name, &error](llvm::StringRef message) { 69*3925204cSMed Ismail Bennani error.SetErrorStringWithFormatv( 70*3925204cSMed Ismail Bennani "ScriptedPythonInterface::{0} ({1}) ERROR = {2}", __FUNCTION__, 71*3925204cSMed Ismail Bennani method_name, message); 72*3925204cSMed Ismail Bennani return T(); 73*3925204cSMed Ismail Bennani }; 74*3925204cSMed Ismail Bennani 75*3925204cSMed Ismail Bennani if (!m_object_instance_sp) 76*3925204cSMed Ismail Bennani return error_with_message("Python object ill-formed"); 77*3925204cSMed Ismail Bennani 78*3925204cSMed Ismail Bennani Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, 79*3925204cSMed Ismail Bennani Locker::FreeLock); 80*3925204cSMed Ismail Bennani 81*3925204cSMed Ismail Bennani PythonObject implementor(PyRefType::Borrowed, 82*3925204cSMed Ismail Bennani (PyObject *)m_object_instance_sp->GetValue()); 83*3925204cSMed Ismail Bennani 84*3925204cSMed Ismail Bennani if (!implementor.IsAllocated()) 85*3925204cSMed Ismail Bennani return error_with_message("Python implementor not allocated."); 86*3925204cSMed Ismail Bennani 87*3925204cSMed Ismail Bennani PythonObject pmeth( 88*3925204cSMed Ismail Bennani PyRefType::Owned, 89*3925204cSMed Ismail Bennani PyObject_GetAttrString(implementor.get(), method_name.str().c_str())); 90*3925204cSMed Ismail Bennani 91*3925204cSMed Ismail Bennani if (PyErr_Occurred()) 92*3925204cSMed Ismail Bennani PyErr_Clear(); 93*3925204cSMed Ismail Bennani 94*3925204cSMed Ismail Bennani if (!pmeth.IsAllocated()) 95*3925204cSMed Ismail Bennani return error_with_message("Python method not allocated."); 96*3925204cSMed Ismail Bennani 97*3925204cSMed Ismail Bennani if (PyCallable_Check(pmeth.get()) == 0) { 98*3925204cSMed Ismail Bennani if (PyErr_Occurred()) 99*3925204cSMed Ismail Bennani PyErr_Clear(); 100*3925204cSMed Ismail Bennani return error_with_message("Python method not callable."); 101*3925204cSMed Ismail Bennani } 102*3925204cSMed Ismail Bennani 103*3925204cSMed Ismail Bennani if (PyErr_Occurred()) 104*3925204cSMed Ismail Bennani PyErr_Clear(); 105*3925204cSMed Ismail Bennani 106*3925204cSMed Ismail Bennani // TODO: make `const char *` when removing support for Python 2. 107*3925204cSMed Ismail Bennani char *format = nullptr; 108*3925204cSMed Ismail Bennani std::string format_buffer; 109*3925204cSMed Ismail Bennani 110*3925204cSMed Ismail Bennani if (sizeof...(Args) > 0) { 111*3925204cSMed Ismail Bennani FormatArgs(format_buffer, args...); 112*3925204cSMed Ismail Bennani // TODO: make `const char *` when removing support for Python 2. 113*3925204cSMed Ismail Bennani format = const_cast<char *>(format_buffer.c_str()); 114*3925204cSMed Ismail Bennani } 115*3925204cSMed Ismail Bennani 116*3925204cSMed Ismail Bennani // TODO: make `const char *` when removing support for Python 2. 117*3925204cSMed Ismail Bennani PythonObject py_return( 118*3925204cSMed Ismail Bennani PyRefType::Owned, 119*3925204cSMed Ismail Bennani PyObject_CallMethod(implementor.get(), 120*3925204cSMed Ismail Bennani const_cast<char *>(method_name.data()), format, 121*3925204cSMed Ismail Bennani args...)); 122*3925204cSMed Ismail Bennani 123*3925204cSMed Ismail Bennani if (PyErr_Occurred()) { 124*3925204cSMed Ismail Bennani PyErr_Print(); 125*3925204cSMed Ismail Bennani PyErr_Clear(); 126*3925204cSMed Ismail Bennani return error_with_message("Python method could not be called."); 127*3925204cSMed Ismail Bennani } 128*3925204cSMed Ismail Bennani 129*3925204cSMed Ismail Bennani if (!py_return.IsAllocated()) 130*3925204cSMed Ismail Bennani return error_with_message("Returned object is null."); 131*3925204cSMed Ismail Bennani 132*3925204cSMed Ismail Bennani return ExtractValueFromPythonObject<T>(py_return, error); 133*3925204cSMed Ismail Bennani } 134*3925204cSMed Ismail Bennani 135*3925204cSMed Ismail Bennani Status GetStatusFromMethod(llvm::StringRef method_name); 136*3925204cSMed Ismail Bennani 137*3925204cSMed Ismail Bennani template <typename T, typename... Args> 138*3925204cSMed Ismail Bennani void FormatArgs(std::string &fmt, T arg, Args... args) const { 139*3925204cSMed Ismail Bennani FormatArgs(fmt, arg); 140*3925204cSMed Ismail Bennani FormatArgs(fmt, args...); 141*3925204cSMed Ismail Bennani } 142*3925204cSMed Ismail Bennani 143*3925204cSMed Ismail Bennani template <typename T> void FormatArgs(std::string &fmt, T arg) const { 144*3925204cSMed Ismail Bennani fmt += GetPythonValueFormatString(arg); 145*3925204cSMed Ismail Bennani } 146*3925204cSMed Ismail Bennani 147*3925204cSMed Ismail Bennani void FormatArgs(std::string &fmt) const {} 148*3925204cSMed Ismail Bennani 149*3925204cSMed Ismail Bennani // The lifetime is managed by the ScriptInterpreter 150*3925204cSMed Ismail Bennani ScriptInterpreterPythonImpl &m_interpreter; 151*3925204cSMed Ismail Bennani }; 152*3925204cSMed Ismail Bennani } // namespace lldb_private 153*3925204cSMed Ismail Bennani 154*3925204cSMed Ismail Bennani #endif // LLDB_ENABLE_PYTHON 155*3925204cSMed Ismail Bennani #endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPYTHONINTERFACE_H 156