brintos

brintos / llvm-project-archived public Read only

0
0
Text · 24.3 KiB · 5f5665c Raw
654 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H10#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H11 12#if LLDB_ENABLE_PYTHON13 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 28namespace lldb_private {29class ScriptInterpreterPythonImpl;30class ScriptedPythonInterface : virtual public ScriptedInterface {31public:32  ScriptedPythonInterface(ScriptInterpreterPythonImpl &interpreter);33  ~ScriptedPythonInterface() override = default;34 35  enum class AbstractMethodCheckerCases {36    eNotImplemented,37    eNotAllocated,38    eNotCallable,39    eUnknownArgumentCount,40    eInvalidArgumentCount,41    eValid42  };43 44  struct AbstractMethodCheckerPayload {45 46    struct InvalidArgumentCountPayload {47      InvalidArgumentCountPayload(size_t required, size_t actual)48          : required_argument_count(required), actual_argument_count(actual) {}49 50      size_t required_argument_count;51      size_t actual_argument_count;52    };53 54    AbstractMethodCheckerCases checker_case;55    std::variant<std::monostate, InvalidArgumentCountPayload> payload;56  };57 58  llvm::Expected<std::map<llvm::StringLiteral, AbstractMethodCheckerPayload>>59  CheckAbstractMethodImplementation(60      const python::PythonDictionary &class_dict) const {61 62    using namespace python;63 64    std::map<llvm::StringLiteral, AbstractMethodCheckerPayload> checker;65#define SET_CASE_AND_CONTINUE(method_name, case)                               \66  {                                                                            \67    checker[method_name] = {case, {}};                                         \68    continue;                                                                  \69  }70 71    for (const AbstractMethodRequirement &requirement :72         GetAbstractMethodRequirements()) {73      llvm::StringLiteral method_name = requirement.name;74      if (!class_dict.HasKey(method_name))75        SET_CASE_AND_CONTINUE(method_name,76                              AbstractMethodCheckerCases::eNotImplemented)77      llvm::Expected<PythonObject> callable_or_err =78          class_dict.GetItem(method_name);79      if (!callable_or_err) {80        llvm::consumeError(callable_or_err.takeError());81        SET_CASE_AND_CONTINUE(method_name,82                              AbstractMethodCheckerCases::eNotAllocated)83      }84 85      PythonCallable callable = callable_or_err->AsType<PythonCallable>();86      if (!callable)87        SET_CASE_AND_CONTINUE(method_name,88                              AbstractMethodCheckerCases::eNotCallable)89 90      if (!requirement.min_arg_count)91        SET_CASE_AND_CONTINUE(method_name, AbstractMethodCheckerCases::eValid)92 93      auto arg_info_or_err = callable.GetArgInfo();94      if (!arg_info_or_err) {95        llvm::consumeError(arg_info_or_err.takeError());96        SET_CASE_AND_CONTINUE(method_name,97                              AbstractMethodCheckerCases::eUnknownArgumentCount)98      }99 100      PythonCallable::ArgInfo arg_info = *arg_info_or_err;101      if (requirement.min_arg_count <= arg_info.max_positional_args) {102        SET_CASE_AND_CONTINUE(method_name, AbstractMethodCheckerCases::eValid)103      } else {104        checker[method_name] = {105            AbstractMethodCheckerCases::eInvalidArgumentCount,106            AbstractMethodCheckerPayload::InvalidArgumentCountPayload(107                requirement.min_arg_count, arg_info.max_positional_args)};108      }109    }110 111#undef SET_CASE_AND_CONTINUE112 113    return checker;114  }115 116  template <typename... Args>117  llvm::Expected<StructuredData::GenericSP>118  CreatePluginObject(llvm::StringRef class_name,119                     StructuredData::Generic *script_obj, Args... args) {120    using namespace python;121    using Locker = ScriptInterpreterPythonImpl::Locker;122 123    Log *log = GetLog(LLDBLog::Script);124    auto create_error = [](llvm::StringLiteral format, auto &&...ts) {125      return llvm::createStringError(126          llvm::formatv(format.data(), std::forward<decltype(ts)>(ts)...)127              .str());128    };129 130    bool has_class_name = !class_name.empty();131    bool has_interpreter_dict =132        !(llvm::StringRef(m_interpreter.GetDictionaryName()).empty());133    if (!has_class_name && !has_interpreter_dict && !script_obj) {134      if (!has_class_name)135        return create_error("Missing script class name.");136      else if (!has_interpreter_dict)137        return create_error("Invalid script interpreter dictionary.");138      else139        return create_error("Missing scripting object.");140    }141 142    Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,143                   Locker::FreeLock);144 145    PythonObject result = {};146 147    if (script_obj) {148      result = PythonObject(PyRefType::Borrowed,149                            static_cast<PyObject *>(script_obj->GetValue()));150    } else {151      auto dict =152          PythonModule::MainModule().ResolveName<python::PythonDictionary>(153              m_interpreter.GetDictionaryName());154      if (!dict.IsAllocated())155        return create_error("Could not find interpreter dictionary: {0}",156                            m_interpreter.GetDictionaryName());157 158      auto init =159          PythonObject::ResolveNameWithDictionary<python::PythonCallable>(160              class_name, dict);161      if (!init.IsAllocated())162        return create_error("Could not find script class: {0}",163                            class_name.data());164 165      std::tuple<Args...> original_args = std::forward_as_tuple(args...);166      auto transformed_args = TransformArgs(original_args);167 168      std::string error_string;169      llvm::Expected<PythonCallable::ArgInfo> arg_info = init.GetArgInfo();170      if (!arg_info) {171        llvm::handleAllErrors(172            arg_info.takeError(),173            [&](PythonException &E) { error_string.append(E.ReadBacktrace()); },174            [&](const llvm::ErrorInfoBase &E) {175              error_string.append(E.message());176            });177        return llvm::createStringError(llvm::inconvertibleErrorCode(),178                                       error_string);179      }180 181      llvm::Expected<PythonObject> expected_return_object =182          create_error("Resulting object is not initialized.");183 184      // This relax the requirement on the number of argument for185      // initializing scripting extension if the size of the interface186      // parameter pack contains 1 less element than the extension maximum187      // number of positional arguments for this initializer.188      //189      // This addresses the cases where the embedded interpreter session190      // dictionary is passed to the extension initializer which is not used191      // most of the time.192      // Note, though none of our API's suggest defining the interfaces with193      // varargs, we have some extant clients that were doing that.  To keep194      // from breaking them, we just say putting a varargs in these signatures195      // turns off argument checking.196      size_t num_args = sizeof...(Args);197      if (arg_info->max_positional_args != PythonCallable::ArgInfo::UNBOUNDED &&198          num_args != arg_info->max_positional_args) {199        if (num_args != arg_info->max_positional_args - 1)200          return create_error("Passed arguments ({0}) doesn't match the number "201                              "of expected arguments ({1}).",202                              num_args, arg_info->max_positional_args);203 204        std::apply(205            [&init, &expected_return_object](auto &&...args) {206              llvm::consumeError(expected_return_object.takeError());207              expected_return_object = init(args...);208            },209            std::tuple_cat(transformed_args, std::make_tuple(dict)));210      } else {211        std::apply(212            [&init, &expected_return_object](auto &&...args) {213              llvm::consumeError(expected_return_object.takeError());214              expected_return_object = init(args...);215            },216            transformed_args);217      }218 219      if (!expected_return_object)220        return expected_return_object.takeError();221      result = expected_return_object.get();222    }223 224    if (!result.IsValid())225      return create_error("Resulting object is not a valid Python Object.");226    if (!result.HasAttribute("__class__"))227      return create_error("Resulting object doesn't have '__class__' member.");228 229    PythonObject obj_class = result.GetAttributeValue("__class__");230    if (!obj_class.IsValid())231      return create_error("Resulting class object is not a valid.");232    if (!obj_class.HasAttribute("__name__"))233      return create_error(234          "Resulting object class doesn't have '__name__' member.");235    PythonString obj_class_name =236        obj_class.GetAttributeValue("__name__").AsType<PythonString>();237 238    PythonObject object_class_mapping_proxy =239        obj_class.GetAttributeValue("__dict__");240    if (!obj_class.HasAttribute("__dict__"))241      return create_error(242          "Resulting object class doesn't have '__dict__' member.");243 244    PythonCallable dict_converter = PythonModule::BuiltinsModule()245                                        .ResolveName("dict")246                                        .AsType<PythonCallable>();247    if (!dict_converter.IsAllocated())248      return create_error(249          "Python 'builtins' module doesn't have 'dict' class.");250 251    PythonDictionary object_class_dict =252        dict_converter(object_class_mapping_proxy).AsType<PythonDictionary>();253    if (!object_class_dict.IsAllocated())254      return create_error("Coudn't create dictionary from resulting object "255                          "class mapping proxy object.");256 257    auto checker_or_err = CheckAbstractMethodImplementation(object_class_dict);258    if (!checker_or_err)259      return checker_or_err.takeError();260 261    llvm::Error abstract_method_errors = llvm::Error::success();262    for (const auto &method_checker : *checker_or_err)263      switch (method_checker.second.checker_case) {264      case AbstractMethodCheckerCases::eNotImplemented:265        abstract_method_errors = llvm::joinErrors(266            std::move(abstract_method_errors),267            std::move(create_error("Abstract method {0}.{1} not implemented.",268                                   obj_class_name.GetString(),269                                   method_checker.first)));270        break;271      case AbstractMethodCheckerCases::eNotAllocated:272        abstract_method_errors = llvm::joinErrors(273            std::move(abstract_method_errors),274            std::move(create_error("Abstract method {0}.{1} not allocated.",275                                   obj_class_name.GetString(),276                                   method_checker.first)));277        break;278      case AbstractMethodCheckerCases::eNotCallable:279        abstract_method_errors = llvm::joinErrors(280            std::move(abstract_method_errors),281            std::move(create_error("Abstract method {0}.{1} not callable.",282                                   obj_class_name.GetString(),283                                   method_checker.first)));284        break;285      case AbstractMethodCheckerCases::eUnknownArgumentCount:286        abstract_method_errors = llvm::joinErrors(287            std::move(abstract_method_errors),288            std::move(create_error(289                "Abstract method {0}.{1} has unknown argument count.",290                obj_class_name.GetString(), method_checker.first)));291        break;292      case AbstractMethodCheckerCases::eInvalidArgumentCount: {293        auto &payload_variant = method_checker.second.payload;294        if (!std::holds_alternative<295                AbstractMethodCheckerPayload::InvalidArgumentCountPayload>(296                payload_variant)) {297          abstract_method_errors = llvm::joinErrors(298              std::move(abstract_method_errors),299              std::move(create_error(300                  "Abstract method {0}.{1} has unexpected argument count.",301                  obj_class_name.GetString(), method_checker.first)));302        } else {303          auto payload = std::get<304              AbstractMethodCheckerPayload::InvalidArgumentCountPayload>(305              payload_variant);306          abstract_method_errors = llvm::joinErrors(307              std::move(abstract_method_errors),308              std::move(309                  create_error("Abstract method {0}.{1} has unexpected "310                               "argument count (expected {2} but has {3}).",311                               obj_class_name.GetString(), method_checker.first,312                               payload.required_argument_count,313                               payload.actual_argument_count)));314        }315      } break;316      case AbstractMethodCheckerCases::eValid:317        LLDB_LOG(log, "Abstract method {0}.{1} implemented & valid.",318                 obj_class_name.GetString(), method_checker.first);319        break;320      }321 322    if (abstract_method_errors) {323      Status error = Status::FromError(std::move(abstract_method_errors));324      LLDB_LOG(log, "Abstract method error in {0}:\n{1}", class_name,325               error.AsCString());326      return error.ToError();327    }328 329    m_object_instance_sp = StructuredData::GenericSP(330        new StructuredPythonObject(std::move(result)));331    return m_object_instance_sp;332  }333 334protected:335  template <typename T = StructuredData::ObjectSP>336  T ExtractValueFromPythonObject(python::PythonObject &p, Status &error) {337    return p.CreateStructuredObject();338  }339 340  template <typename T = StructuredData::ObjectSP, typename... Args>341  T Dispatch(llvm::StringRef method_name, Status &error, Args &&...args) {342    using namespace python;343    using Locker = ScriptInterpreterPythonImpl::Locker;344 345    std::string caller_signature =346        llvm::Twine(LLVM_PRETTY_FUNCTION + llvm::Twine(" (") +347                    llvm::Twine(method_name) + llvm::Twine(")"))348            .str();349    if (!m_object_instance_sp)350      return ErrorWithMessage<T>(caller_signature, "Python object ill-formed",351                                 error);352 353    Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN,354                   Locker::FreeLock);355 356    PythonObject implementor(PyRefType::Borrowed,357                             (PyObject *)m_object_instance_sp->GetValue());358 359    if (!implementor.IsAllocated())360      return llvm::is_contained(GetAbstractMethods(), method_name)361                 ? ErrorWithMessage<T>(caller_signature,362                                       "Python implementor not allocated.",363                                       error)364                 : T{};365 366    std::tuple<Args...> original_args = std::forward_as_tuple(args...);367    auto transformed_args = TransformArgs(original_args);368 369    llvm::Expected<PythonObject> expected_return_object =370        llvm::make_error<llvm::StringError>("Not initialized.",371                                            llvm::inconvertibleErrorCode());372    std::apply(373        [&implementor, &method_name, &expected_return_object](auto &&...args) {374          llvm::consumeError(expected_return_object.takeError());375          expected_return_object =376              implementor.CallMethod(method_name.data(), args...);377        },378        transformed_args);379 380    if (llvm::Error e = expected_return_object.takeError()) {381      error = Status::FromError(std::move(e));382      return ErrorWithMessage<T>(caller_signature,383                                 "Python method could not be called.", error);384    }385 386    PythonObject py_return = std::move(expected_return_object.get());387 388    // Now that we called the python method with the transformed arguments,389    // we need to interate again over both the original and transformed390    // parameter pack, and transform back the parameter that were passed in391    // the original parameter pack as references or pointers.392    if (sizeof...(Args) > 0)393      if (!ReassignPtrsOrRefsArgs(original_args, transformed_args))394        return ErrorWithMessage<T>(395            caller_signature,396            "Couldn't re-assign reference and pointer arguments.", error);397 398    if (!py_return.IsAllocated())399      return {};400    return ExtractValueFromPythonObject<T>(py_return, error);401  }402 403  template <typename... Args>404  Status GetStatusFromMethod(llvm::StringRef method_name, Args &&...args) {405    Status error;406    Dispatch<Status>(method_name, error, std::forward<Args>(args)...);407 408    return error;409  }410 411  template <typename T> T Transform(T object) {412    // No Transformation for generic usage413    return {object};414  }415 416  python::PythonObject Transform(bool arg) {417    // Boolean arguments need to be turned into python objects.418    return python::PythonBoolean(arg);419  }420 421  python::PythonObject Transform(const Status &arg) {422    return python::SWIGBridge::ToSWIGWrapper(arg.Clone());423  }424 425  python::PythonObject Transform(Status &&arg) {426    return python::SWIGBridge::ToSWIGWrapper(std::move(arg));427  }428 429  python::PythonObject Transform(const StructuredDataImpl &arg) {430    return python::SWIGBridge::ToSWIGWrapper(arg);431  }432 433  python::PythonObject Transform(lldb::ExecutionContextRefSP arg) {434    return python::SWIGBridge::ToSWIGWrapper(arg);435  }436 437  python::PythonObject Transform(lldb::TargetSP arg) {438    return python::SWIGBridge::ToSWIGWrapper(arg);439  }440 441  python::PythonObject Transform(lldb::BreakpointSP arg) {442    return python::SWIGBridge::ToSWIGWrapper(arg);443  }444 445  python::PythonObject Transform(lldb::BreakpointLocationSP arg) {446    return python::SWIGBridge::ToSWIGWrapper(arg);447  }448 449  python::PythonObject Transform(lldb::ProcessSP arg) {450    return python::SWIGBridge::ToSWIGWrapper(arg);451  }452 453  python::PythonObject Transform(lldb::ThreadSP arg) {454    return python::SWIGBridge::ToSWIGWrapper(arg);455  }456 457  python::PythonObject Transform(lldb::StackFrameListSP arg) {458    return python::SWIGBridge::ToSWIGWrapper(arg);459  }460 461  python::PythonObject Transform(lldb::ThreadPlanSP arg) {462    return python::SWIGBridge::ToSWIGWrapper(arg);463  }464 465  python::PythonObject Transform(lldb::ProcessAttachInfoSP arg) {466    return python::SWIGBridge::ToSWIGWrapper(arg);467  }468 469  python::PythonObject Transform(lldb::ProcessLaunchInfoSP arg) {470    return python::SWIGBridge::ToSWIGWrapper(arg);471  }472 473  python::PythonObject Transform(Event *arg) {474    return python::SWIGBridge::ToSWIGWrapper(arg);475  }476 477  python::PythonObject Transform(const SymbolContext &arg) {478    return python::SWIGBridge::ToSWIGWrapper(arg);479  }480 481  python::PythonObject Transform(lldb::StreamSP arg) {482    return python::SWIGBridge::ToSWIGWrapper(arg.get());483  }484 485  python::PythonObject Transform(lldb::StackFrameSP arg) {486    return python::SWIGBridge::ToSWIGWrapper(arg);487  }488 489  python::PythonObject Transform(lldb::DataExtractorSP arg) {490    return python::SWIGBridge::ToSWIGWrapper(arg);491  }492 493  python::PythonObject Transform(lldb::DescriptionLevel arg) {494    return python::SWIGBridge::ToSWIGWrapper(arg);495  }496 497  template <typename T, typename U>498  void ReverseTransform(T &original_arg, U transformed_arg, Status &error) {499    // If U is not a PythonObject, don't touch it!500  }501 502  template <typename T>503  void ReverseTransform(T &original_arg, python::PythonObject transformed_arg,504                        Status &error) {505    original_arg = ExtractValueFromPythonObject<T>(transformed_arg, error);506  }507 508  void ReverseTransform(bool &original_arg,509                        python::PythonObject transformed_arg, Status &error) {510    python::PythonBoolean boolean_arg = python::PythonBoolean(511        python::PyRefType::Borrowed, transformed_arg.get());512    if (boolean_arg.IsValid())513      original_arg = boolean_arg.GetValue();514    else515      error = Status::FromErrorStringWithFormatv(516          "{}: Invalid boolean argument.", LLVM_PRETTY_FUNCTION);517  }518 519  template <std::size_t... I, typename... Args>520  auto TransformTuple(const std::tuple<Args...> &args,521                      std::index_sequence<I...>) {522    return std::make_tuple(Transform(std::get<I>(args))...);523  }524 525  // This will iterate over the Dispatch parameter pack and replace in-place526  // every `lldb_private` argument that has a SB counterpart.527  template <typename... Args>528  auto TransformArgs(const std::tuple<Args...> &args) {529    return TransformTuple(args, std::make_index_sequence<sizeof...(Args)>());530  }531 532  template <typename T, typename U>533  void TransformBack(T &original_arg, U transformed_arg, Status &error) {534    ReverseTransform(original_arg, transformed_arg, error);535  }536 537  template <std::size_t... I, typename... Ts, typename... Us>538  bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args,539                              std::tuple<Us...> &transformed_args,540                              std::index_sequence<I...>) {541    Status error;542    (TransformBack(std::get<I>(original_args), std::get<I>(transformed_args),543                   error),544     ...);545    return error.Success();546  }547 548  template <typename... Ts, typename... Us>549  bool ReassignPtrsOrRefsArgs(std::tuple<Ts...> &original_args,550                              std::tuple<Us...> &transformed_args) {551    if (sizeof...(Ts) != sizeof...(Us))552      return false;553 554    return ReassignPtrsOrRefsArgs(original_args, transformed_args,555                                  std::make_index_sequence<sizeof...(Ts)>());556  }557 558  template <typename T, typename... Args>559  void FormatArgs(std::string &fmt, T arg, Args... args) const {560    FormatArgs(fmt, arg);561    FormatArgs(fmt, args...);562  }563 564  template <typename T> void FormatArgs(std::string &fmt, T arg) const {565    fmt += python::PythonFormat<T>::format;566  }567 568  void FormatArgs(std::string &fmt) const {}569 570  // The lifetime is managed by the ScriptInterpreter571  ScriptInterpreterPythonImpl &m_interpreter;572};573 574template <>575StructuredData::ArraySP576ScriptedPythonInterface::ExtractValueFromPythonObject<StructuredData::ArraySP>(577    python::PythonObject &p, Status &error);578 579template <>580StructuredData::DictionarySP581ScriptedPythonInterface::ExtractValueFromPythonObject<582    StructuredData::DictionarySP>(python::PythonObject &p, Status &error);583 584template <>585Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>(586    python::PythonObject &p, Status &error);587 588template <>589Event *ScriptedPythonInterface::ExtractValueFromPythonObject<Event *>(590    python::PythonObject &p, Status &error);591 592template <>593SymbolContext594ScriptedPythonInterface::ExtractValueFromPythonObject<SymbolContext>(595    python::PythonObject &p, Status &error);596 597template <>598lldb::StreamSP599ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StreamSP>(600    python::PythonObject &p, Status &error);601 602template <>603lldb::StackFrameSP604ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StackFrameSP>(605    python::PythonObject &p, Status &error);606 607template <>608lldb::BreakpointSP609ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>(610    python::PythonObject &p, Status &error);611 612template <>613lldb::BreakpointLocationSP614ScriptedPythonInterface::ExtractValueFromPythonObject<615    lldb::BreakpointLocationSP>(python::PythonObject &p, Status &error);616 617template <>618lldb::ProcessAttachInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject<619    lldb::ProcessAttachInfoSP>(python::PythonObject &p, Status &error);620 621template <>622lldb::ProcessLaunchInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject<623    lldb::ProcessLaunchInfoSP>(python::PythonObject &p, Status &error);624 625template <>626lldb::DataExtractorSP627ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>(628    python::PythonObject &p, Status &error);629 630template <>631std::optional<MemoryRegionInfo>632ScriptedPythonInterface::ExtractValueFromPythonObject<633    std::optional<MemoryRegionInfo>>(python::PythonObject &p, Status &error);634 635template <>636lldb::ExecutionContextRefSP637ScriptedPythonInterface::ExtractValueFromPythonObject<638    lldb::ExecutionContextRefSP>(python::PythonObject &p, Status &error);639 640template <>641lldb::DescriptionLevel642ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DescriptionLevel>(643    python::PythonObject &p, Status &error);644 645template <>646lldb::StackFrameListSP647ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StackFrameListSP>(648    python::PythonObject &p, Status &error);649 650} // namespace lldb_private651 652#endif // LLDB_ENABLE_PYTHON653#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDPYTHONINTERFACE_H654