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 // clang-format off 14 // LLDB Python header must be included first 15 #include "../lldb-python.h" 16 //clang-format on 17 #endif 18 19 20 #include <optional> 21 #include <sstream> 22 #include <tuple> 23 #include <type_traits> 24 #include <utility> 25 26 #include "lldb/Host/Config.h" 27 #include "lldb/Interpreter/Interfaces/ScriptedInterface.h" 28 #include "lldb/Utility/DataBufferHeap.h" 29 30 #if LLDB_ENABLE_PYTHON 31 32 #include "../PythonDataObjects.h" 33 #include "../SWIGPythonBridge.h" 34 #include "../ScriptInterpreterPythonImpl.h" 35 36 namespace lldb_private { 37 class ScriptInterpreterPythonImpl; 38 class ScriptedPythonInterface : virtual public ScriptedInterface { 39 public: 40 ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter); 41 ~ScriptedPythonInterface() override = default; 42 43 enum class AbstractMethodCheckerCases { 44 eNotImplemented, 45 eNotAllocated, 46 eNotCallable, 47 eValid 48 }; 49 50 llvm::Expected<std::map<llvm::StringLiteral, AbstractMethodCheckerCases>> 51 CheckAbstractMethodImplementation( 52 const python::PythonDictionary &class_dict) const { 53 54 using namespace python; 55 56 std::map<llvm::StringLiteral, AbstractMethodCheckerCases> checker; 57 #define SET_ERROR_AND_CONTINUE(method_name, error) \ 58 { \ 59 checker[method_name] = error; \ 60 continue; \ 61 } 62 63 for (const llvm::StringLiteral &method_name : GetAbstractMethods()) { 64 if (!class_dict.HasKey(method_name)) 65 SET_ERROR_AND_CONTINUE(method_name, 66 AbstractMethodCheckerCases::eNotImplemented) 67 auto callable_or_err = class_dict.GetItem(method_name); 68 if (!callable_or_err) 69 SET_ERROR_AND_CONTINUE(method_name, 70 AbstractMethodCheckerCases::eNotAllocated) 71 if (!PythonCallable::Check(callable_or_err.get().get())) 72 SET_ERROR_AND_CONTINUE(method_name, 73 AbstractMethodCheckerCases::eNotCallable) 74 checker[method_name] = AbstractMethodCheckerCases::eValid; 75 } 76 77 #undef HANDLE_ERROR 78 79 return checker; 80 } 81 82 template <typename... Args> 83 llvm::Expected<StructuredData::GenericSP> 84 CreatePluginObject(llvm::StringRef class_name, 85 StructuredData::Generic *script_obj, Args... args) { 86 using namespace python; 87 using Locker = ScriptInterpreterPythonImpl::Locker; 88 89 auto create_error = [](std::string message) { 90 return llvm::createStringError(llvm::inconvertibleErrorCode(), message); 91 }; 92 93 bool has_class_name = !class_name.empty(); 94 bool has_interpreter_dict = 95 !(llvm::StringRef(m_interpreter.GetDictionaryName()).empty()); 96 if (!has_class_name && !has_interpreter_dict && !script_obj) { 97 if (!has_class_name) 98 return create_error("Missing script class name."); 99 else if (!has_interpreter_dict) 100 return create_error("Invalid script interpreter dictionary."); 101 else 102 return create_error("Missing scripting object."); 103 } 104 105 Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, 106 Locker::FreeLock); 107 108 PythonObject result = {}; 109 110 if (script_obj) { 111 result = PythonObject(PyRefType::Borrowed, 112 static_cast<PyObject *>(script_obj->GetValue())); 113 } else { 114 auto dict = 115 PythonModule::MainModule().ResolveName<python::PythonDictionary>( 116 m_interpreter.GetDictionaryName()); 117 if (!dict.IsAllocated()) 118 return create_error( 119 llvm::formatv("Could not find interpreter dictionary: %s", 120 m_interpreter.GetDictionaryName())); 121 122 auto init = 123 PythonObject::ResolveNameWithDictionary<python::PythonCallable>( 124 class_name, dict); 125 if (!init.IsAllocated()) 126 return create_error(llvm::formatv("Could not find script class: {0}", 127 class_name.data())); 128 129 std::tuple<Args...> original_args = std::forward_as_tuple(args...); 130 auto transformed_args = TransformArgs(original_args); 131 132 std::string error_string; 133 llvm::Expected<PythonCallable::ArgInfo> arg_info = init.GetArgInfo(); 134 if (!arg_info) { 135 llvm::handleAllErrors( 136 arg_info.takeError(), 137 [&](PythonException &E) { error_string.append(E.ReadBacktrace()); }, 138 [&](const llvm::ErrorInfoBase &E) { 139 error_string.append(E.message()); 140 }); 141 return llvm::createStringError(llvm::inconvertibleErrorCode(), 142 error_string); 143 } 144 145 llvm::Expected<PythonObject> expected_return_object = 146 create_error("Resulting object is not initialized."); 147 148 std::apply( 149 [&init, &expected_return_object](auto &&...args) { 150 llvm::consumeError(expected_return_object.takeError()); 151 expected_return_object = init(args...); 152 }, 153 transformed_args); 154 155 if (!expected_return_object) 156 return expected_return_object.takeError(); 157 result = expected_return_object.get(); 158 } 159 160 if (!result.IsValid()) 161 return create_error("Resulting object is not a valid Python Object."); 162 if (!result.HasAttribute("__class__")) 163 return create_error("Resulting object doesn't have '__class__' member."); 164 165 PythonObject obj_class = result.GetAttributeValue("__class__"); 166 if (!obj_class.IsValid()) 167 return create_error("Resulting class object is not a valid."); 168 if (!obj_class.HasAttribute("__name__")) 169 return create_error( 170 "Resulting object class doesn't have '__name__' member."); 171 PythonString obj_class_name = 172 obj_class.GetAttributeValue("__name__").AsType<PythonString>(); 173 174 PythonObject object_class_mapping_proxy = 175 obj_class.GetAttributeValue("__dict__"); 176 if (!obj_class.HasAttribute("__dict__")) 177 return create_error( 178 "Resulting object class doesn't have '__dict__' member."); 179 180 PythonCallable dict_converter = PythonModule::BuiltinsModule() 181 .ResolveName("dict") 182 .AsType<PythonCallable>(); 183 if (!dict_converter.IsAllocated()) 184 return create_error( 185 "Python 'builtins' module doesn't have 'dict' class."); 186 187 PythonDictionary object_class_dict = 188 dict_converter(object_class_mapping_proxy).AsType<PythonDictionary>(); 189 if (!object_class_dict.IsAllocated()) 190 return create_error("Coudn't create dictionary from resulting object " 191 "class mapping proxy object."); 192 193 auto checker_or_err = CheckAbstractMethodImplementation(object_class_dict); 194 if (!checker_or_err) 195 return checker_or_err.takeError(); 196 197 for (const auto &method_checker : *checker_or_err) 198 switch (method_checker.second) { 199 case AbstractMethodCheckerCases::eNotImplemented: 200 LLDB_LOG(GetLog(LLDBLog::Script), 201 "Abstract method {0}.{1} not implemented.", 202 obj_class_name.GetString(), method_checker.first); 203 break; 204 case AbstractMethodCheckerCases::eNotAllocated: 205 LLDB_LOG(GetLog(LLDBLog::Script), 206 "Abstract method {0}.{1} not allocated.", 207 obj_class_name.GetString(), method_checker.first); 208 break; 209 case AbstractMethodCheckerCases::eNotCallable: 210 LLDB_LOG(GetLog(LLDBLog::Script), 211 "Abstract method {0}.{1} not callable.", 212 obj_class_name.GetString(), method_checker.first); 213 break; 214 case AbstractMethodCheckerCases::eValid: 215 LLDB_LOG(GetLog(LLDBLog::Script), 216 "Abstract method {0}.{1} implemented & valid.", 217 obj_class_name.GetString(), method_checker.first); 218 break; 219 } 220 221 for (const auto &method_checker : *checker_or_err) 222 if (method_checker.second != AbstractMethodCheckerCases::eValid) 223 return create_error( 224 llvm::formatv("Abstract method {0}.{1} missing. Enable lldb " 225 "script log for more details.", 226 obj_class_name.GetString(), method_checker.first)); 227 228 m_object_instance_sp = StructuredData::GenericSP( 229 new StructuredPythonObject(std::move(result))); 230 return m_object_instance_sp; 231 } 232 233 protected: 234 template <typename T = StructuredData::ObjectSP> 235 T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) { 236 return p.CreateStructuredObject(); 237 } 238 239 template <typename T = StructuredData::ObjectSP, typename... Args> 240 T Dispatch(llvm::StringRef method_name, Status &error, Args &&...args) { 241 using namespace python; 242 using Locker = ScriptInterpreterPythonImpl::Locker; 243 244 std::string caller_signature = 245 llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(" (") + 246 llvm::Twine(method_name) + llvm::Twine(")")) 247 .str(); 248 if (!m_object_instance_sp) 249 return ErrorWithMessage<T>(caller_signature, "Python object ill-formed", 250 error); 251 252 Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, 253 Locker::FreeLock); 254 255 PythonObject implementor(PyRefType::Borrowed, 256 (PyObject *)m_object_instance_sp->GetValue()); 257 258 if (!implementor.IsAllocated()) 259 return llvm::is_contained(GetAbstractMethods(), method_name) 260 ? ErrorWithMessage<T>(caller_signature, 261 "Python implementor not allocated.", 262 error) 263 : T{}; 264 265 std::tuple<Args...> original_args = std::forward_as_tuple(args...); 266 auto transformed_args = TransformArgs(original_args); 267 268 llvm::Expected<PythonObject> expected_return_object = 269 llvm::make_error<llvm::StringError>("Not initialized.", 270 llvm::inconvertibleErrorCode()); 271 std::apply( 272 [&implementor, &method_name, &expected_return_object](auto &&...args) { 273 llvm::consumeError(expected_return_object.takeError()); 274 expected_return_object = 275 implementor.CallMethod(method_name.data(), args...); 276 }, 277 transformed_args); 278 279 if (llvm::Error e = expected_return_object.takeError()) { 280 error.SetErrorString(llvm::toString(std::move(e)).c_str()); 281 return ErrorWithMessage<T>(caller_signature, 282 "Python method could not be called.", error); 283 } 284 285 PythonObject py_return = std::move(expected_return_object.get()); 286 287 // Now that we called the python method with the transformed arguments, 288 // we need to interate again over both the original and transformed 289 // parameter pack, and transform back the parameter that were passed in 290 // the original parameter pack as references or pointers. 291 if (sizeof...(Args) > 0) 292 if (!ReassignPtrsOrRefsArgs(original_args, transformed_args)) 293 return ErrorWithMessage<T>( 294 caller_signature, 295 "Couldn't re-assign reference and pointer arguments.", error); 296 297 if (!py_return.IsAllocated()) 298 return {}; 299 return ExtractValueFromPythonObject<T>(py_return, error); 300 } 301 302 template <typename... Args> 303 Status GetStatusFromMethod(llvm::StringRef method_name, Args &&...args) { 304 Status error; 305 Dispatch<Status>(method_name, error, std::forward<Args>(args)...); 306 307 return error; 308 } 309 310 template <typename T> T Transform(T object) { 311 // No Transformation for generic usage 312 return {object}; 313 } 314 315 python::PythonObject Transform(bool arg) { 316 // Boolean arguments need to be turned into python objects. 317 return python::PythonBoolean(arg); 318 } 319 320 python::PythonObject Transform(Status arg) { 321 return python::SWIGBridge::ToSWIGWrapper(arg); 322 } 323 324 python::PythonObject Transform(const StructuredDataImpl &arg) { 325 return python::SWIGBridge::ToSWIGWrapper(arg); 326 } 327 328 python::PythonObject Transform(lldb::ExecutionContextRefSP arg) { 329 return python::SWIGBridge::ToSWIGWrapper(arg); 330 } 331 332 python::PythonObject Transform(lldb::ProcessSP arg) { 333 return python::SWIGBridge::ToSWIGWrapper(arg); 334 } 335 336 python::PythonObject Transform(lldb::ThreadPlanSP arg) { 337 return python::SWIGBridge::ToSWIGWrapper(arg); 338 } 339 340 python::PythonObject Transform(lldb::ProcessAttachInfoSP arg) { 341 return python::SWIGBridge::ToSWIGWrapper(arg); 342 } 343 344 python::PythonObject Transform(lldb::ProcessLaunchInfoSP arg) { 345 return python::SWIGBridge::ToSWIGWrapper(arg); 346 } 347 348 python::PythonObject Transform(Event *arg) { 349 return python::SWIGBridge::ToSWIGWrapper(arg); 350 } 351 352 python::PythonObject Transform(lldb::StreamSP arg) { 353 return python::SWIGBridge::ToSWIGWrapper(arg.get()); 354 } 355 356 python::PythonObject Transform(lldb::DataExtractorSP arg) { 357 return python::SWIGBridge::ToSWIGWrapper(arg); 358 } 359 360 template <typename T, typename U> 361 void ReverseTransform(T &original_arg, U transformed_arg, Status &error) { 362 // If U is not a PythonObject, don't touch it! 363 return; 364 } 365 366 template <typename T> 367 void ReverseTransform(T &original_arg, python::PythonObject transformed_arg, 368 Status &error) { 369 original_arg = ExtractValueFromPythonObject<T>(transformed_arg, error); 370 } 371 372 void ReverseTransform(bool &original_arg, 373 python::PythonObject transformed_arg, Status &error) { 374 python::PythonBoolean boolean_arg = python::PythonBoolean( 375 python::PyRefType::Borrowed, transformed_arg.get()); 376 if (boolean_arg.IsValid()) 377 original_arg = boolean_arg.GetValue(); 378 else 379 error.SetErrorString( 380 llvm::formatv("{}: Invalid boolean argument.", LLVM_PRETTY_FUNCTION) 381 .str()); 382 } 383 384 template <std::size_t... I, typename... Args> 385 auto TransformTuple(const std::tuple<Args...> &args, 386 std::index_sequence<I...>) { 387 return std::make_tuple(Transform(std::get<I>(args))...); 388 } 389 390 // This will iterate over the Dispatch parameter pack and replace in-place 391 // every `lldb_private` argument that has a SB counterpart. 392 template <typename... Args> 393 auto TransformArgs(const std::tuple<Args...> &args) { 394 return TransformTuple(args, std::make_index_sequence<sizeof...(Args)>()); 395 } 396 397 template <typename T, typename U> 398 void TransformBack(T &original_arg, U transformed_arg, Status &error) { 399 ReverseTransform(original_arg, transformed_arg, error); 400 } 401 402 template <std::size_t... I, typename... Ts, typename... Us> 403 bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args, 404 std::tuple<Us...> &transformed_args, 405 std::index_sequence<I...>) { 406 Status error; 407 (TransformBack(std::get<I>(original_args), std::get<I>(transformed_args), 408 error), 409 ...); 410 return error.Success(); 411 } 412 413 template <typename... Ts, typename... Us> 414 bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args, 415 std::tuple<Us...> &transformed_args) { 416 if (sizeof...(Ts) != sizeof...(Us)) 417 return false; 418 419 return ReassignPtrsOrRefsArgs(original_args, transformed_args, 420 std::make_index_sequence<sizeof...(Ts)>()); 421 } 422 423 template <typename T, typename... Args> 424 void FormatArgs(std::string &fmt, T arg, Args... args) const { 425 FormatArgs(fmt, arg); 426 FormatArgs(fmt, args...); 427 } 428 429 template <typename T> void FormatArgs(std::string &fmt, T arg) const { 430 fmt += python::PythonFormat<T>::format; 431 } 432 433 void FormatArgs(std::string &fmt) const {} 434 435 // The lifetime is managed by the ScriptInterpreter 436 ScriptInterpreterPythonImpl &m_interpreter; 437 }; 438 439 template <> 440 StructuredData::ArraySP 441 ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>( 442 python::PythonObject &p, Status &error); 443 444 template <> 445 StructuredData::DictionarySP 446 ScriptedPythonInterface::ExtractValueFromPythonObject< 447 StructuredData::DictionarySP>(python::PythonObject &p, Status &error); 448 449 template <> 450 Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>( 451 python::PythonObject &p, Status &error); 452 453 template <> 454 Event *ScriptedPythonInterface::ExtractValueFromPythonObject<Event *>( 455 python::PythonObject &p, Status &error); 456 457 template <> 458 lldb::StreamSP 459 ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StreamSP>( 460 python::PythonObject &p, Status &error); 461 462 template <> 463 lldb::BreakpointSP 464 ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>( 465 python::PythonObject &p, Status &error); 466 467 template <> 468 lldb::ProcessAttachInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject< 469 lldb::ProcessAttachInfoSP>(python::PythonObject &p, Status &error); 470 471 template <> 472 lldb::ProcessLaunchInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject< 473 lldb::ProcessLaunchInfoSP>(python::PythonObject &p, Status &error); 474 475 template <> 476 lldb::DataExtractorSP 477 ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>( 478 python::PythonObject &p, Status &error); 479 480 template <> 481 std::optional<MemoryRegionInfo> 482 ScriptedPythonInterface::ExtractValueFromPythonObject< 483 std::optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error); 484 485 } // namespace lldb_private 486 487 #endif // LLDB_ENABLE_PYTHON 488 #endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H 489