Path: blob/main/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
39638 views
//===-- PythonDataObjects.cpp ---------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/Host/Config.h"910#if LLDB_ENABLE_PYTHON1112#include "PythonDataObjects.h"13#include "ScriptInterpreterPython.h"1415#include "lldb/Host/File.h"16#include "lldb/Host/FileSystem.h"17#include "lldb/Interpreter/ScriptInterpreter.h"18#include "lldb/Utility/LLDBLog.h"19#include "lldb/Utility/Log.h"20#include "lldb/Utility/Stream.h"2122#include "llvm/Support/Casting.h"23#include "llvm/Support/ConvertUTF.h"24#include "llvm/Support/Errno.h"2526#include <cstdio>27#include <variant>2829using namespace lldb_private;30using namespace lldb;31using namespace lldb_private::python;32using llvm::cantFail;33using llvm::Error;34using llvm::Expected;35using llvm::Twine;3637template <> Expected<bool> python::As<bool>(Expected<PythonObject> &&obj) {38if (!obj)39return obj.takeError();40return obj.get().IsTrue();41}4243template <>44Expected<long long> python::As<long long>(Expected<PythonObject> &&obj) {45if (!obj)46return obj.takeError();47return obj->AsLongLong();48}4950template <>51Expected<unsigned long long>52python::As<unsigned long long>(Expected<PythonObject> &&obj) {53if (!obj)54return obj.takeError();55return obj->AsUnsignedLongLong();56}5758template <>59Expected<std::string> python::As<std::string>(Expected<PythonObject> &&obj) {60if (!obj)61return obj.takeError();62PyObject *str_obj = PyObject_Str(obj.get().get());63if (!str_obj)64return llvm::make_error<PythonException>();65auto str = Take<PythonString>(str_obj);66auto utf8 = str.AsUTF8();67if (!utf8)68return utf8.takeError();69return std::string(utf8.get());70}7172static bool python_is_finalizing() {73#if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 13) || (PY_MAJOR_VERSION > 3)74return Py_IsFinalizing();75#elif PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 776return _Py_Finalizing != nullptr;77#else78return _Py_IsFinalizing();79#endif80}8182void PythonObject::Reset() {83if (m_py_obj && Py_IsInitialized()) {84if (python_is_finalizing()) {85// Leak m_py_obj rather than crashing the process.86// https://docs.python.org/3/c-api/init.html#c.PyGILState_Ensure87} else {88PyGILState_STATE state = PyGILState_Ensure();89Py_DECREF(m_py_obj);90PyGILState_Release(state);91}92}93m_py_obj = nullptr;94}9596Expected<long long> PythonObject::AsLongLong() const {97if (!m_py_obj)98return nullDeref();99assert(!PyErr_Occurred());100long long r = PyLong_AsLongLong(m_py_obj);101if (PyErr_Occurred())102return exception();103return r;104}105106Expected<unsigned long long> PythonObject::AsUnsignedLongLong() const {107if (!m_py_obj)108return nullDeref();109assert(!PyErr_Occurred());110long long r = PyLong_AsUnsignedLongLong(m_py_obj);111if (PyErr_Occurred())112return exception();113return r;114}115116// wraps on overflow, instead of raising an error.117Expected<unsigned long long> PythonObject::AsModuloUnsignedLongLong() const {118if (!m_py_obj)119return nullDeref();120assert(!PyErr_Occurred());121unsigned long long r = PyLong_AsUnsignedLongLongMask(m_py_obj);122// FIXME: We should fetch the exception message and hoist it.123if (PyErr_Occurred())124return exception();125return r;126}127128void StructuredPythonObject::Serialize(llvm::json::OStream &s) const {129s.value(llvm::formatv("Python Obj: {0:X}", GetValue()).str());130}131132// PythonObject133134void PythonObject::Dump(Stream &strm) const {135if (m_py_obj) {136FILE *file = llvm::sys::RetryAfterSignal(nullptr, ::tmpfile);137if (file) {138::PyObject_Print(m_py_obj, file, 0);139const long length = ftell(file);140if (length) {141::rewind(file);142std::vector<char> file_contents(length, '\0');143const size_t length_read =144::fread(file_contents.data(), 1, file_contents.size(), file);145if (length_read > 0)146strm.Write(file_contents.data(), length_read);147}148::fclose(file);149}150} else151strm.PutCString("NULL");152}153154PyObjectType PythonObject::GetObjectType() const {155if (!IsAllocated())156return PyObjectType::None;157158if (PythonModule::Check(m_py_obj))159return PyObjectType::Module;160if (PythonList::Check(m_py_obj))161return PyObjectType::List;162if (PythonTuple::Check(m_py_obj))163return PyObjectType::Tuple;164if (PythonDictionary::Check(m_py_obj))165return PyObjectType::Dictionary;166if (PythonString::Check(m_py_obj))167return PyObjectType::String;168if (PythonBytes::Check(m_py_obj))169return PyObjectType::Bytes;170if (PythonByteArray::Check(m_py_obj))171return PyObjectType::ByteArray;172if (PythonBoolean::Check(m_py_obj))173return PyObjectType::Boolean;174if (PythonInteger::Check(m_py_obj))175return PyObjectType::Integer;176if (PythonFile::Check(m_py_obj))177return PyObjectType::File;178if (PythonCallable::Check(m_py_obj))179return PyObjectType::Callable;180return PyObjectType::Unknown;181}182183PythonString PythonObject::Repr() const {184if (!m_py_obj)185return PythonString();186PyObject *repr = PyObject_Repr(m_py_obj);187if (!repr)188return PythonString();189return PythonString(PyRefType::Owned, repr);190}191192PythonString PythonObject::Str() const {193if (!m_py_obj)194return PythonString();195PyObject *str = PyObject_Str(m_py_obj);196if (!str)197return PythonString();198return PythonString(PyRefType::Owned, str);199}200201PythonObject202PythonObject::ResolveNameWithDictionary(llvm::StringRef name,203const PythonDictionary &dict) {204size_t dot_pos = name.find('.');205llvm::StringRef piece = name.substr(0, dot_pos);206PythonObject result = dict.GetItemForKey(PythonString(piece));207if (dot_pos == llvm::StringRef::npos) {208// There was no dot, we're done.209return result;210}211212// There was a dot. The remaining portion of the name should be looked up in213// the context of the object that was found in the dictionary.214return result.ResolveName(name.substr(dot_pos + 1));215}216217PythonObject PythonObject::ResolveName(llvm::StringRef name) const {218// Resolve the name in the context of the specified object. If, for example,219// `this` refers to a PyModule, then this will look for `name` in this220// module. If `this` refers to a PyType, then it will resolve `name` as an221// attribute of that type. If `this` refers to an instance of an object,222// then it will resolve `name` as the value of the specified field.223//224// This function handles dotted names so that, for example, if `m_py_obj`225// refers to the `sys` module, and `name` == "path.append", then it will find226// the function `sys.path.append`.227228size_t dot_pos = name.find('.');229if (dot_pos == llvm::StringRef::npos) {230// No dots in the name, we should be able to find the value immediately as231// an attribute of `m_py_obj`.232return GetAttributeValue(name);233}234235// Look up the first piece of the name, and resolve the rest as a child of236// that.237PythonObject parent = ResolveName(name.substr(0, dot_pos));238if (!parent.IsAllocated())239return PythonObject();240241// Tail recursion.. should be optimized by the compiler242return parent.ResolveName(name.substr(dot_pos + 1));243}244245bool PythonObject::HasAttribute(llvm::StringRef attr) const {246if (!IsValid())247return false;248PythonString py_attr(attr);249return !!PyObject_HasAttr(m_py_obj, py_attr.get());250}251252PythonObject PythonObject::GetAttributeValue(llvm::StringRef attr) const {253if (!IsValid())254return PythonObject();255256PythonString py_attr(attr);257if (!PyObject_HasAttr(m_py_obj, py_attr.get()))258return PythonObject();259260return PythonObject(PyRefType::Owned,261PyObject_GetAttr(m_py_obj, py_attr.get()));262}263264StructuredData::ObjectSP PythonObject::CreateStructuredObject() const {265assert(PyGILState_Check());266switch (GetObjectType()) {267case PyObjectType::Dictionary:268return PythonDictionary(PyRefType::Borrowed, m_py_obj)269.CreateStructuredDictionary();270case PyObjectType::Boolean:271return PythonBoolean(PyRefType::Borrowed, m_py_obj)272.CreateStructuredBoolean();273case PyObjectType::Integer: {274StructuredData::IntegerSP int_sp =275PythonInteger(PyRefType::Borrowed, m_py_obj).CreateStructuredInteger();276if (std::holds_alternative<StructuredData::UnsignedIntegerSP>(int_sp))277return std::get<StructuredData::UnsignedIntegerSP>(int_sp);278if (std::holds_alternative<StructuredData::SignedIntegerSP>(int_sp))279return std::get<StructuredData::SignedIntegerSP>(int_sp);280return nullptr;281};282case PyObjectType::List:283return PythonList(PyRefType::Borrowed, m_py_obj).CreateStructuredArray();284case PyObjectType::String:285return PythonString(PyRefType::Borrowed, m_py_obj).CreateStructuredString();286case PyObjectType::Bytes:287return PythonBytes(PyRefType::Borrowed, m_py_obj).CreateStructuredString();288case PyObjectType::ByteArray:289return PythonByteArray(PyRefType::Borrowed, m_py_obj)290.CreateStructuredString();291case PyObjectType::None:292return StructuredData::ObjectSP();293default:294return StructuredData::ObjectSP(new StructuredPythonObject(295PythonObject(PyRefType::Borrowed, m_py_obj)));296}297}298299// PythonString300301PythonBytes::PythonBytes(llvm::ArrayRef<uint8_t> bytes) { SetBytes(bytes); }302303PythonBytes::PythonBytes(const uint8_t *bytes, size_t length) {304SetBytes(llvm::ArrayRef<uint8_t>(bytes, length));305}306307bool PythonBytes::Check(PyObject *py_obj) {308if (!py_obj)309return false;310return PyBytes_Check(py_obj);311}312313llvm::ArrayRef<uint8_t> PythonBytes::GetBytes() const {314if (!IsValid())315return llvm::ArrayRef<uint8_t>();316317Py_ssize_t size;318char *c;319320PyBytes_AsStringAndSize(m_py_obj, &c, &size);321return llvm::ArrayRef<uint8_t>(reinterpret_cast<uint8_t *>(c), size);322}323324size_t PythonBytes::GetSize() const {325if (!IsValid())326return 0;327return PyBytes_Size(m_py_obj);328}329330void PythonBytes::SetBytes(llvm::ArrayRef<uint8_t> bytes) {331const char *data = reinterpret_cast<const char *>(bytes.data());332*this = Take<PythonBytes>(PyBytes_FromStringAndSize(data, bytes.size()));333}334335StructuredData::StringSP PythonBytes::CreateStructuredString() const {336StructuredData::StringSP result(new StructuredData::String);337Py_ssize_t size;338char *c;339PyBytes_AsStringAndSize(m_py_obj, &c, &size);340result->SetValue(std::string(c, size));341return result;342}343344PythonByteArray::PythonByteArray(llvm::ArrayRef<uint8_t> bytes)345: PythonByteArray(bytes.data(), bytes.size()) {}346347PythonByteArray::PythonByteArray(const uint8_t *bytes, size_t length) {348const char *str = reinterpret_cast<const char *>(bytes);349*this = Take<PythonByteArray>(PyByteArray_FromStringAndSize(str, length));350}351352bool PythonByteArray::Check(PyObject *py_obj) {353if (!py_obj)354return false;355return PyByteArray_Check(py_obj);356}357358llvm::ArrayRef<uint8_t> PythonByteArray::GetBytes() const {359if (!IsValid())360return llvm::ArrayRef<uint8_t>();361362char *c = PyByteArray_AsString(m_py_obj);363size_t size = GetSize();364return llvm::ArrayRef<uint8_t>(reinterpret_cast<uint8_t *>(c), size);365}366367size_t PythonByteArray::GetSize() const {368if (!IsValid())369return 0;370371return PyByteArray_Size(m_py_obj);372}373374StructuredData::StringSP PythonByteArray::CreateStructuredString() const {375StructuredData::StringSP result(new StructuredData::String);376llvm::ArrayRef<uint8_t> bytes = GetBytes();377const char *str = reinterpret_cast<const char *>(bytes.data());378result->SetValue(std::string(str, bytes.size()));379return result;380}381382// PythonString383384Expected<PythonString> PythonString::FromUTF8(llvm::StringRef string) {385PyObject *str = PyUnicode_FromStringAndSize(string.data(), string.size());386if (!str)387return llvm::make_error<PythonException>();388return Take<PythonString>(str);389}390391PythonString::PythonString(llvm::StringRef string) { SetString(string); }392393bool PythonString::Check(PyObject *py_obj) {394if (!py_obj)395return false;396397if (PyUnicode_Check(py_obj))398return true;399return false;400}401402llvm::StringRef PythonString::GetString() const {403auto s = AsUTF8();404if (!s) {405llvm::consumeError(s.takeError());406return llvm::StringRef("");407}408return s.get();409}410411Expected<llvm::StringRef> PythonString::AsUTF8() const {412if (!IsValid())413return nullDeref();414415Py_ssize_t size;416const char *data;417418data = PyUnicode_AsUTF8AndSize(m_py_obj, &size);419420if (!data)421return exception();422423return llvm::StringRef(data, size);424}425426size_t PythonString::GetSize() const {427if (IsValid()) {428#if PY_MINOR_VERSION >= 3429return PyUnicode_GetLength(m_py_obj);430#else431return PyUnicode_GetSize(m_py_obj);432#endif433}434return 0;435}436437void PythonString::SetString(llvm::StringRef string) {438auto s = FromUTF8(string);439if (!s) {440llvm::consumeError(s.takeError());441Reset();442} else {443*this = std::move(s.get());444}445}446447StructuredData::StringSP PythonString::CreateStructuredString() const {448StructuredData::StringSP result(new StructuredData::String);449result->SetValue(GetString());450return result;451}452453// PythonInteger454455PythonInteger::PythonInteger(int64_t value) { SetInteger(value); }456457bool PythonInteger::Check(PyObject *py_obj) {458if (!py_obj)459return false;460461// Python 3 does not have PyInt_Check. There is only one type of integral462// value, long.463return PyLong_Check(py_obj);464}465466void PythonInteger::SetInteger(int64_t value) {467*this = Take<PythonInteger>(PyLong_FromLongLong(value));468}469470StructuredData::IntegerSP PythonInteger::CreateStructuredInteger() const {471StructuredData::UnsignedIntegerSP uint_sp = CreateStructuredUnsignedInteger();472return uint_sp ? StructuredData::IntegerSP(uint_sp)473: CreateStructuredSignedInteger();474}475476StructuredData::UnsignedIntegerSP477PythonInteger::CreateStructuredUnsignedInteger() const {478StructuredData::UnsignedIntegerSP result = nullptr;479llvm::Expected<unsigned long long> value = AsUnsignedLongLong();480if (!value)481llvm::consumeError(value.takeError());482else483result = std::make_shared<StructuredData::UnsignedInteger>(value.get());484485return result;486}487488StructuredData::SignedIntegerSP489PythonInteger::CreateStructuredSignedInteger() const {490StructuredData::SignedIntegerSP result = nullptr;491llvm::Expected<long long> value = AsLongLong();492if (!value)493llvm::consumeError(value.takeError());494else495result = std::make_shared<StructuredData::SignedInteger>(value.get());496497return result;498}499500// PythonBoolean501502PythonBoolean::PythonBoolean(bool value) {503SetValue(value);504}505506bool PythonBoolean::Check(PyObject *py_obj) {507return py_obj ? PyBool_Check(py_obj) : false;508}509510bool PythonBoolean::GetValue() const {511return m_py_obj ? PyObject_IsTrue(m_py_obj) : false;512}513514void PythonBoolean::SetValue(bool value) {515*this = Take<PythonBoolean>(PyBool_FromLong(value));516}517518StructuredData::BooleanSP PythonBoolean::CreateStructuredBoolean() const {519StructuredData::BooleanSP result(new StructuredData::Boolean);520result->SetValue(GetValue());521return result;522}523524// PythonList525526PythonList::PythonList(PyInitialValue value) {527if (value == PyInitialValue::Empty)528*this = Take<PythonList>(PyList_New(0));529}530531PythonList::PythonList(int list_size) {532*this = Take<PythonList>(PyList_New(list_size));533}534535bool PythonList::Check(PyObject *py_obj) {536if (!py_obj)537return false;538return PyList_Check(py_obj);539}540541uint32_t PythonList::GetSize() const {542if (IsValid())543return PyList_GET_SIZE(m_py_obj);544return 0;545}546547PythonObject PythonList::GetItemAtIndex(uint32_t index) const {548if (IsValid())549return PythonObject(PyRefType::Borrowed, PyList_GetItem(m_py_obj, index));550return PythonObject();551}552553void PythonList::SetItemAtIndex(uint32_t index, const PythonObject &object) {554if (IsAllocated() && object.IsValid()) {555// PyList_SetItem is documented to "steal" a reference, so we need to556// convert it to an owned reference by incrementing it.557Py_INCREF(object.get());558PyList_SetItem(m_py_obj, index, object.get());559}560}561562void PythonList::AppendItem(const PythonObject &object) {563if (IsAllocated() && object.IsValid()) {564// `PyList_Append` does *not* steal a reference, so do not call `Py_INCREF`565// here like we do with `PyList_SetItem`.566PyList_Append(m_py_obj, object.get());567}568}569570StructuredData::ArraySP PythonList::CreateStructuredArray() const {571StructuredData::ArraySP result(new StructuredData::Array);572uint32_t count = GetSize();573for (uint32_t i = 0; i < count; ++i) {574PythonObject obj = GetItemAtIndex(i);575result->AddItem(obj.CreateStructuredObject());576}577return result;578}579580// PythonTuple581582PythonTuple::PythonTuple(PyInitialValue value) {583if (value == PyInitialValue::Empty)584*this = Take<PythonTuple>(PyTuple_New(0));585}586587PythonTuple::PythonTuple(int tuple_size) {588*this = Take<PythonTuple>(PyTuple_New(tuple_size));589}590591PythonTuple::PythonTuple(std::initializer_list<PythonObject> objects) {592m_py_obj = PyTuple_New(objects.size());593594uint32_t idx = 0;595for (auto object : objects) {596if (object.IsValid())597SetItemAtIndex(idx, object);598idx++;599}600}601602PythonTuple::PythonTuple(std::initializer_list<PyObject *> objects) {603m_py_obj = PyTuple_New(objects.size());604605uint32_t idx = 0;606for (auto py_object : objects) {607PythonObject object(PyRefType::Borrowed, py_object);608if (object.IsValid())609SetItemAtIndex(idx, object);610idx++;611}612}613614bool PythonTuple::Check(PyObject *py_obj) {615if (!py_obj)616return false;617return PyTuple_Check(py_obj);618}619620uint32_t PythonTuple::GetSize() const {621if (IsValid())622return PyTuple_GET_SIZE(m_py_obj);623return 0;624}625626PythonObject PythonTuple::GetItemAtIndex(uint32_t index) const {627if (IsValid())628return PythonObject(PyRefType::Borrowed, PyTuple_GetItem(m_py_obj, index));629return PythonObject();630}631632void PythonTuple::SetItemAtIndex(uint32_t index, const PythonObject &object) {633if (IsAllocated() && object.IsValid()) {634// PyTuple_SetItem is documented to "steal" a reference, so we need to635// convert it to an owned reference by incrementing it.636Py_INCREF(object.get());637PyTuple_SetItem(m_py_obj, index, object.get());638}639}640641StructuredData::ArraySP PythonTuple::CreateStructuredArray() const {642StructuredData::ArraySP result(new StructuredData::Array);643uint32_t count = GetSize();644for (uint32_t i = 0; i < count; ++i) {645PythonObject obj = GetItemAtIndex(i);646result->AddItem(obj.CreateStructuredObject());647}648return result;649}650651// PythonDictionary652653PythonDictionary::PythonDictionary(PyInitialValue value) {654if (value == PyInitialValue::Empty)655*this = Take<PythonDictionary>(PyDict_New());656}657658bool PythonDictionary::Check(PyObject *py_obj) {659if (!py_obj)660return false;661662return PyDict_Check(py_obj);663}664665bool PythonDictionary::HasKey(const llvm::Twine &key) const {666if (!IsValid())667return false;668669PythonString key_object(key.isSingleStringRef() ? key.getSingleStringRef()670: key.str());671672if (int res = PyDict_Contains(m_py_obj, key_object.get()) > 0)673return res;674675PyErr_Print();676return false;677}678679uint32_t PythonDictionary::GetSize() const {680if (IsValid())681return PyDict_Size(m_py_obj);682return 0;683}684685PythonList PythonDictionary::GetKeys() const {686if (IsValid())687return PythonList(PyRefType::Owned, PyDict_Keys(m_py_obj));688return PythonList(PyInitialValue::Invalid);689}690691PythonObject PythonDictionary::GetItemForKey(const PythonObject &key) const {692auto item = GetItem(key);693if (!item) {694llvm::consumeError(item.takeError());695return PythonObject();696}697return std::move(item.get());698}699700Expected<PythonObject>701PythonDictionary::GetItem(const PythonObject &key) const {702if (!IsValid())703return nullDeref();704PyObject *o = PyDict_GetItemWithError(m_py_obj, key.get());705if (PyErr_Occurred())706return exception();707if (!o)708return keyError();709return Retain<PythonObject>(o);710}711712Expected<PythonObject> PythonDictionary::GetItem(const Twine &key) const {713if (!IsValid())714return nullDeref();715PyObject *o = PyDict_GetItemString(m_py_obj, NullTerminated(key));716if (PyErr_Occurred())717return exception();718if (!o)719return keyError();720return Retain<PythonObject>(o);721}722723Error PythonDictionary::SetItem(const PythonObject &key,724const PythonObject &value) const {725if (!IsValid() || !value.IsValid())726return nullDeref();727int r = PyDict_SetItem(m_py_obj, key.get(), value.get());728if (r < 0)729return exception();730return Error::success();731}732733Error PythonDictionary::SetItem(const Twine &key,734const PythonObject &value) const {735if (!IsValid() || !value.IsValid())736return nullDeref();737int r = PyDict_SetItemString(m_py_obj, NullTerminated(key), value.get());738if (r < 0)739return exception();740return Error::success();741}742743void PythonDictionary::SetItemForKey(const PythonObject &key,744const PythonObject &value) {745Error error = SetItem(key, value);746if (error)747llvm::consumeError(std::move(error));748}749750StructuredData::DictionarySP751PythonDictionary::CreateStructuredDictionary() const {752StructuredData::DictionarySP result(new StructuredData::Dictionary);753PythonList keys(GetKeys());754uint32_t num_keys = keys.GetSize();755for (uint32_t i = 0; i < num_keys; ++i) {756PythonObject key = keys.GetItemAtIndex(i);757PythonObject value = GetItemForKey(key);758StructuredData::ObjectSP structured_value = value.CreateStructuredObject();759result->AddItem(key.Str().GetString(), structured_value);760}761return result;762}763764PythonModule PythonModule::BuiltinsModule() { return AddModule("builtins"); }765766PythonModule PythonModule::MainModule() { return AddModule("__main__"); }767768PythonModule PythonModule::AddModule(llvm::StringRef module) {769std::string str = module.str();770return PythonModule(PyRefType::Borrowed, PyImport_AddModule(str.c_str()));771}772773Expected<PythonModule> PythonModule::Import(const Twine &name) {774PyObject *mod = PyImport_ImportModule(NullTerminated(name));775if (!mod)776return exception();777return Take<PythonModule>(mod);778}779780Expected<PythonObject> PythonModule::Get(const Twine &name) {781if (!IsValid())782return nullDeref();783PyObject *dict = PyModule_GetDict(m_py_obj);784if (!dict)785return exception();786PyObject *item = PyDict_GetItemString(dict, NullTerminated(name));787if (!item)788return exception();789return Retain<PythonObject>(item);790}791792bool PythonModule::Check(PyObject *py_obj) {793if (!py_obj)794return false;795796return PyModule_Check(py_obj);797}798799PythonDictionary PythonModule::GetDictionary() const {800if (!IsValid())801return PythonDictionary();802return Retain<PythonDictionary>(PyModule_GetDict(m_py_obj));803}804805bool PythonCallable::Check(PyObject *py_obj) {806if (!py_obj)807return false;808809return PyCallable_Check(py_obj);810}811812#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3813static const char get_arg_info_script[] = R"(814from inspect import signature, Parameter, ismethod815from collections import namedtuple816ArgInfo = namedtuple('ArgInfo', ['count', 'has_varargs'])817def main(f):818count = 0819varargs = False820for parameter in signature(f).parameters.values():821kind = parameter.kind822if kind in (Parameter.POSITIONAL_ONLY,823Parameter.POSITIONAL_OR_KEYWORD):824count += 1825elif kind == Parameter.VAR_POSITIONAL:826varargs = True827elif kind in (Parameter.KEYWORD_ONLY,828Parameter.VAR_KEYWORD):829pass830else:831raise Exception(f'unknown parameter kind: {kind}')832return ArgInfo(count, varargs)833)";834#endif835836Expected<PythonCallable::ArgInfo> PythonCallable::GetArgInfo() const {837ArgInfo result = {};838if (!IsValid())839return nullDeref();840841#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3842843// no need to synchronize access to this global, we already have the GIL844static PythonScript get_arg_info(get_arg_info_script);845Expected<PythonObject> pyarginfo = get_arg_info(*this);846if (!pyarginfo)847return pyarginfo.takeError();848long long count =849cantFail(As<long long>(pyarginfo.get().GetAttribute("count")));850bool has_varargs =851cantFail(As<bool>(pyarginfo.get().GetAttribute("has_varargs")));852result.max_positional_args = has_varargs ? ArgInfo::UNBOUNDED : count;853854#else855PyObject *py_func_obj;856bool is_bound_method = false;857bool is_class = false;858859if (PyType_Check(m_py_obj) || PyClass_Check(m_py_obj)) {860auto init = GetAttribute("__init__");861if (!init)862return init.takeError();863py_func_obj = init.get().get();864is_class = true;865} else {866py_func_obj = m_py_obj;867}868869if (PyMethod_Check(py_func_obj)) {870py_func_obj = PyMethod_GET_FUNCTION(py_func_obj);871PythonObject im_self = GetAttributeValue("im_self");872if (im_self.IsValid() && !im_self.IsNone())873is_bound_method = true;874} else {875// see if this is a callable object with an __call__ method876if (!PyFunction_Check(py_func_obj)) {877PythonObject __call__ = GetAttributeValue("__call__");878if (__call__.IsValid()) {879auto __callable__ = __call__.AsType<PythonCallable>();880if (__callable__.IsValid()) {881py_func_obj = PyMethod_GET_FUNCTION(__callable__.get());882PythonObject im_self = __callable__.GetAttributeValue("im_self");883if (im_self.IsValid() && !im_self.IsNone())884is_bound_method = true;885}886}887}888}889890if (!py_func_obj)891return result;892893PyCodeObject *code = (PyCodeObject *)PyFunction_GET_CODE(py_func_obj);894if (!code)895return result;896897auto count = code->co_argcount;898bool has_varargs = !!(code->co_flags & CO_VARARGS);899result.max_positional_args =900has_varargs ? ArgInfo::UNBOUNDED901: (count - (int)is_bound_method) - (int)is_class;902903#endif904905return result;906}907908constexpr unsigned909PythonCallable::ArgInfo::UNBOUNDED; // FIXME delete after c++17910911PythonObject PythonCallable::operator()() {912return PythonObject(PyRefType::Owned, PyObject_CallObject(m_py_obj, nullptr));913}914915PythonObject PythonCallable::916operator()(std::initializer_list<PyObject *> args) {917PythonTuple arg_tuple(args);918return PythonObject(PyRefType::Owned,919PyObject_CallObject(m_py_obj, arg_tuple.get()));920}921922PythonObject PythonCallable::923operator()(std::initializer_list<PythonObject> args) {924PythonTuple arg_tuple(args);925return PythonObject(PyRefType::Owned,926PyObject_CallObject(m_py_obj, arg_tuple.get()));927}928929bool PythonFile::Check(PyObject *py_obj) {930if (!py_obj)931return false;932// In Python 3, there is no `PyFile_Check`, and in fact PyFile is not even a933// first-class object type anymore. `PyFile_FromFd` is just a thin wrapper934// over `io.open()`, which returns some object derived from `io.IOBase`. As a935// result, the only way to detect a file in Python 3 is to check whether it936// inherits from `io.IOBase`.937auto io_module = PythonModule::Import("io");938if (!io_module) {939llvm::consumeError(io_module.takeError());940return false;941}942auto iobase = io_module.get().Get("IOBase");943if (!iobase) {944llvm::consumeError(iobase.takeError());945return false;946}947int r = PyObject_IsInstance(py_obj, iobase.get().get());948if (r < 0) {949llvm::consumeError(exception()); // clear the exception and log it.950return false;951}952return !!r;953}954955const char *PythonException::toCString() const {956if (!m_repr_bytes)957return "unknown exception";958return PyBytes_AS_STRING(m_repr_bytes);959}960961PythonException::PythonException(const char *caller) {962assert(PyErr_Occurred());963m_exception_type = m_exception = m_traceback = m_repr_bytes = nullptr;964PyErr_Fetch(&m_exception_type, &m_exception, &m_traceback);965PyErr_NormalizeException(&m_exception_type, &m_exception, &m_traceback);966PyErr_Clear();967if (m_exception) {968PyObject *repr = PyObject_Repr(m_exception);969if (repr) {970m_repr_bytes = PyUnicode_AsEncodedString(repr, "utf-8", nullptr);971if (!m_repr_bytes) {972PyErr_Clear();973}974Py_XDECREF(repr);975} else {976PyErr_Clear();977}978}979Log *log = GetLog(LLDBLog::Script);980if (caller)981LLDB_LOGF(log, "%s failed with exception: %s", caller, toCString());982else983LLDB_LOGF(log, "python exception: %s", toCString());984}985void PythonException::Restore() {986if (m_exception_type && m_exception) {987PyErr_Restore(m_exception_type, m_exception, m_traceback);988} else {989PyErr_SetString(PyExc_Exception, toCString());990}991m_exception_type = m_exception = m_traceback = nullptr;992}993994PythonException::~PythonException() {995Py_XDECREF(m_exception_type);996Py_XDECREF(m_exception);997Py_XDECREF(m_traceback);998Py_XDECREF(m_repr_bytes);999}10001001void PythonException::log(llvm::raw_ostream &OS) const { OS << toCString(); }10021003std::error_code PythonException::convertToErrorCode() const {1004return llvm::inconvertibleErrorCode();1005}10061007bool PythonException::Matches(PyObject *exc) const {1008return PyErr_GivenExceptionMatches(m_exception_type, exc);1009}10101011const char read_exception_script[] = R"(1012import sys1013from traceback import print_exception1014if sys.version_info.major < 3:1015from StringIO import StringIO1016else:1017from io import StringIO1018def main(exc_type, exc_value, tb):1019f = StringIO()1020print_exception(exc_type, exc_value, tb, file=f)1021return f.getvalue()1022)";10231024std::string PythonException::ReadBacktrace() const {10251026if (!m_traceback)1027return toCString();10281029// no need to synchronize access to this global, we already have the GIL1030static PythonScript read_exception(read_exception_script);10311032Expected<std::string> backtrace = As<std::string>(1033read_exception(m_exception_type, m_exception, m_traceback));10341035if (!backtrace) {1036std::string message =1037std::string(toCString()) + "\n" +1038"Traceback unavailable, an error occurred while reading it:\n";1039return (message + llvm::toString(backtrace.takeError()));1040}10411042return std::move(backtrace.get());1043}10441045char PythonException::ID = 0;10461047llvm::Expected<File::OpenOptions>1048GetOptionsForPyObject(const PythonObject &obj) {1049auto options = File::OpenOptions(0);1050auto readable = As<bool>(obj.CallMethod("readable"));1051if (!readable)1052return readable.takeError();1053auto writable = As<bool>(obj.CallMethod("writable"));1054if (!writable)1055return writable.takeError();1056if (readable.get() && writable.get())1057options |= File::eOpenOptionReadWrite;1058else if (writable.get())1059options |= File::eOpenOptionWriteOnly;1060else if (readable.get())1061options |= File::eOpenOptionReadOnly;1062return options;1063}10641065// Base class template for python files. All it knows how to do1066// is hold a reference to the python object and close or flush it1067// when the File is closed.1068namespace {1069template <typename Base> class OwnedPythonFile : public Base {1070public:1071template <typename... Args>1072OwnedPythonFile(const PythonFile &file, bool borrowed, Args... args)1073: Base(args...), m_py_obj(file), m_borrowed(borrowed) {1074assert(m_py_obj);1075}10761077~OwnedPythonFile() override {1078assert(m_py_obj);1079GIL takeGIL;1080Close();1081// we need to ensure the python object is released while we still1082// hold the GIL1083m_py_obj.Reset();1084}10851086bool IsPythonSideValid() const {1087GIL takeGIL;1088auto closed = As<bool>(m_py_obj.GetAttribute("closed"));1089if (!closed) {1090llvm::consumeError(closed.takeError());1091return false;1092}1093return !closed.get();1094}10951096bool IsValid() const override {1097return IsPythonSideValid() && Base::IsValid();1098}10991100Status Close() override {1101assert(m_py_obj);1102Status py_error, base_error;1103GIL takeGIL;1104if (!m_borrowed) {1105auto r = m_py_obj.CallMethod("close");1106if (!r)1107py_error = Status(r.takeError());1108}1109base_error = Base::Close();1110if (py_error.Fail())1111return py_error;1112return base_error;1113};11141115PyObject *GetPythonObject() const {1116assert(m_py_obj.IsValid());1117return m_py_obj.get();1118}11191120static bool classof(const File *file) = delete;11211122protected:1123PythonFile m_py_obj;1124bool m_borrowed;1125};1126} // namespace11271128// A SimplePythonFile is a OwnedPythonFile that just does all I/O as1129// a NativeFile1130namespace {1131class SimplePythonFile : public OwnedPythonFile<NativeFile> {1132public:1133SimplePythonFile(const PythonFile &file, bool borrowed, int fd,1134File::OpenOptions options)1135: OwnedPythonFile(file, borrowed, fd, options, false) {}11361137static char ID;1138bool isA(const void *classID) const override {1139return classID == &ID || NativeFile::isA(classID);1140}1141static bool classof(const File *file) { return file->isA(&ID); }1142};1143char SimplePythonFile::ID = 0;1144} // namespace11451146namespace {1147class PythonBuffer {1148public:1149PythonBuffer &operator=(const PythonBuffer &) = delete;1150PythonBuffer(const PythonBuffer &) = delete;11511152static Expected<PythonBuffer> Create(PythonObject &obj,1153int flags = PyBUF_SIMPLE) {1154Py_buffer py_buffer = {};1155PyObject_GetBuffer(obj.get(), &py_buffer, flags);1156if (!py_buffer.obj)1157return llvm::make_error<PythonException>();1158return PythonBuffer(py_buffer);1159}11601161PythonBuffer(PythonBuffer &&other) {1162m_buffer = other.m_buffer;1163other.m_buffer.obj = nullptr;1164}11651166~PythonBuffer() {1167if (m_buffer.obj)1168PyBuffer_Release(&m_buffer);1169}11701171Py_buffer &get() { return m_buffer; }11721173private:1174// takes ownership of the buffer.1175PythonBuffer(const Py_buffer &py_buffer) : m_buffer(py_buffer) {}1176Py_buffer m_buffer;1177};1178} // namespace11791180// Shared methods between TextPythonFile and BinaryPythonFile1181namespace {1182class PythonIOFile : public OwnedPythonFile<File> {1183public:1184PythonIOFile(const PythonFile &file, bool borrowed)1185: OwnedPythonFile(file, borrowed) {}11861187~PythonIOFile() override { Close(); }11881189bool IsValid() const override { return IsPythonSideValid(); }11901191Status Close() override {1192assert(m_py_obj);1193GIL takeGIL;1194if (m_borrowed)1195return Flush();1196auto r = m_py_obj.CallMethod("close");1197if (!r)1198return Status(r.takeError());1199return Status();1200}12011202Status Flush() override {1203GIL takeGIL;1204auto r = m_py_obj.CallMethod("flush");1205if (!r)1206return Status(r.takeError());1207return Status();1208}12091210Expected<File::OpenOptions> GetOptions() const override {1211GIL takeGIL;1212return GetOptionsForPyObject(m_py_obj);1213}12141215static char ID;1216bool isA(const void *classID) const override {1217return classID == &ID || File::isA(classID);1218}1219static bool classof(const File *file) { return file->isA(&ID); }1220};1221char PythonIOFile::ID = 0;1222} // namespace12231224namespace {1225class BinaryPythonFile : public PythonIOFile {1226protected:1227int m_descriptor;12281229public:1230BinaryPythonFile(int fd, const PythonFile &file, bool borrowed)1231: PythonIOFile(file, borrowed),1232m_descriptor(File::DescriptorIsValid(fd) ? fd1233: File::kInvalidDescriptor) {}12341235int GetDescriptor() const override { return m_descriptor; }12361237Status Write(const void *buf, size_t &num_bytes) override {1238GIL takeGIL;1239PyObject *pybuffer_p = PyMemoryView_FromMemory(1240const_cast<char *>((const char *)buf), num_bytes, PyBUF_READ);1241if (!pybuffer_p)1242return Status(llvm::make_error<PythonException>());1243auto pybuffer = Take<PythonObject>(pybuffer_p);1244num_bytes = 0;1245auto bytes_written = As<long long>(m_py_obj.CallMethod("write", pybuffer));1246if (!bytes_written)1247return Status(bytes_written.takeError());1248if (bytes_written.get() < 0)1249return Status(".write() method returned a negative number!");1250static_assert(sizeof(long long) >= sizeof(size_t), "overflow");1251num_bytes = bytes_written.get();1252return Status();1253}12541255Status Read(void *buf, size_t &num_bytes) override {1256GIL takeGIL;1257static_assert(sizeof(long long) >= sizeof(size_t), "overflow");1258auto pybuffer_obj =1259m_py_obj.CallMethod("read", (unsigned long long)num_bytes);1260if (!pybuffer_obj)1261return Status(pybuffer_obj.takeError());1262num_bytes = 0;1263if (pybuffer_obj.get().IsNone()) {1264// EOF1265num_bytes = 0;1266return Status();1267}1268auto pybuffer = PythonBuffer::Create(pybuffer_obj.get());1269if (!pybuffer)1270return Status(pybuffer.takeError());1271memcpy(buf, pybuffer.get().get().buf, pybuffer.get().get().len);1272num_bytes = pybuffer.get().get().len;1273return Status();1274}1275};1276} // namespace12771278namespace {1279class TextPythonFile : public PythonIOFile {1280protected:1281int m_descriptor;12821283public:1284TextPythonFile(int fd, const PythonFile &file, bool borrowed)1285: PythonIOFile(file, borrowed),1286m_descriptor(File::DescriptorIsValid(fd) ? fd1287: File::kInvalidDescriptor) {}12881289int GetDescriptor() const override { return m_descriptor; }12901291Status Write(const void *buf, size_t &num_bytes) override {1292GIL takeGIL;1293auto pystring =1294PythonString::FromUTF8(llvm::StringRef((const char *)buf, num_bytes));1295if (!pystring)1296return Status(pystring.takeError());1297num_bytes = 0;1298auto bytes_written =1299As<long long>(m_py_obj.CallMethod("write", pystring.get()));1300if (!bytes_written)1301return Status(bytes_written.takeError());1302if (bytes_written.get() < 0)1303return Status(".write() method returned a negative number!");1304static_assert(sizeof(long long) >= sizeof(size_t), "overflow");1305num_bytes = bytes_written.get();1306return Status();1307}13081309Status Read(void *buf, size_t &num_bytes) override {1310GIL takeGIL;1311size_t num_chars = num_bytes / 6;1312size_t orig_num_bytes = num_bytes;1313num_bytes = 0;1314if (orig_num_bytes < 6) {1315return Status("can't read less than 6 bytes from a utf8 text stream");1316}1317auto pystring = As<PythonString>(1318m_py_obj.CallMethod("read", (unsigned long long)num_chars));1319if (!pystring)1320return Status(pystring.takeError());1321if (pystring.get().IsNone()) {1322// EOF1323return Status();1324}1325auto stringref = pystring.get().AsUTF8();1326if (!stringref)1327return Status(stringref.takeError());1328num_bytes = stringref.get().size();1329memcpy(buf, stringref.get().begin(), num_bytes);1330return Status();1331}1332};1333} // namespace13341335llvm::Expected<FileSP> PythonFile::ConvertToFile(bool borrowed) {1336if (!IsValid())1337return llvm::createStringError(llvm::inconvertibleErrorCode(),1338"invalid PythonFile");13391340int fd = PyObject_AsFileDescriptor(m_py_obj);1341if (fd < 0) {1342PyErr_Clear();1343return ConvertToFileForcingUseOfScriptingIOMethods(borrowed);1344}1345auto options = GetOptionsForPyObject(*this);1346if (!options)1347return options.takeError();13481349File::OpenOptions rw =1350options.get() & (File::eOpenOptionReadOnly | File::eOpenOptionWriteOnly |1351File::eOpenOptionReadWrite);1352if (rw == File::eOpenOptionWriteOnly || rw == File::eOpenOptionReadWrite) {1353// LLDB and python will not share I/O buffers. We should probably1354// flush the python buffers now.1355auto r = CallMethod("flush");1356if (!r)1357return r.takeError();1358}13591360FileSP file_sp;1361if (borrowed) {1362// In this case we don't need to retain the python1363// object at all.1364file_sp = std::make_shared<NativeFile>(fd, options.get(), false);1365} else {1366file_sp = std::static_pointer_cast<File>(1367std::make_shared<SimplePythonFile>(*this, borrowed, fd, options.get()));1368}1369if (!file_sp->IsValid())1370return llvm::createStringError(llvm::inconvertibleErrorCode(),1371"invalid File");13721373return file_sp;1374}13751376llvm::Expected<FileSP>1377PythonFile::ConvertToFileForcingUseOfScriptingIOMethods(bool borrowed) {13781379assert(!PyErr_Occurred());13801381if (!IsValid())1382return llvm::createStringError(llvm::inconvertibleErrorCode(),1383"invalid PythonFile");13841385int fd = PyObject_AsFileDescriptor(m_py_obj);1386if (fd < 0) {1387PyErr_Clear();1388fd = File::kInvalidDescriptor;1389}13901391auto io_module = PythonModule::Import("io");1392if (!io_module)1393return io_module.takeError();1394auto textIOBase = io_module.get().Get("TextIOBase");1395if (!textIOBase)1396return textIOBase.takeError();1397auto rawIOBase = io_module.get().Get("RawIOBase");1398if (!rawIOBase)1399return rawIOBase.takeError();1400auto bufferedIOBase = io_module.get().Get("BufferedIOBase");1401if (!bufferedIOBase)1402return bufferedIOBase.takeError();14031404FileSP file_sp;14051406auto isTextIO = IsInstance(textIOBase.get());1407if (!isTextIO)1408return isTextIO.takeError();1409if (isTextIO.get())1410file_sp = std::static_pointer_cast<File>(1411std::make_shared<TextPythonFile>(fd, *this, borrowed));14121413auto isRawIO = IsInstance(rawIOBase.get());1414if (!isRawIO)1415return isRawIO.takeError();1416auto isBufferedIO = IsInstance(bufferedIOBase.get());1417if (!isBufferedIO)1418return isBufferedIO.takeError();14191420if (isRawIO.get() || isBufferedIO.get()) {1421file_sp = std::static_pointer_cast<File>(1422std::make_shared<BinaryPythonFile>(fd, *this, borrowed));1423}14241425if (!file_sp)1426return llvm::createStringError(llvm::inconvertibleErrorCode(),1427"python file is neither text nor binary");14281429if (!file_sp->IsValid())1430return llvm::createStringError(llvm::inconvertibleErrorCode(),1431"invalid File");14321433return file_sp;1434}14351436Expected<PythonFile> PythonFile::FromFile(File &file, const char *mode) {1437if (!file.IsValid())1438return llvm::createStringError(llvm::inconvertibleErrorCode(),1439"invalid file");14401441if (auto *simple = llvm::dyn_cast<SimplePythonFile>(&file))1442return Retain<PythonFile>(simple->GetPythonObject());1443if (auto *pythonio = llvm::dyn_cast<PythonIOFile>(&file))1444return Retain<PythonFile>(pythonio->GetPythonObject());14451446if (!mode) {1447auto m = file.GetOpenMode();1448if (!m)1449return m.takeError();1450mode = m.get();1451}14521453PyObject *file_obj;1454file_obj = PyFile_FromFd(file.GetDescriptor(), nullptr, mode, -1, nullptr,1455"ignore", nullptr, /*closefd=*/0);14561457if (!file_obj)1458return exception();14591460return Take<PythonFile>(file_obj);1461}14621463Error PythonScript::Init() {1464if (function.IsValid())1465return Error::success();14661467PythonDictionary globals(PyInitialValue::Empty);1468auto builtins = PythonModule::BuiltinsModule();1469if (Error error = globals.SetItem("__builtins__", builtins))1470return error;1471PyObject *o =1472PyRun_String(script, Py_file_input, globals.get(), globals.get());1473if (!o)1474return exception();1475Take<PythonObject>(o);1476auto f = As<PythonCallable>(globals.GetItem("main"));1477if (!f)1478return f.takeError();1479function = std::move(f.get());14801481return Error::success();1482}14831484llvm::Expected<PythonObject>1485python::runStringOneLine(const llvm::Twine &string,1486const PythonDictionary &globals,1487const PythonDictionary &locals) {1488if (!globals.IsValid() || !locals.IsValid())1489return nullDeref();14901491PyObject *code =1492Py_CompileString(NullTerminated(string), "<string>", Py_eval_input);1493if (!code) {1494PyErr_Clear();1495code =1496Py_CompileString(NullTerminated(string), "<string>", Py_single_input);1497}1498if (!code)1499return exception();1500auto code_ref = Take<PythonObject>(code);15011502PyObject *result = PyEval_EvalCode(code, globals.get(), locals.get());15031504if (!result)1505return exception();15061507return Take<PythonObject>(result);1508}15091510llvm::Expected<PythonObject>1511python::runStringMultiLine(const llvm::Twine &string,1512const PythonDictionary &globals,1513const PythonDictionary &locals) {1514if (!globals.IsValid() || !locals.IsValid())1515return nullDeref();1516PyObject *result = PyRun_String(NullTerminated(string), Py_file_input,1517globals.get(), locals.get());1518if (!result)1519return exception();1520return Take<PythonObject>(result);1521}15221523#endif152415251526