1 //===-- ScriptedPythonInterface.h -------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H 10 #define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H 11 12 #if LLDB_ENABLE_PYTHON 13 14 #include <optional> 15 #include <sstream> 16 #include <tuple> 17 #include <type_traits> 18 #include <utility> 19 20 #include "lldb/Host/Config.h" 21 #include "lldb/Interpreter/Interfaces/ScriptedInterface.h" 22 #include "lldb/Utility/DataBufferHeap.h" 23 24 #include "../PythonDataObjects.h" 25 #include "../SWIGPythonBridge.h" 26 #include "../ScriptInterpreterPythonImpl.h" 27 28 namespace lldb_private { 29 class ScriptInterpreterPythonImpl; 30 class ScriptedPythonInterface : virtual public ScriptedInterface { 31 public: 32 ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter); 33 ~ScriptedPythonInterface() override = default; 34 35 template <typename... Args> 36 llvm::Expected<StructuredData::GenericSP> 37 CreatePluginObject(llvm::StringRef class_name, 38 StructuredData::Generic *script_obj, Args... args) { 39 using namespace python; 40 using Locker = ScriptInterpreterPythonImpl::Locker; 41 42 bool has_class_name = !class_name.empty(); 43 bool has_interpreter_dict = 44 !(llvm::StringRef(m_interpreter.GetDictionaryName()).empty()); 45 if (!has_class_name && !has_interpreter_dict && !script_obj) { 46 if (!has_class_name) 47 return llvm::createStringError(llvm::inconvertibleErrorCode(), 48 "Missing script class name."); 49 else if (!has_interpreter_dict) 50 return llvm::createStringError( 51 llvm::inconvertibleErrorCode(), 52 "Invalid script interpreter dictionary."); 53 else 54 return llvm::createStringError(llvm::inconvertibleErrorCode(), 55 "Missing scripting object."); 56 } 57 58 Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, 59 Locker::FreeLock); 60 61 PythonObject result = {}; 62 63 if (script_obj) { 64 result = PythonObject(PyRefType::Borrowed, 65 static_cast<PyObject *>(script_obj->GetValue())); 66 } else { 67 auto dict = 68 PythonModule::MainModule().ResolveName<python::PythonDictionary>( 69 m_interpreter.GetDictionaryName()); 70 if (!dict.IsAllocated()) { 71 return llvm::createStringError( 72 llvm::inconvertibleErrorCode(), 73 "Could not find interpreter dictionary: %s", 74 m_interpreter.GetDictionaryName()); 75 } 76 77 auto method = 78 PythonObject::ResolveNameWithDictionary<python::PythonCallable>( 79 class_name, dict); 80 if (!method.IsAllocated()) 81 return llvm::createStringError(llvm::inconvertibleErrorCode(), 82 "Could not find script class: %s", 83 class_name.data()); 84 85 std::tuple<Args...> original_args = std::forward_as_tuple(args...); 86 auto transformed_args = TransformArgs(original_args); 87 88 std::string error_string; 89 llvm::Expected<PythonCallable::ArgInfo> arg_info = method.GetArgInfo(); 90 if (!arg_info) { 91 llvm::handleAllErrors( 92 arg_info.takeError(), 93 [&](PythonException &E) { error_string.append(E.ReadBacktrace()); }, 94 [&](const llvm::ErrorInfoBase &E) { 95 error_string.append(E.message()); 96 }); 97 return llvm::createStringError(llvm::inconvertibleErrorCode(), 98 error_string); 99 } 100 101 llvm::Expected<PythonObject> expected_return_object = 102 llvm::createStringError(llvm::inconvertibleErrorCode(), 103 "Resulting object is not initialized."); 104 105 std::apply( 106 [&method, &expected_return_object](auto &&...args) { 107 llvm::consumeError(expected_return_object.takeError()); 108 expected_return_object = method(args...); 109 }, 110 transformed_args); 111 112 if (llvm::Error e = expected_return_object.takeError()) 113 return e; 114 result = std::move(expected_return_object.get()); 115 } 116 117 if (!result.IsValid()) 118 return llvm::createStringError( 119 llvm::inconvertibleErrorCode(), 120 "Resulting object is not a valid Python Object."); 121 122 m_object_instance_sp = StructuredData::GenericSP( 123 new StructuredPythonObject(std::move(result))); 124 return m_object_instance_sp; 125 } 126 127 protected: 128 template <typename T = StructuredData::ObjectSP> 129 T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) { 130 return p.CreateStructuredObject(); 131 } 132 133 template <typename T = StructuredData::ObjectSP, typename... Args> 134 T Dispatch(llvm::StringRef method_name, Status &error, Args &&...args) { 135 using namespace python; 136 using Locker = ScriptInterpreterPythonImpl::Locker; 137 138 std::string caller_signature = 139 llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(" (") + 140 llvm::Twine(method_name) + llvm::Twine(")")) 141 .str(); 142 if (!m_object_instance_sp) 143 return ErrorWithMessage<T>(caller_signature, "Python object ill-formed", 144 error); 145 146 Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, 147 Locker::FreeLock); 148 149 PythonObject implementor(PyRefType::Borrowed, 150 (PyObject *)m_object_instance_sp->GetValue()); 151 152 if (!implementor.IsAllocated()) 153 return ErrorWithMessage<T>(caller_signature, 154 "Python implementor not allocated.", error); 155 156 std::tuple<Args...> original_args = std::forward_as_tuple(args...); 157 auto transformed_args = TransformArgs(original_args); 158 159 llvm::Expected<PythonObject> expected_return_object = 160 llvm::make_error<llvm::StringError>("Not initialized.", 161 llvm::inconvertibleErrorCode()); 162 std::apply( 163 [&implementor, &method_name, &expected_return_object](auto &&...args) { 164 llvm::consumeError(expected_return_object.takeError()); 165 expected_return_object = 166 implementor.CallMethod(method_name.data(), args...); 167 }, 168 transformed_args); 169 170 if (llvm::Error e = expected_return_object.takeError()) { 171 error.SetErrorString(llvm::toString(std::move(e)).c_str()); 172 return ErrorWithMessage<T>(caller_signature, 173 "Python method could not be called.", error); 174 } 175 176 PythonObject py_return = std::move(expected_return_object.get()); 177 178 // Now that we called the python method with the transformed arguments, 179 // we need to interate again over both the original and transformed 180 // parameter pack, and transform back the parameter that were passed in 181 // the original parameter pack as references or pointers. 182 if (sizeof...(Args) > 0) 183 if (!ReassignPtrsOrRefsArgs(original_args, transformed_args)) 184 return ErrorWithMessage<T>( 185 caller_signature, 186 "Couldn't re-assign reference and pointer arguments.", error); 187 188 if (!py_return.IsAllocated()) 189 return {}; 190 return ExtractValueFromPythonObject<T>(py_return, error); 191 } 192 193 template <typename... Args> 194 Status GetStatusFromMethod(llvm::StringRef method_name, Args &&...args) { 195 Status error; 196 Dispatch<Status>(method_name, error, std::forward<Args>(args)...); 197 198 return error; 199 } 200 201 template <typename T> T Transform(T object) { 202 // No Transformation for generic usage 203 return {object}; 204 } 205 206 python::PythonObject Transform(bool arg) { 207 // Boolean arguments need to be turned into python objects. 208 return python::PythonBoolean(arg); 209 } 210 211 python::PythonObject Transform(Status arg) { 212 return python::SWIGBridge::ToSWIGWrapper(arg); 213 } 214 215 python::PythonObject Transform(const StructuredDataImpl &arg) { 216 return python::SWIGBridge::ToSWIGWrapper(arg); 217 } 218 219 python::PythonObject Transform(lldb::ExecutionContextRefSP arg) { 220 return python::SWIGBridge::ToSWIGWrapper(arg); 221 } 222 223 python::PythonObject Transform(lldb::ProcessAttachInfoSP arg) { 224 return python::SWIGBridge::ToSWIGWrapper(arg); 225 } 226 227 python::PythonObject Transform(lldb::ProcessLaunchInfoSP arg) { 228 return python::SWIGBridge::ToSWIGWrapper(arg); 229 } 230 231 python::PythonObject Transform(lldb::DataExtractorSP arg) { 232 return python::SWIGBridge::ToSWIGWrapper(arg); 233 } 234 235 template <typename T, typename U> 236 void ReverseTransform(T &original_arg, U transformed_arg, Status &error) { 237 // If U is not a PythonObject, don't touch it! 238 return; 239 } 240 241 template <typename T> 242 void ReverseTransform(T &original_arg, python::PythonObject transformed_arg, 243 Status &error) { 244 original_arg = ExtractValueFromPythonObject<T>(transformed_arg, error); 245 } 246 247 void ReverseTransform(bool &original_arg, 248 python::PythonObject transformed_arg, Status &error) { 249 python::PythonBoolean boolean_arg = python::PythonBoolean( 250 python::PyRefType::Borrowed, transformed_arg.get()); 251 if (boolean_arg.IsValid()) 252 original_arg = boolean_arg.GetValue(); 253 else 254 error.SetErrorString( 255 llvm::formatv("{}: Invalid boolean argument.", LLVM_PRETTY_FUNCTION) 256 .str()); 257 } 258 259 template <std::size_t... I, typename... Args> 260 auto TransformTuple(const std::tuple<Args...> &args, 261 std::index_sequence<I...>) { 262 return std::make_tuple(Transform(std::get<I>(args))...); 263 } 264 265 // This will iterate over the Dispatch parameter pack and replace in-place 266 // every `lldb_private` argument that has a SB counterpart. 267 template <typename... Args> 268 auto TransformArgs(const std::tuple<Args...> &args) { 269 return TransformTuple(args, std::make_index_sequence<sizeof...(Args)>()); 270 } 271 272 template <typename T, typename U> 273 void TransformBack(T &original_arg, U transformed_arg, Status &error) { 274 ReverseTransform(original_arg, transformed_arg, error); 275 } 276 277 template <std::size_t... I, typename... Ts, typename... Us> 278 bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args, 279 std::tuple<Us...> &transformed_args, 280 std::index_sequence<I...>) { 281 Status error; 282 (TransformBack(std::get<I>(original_args), std::get<I>(transformed_args), 283 error), 284 ...); 285 return error.Success(); 286 } 287 288 template <typename... Ts, typename... Us> 289 bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args, 290 std::tuple<Us...> &transformed_args) { 291 if (sizeof...(Ts) != sizeof...(Us)) 292 return false; 293 294 return ReassignPtrsOrRefsArgs(original_args, transformed_args, 295 std::make_index_sequence<sizeof...(Ts)>()); 296 } 297 298 template <typename T, typename... Args> 299 void FormatArgs(std::string &fmt, T arg, Args... args) const { 300 FormatArgs(fmt, arg); 301 FormatArgs(fmt, args...); 302 } 303 304 template <typename T> void FormatArgs(std::string &fmt, T arg) const { 305 fmt += python::PythonFormat<T>::format; 306 } 307 308 void FormatArgs(std::string &fmt) const {} 309 310 // The lifetime is managed by the ScriptInterpreter 311 ScriptInterpreterPythonImpl &m_interpreter; 312 }; 313 314 template <> 315 StructuredData::ArraySP 316 ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>( 317 python::PythonObject &p, Status &error); 318 319 template <> 320 StructuredData::DictionarySP 321 ScriptedPythonInterface::ExtractValueFromPythonObject< 322 StructuredData::DictionarySP>(python::PythonObject &p, Status &error); 323 324 template <> 325 Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>( 326 python::PythonObject &p, Status &error); 327 328 template <> 329 lldb::BreakpointSP 330 ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>( 331 python::PythonObject &p, Status &error); 332 333 template <> 334 lldb::ProcessAttachInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject< 335 lldb::ProcessAttachInfoSP>(python::PythonObject &p, Status &error); 336 337 template <> 338 lldb::ProcessLaunchInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject< 339 lldb::ProcessLaunchInfoSP>(python::PythonObject &p, Status &error); 340 341 template <> 342 lldb::DataExtractorSP 343 ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>( 344 python::PythonObject &p, Status &error); 345 346 template <> 347 std::optional<MemoryRegionInfo> 348 ScriptedPythonInterface::ExtractValueFromPythonObject< 349 std::optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error); 350 351 } // namespace lldb_private 352 353 #endif // LLDB_ENABLE_PYTHON 354 #endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H 355