
With this change, liblldb is 95% of the way towards being able to work under both Python 2.x and Python 3.x. This should introduce no functional change for Python 2.x, but for Python 3.x there are some important changes. Primarily, these are: 1) PyString doesn't exist in Python 3. Everything is a PyUnicode. To account for this, PythonString now stores a PyBytes instead of a PyString. In Python 2, this is equivalent to a PyUnicode, and in Python 3, we do a conversion from PyUnicode to PyBytes and store the PyBytes. 2) PyInt doesn't exist in Python 3. Everything is a PyLong. To account for this, PythonInteger stores a PyLong instead of a PyInt. In Python 2.x, this requires doing a conversion to PyLong when creating a PythonInteger from a PyInt. In 3.x, there is no PyInt anyway, so we can assume everything is a PyLong. 3) PyFile_FromFile doesn't exist in Python 3. Instead there is a PyFile_FromFd. This is not addressed in this patch because it will require quite a large change to plumb fd's all the way through the system into the ScriptInterpreter. This is the only remaining piece of the puzzle to get LLDB supporting Python 3.x. Being able to run the test suite is not addressed in this patch. After the extension module can compile and you can enter an embedded 3.x interpreter, the test suite will be addressed in a followup. llvm-svn: 249886
616 lines
14 KiB
C++
616 lines
14 KiB
C++
//===-- PythonDataObjects.cpp ------------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifdef LLDB_DISABLE_PYTHON
|
|
|
|
// Python is disabled in this build
|
|
|
|
#else
|
|
|
|
#include "lldb-python.h"
|
|
#include "PythonDataObjects.h"
|
|
#include "ScriptInterpreterPython.h"
|
|
|
|
#include "lldb/Core/Stream.h"
|
|
#include "lldb/Host/File.h"
|
|
#include "lldb/Interpreter/ScriptInterpreter.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
using namespace lldb_private;
|
|
using namespace lldb;
|
|
|
|
void
|
|
StructuredPythonObject::Dump(Stream &s) const
|
|
{
|
|
s << "Python Obj: 0x" << GetValue();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// PythonObject
|
|
//----------------------------------------------------------------------
|
|
|
|
void
|
|
PythonObject::Dump (Stream &strm) const
|
|
{
|
|
if (m_py_obj)
|
|
{
|
|
FILE *file = ::tmpfile();
|
|
if (file)
|
|
{
|
|
::PyObject_Print (m_py_obj, file, 0);
|
|
const long length = ftell (file);
|
|
if (length)
|
|
{
|
|
::rewind(file);
|
|
std::vector<char> file_contents (length,'\0');
|
|
const size_t length_read = ::fread (file_contents.data(), 1, file_contents.size(), file);
|
|
if (length_read > 0)
|
|
strm.Write (file_contents.data(), length_read);
|
|
}
|
|
::fclose (file);
|
|
}
|
|
}
|
|
else
|
|
strm.PutCString ("NULL");
|
|
}
|
|
|
|
PyObjectType
|
|
PythonObject::GetObjectType() const
|
|
{
|
|
if (IsNULLOrNone())
|
|
return PyObjectType::None;
|
|
|
|
if (PyList_Check(m_py_obj))
|
|
return PyObjectType::List;
|
|
if (PyDict_Check(m_py_obj))
|
|
return PyObjectType::Dictionary;
|
|
if (PyUnicode_Check(m_py_obj))
|
|
return PyObjectType::String;
|
|
if (PyLong_Check(m_py_obj))
|
|
return PyObjectType::Integer;
|
|
#if PY_MAJOR_VERSION < 3
|
|
// These functions don't exist in Python 3.x. PyString is PyUnicode
|
|
// and PyInt is PyLong.
|
|
if (PyString_Check(m_py_obj))
|
|
return PyObjectType::String;
|
|
if (PyInt_Check(m_py_obj))
|
|
return PyObjectType::Integer;
|
|
#endif
|
|
return PyObjectType::Unknown;
|
|
}
|
|
|
|
PythonString
|
|
PythonObject::Repr ()
|
|
{
|
|
if (!m_py_obj)
|
|
return PythonString ();
|
|
PyObject *repr = PyObject_Repr(m_py_obj);
|
|
if (!repr)
|
|
return PythonString ();
|
|
return PythonString(repr);
|
|
}
|
|
|
|
PythonString
|
|
PythonObject::Str ()
|
|
{
|
|
if (!m_py_obj)
|
|
return PythonString ();
|
|
PyObject *str = PyObject_Str(m_py_obj);
|
|
if (!str)
|
|
return PythonString ();
|
|
return PythonString(str);
|
|
}
|
|
|
|
bool
|
|
PythonObject::IsNULLOrNone () const
|
|
{
|
|
return ((m_py_obj == nullptr) || (m_py_obj == Py_None));
|
|
}
|
|
|
|
StructuredData::ObjectSP
|
|
PythonObject::CreateStructuredObject() const
|
|
{
|
|
switch (GetObjectType())
|
|
{
|
|
case PyObjectType::Dictionary:
|
|
return PythonDictionary(m_py_obj).CreateStructuredDictionary();
|
|
case PyObjectType::Integer:
|
|
return PythonInteger(m_py_obj).CreateStructuredInteger();
|
|
case PyObjectType::List:
|
|
return PythonList(m_py_obj).CreateStructuredArray();
|
|
case PyObjectType::String:
|
|
return PythonString(m_py_obj).CreateStructuredString();
|
|
case PyObjectType::None:
|
|
return StructuredData::ObjectSP();
|
|
default:
|
|
return StructuredData::ObjectSP(new StructuredPythonObject(m_py_obj));
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// PythonString
|
|
//----------------------------------------------------------------------
|
|
|
|
PythonString::PythonString (PyObject *py_obj) :
|
|
PythonObject()
|
|
{
|
|
Reset(py_obj); // Use "Reset()" to ensure that py_obj is a string
|
|
}
|
|
|
|
PythonString::PythonString (const PythonObject &object) :
|
|
PythonObject()
|
|
{
|
|
Reset(object.get()); // Use "Reset()" to ensure that py_obj is a string
|
|
}
|
|
|
|
PythonString::PythonString(llvm::StringRef string)
|
|
: PythonObject()
|
|
{
|
|
SetString(string);
|
|
}
|
|
|
|
PythonString::PythonString(const char *string)
|
|
: PythonObject()
|
|
{
|
|
SetString(llvm::StringRef(string));
|
|
}
|
|
|
|
PythonString::PythonString () :
|
|
PythonObject()
|
|
{
|
|
}
|
|
|
|
PythonString::~PythonString ()
|
|
{
|
|
}
|
|
|
|
bool
|
|
PythonString::Check(PyObject *py_obj)
|
|
{
|
|
if (!py_obj)
|
|
return false;
|
|
#if PY_MAJOR_VERSION >= 3
|
|
// Python 3 does not have PyString objects, only PyUnicode.
|
|
return PyUnicode_Check(py_obj);
|
|
#else
|
|
return PyUnicode_Check(py_obj) || PyString_Check(py_obj);
|
|
#endif
|
|
}
|
|
|
|
bool
|
|
PythonString::Reset(PyObject *py_obj)
|
|
{
|
|
if (!PythonString::Check(py_obj))
|
|
{
|
|
PythonObject::Reset(nullptr);
|
|
return false;
|
|
}
|
|
|
|
// Convert this to a PyBytes object, and only store the PyBytes. Note that in
|
|
// Python 2.x, PyString and PyUnicode are interchangeable, and PyBytes is an alias
|
|
// of PyString. So on 2.x, if we get into this branch, we already have a PyBytes.
|
|
//#if PY_MAJOR_VERSION >= 3
|
|
if (PyUnicode_Check(py_obj))
|
|
{
|
|
PyObject *unicode = py_obj;
|
|
py_obj = PyUnicode_AsUTF8String(py_obj);
|
|
Py_XDECREF(unicode);
|
|
}
|
|
//#endif
|
|
|
|
assert(PyBytes_Check(py_obj) && "PythonString::Reset received a non-string");
|
|
return PythonObject::Reset(py_obj);
|
|
}
|
|
|
|
llvm::StringRef
|
|
PythonString::GetString() const
|
|
{
|
|
if (m_py_obj)
|
|
{
|
|
Py_ssize_t size;
|
|
char *c;
|
|
PyBytes_AsStringAndSize(m_py_obj, &c, &size);
|
|
return llvm::StringRef(c, size);
|
|
}
|
|
return llvm::StringRef();
|
|
}
|
|
|
|
size_t
|
|
PythonString::GetSize() const
|
|
{
|
|
if (m_py_obj)
|
|
return PyBytes_Size(m_py_obj);
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
PythonString::SetString (llvm::StringRef string)
|
|
{
|
|
#if PY_MAJOR_VERSION >= 3
|
|
PyObject *unicode = PyUnicode_FromStringAndSize(string.data(), string.size());
|
|
PyObject *bytes = PyUnicode_AsUTF8String(unicode);
|
|
PythonObject::Reset(bytes);
|
|
Py_XDECREF(unicode);
|
|
#else
|
|
PythonObject::Reset(PyString_FromStringAndSize(string.data(), string.size()));
|
|
#endif
|
|
}
|
|
|
|
StructuredData::StringSP
|
|
PythonString::CreateStructuredString() const
|
|
{
|
|
StructuredData::StringSP result(new StructuredData::String);
|
|
result->SetValue(GetString());
|
|
return result;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// PythonInteger
|
|
//----------------------------------------------------------------------
|
|
|
|
PythonInteger::PythonInteger (PyObject *py_obj) :
|
|
PythonObject()
|
|
{
|
|
Reset(py_obj); // Use "Reset()" to ensure that py_obj is a integer type
|
|
}
|
|
|
|
PythonInteger::PythonInteger (const PythonObject &object) :
|
|
PythonObject()
|
|
{
|
|
Reset(object.get()); // Use "Reset()" to ensure that py_obj is a integer type
|
|
}
|
|
|
|
PythonInteger::PythonInteger (int64_t value) :
|
|
PythonObject()
|
|
{
|
|
SetInteger (value);
|
|
}
|
|
|
|
|
|
PythonInteger::~PythonInteger ()
|
|
{
|
|
}
|
|
|
|
bool
|
|
PythonInteger::Check(PyObject *py_obj)
|
|
{
|
|
if (!py_obj)
|
|
return false;
|
|
|
|
#if PY_MAJOR_VERSION >= 3
|
|
// Python 3 does not have PyInt_Check. There is only one type of
|
|
// integral value, long.
|
|
return PyLong_Check(py_obj);
|
|
#else
|
|
return PyLong_Check(py_obj) || PyInt_Check(py_obj);
|
|
#endif
|
|
}
|
|
|
|
bool
|
|
PythonInteger::Reset(PyObject *py_obj)
|
|
{
|
|
if (!PythonInteger::Check(py_obj))
|
|
{
|
|
PythonObject::Reset(nullptr);
|
|
return false;
|
|
}
|
|
|
|
#if PY_MAJOR_VERSION < 3
|
|
// Always store this as a PyLong, which makes interoperability between
|
|
// Python 2.x and Python 3.x easier. This is only necessary in 2.x,
|
|
// since 3.x doesn't even have a PyInt.
|
|
if (PyInt_Check(py_obj))
|
|
{
|
|
PyObject *py_long = PyLong_FromLongLong(PyInt_AsLong(py_obj));
|
|
Py_XDECREF(py_obj);
|
|
py_obj = py_long;
|
|
}
|
|
#endif
|
|
|
|
assert(PyLong_Check(py_obj) && "Couldn't get a PyLong from this PyObject");
|
|
|
|
return PythonObject::Reset(py_obj);
|
|
}
|
|
|
|
int64_t
|
|
PythonInteger::GetInteger() const
|
|
{
|
|
if (m_py_obj)
|
|
{
|
|
assert(PyLong_Check(m_py_obj) && "PythonInteger::GetInteger has a PyObject that isn't a PyLong");
|
|
|
|
return PyLong_AsLongLong(m_py_obj);
|
|
}
|
|
return UINT64_MAX;
|
|
}
|
|
|
|
void
|
|
PythonInteger::SetInteger (int64_t value)
|
|
{
|
|
PythonObject::Reset(PyLong_FromLongLong(value));
|
|
}
|
|
|
|
StructuredData::IntegerSP
|
|
PythonInteger::CreateStructuredInteger() const
|
|
{
|
|
StructuredData::IntegerSP result(new StructuredData::Integer);
|
|
result->SetValue(GetInteger());
|
|
return result;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// PythonList
|
|
//----------------------------------------------------------------------
|
|
|
|
PythonList::PythonList()
|
|
: PythonObject(PyList_New(0))
|
|
{
|
|
}
|
|
|
|
PythonList::PythonList (PyObject *py_obj) :
|
|
PythonObject()
|
|
{
|
|
Reset(py_obj); // Use "Reset()" to ensure that py_obj is a list
|
|
}
|
|
|
|
|
|
PythonList::PythonList (const PythonObject &object) :
|
|
PythonObject()
|
|
{
|
|
Reset(object.get()); // Use "Reset()" to ensure that py_obj is a list
|
|
}
|
|
|
|
PythonList::~PythonList ()
|
|
{
|
|
}
|
|
|
|
bool
|
|
PythonList::Check(PyObject *py_obj)
|
|
{
|
|
if (!py_obj)
|
|
return false;
|
|
return PyList_Check(py_obj);
|
|
}
|
|
|
|
bool
|
|
PythonList::Reset(PyObject *py_obj)
|
|
{
|
|
if (!PythonList::Check(py_obj))
|
|
{
|
|
PythonObject::Reset(nullptr);
|
|
return false;
|
|
}
|
|
|
|
return PythonObject::Reset(py_obj);
|
|
}
|
|
|
|
uint32_t
|
|
PythonList::GetSize() const
|
|
{
|
|
if (m_py_obj)
|
|
return PyList_GET_SIZE(m_py_obj);
|
|
return 0;
|
|
}
|
|
|
|
PythonObject
|
|
PythonList::GetItemAtIndex(uint32_t index) const
|
|
{
|
|
if (m_py_obj)
|
|
return PythonObject(PyList_GetItem(m_py_obj, index));
|
|
return PythonObject();
|
|
}
|
|
|
|
void
|
|
PythonList::SetItemAtIndex (uint32_t index, const PythonObject & object)
|
|
{
|
|
if (m_py_obj && object)
|
|
PyList_SetItem(m_py_obj, index, object.get());
|
|
}
|
|
|
|
void
|
|
PythonList::AppendItem (const PythonObject &object)
|
|
{
|
|
if (m_py_obj && object)
|
|
PyList_Append(m_py_obj, object.get());
|
|
}
|
|
|
|
StructuredData::ArraySP
|
|
PythonList::CreateStructuredArray() const
|
|
{
|
|
StructuredData::ArraySP result(new StructuredData::Array);
|
|
uint32_t count = GetSize();
|
|
for (uint32_t i = 0; i < count; ++i)
|
|
{
|
|
PythonObject obj = GetItemAtIndex(i);
|
|
result->AddItem(obj.CreateStructuredObject());
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// PythonDictionary
|
|
//----------------------------------------------------------------------
|
|
|
|
PythonDictionary::PythonDictionary()
|
|
: PythonObject(PyDict_New())
|
|
{
|
|
}
|
|
|
|
PythonDictionary::PythonDictionary (PyObject *py_obj) :
|
|
PythonObject(py_obj)
|
|
{
|
|
Reset(py_obj); // Use "Reset()" to ensure that py_obj is a dictionary
|
|
}
|
|
|
|
|
|
PythonDictionary::PythonDictionary (const PythonObject &object) :
|
|
PythonObject()
|
|
{
|
|
Reset(object.get()); // Use "Reset()" to ensure that py_obj is a dictionary
|
|
}
|
|
|
|
PythonDictionary::~PythonDictionary ()
|
|
{
|
|
}
|
|
|
|
bool
|
|
PythonDictionary::Check(PyObject *py_obj)
|
|
{
|
|
if (!py_obj)
|
|
return false;
|
|
|
|
return PyDict_Check(py_obj);
|
|
}
|
|
|
|
bool
|
|
PythonDictionary::Reset(PyObject *py_obj)
|
|
{
|
|
if (!PythonDictionary::Check(py_obj))
|
|
{
|
|
PythonObject::Reset(nullptr);
|
|
return false;
|
|
}
|
|
|
|
return PythonObject::Reset(py_obj);
|
|
}
|
|
|
|
uint32_t
|
|
PythonDictionary::GetSize() const
|
|
{
|
|
if (m_py_obj)
|
|
return PyDict_Size(m_py_obj);
|
|
return 0;
|
|
}
|
|
|
|
PythonObject
|
|
PythonDictionary::GetItemForKey (const char *key) const
|
|
{
|
|
if (key && key[0])
|
|
{
|
|
PythonString python_key(key);
|
|
return GetItemForKey(python_key);
|
|
}
|
|
return PythonObject();
|
|
}
|
|
|
|
|
|
PythonObject
|
|
PythonDictionary::GetItemForKey (const PythonString &key) const
|
|
{
|
|
if (m_py_obj && key)
|
|
return PythonObject(PyDict_GetItem(m_py_obj, key.get()));
|
|
return PythonObject();
|
|
}
|
|
|
|
|
|
const char *
|
|
PythonDictionary::GetItemForKeyAsString (const PythonString &key, const char *fail_value) const
|
|
{
|
|
if (m_py_obj && key)
|
|
{
|
|
PyObject *py_obj = PyDict_GetItem(m_py_obj, key.get());
|
|
if (py_obj && PythonString::Check(py_obj))
|
|
{
|
|
PythonString str(py_obj);
|
|
return str.GetString().data();
|
|
}
|
|
}
|
|
return fail_value;
|
|
}
|
|
|
|
int64_t
|
|
PythonDictionary::GetItemForKeyAsInteger (const PythonString &key, int64_t fail_value) const
|
|
{
|
|
if (m_py_obj && key)
|
|
{
|
|
PyObject *py_obj = PyDict_GetItem(m_py_obj, key.get());
|
|
if (PythonInteger::Check(py_obj))
|
|
{
|
|
PythonInteger int_obj(py_obj);
|
|
return int_obj.GetInteger();
|
|
}
|
|
}
|
|
return fail_value;
|
|
}
|
|
|
|
PythonList
|
|
PythonDictionary::GetKeys () const
|
|
{
|
|
if (m_py_obj)
|
|
return PythonList(PyDict_Keys(m_py_obj));
|
|
return PythonList();
|
|
}
|
|
|
|
PythonString
|
|
PythonDictionary::GetKeyAtPosition (uint32_t pos) const
|
|
{
|
|
PyObject *key, *value;
|
|
Py_ssize_t pos_iter = 0;
|
|
|
|
if (m_py_obj)
|
|
{
|
|
while (PyDict_Next(m_py_obj, &pos_iter, &key, &value))
|
|
{
|
|
if (pos-- == 0)
|
|
return PythonString(key);
|
|
}
|
|
}
|
|
return PythonString();
|
|
}
|
|
|
|
PythonObject
|
|
PythonDictionary::GetValueAtPosition (uint32_t pos) const
|
|
{
|
|
PyObject *key, *value;
|
|
Py_ssize_t pos_iter = 0;
|
|
|
|
if (!m_py_obj)
|
|
return PythonObject();
|
|
|
|
while (PyDict_Next(m_py_obj, &pos_iter, &key, &value)) {
|
|
if (pos-- == 0)
|
|
return PythonObject(value);
|
|
}
|
|
return PythonObject();
|
|
}
|
|
|
|
void
|
|
PythonDictionary::SetItemForKey (const PythonString &key, PyObject *value)
|
|
{
|
|
if (m_py_obj && key && value)
|
|
PyDict_SetItem(m_py_obj, key.get(), value);
|
|
}
|
|
|
|
void
|
|
PythonDictionary::SetItemForKey (const PythonString &key, const PythonObject &value)
|
|
{
|
|
if (m_py_obj && key && value)
|
|
PyDict_SetItem(m_py_obj, key.get(), value.get());
|
|
}
|
|
|
|
StructuredData::DictionarySP
|
|
PythonDictionary::CreateStructuredDictionary() const
|
|
{
|
|
StructuredData::DictionarySP result(new StructuredData::Dictionary);
|
|
PythonList keys(GetKeys());
|
|
uint32_t num_keys = keys.GetSize();
|
|
for (uint32_t i = 0; i < num_keys; ++i)
|
|
{
|
|
PythonObject key = keys.GetItemAtIndex(i);
|
|
PythonString key_str = key.Str();
|
|
PythonObject value = GetItemForKey(key);
|
|
StructuredData::ObjectSP structured_value = value.CreateStructuredObject();
|
|
result->AddItem(key_str.GetString(), structured_value);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
#endif
|