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 std::move(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::ProcessSP arg) { 224 return python::SWIGBridge::ToSWIGWrapper(arg); 225 } 226 227 python::PythonObject Transform(lldb::ThreadPlanSP arg) { 228 return python::SWIGBridge::ToSWIGWrapper(arg); 229 } 230 231 python::PythonObject Transform(lldb::ProcessAttachInfoSP arg) { 232 return python::SWIGBridge::ToSWIGWrapper(arg); 233 } 234 235 python::PythonObject Transform(lldb::ProcessLaunchInfoSP arg) { 236 return python::SWIGBridge::ToSWIGWrapper(arg); 237 } 238 239 python::PythonObject Transform(Event *arg) { 240 return python::SWIGBridge::ToSWIGWrapper(arg); 241 } 242 243 python::PythonObject Transform(Stream *arg) { 244 return python::SWIGBridge::ToSWIGWrapper(arg); 245 } 246 247 python::PythonObject Transform(lldb::DataExtractorSP arg) { 248 return python::SWIGBridge::ToSWIGWrapper(arg); 249 } 250 251 template <typename T, typename U> 252 void ReverseTransform(T &original_arg, U transformed_arg, Status &error) { 253 // If U is not a PythonObject, don't touch it! 254 return; 255 } 256 257 template <typename T> 258 void ReverseTransform(T &original_arg, python::PythonObject transformed_arg, 259 Status &error) { 260 original_arg = ExtractValueFromPythonObject<T>(transformed_arg, error); 261 } 262 263 void ReverseTransform(bool &original_arg, 264 python::PythonObject transformed_arg, Status &error) { 265 python::PythonBoolean boolean_arg = python::PythonBoolean( 266 python::PyRefType::Borrowed, transformed_arg.get()); 267 if (boolean_arg.IsValid()) 268 original_arg = boolean_arg.GetValue(); 269 else 270 error.SetErrorString( 271 llvm::formatv("{}: Invalid boolean argument.", LLVM_PRETTY_FUNCTION) 272 .str()); 273 } 274 275 template <std::size_t... I, typename... Args> 276 auto TransformTuple(const std::tuple<Args...> &args, 277 std::index_sequence<I...>) { 278 return std::make_tuple(Transform(std::get<I>(args))...); 279 } 280 281 // This will iterate over the Dispatch parameter pack and replace in-place 282 // every `lldb_private` argument that has a SB counterpart. 283 template <typename... Args> 284 auto TransformArgs(const std::tuple<Args...> &args) { 285 return TransformTuple(args, std::make_index_sequence<sizeof...(Args)>()); 286 } 287 288 template <typename T, typename U> 289 void TransformBack(T &original_arg, U transformed_arg, Status &error) { 290 ReverseTransform(original_arg, transformed_arg, error); 291 } 292 293 template <std::size_t... I, typename... Ts, typename... Us> 294 bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args, 295 std::tuple<Us...> &transformed_args, 296 std::index_sequence<I...>) { 297 Status error; 298 (TransformBack(std::get<I>(original_args), std::get<I>(transformed_args), 299 error), 300 ...); 301 return error.Success(); 302 } 303 304 template <typename... Ts, typename... Us> 305 bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args, 306 std::tuple<Us...> &transformed_args) { 307 if (sizeof...(Ts) != sizeof...(Us)) 308 return false; 309 310 return ReassignPtrsOrRefsArgs(original_args, transformed_args, 311 std::make_index_sequence<sizeof...(Ts)>()); 312 } 313 314 template <typename T, typename... Args> 315 void FormatArgs(std::string &fmt, T arg, Args... args) const { 316 FormatArgs(fmt, arg); 317 FormatArgs(fmt, args...); 318 } 319 320 template <typename T> void FormatArgs(std::string &fmt, T arg) const { 321 fmt += python::PythonFormat<T>::format; 322 } 323 324 void FormatArgs(std::string &fmt) const {} 325 326 // The lifetime is managed by the ScriptInterpreter 327 ScriptInterpreterPythonImpl &m_interpreter; 328 }; 329 330 template <> 331 StructuredData::ArraySP 332 ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>( 333 python::PythonObject &p, Status &error); 334 335 template <> 336 StructuredData::DictionarySP 337 ScriptedPythonInterface::ExtractValueFromPythonObject< 338 StructuredData::DictionarySP>(python::PythonObject &p, Status &error); 339 340 template <> 341 Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>( 342 python::PythonObject &p, Status &error); 343 344 template <> 345 Event *ScriptedPythonInterface::ExtractValueFromPythonObject<Event *>( 346 python::PythonObject &p, Status &error); 347 348 template <> 349 Stream *ScriptedPythonInterface::ExtractValueFromPythonObject<Stream *>( 350 python::PythonObject &p, Status &error); 351 352 template <> 353 lldb::BreakpointSP 354 ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>( 355 python::PythonObject &p, Status &error); 356 357 template <> 358 lldb::ProcessAttachInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject< 359 lldb::ProcessAttachInfoSP>(python::PythonObject &p, Status &error); 360 361 template <> 362 lldb::ProcessLaunchInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject< 363 lldb::ProcessLaunchInfoSP>(python::PythonObject &p, Status &error); 364 365 template <> 366 lldb::DataExtractorSP 367 ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>( 368 python::PythonObject &p, Status &error); 369 370 template <> 371 std::optional<MemoryRegionInfo> 372 ScriptedPythonInterface::ExtractValueFromPythonObject< 373 std::optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error); 374 375 } // namespace lldb_private 376 377 #endif // LLDB_ENABLE_PYTHON 378 #endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H 379