drgn/libdrgn/python/object.c
Omar Sandoval 78316a28fb libdrgn: remove half-baked support for complex types
We've nominally supported complex types since commit 75c3679147
("Rewrite drgn core in C"), but parsing them from DWARF has been
incorrect from the start (they don't have a DW_AT_type attribute like we
assume), and we never implemented proper support for complex objects.
Drop the partial implementation; we can bring it back (properly) if
someone requests it.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-02-17 14:56:33 -08:00

1904 lines
47 KiB
C

// Copyright (c) Facebook, Inc. and its affiliates.
// SPDX-License-Identifier: GPL-3.0+
#include <inttypes.h>
#include <math.h>
#include "drgnpy.h"
#include "../error.h"
#include "../object.h"
#include "../program.h"
#include "../serialize.h"
#include "../type.h"
#include "../util.h"
static int DrgnObject_literal(struct drgn_object *res, PyObject *literal)
{
struct drgn_error *err;
if (PyBool_Check(literal)) {
err = drgn_object_bool_literal(res, literal == Py_True);
} else if (PyLong_Check(literal)) {
unsigned long long uvalue;
bool is_negative;
is_negative = Py_SIZE(literal) < 0;
if (is_negative) {
literal = PyNumber_Negative(literal);
if (!literal)
return -1;
}
uvalue = PyLong_AsUnsignedLongLong(literal);
if (is_negative)
Py_DECREF(literal);
if (uvalue == (unsigned long long)-1 && PyErr_Occurred())
return -1;
err = drgn_object_integer_literal(res, uvalue);
if (!err && is_negative)
err = drgn_object_neg(res, res);
} else if (PyFloat_Check(literal)) {
err = drgn_object_float_literal(res,
PyFloat_AS_DOUBLE(literal));
} else {
return 1;
}
if (err) {
set_drgn_error(err);
return -1;
}
return 0;
}
static int serialize_py_object(struct drgn_program *prog, char *buf,
uint64_t buf_bit_size, uint64_t bit_offset,
PyObject *value_obj,
struct drgn_object_type *type,
bool little_endian);
static int serialize_compound_value(struct drgn_program *prog, char *buf,
uint64_t buf_bit_size, uint64_t bit_offset,
PyObject *value_obj,
struct drgn_object_type *type,
bool little_endian)
{
struct drgn_error *err;
int ret = -1;
if (!PyMapping_Check(value_obj)) {
set_error_type_name("'%s' value must be dictionary or mapping",
drgn_object_type_qualified(type));
return -1;
}
PyObject *tmp = PyMapping_Items(value_obj);
if (!tmp)
return -1;
/*
* Since Python 3.7, PyMapping_Items() always returns a list. However,
* before that, it could also return a tuple.
*/
PyObject *items = PySequence_Fast(tmp, "items must be sequence");
Py_DECREF(tmp);
if (!items)
return -1;
Py_ssize_t num_items = PySequence_Fast_GET_SIZE(items);
for (Py_ssize_t i = 0; i < num_items; i++) {
PyObject *item = PySequence_Fast_GET_ITEM(items, i);
if (!PyTuple_Check(item) || PyTuple_GET_SIZE(item) != 2) {
PyErr_SetString(PyExc_TypeError, "invalid item");
goto out;
}
PyObject *key = PyTuple_GET_ITEM(item, 0);
if (!PyUnicode_Check(key)) {
PyErr_SetString(PyExc_TypeError,
"member key must be string");
goto out;
}
const char *member_name = PyUnicode_AsUTF8(key);
if (!member_name)
goto out;
struct drgn_type_member *member;
uint64_t member_bit_offset;
err = drgn_type_find_member(type->underlying_type, member_name,
&member, &member_bit_offset);
if (err) {
set_drgn_error(err);
goto out;
}
struct drgn_qualified_type member_qualified_type;
uint64_t member_bit_field_size;
err = drgn_member_type(member, &member_qualified_type,
&member_bit_field_size);
if (err) {
set_drgn_error(err);
goto out;
}
struct drgn_object_type member_type = {
.type = member_qualified_type.type,
.qualifiers = member_qualified_type.qualifiers,
.underlying_type =
drgn_underlying_type(member_qualified_type.type),
.bit_field_size = member_bit_field_size,
};
if (serialize_py_object(prog, buf, buf_bit_size,
bit_offset + member->bit_offset,
PyTuple_GET_ITEM(item, 1),
&member_type, little_endian) == -1)
goto out;
}
ret = 0;
out:
Py_DECREF(items);
return ret;
}
static int serialize_array_value(struct drgn_program *prog, char *buf,
uint64_t buf_bit_size, uint64_t bit_offset,
PyObject *value_obj,
struct drgn_object_type *type,
bool little_endian)
{
struct drgn_error *err;
struct drgn_qualified_type qualified_type;
struct drgn_object_type element_type;
uint64_t element_bit_size, length;
PyObject *seq;
size_t seq_length, i;
qualified_type = drgn_type_type(type->underlying_type);
element_type.type = qualified_type.type;
element_type.qualifiers = qualified_type.qualifiers;
element_type.underlying_type = drgn_underlying_type(element_type.type);
element_type.bit_field_size = 0;
err = drgn_type_bit_size(element_type.underlying_type,
&element_bit_size);
if (err) {
set_drgn_error(err);
return -1;
}
length = drgn_type_length(type->underlying_type);
if (length > PY_SSIZE_T_MAX) {
PyErr_NoMemory();
return -1;
}
seq = PySequence_Fast(value_obj, "");
if (!seq) {
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
set_error_type_name("'%s' value must be iterable",
drgn_object_type_qualified(type));
}
return -1;
}
seq_length = PySequence_Fast_GET_SIZE(seq);
if (seq_length > length) {
Py_DECREF(seq);
PyErr_SetString(PyExc_ValueError,
"too many items in array value");
return -1;
}
for (i = 0; i < seq_length; i++) {
if (serialize_py_object(prog, buf, buf_bit_size,
bit_offset + i * element_bit_size,
PySequence_Fast_GET_ITEM(seq, i),
&element_type, little_endian) == -1) {
Py_DECREF(seq);
return -1;
}
}
Py_DECREF(seq);
return 0;
}
static int serialize_py_object(struct drgn_program *prog, char *buf,
uint64_t buf_bit_size, uint64_t bit_offset,
PyObject *value_obj,
struct drgn_object_type *type,
bool little_endian)
{
struct drgn_error *err;
enum drgn_object_encoding encoding;
uint64_t bit_size, bit_end;
err = drgn_object_type_encoding_and_size(type, &encoding, &bit_size);
if (err) {
set_drgn_error(err);
return -1;
}
err = sanity_check_object(encoding, type->bit_field_size, bit_size);
if (err) {
set_drgn_error(err);
return -1;
}
if (__builtin_add_overflow(bit_offset, bit_size, &bit_end) ||
bit_end > buf_bit_size) {
err = drgn_error_create(DRGN_ERROR_OUT_OF_BOUNDS,
"out of bounds of value");
set_drgn_error(err);
return -1;
}
switch (encoding) {
case DRGN_OBJECT_ENCODING_SIGNED:
case DRGN_OBJECT_ENCODING_UNSIGNED: {
PyObject *long_obj;
union {
int64_t svalue;
uint64_t uvalue;
} tmp;
if (!PyNumber_Check(value_obj)) {
set_error_type_name("'%s' value must be number",
drgn_object_type_qualified(type));
return -1;
}
long_obj = PyNumber_Long(value_obj);
if (!long_obj)
return -1;
tmp.uvalue = PyLong_AsUnsignedLongLongMask(long_obj);
Py_DECREF(long_obj);
if (tmp.uvalue == (unsigned long long)-1 && PyErr_Occurred())
return -1;
if (encoding == DRGN_OBJECT_ENCODING_SIGNED)
tmp.svalue = truncate_signed(tmp.svalue, bit_size);
else
tmp.uvalue = truncate_unsigned(tmp.uvalue, bit_size);
serialize_bits(buf, bit_offset, tmp.uvalue, bit_size,
little_endian);
return 0;
}
case DRGN_OBJECT_ENCODING_FLOAT: {
union {
uint64_t uvalue;
double fvalue64;
float fvalue32;
} tmp;
double fvalue;
if (!PyNumber_Check(value_obj)) {
set_error_type_name("'%s' value must be number",
drgn_object_type_qualified(type));
return -1;
}
fvalue = PyFloat_AsDouble(value_obj);
if (fvalue == -1.0 && PyErr_Occurred())
return -1;
if (bit_size == 64)
tmp.fvalue64 = fvalue;
else
tmp.fvalue32 = fvalue;
serialize_bits(buf, bit_offset, tmp.uvalue, bit_size,
little_endian);
return 0;
}
case DRGN_OBJECT_ENCODING_BUFFER:
switch (drgn_type_kind(type->underlying_type)) {
case DRGN_TYPE_STRUCT:
case DRGN_TYPE_UNION:
case DRGN_TYPE_CLASS:
return serialize_compound_value(prog, buf, buf_bit_size,
bit_offset, value_obj,
type, little_endian);
case DRGN_TYPE_ARRAY:
return serialize_array_value(prog, buf, buf_bit_size,
bit_offset, value_obj,
type, little_endian);
default:
break;
}
break;
default:
break;
}
UNREACHABLE();
}
static int buffer_object_from_value(struct drgn_object *res,
struct drgn_qualified_type qualified_type,
PyObject *value_obj,
enum drgn_byte_order byte_order)
{
struct drgn_error *err;
bool little_endian;
err = drgn_byte_order_to_little_endian(drgn_object_program(res),
byte_order, &little_endian);
if (err) {
set_drgn_error(err);
return -1;
}
struct drgn_object_type type;
enum drgn_object_encoding encoding;
uint64_t bit_size;
err = drgn_object_set_common(qualified_type, 0, &type, &encoding,
&bit_size);
if (err) {
set_drgn_error(err);
return -1;
}
uint64_t size = drgn_value_size(bit_size);
if (size > SIZE_MAX) {
PyErr_NoMemory();
return -1;
}
union drgn_value value;
char *buf;
if (size <= sizeof(value.ibuf)) {
buf = value.ibuf;
} else {
buf = malloc64(size);
if (!buf) {
PyErr_NoMemory();
return -1;
}
value.bufp = buf;
}
memset(buf, 0, size);
if (serialize_py_object(drgn_object_program(res), buf, bit_size, 0,
value_obj, &type, little_endian) == -1) {
if (buf != value.ibuf)
free(buf);
return -1;
}
drgn_object_reinit(res, &type, encoding, bit_size, DRGN_OBJECT_VALUE);
res->value = value;
res->little_endian = little_endian;
return 0;
}
static DrgnObject *DrgnObject_new(PyTypeObject *subtype, PyObject *args,
PyObject *kwds)
{
static char *keywords[] = {
"prog", "type", "value", "address", "byteorder",
"bit_offset", "bit_field_size", NULL,
};
struct drgn_error *err;
Program *prog;
PyObject *type_obj = Py_None, *value_obj = Py_None;
struct index_arg address = { .allow_none = true, .is_none = true };
struct byteorder_arg byteorder = {
.allow_none = true,
.is_none = true,
.value = DRGN_PROGRAM_ENDIAN,
};
struct index_arg bit_offset = { .allow_none = true, .is_none = true };
struct index_arg bit_field_size = { .allow_none = true, .is_none = true };
struct drgn_qualified_type qualified_type;
DrgnObject *obj;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|OO$O&O&O&O&:Object",
keywords, &Program_type, &prog,
&type_obj, &value_obj, index_converter,
&address, byteorder_converter,
&byteorder, index_converter,
&bit_offset, index_converter,
&bit_field_size))
return NULL;
if (Program_type_arg(prog, type_obj, true, &qualified_type) == -1)
return NULL;
if (!bit_field_size.is_none && bit_field_size.uvalue == 0) {
PyErr_SetString(PyExc_ValueError,
"bit field size cannot be zero");
return NULL;
}
obj = DrgnObject_alloc(prog);
if (!obj)
return NULL;
if (!address.is_none && value_obj != Py_None) {
PyErr_SetString(PyExc_ValueError,
"object cannot have address and value");
goto err;
} else if (!address.is_none) {
if (!qualified_type.type) {
PyErr_SetString(PyExc_ValueError,
"reference must have type");
goto err;
}
err = drgn_object_set_reference(&obj->obj, qualified_type,
address.uvalue,
bit_offset.uvalue,
bit_field_size.uvalue,
byteorder.value);
} else if (value_obj != Py_None && !qualified_type.type) {
int ret;
if (!byteorder.is_none) {
PyErr_SetString(PyExc_ValueError,
"literal cannot have byteorder");
goto err;
}
if (!bit_offset.is_none) {
PyErr_SetString(PyExc_ValueError,
"literal cannot have bit offset");
goto err;
}
if (!bit_field_size.is_none) {
PyErr_SetString(PyExc_ValueError,
"literal cannot be bit field");
goto err;
}
ret = DrgnObject_literal(&obj->obj, value_obj);
if (ret == -1) {
goto err;
} else if (ret) {
PyErr_Format(PyExc_TypeError,
"cannot create %s literal",
Py_TYPE(value_obj)->tp_name);
goto err;
}
err = NULL;
} else if (value_obj != Py_None) {
if (!bit_offset.is_none) {
PyErr_SetString(PyExc_ValueError,
"value cannot have bit offset");
goto err;
}
enum drgn_object_encoding encoding =
drgn_type_object_encoding(qualified_type.type);
if (!drgn_object_encoding_is_complete(encoding)) {
err = drgn_error_incomplete_type("cannot create value with %s type",
qualified_type.type);
set_drgn_error(err);
goto err;
}
if (!bit_field_size.is_none &&
encoding != DRGN_OBJECT_ENCODING_SIGNED &&
encoding != DRGN_OBJECT_ENCODING_UNSIGNED) {
PyErr_SetString(PyExc_ValueError,
"bit field must be integer");
goto err;
}
if (encoding != DRGN_OBJECT_ENCODING_BUFFER && !byteorder.is_none) {
PyErr_SetString(PyExc_ValueError,
"primitive value cannot have byteorder");
goto err;
}
switch (encoding) {
case DRGN_OBJECT_ENCODING_BUFFER:
if (buffer_object_from_value(&obj->obj, qualified_type,
value_obj,
byteorder.value) == -1)
goto err;
err = NULL;
break;
case DRGN_OBJECT_ENCODING_SIGNED:
case DRGN_OBJECT_ENCODING_UNSIGNED: {
PyObject *long_obj;
union {
int64_t svalue;
uint64_t uvalue;
} tmp;
if (!PyNumber_Check(value_obj)) {
set_error_type_name("'%s' value must be number",
qualified_type);
goto err;
}
long_obj = PyNumber_Long(value_obj);
if (!long_obj)
goto err;
tmp.uvalue = PyLong_AsUnsignedLongLongMask(long_obj);
Py_DECREF(long_obj);
if (tmp.uvalue == (unsigned long long)-1 &&
PyErr_Occurred())
goto err;
if (encoding == DRGN_OBJECT_ENCODING_SIGNED) {
err = drgn_object_set_signed(&obj->obj,
qualified_type,
tmp.svalue,
bit_field_size.uvalue);
} else {
err = drgn_object_set_unsigned(&obj->obj,
qualified_type,
tmp.uvalue,
bit_field_size.uvalue);
}
break;
}
case DRGN_OBJECT_ENCODING_FLOAT: {
double fvalue;
if (!PyNumber_Check(value_obj)) {
set_error_type_name("'%s' value must be number",
qualified_type);
goto err;
}
fvalue = PyFloat_AsDouble(value_obj);
if (fvalue == -1.0 && PyErr_Occurred())
goto err;
err = drgn_object_set_float(&obj->obj, qualified_type,
fvalue);
break;
}
default:
UNREACHABLE();
}
} else {
if (!qualified_type.type) {
PyErr_SetString(PyExc_ValueError,
"absent object must have type");
goto err;
}
if (!byteorder.is_none) {
PyErr_SetString(PyExc_ValueError,
"absent object cannot have byteorder");
goto err;
}
if (!bit_offset.is_none) {
PyErr_SetString(PyExc_ValueError,
"absent object cannot have bit offset");
goto err;
}
err = drgn_object_set_absent(&obj->obj, qualified_type,
bit_field_size.uvalue);
}
if (err) {
set_drgn_error(err);
goto err;
}
return obj;
err:
Py_DECREF(obj);
return NULL;
}
static void DrgnObject_dealloc(DrgnObject *self)
{
Py_DECREF(DrgnObject_prog(self));
drgn_object_deinit(&self->obj);
Py_TYPE(self)->tp_free((PyObject *)self);
}
static PyObject *DrgnObject_value_impl(struct drgn_object *obj);
static PyObject *DrgnObject_compound_value(struct drgn_object *obj,
struct drgn_type *underlying_type)
{
struct drgn_error *err;
PyObject *dict;
struct drgn_object member;
struct drgn_type_member *members;
size_t num_members, i;
if (!drgn_type_is_complete(underlying_type)) {
PyErr_Format(PyExc_TypeError,
"cannot get value of incomplete %s",
drgn_type_kind_spelling[drgn_type_kind(underlying_type)]);
return NULL;
}
dict = PyDict_New();
if (!dict)
return NULL;
drgn_object_init(&member, drgn_object_program(obj));
members = drgn_type_members(underlying_type);
num_members = drgn_type_num_members(underlying_type);
for (i = 0; i < num_members; i++) {
struct drgn_qualified_type member_type;
uint64_t member_bit_field_size;
err = drgn_member_type(&members[i], &member_type,
&member_bit_field_size);
if (err) {
set_drgn_error(err);
Py_CLEAR(dict);
goto out;
}
err = drgn_object_slice(&member, obj, member_type,
members[i].bit_offset,
member_bit_field_size);
if (err) {
set_drgn_error(err);
Py_CLEAR(dict);
goto out;
}
PyObject *member_value = DrgnObject_value_impl(&member);
if (!member_value) {
Py_CLEAR(dict);
goto out;
}
int ret;
if (members[i].name) {
ret = PyDict_SetItemString(dict, members[i].name,
member_value);
} else {
ret = PyDict_Update(dict, member_value);
}
Py_DECREF(member_value);
if (ret) {
Py_CLEAR(dict);
goto out;
}
}
out:
drgn_object_deinit(&member);
return dict;
}
static PyObject *DrgnObject_array_value(struct drgn_object *obj,
struct drgn_type *underlying_type)
{
struct drgn_error *err;
struct drgn_qualified_type element_type;
uint64_t element_bit_size, length, i;
PyObject *list;
struct drgn_object element;
element_type = drgn_type_type(underlying_type);
err = drgn_type_bit_size(element_type.type, &element_bit_size);
if (err)
return set_drgn_error(err);
length = drgn_type_length(underlying_type);
if (length > PY_SSIZE_T_MAX) {
PyErr_NoMemory();
return NULL;
}
list = PyList_New(length);
if (!list)
return NULL;
drgn_object_init(&element, drgn_object_program(obj));
for (i = 0; i < length; i++) {
PyObject *element_value;
err = drgn_object_slice(&element, obj, element_type,
i * element_bit_size, 0);
if (err) {
set_drgn_error(err);
Py_CLEAR(list);
goto out;
}
element_value = DrgnObject_value_impl(&element);
if (!element_value) {
Py_CLEAR(list);
goto out;
}
PyList_SET_ITEM(list, i, element_value);
}
out:
drgn_object_deinit(&element);
return list;
}
static PyObject *DrgnObject_value_impl(struct drgn_object *obj)
{
struct drgn_error *err;
struct drgn_type *underlying_type;
if (!drgn_object_encoding_is_complete(obj->encoding)) {
err = drgn_error_incomplete_type("cannot read object with %s type",
obj->type);
return set_drgn_error(err);
}
underlying_type = drgn_underlying_type(obj->type);
switch (obj->encoding) {
case DRGN_OBJECT_ENCODING_SIGNED: {
int64_t svalue;
err = drgn_object_read_signed(obj, &svalue);
if (err)
return set_drgn_error(err);
return PyLong_FromLongLong(svalue);
}
case DRGN_OBJECT_ENCODING_UNSIGNED: {
uint64_t uvalue;
err = drgn_object_read_unsigned(obj, &uvalue);
if (err)
return set_drgn_error(err);
if (drgn_type_kind(underlying_type) == DRGN_TYPE_BOOL)
Py_RETURN_BOOL(uvalue);
else
return PyLong_FromUnsignedLongLong(uvalue);
}
case DRGN_OBJECT_ENCODING_FLOAT: {
double fvalue;
err = drgn_object_read_float(obj, &fvalue);
if (err)
return set_drgn_error(err);
return PyFloat_FromDouble(fvalue);
}
case DRGN_OBJECT_ENCODING_BUFFER:
switch (drgn_type_kind(underlying_type)) {
case DRGN_TYPE_STRUCT:
case DRGN_TYPE_UNION:
case DRGN_TYPE_CLASS:
return DrgnObject_compound_value(obj, underlying_type);
case DRGN_TYPE_ARRAY:
return DrgnObject_array_value(obj, underlying_type);
default:
break;
}
break;
default:
break;
}
UNREACHABLE();
}
static PyObject *DrgnObject_value(DrgnObject *self)
{
return DrgnObject_value_impl(&self->obj);
}
static PyObject *DrgnObject_string(DrgnObject *self)
{
struct drgn_error *err;
char *str;
PyObject *ret;
err = drgn_object_read_c_string(&self->obj, &str);
if (err)
return set_drgn_error(err);
ret = PyBytes_FromString(str);
free(str);
return ret;
}
static DrgnObject *DrgnObject_address_of(DrgnObject *self)
{
struct drgn_error *err;
DrgnObject *res;
res = DrgnObject_alloc(DrgnObject_prog(self));
if (!res)
return NULL;
err = drgn_object_address_of(&res->obj, &self->obj);
if (err) {
Py_DECREF(res);
return set_drgn_error(err);
}
return res;
}
static DrgnObject *DrgnObject_read(DrgnObject *self)
{
struct drgn_error *err;
DrgnObject *res;
SWITCH_ENUM(self->obj.kind,
case DRGN_OBJECT_VALUE:
Py_INCREF(self);
return self;
case DRGN_OBJECT_REFERENCE:
res = DrgnObject_alloc(DrgnObject_prog(self));
if (!res)
return NULL;
err = drgn_object_read(&res->obj, &self->obj);
if (err) {
Py_DECREF(res);
return set_drgn_error(err);
}
return res;
case DRGN_OBJECT_ABSENT:
return set_drgn_error(&drgn_error_object_absent);
)
}
static int append_byte_order(PyObject *parts, struct drgn_program *prog,
bool little_endian)
{
struct drgn_error *err;
if (prog->has_platform) {
bool prog_little_endian;
err = drgn_program_is_little_endian(prog, &prog_little_endian);
if (err) {
set_drgn_error(err);
return -1;
}
if (little_endian == prog_little_endian)
return 0;
}
return append_format(parts, ", byteorder='%s'",
little_endian ? "little" : "big");
}
static int append_bit_offset(PyObject *parts, uint8_t bit_offset)
{
if (bit_offset == 0)
return 0;
return append_format(parts, ", bit_offset=%d", bit_offset);
}
static PyObject *DrgnObject_repr(DrgnObject *self)
{
struct drgn_error *err;
PyObject *parts, *tmp, *ret = NULL;
char *type_name;
parts = PyList_New(0);
if (!parts)
return NULL;
err = drgn_format_type_name(drgn_object_qualified_type(&self->obj),
&type_name);
if (err) {
set_drgn_error(err);
goto out;
}
tmp = PyUnicode_FromString(type_name);
free(type_name);
if (!tmp)
goto out;
if (append_format(parts, "Object(prog, %R", tmp) == -1) {
Py_DECREF(tmp);
goto out;
}
Py_DECREF(tmp);
SWITCH_ENUM(self->obj.kind,
case DRGN_OBJECT_VALUE: {
if (append_string(parts, ", value=") == -1)
goto out;
PyObject *value_obj = DrgnObject_value(self);
if (!value_obj)
goto out;
if (drgn_type_kind(drgn_underlying_type(self->obj.type)) ==
DRGN_TYPE_POINTER)
tmp = PyNumber_ToBase(value_obj, 16);
else
tmp = PyObject_Repr(value_obj);
Py_DECREF(value_obj);
if (!tmp)
goto out;
if (PyList_Append(parts, tmp) == -1) {
Py_DECREF(tmp);
goto out;
}
Py_DECREF(tmp);
if (self->obj.encoding == DRGN_OBJECT_ENCODING_BUFFER &&
append_byte_order(parts, drgn_object_program(&self->obj),
self->obj.little_endian) == -1)
goto out;
break;
}
case DRGN_OBJECT_REFERENCE: {
char buf[17];
snprintf(buf, sizeof(buf), "%" PRIx64, self->obj.address);
if (append_format(parts, ", address=0x%s", buf) == -1)
goto out;
if (append_byte_order(parts, drgn_object_program(&self->obj),
self->obj.little_endian) == -1 ||
append_bit_offset(parts, self->obj.bit_offset) == -1)
goto out;
break;
}
case DRGN_OBJECT_ABSENT:
break;
)
if (self->obj.is_bit_field &&
append_format(parts, ", bit_field_size=%llu",
(unsigned long long)self->obj.bit_size) == -1)
goto out;
if (append_string(parts, ")") == -1)
goto out;
ret = join_strings(parts);
out:
Py_DECREF(parts);
return ret;
}
static PyObject *DrgnObject_str(DrgnObject *self)
{
struct drgn_error *err;
char *str;
PyObject *ret;
err = drgn_format_object(&self->obj, SIZE_MAX,
DRGN_FORMAT_OBJECT_PRETTY, &str);
if (err)
return set_drgn_error(err);
ret = PyUnicode_FromString(str);
free(str);
return ret;
}
struct format_object_flag_arg {
enum drgn_format_object_flags *flags;
enum drgn_format_object_flags value;
};
static int format_object_flag_converter(PyObject *o, void *p)
{
struct format_object_flag_arg *arg = p;
int ret;
if (o == Py_None)
return 1;
ret = PyObject_IsTrue(o);
if (ret == -1)
return 0;
if (ret)
*arg->flags |= arg->value;
else
*arg->flags &= ~arg->value;
return 1;
}
static PyObject *DrgnObject_format(DrgnObject *self, PyObject *args,
PyObject *kwds)
{
#define FLAGS \
X(dereference, DRGN_FORMAT_OBJECT_DEREFERENCE) \
X(symbolize, DRGN_FORMAT_OBJECT_SYMBOLIZE) \
X(string, DRGN_FORMAT_OBJECT_STRING) \
X(char, DRGN_FORMAT_OBJECT_CHAR) \
X(type_name, DRGN_FORMAT_OBJECT_TYPE_NAME) \
X(member_type_names, DRGN_FORMAT_OBJECT_MEMBER_TYPE_NAMES) \
X(element_type_names, DRGN_FORMAT_OBJECT_ELEMENT_TYPE_NAMES) \
X(members_same_line, DRGN_FORMAT_OBJECT_MEMBERS_SAME_LINE) \
X(elements_same_line, DRGN_FORMAT_OBJECT_ELEMENTS_SAME_LINE) \
X(member_names, DRGN_FORMAT_OBJECT_MEMBER_NAMES) \
X(element_indices, DRGN_FORMAT_OBJECT_ELEMENT_INDICES) \
X(implicit_members, DRGN_FORMAT_OBJECT_IMPLICIT_MEMBERS) \
X(implicit_elements, DRGN_FORMAT_OBJECT_IMPLICIT_ELEMENTS)
static char *keywords[] = {
#define X(name, value) #name,
FLAGS
#undef X
"columns",
NULL,
};
struct drgn_error *err;
PyObject *columns_obj = Py_None;
size_t columns = SIZE_MAX;
enum drgn_format_object_flags flags = DRGN_FORMAT_OBJECT_PRETTY;
#define X(name, value) \
struct format_object_flag_arg name##_arg = { &flags, value };
FLAGS
#undef X
char *str;
PyObject *ret;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$"
#define X(name, value) "O&"
FLAGS
#undef X
"O", keywords,
#define X(name, value) format_object_flag_converter, &name##_arg,
FLAGS
#undef X
&columns_obj))
return NULL;
if (columns_obj != Py_None) {
columns_obj = PyNumber_Index(columns_obj);
if (!columns_obj)
return NULL;
columns = PyLong_AsSize_t(columns_obj);
Py_DECREF(columns_obj);
if (columns == (size_t)-1 && PyErr_Occurred())
return NULL;
}
err = drgn_format_object(&self->obj, columns, flags, &str);
if (err)
return set_drgn_error(err);
ret = PyUnicode_FromString(str);
free(str);
return ret;
#undef FLAGS
}
static Program *DrgnObject_get_prog(DrgnObject *self, void *arg)
{
Py_INCREF(DrgnObject_prog(self));
return DrgnObject_prog(self);
}
static PyObject *DrgnObject_get_type(DrgnObject *self, void *arg)
{
return DrgnType_wrap(drgn_object_qualified_type(&self->obj));
}
static PyObject *DrgnObject_get_absent(DrgnObject *self, void *arg)
{
Py_RETURN_BOOL(self->obj.kind == DRGN_OBJECT_ABSENT);
}
static PyObject *DrgnObject_get_address(DrgnObject *self, void *arg)
{
if (self->obj.kind == DRGN_OBJECT_REFERENCE)
return PyLong_FromUnsignedLongLong(self->obj.address);
else
Py_RETURN_NONE;
}
static PyObject *DrgnObject_get_byteorder(DrgnObject *self, void *arg)
{
SWITCH_ENUM(self->obj.kind,
case DRGN_OBJECT_VALUE:
if (self->obj.encoding == DRGN_OBJECT_ENCODING_BUFFER)
return byteorder_string(self->obj.little_endian);
else
Py_RETURN_NONE;
case DRGN_OBJECT_REFERENCE:
return byteorder_string(self->obj.little_endian);
case DRGN_OBJECT_ABSENT:
Py_RETURN_NONE;
)
}
static PyObject *DrgnObject_get_bit_offset(DrgnObject *self, void *arg)
{
SWITCH_ENUM(self->obj.kind,
case DRGN_OBJECT_REFERENCE:
return PyLong_FromLong(self->obj.bit_offset);
case DRGN_OBJECT_VALUE:
case DRGN_OBJECT_ABSENT:
Py_RETURN_NONE;
)
}
static PyObject *DrgnObject_get_bit_field_size(DrgnObject *self, void *arg)
{
if (self->obj.is_bit_field)
return PyLong_FromUnsignedLongLong(self->obj.bit_size);
else
Py_RETURN_NONE;
}
static int DrgnObject_binary_operand(PyObject *self, PyObject *other,
struct drgn_object **obj,
struct drgn_object *tmp)
{
if (PyObject_TypeCheck(self, &DrgnObject_type)) {
*obj = &((DrgnObject *)self)->obj;
return 0;
} else {
*obj = tmp;
/* If self isn't a DrgnObject, then other must be. */
drgn_object_init(tmp,
drgn_object_program(&((DrgnObject *)other)->obj));
return DrgnObject_literal(tmp, self);
}
}
#define DrgnObject_BINARY_OP(op) \
static PyObject *DrgnObject_##op(PyObject *left, PyObject *right) \
{ \
struct drgn_error *err; \
struct drgn_object *lhs, lhs_tmp, *rhs, rhs_tmp; \
DrgnObject *res = NULL; \
int ret; \
\
ret = DrgnObject_binary_operand(left, right, &lhs, &lhs_tmp); \
if (ret) \
goto out; \
ret = DrgnObject_binary_operand(right, left, &rhs, &rhs_tmp); \
if (ret) \
goto out_lhs; \
\
res = DrgnObject_alloc(container_of(drgn_object_program(lhs), Program, \
prog)); \
if (!res) { \
ret = -1; \
goto out_rhs; \
} \
\
err = drgn_object_##op(&res->obj, lhs, rhs); \
if (err) { \
set_drgn_error(err); \
Py_DECREF(res); \
ret = -1; \
goto out_rhs; \
} \
\
out_rhs: \
if (rhs == &rhs_tmp) \
drgn_object_deinit(&rhs_tmp); \
out_lhs: \
if (lhs == &lhs_tmp) \
drgn_object_deinit(&lhs_tmp); \
out: \
if (ret == -1) \
return NULL; \
else if (ret) \
Py_RETURN_NOTIMPLEMENTED; \
else \
return (PyObject *)res; \
}
DrgnObject_BINARY_OP(add)
DrgnObject_BINARY_OP(sub)
DrgnObject_BINARY_OP(mul)
DrgnObject_BINARY_OP(div)
DrgnObject_BINARY_OP(mod)
DrgnObject_BINARY_OP(lshift)
DrgnObject_BINARY_OP(rshift)
DrgnObject_BINARY_OP(and)
DrgnObject_BINARY_OP(or)
DrgnObject_BINARY_OP(xor)
#undef DrgnObject_BINARY_OP
#define DrgnObject_UNARY_OP(op) \
static DrgnObject *DrgnObject_##op(DrgnObject *self) \
{ \
struct drgn_error *err; \
DrgnObject *res; \
\
res = DrgnObject_alloc(DrgnObject_prog(self)); \
if (!res) \
return NULL; \
\
err = drgn_object_##op(&res->obj, &self->obj); \
if (err) { \
Py_DECREF(res); \
return set_drgn_error(err); \
} \
return res; \
}
DrgnObject_UNARY_OP(pos)
DrgnObject_UNARY_OP(neg)
DrgnObject_UNARY_OP(not)
#undef DrgnObject_UNARY_OP
static int DrgnObject_bool(DrgnObject *self)
{
struct drgn_error *err;
bool ret;
err = drgn_object_bool(&self->obj, &ret);
if (err) {
set_drgn_error(err);
return -1;
}
return ret;
}
static PyObject *DrgnObject_int(DrgnObject *self)
{
struct drgn_error *err;
union drgn_value value_mem;
const union drgn_value *value;
PyObject *ret;
if (!drgn_type_is_scalar(self->obj.type)) {
return set_error_type_name("cannot convert '%s' to int",
drgn_object_qualified_type(&self->obj));
}
err = drgn_object_read_value(&self->obj, &value_mem, &value);
if (err)
return set_drgn_error(err);
switch (self->obj.encoding) {
case DRGN_OBJECT_ENCODING_SIGNED:
ret = PyLong_FromLongLong(value->svalue);
break;
case DRGN_OBJECT_ENCODING_UNSIGNED:
ret = PyLong_FromUnsignedLongLong(value->uvalue);
break;
case DRGN_OBJECT_ENCODING_FLOAT:
ret = PyLong_FromDouble(value->fvalue);
break;
default:
UNREACHABLE();
}
drgn_object_deinit_value(&self->obj, value);
return ret;
}
static PyObject *DrgnObject_float(DrgnObject *self)
{
struct drgn_error *err;
union drgn_value value_mem;
const union drgn_value *value;
PyObject *ret;
if (!drgn_type_is_arithmetic(self->obj.type)) {
return set_error_type_name("cannot convert '%s' to float",
drgn_object_qualified_type(&self->obj));
}
err = drgn_object_read_value(&self->obj, &value_mem, &value);
if (err)
return set_drgn_error(err);
switch (self->obj.encoding) {
case DRGN_OBJECT_ENCODING_SIGNED:
ret = PyFloat_FromDouble(value->svalue);
break;
case DRGN_OBJECT_ENCODING_UNSIGNED:
ret = PyFloat_FromDouble(value->uvalue);
break;
case DRGN_OBJECT_ENCODING_FLOAT:
ret = PyFloat_FromDouble(value->fvalue);
break;
default:
UNREACHABLE();
}
drgn_object_deinit_value(&self->obj, value);
return ret;
}
static PyObject *DrgnObject_index(DrgnObject *self)
{
struct drgn_error *err;
struct drgn_type *underlying_type;
union drgn_value value_mem;
const union drgn_value *value;
PyObject *ret;
underlying_type = drgn_underlying_type(self->obj.type);
if (!drgn_type_is_integer(underlying_type) &&
drgn_type_kind(underlying_type) != DRGN_TYPE_POINTER) {
return set_error_type_name("'%s' object cannot be interpreted as an integer",
drgn_object_qualified_type(&self->obj));
}
err = drgn_object_read_value(&self->obj, &value_mem, &value);
if (err)
return set_drgn_error(err);
switch (self->obj.encoding) {
case DRGN_OBJECT_ENCODING_SIGNED:
ret = PyLong_FromLongLong(value->svalue);
break;
case DRGN_OBJECT_ENCODING_UNSIGNED:
ret = PyLong_FromUnsignedLongLong(value->uvalue);
break;
default:
UNREACHABLE();
}
drgn_object_deinit_value(&self->obj, value);
return ret;
}
static PyObject *DrgnObject_round(DrgnObject *self, PyObject *args,
PyObject *kwds)
{
static char *keywords[] = {"ndigits", NULL};
PyObject *ndigits = Py_None, *value, *ret;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:round", keywords,
&ndigits))
return NULL;
if (!drgn_type_is_arithmetic(self->obj.type)) {
return set_error_type_name("cannot round '%s'",
drgn_object_qualified_type(&self->obj));
}
value = DrgnObject_value(self);
if (!value)
return NULL;
if (ndigits == Py_None) {
ret = PyObject_CallMethod(value, "__round__", NULL);
Py_DECREF(value);
} else {
PyObject *args, *kwds, *tmp, *type;
tmp = PyObject_CallMethod(value, "__round__", "O", ndigits);
Py_DECREF(value);
if (!tmp)
return NULL;
value = tmp;
kwds = PyDict_New();
if (!kwds) {
Py_DECREF(value);
return NULL;
}
if (PyDict_SetItemString(kwds, "value", value) == -1) {
Py_DECREF(value);
return NULL;
}
Py_DECREF(value);
type = DrgnObject_get_type(self, NULL);
if (!type) {
Py_DECREF(kwds);
return NULL;
}
args = Py_BuildValue("OO", DrgnObject_prog(self), type);
Py_DECREF(type);
if (!args) {
Py_DECREF(kwds);
return NULL;
}
ret = PyObject_Call((PyObject *)&DrgnObject_type, args, kwds);
Py_DECREF(args);
Py_DECREF(kwds);
}
return ret;
}
#define DrgnObject_round_method(func) \
static PyObject *DrgnObject_##func(DrgnObject *self) \
{ \
struct drgn_error *err; \
union drgn_value value_mem; \
const union drgn_value *value; \
PyObject *ret; \
\
if (!drgn_type_is_arithmetic(self->obj.type)) { \
return set_error_type_name("cannot round '%s'", \
drgn_object_qualified_type(&self->obj));\
} \
\
err = drgn_object_read_value(&self->obj, &value_mem, &value); \
if (err) \
return set_drgn_error(err); \
\
switch (self->obj.encoding) { \
case DRGN_OBJECT_ENCODING_SIGNED: \
ret = PyLong_FromLongLong(value->svalue); \
break; \
case DRGN_OBJECT_ENCODING_UNSIGNED: \
ret = PyLong_FromUnsignedLongLong(value->uvalue); \
break; \
case DRGN_OBJECT_ENCODING_FLOAT: \
ret = PyLong_FromDouble(func(value->fvalue)); \
break; \
default: \
UNREACHABLE(); \
} \
drgn_object_deinit_value(&self->obj, value); \
return ret; \
}
DrgnObject_round_method(trunc)
DrgnObject_round_method(floor)
DrgnObject_round_method(ceil)
static PyObject *DrgnObject_richcompare(PyObject *left, PyObject *right, int op)
{
struct drgn_error *err;
struct drgn_object *lhs, lhs_tmp, *rhs, rhs_tmp;
int ret, cmp;
ret = DrgnObject_binary_operand(left, right, &lhs, &lhs_tmp);
if (ret)
goto out;
ret = DrgnObject_binary_operand(right, left, &rhs, &rhs_tmp);
if (ret)
goto out_lhs;
err = drgn_object_cmp(lhs, rhs, &cmp);
if (err) {
set_drgn_error(err);
ret = -1;
}
if (rhs == &rhs_tmp)
drgn_object_deinit(&rhs_tmp);
out_lhs:
if (lhs == &lhs_tmp)
drgn_object_deinit(&lhs_tmp);
out:
if (ret == -1)
return NULL;
else if (ret)
Py_RETURN_NOTIMPLEMENTED;
else
Py_RETURN_RICHCOMPARE(cmp, 0, op);
}
static DrgnObject *DrgnObject_member(DrgnObject *self, PyObject *args,
PyObject *kwds)
{
static char *keywords[] = {"name", NULL};
struct drgn_error *err;
const char *name;
DrgnObject *res;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s:member_", keywords,
&name))
return NULL;
res = DrgnObject_alloc(DrgnObject_prog(self));
if (!res)
return NULL;
if (self->obj.encoding == DRGN_OBJECT_ENCODING_UNSIGNED) {
err = drgn_object_member_dereference(&res->obj, &self->obj,
name);
} else {
err = drgn_object_member(&res->obj, &self->obj, name);
}
if (err) {
Py_DECREF(res);
return set_drgn_error(err);
}
return res;
}
static PyObject *DrgnObject_getattro(DrgnObject *self, PyObject *attr_name)
{
struct drgn_error *err;
PyObject *attr;
const char *name;
DrgnObject *res;
/*
* In Python 3.7 and newer, _PyObject_GenericGetAttrWithDict() can
* suppress the AttributeError if the attribute isn't found. This makes
* member lookups much more efficient.
*/
#define GETATTR_SUPPRESS (PY_VERSION_HEX >= 0x030700b1)
#if GETATTR_SUPPRESS
attr = _PyObject_GenericGetAttrWithDict((PyObject *)self, attr_name,
NULL, 1);
if (attr || PyErr_Occurred())
return attr;
#else
PyObject *exc_type, *exc_value, *exc_traceback;
attr = PyObject_GenericGetAttr((PyObject *)self, attr_name);
if (attr || !PyErr_ExceptionMatches(PyExc_AttributeError))
return attr;
PyErr_Fetch(&exc_type, &exc_value, &exc_traceback);
#endif
name = PyUnicode_AsUTF8(attr_name);
if (!name) {
res = NULL;
goto out;
}
res = DrgnObject_alloc(DrgnObject_prog(self));
if (!res)
goto out;
if (self->obj.encoding == DRGN_OBJECT_ENCODING_UNSIGNED) {
err = drgn_object_member_dereference(&res->obj, &self->obj,
name);
} else {
err = drgn_object_member(&res->obj, &self->obj, name);
}
if (err) {
Py_CLEAR(res);
if (err->code == DRGN_ERROR_TYPE) {
/*
* If the object doesn't have a compound type, raise a
* generic AttributeError (or restore the original one
* if we weren't able to suppress it).
*/
#if GETATTR_SUPPRESS
PyErr_Format(PyExc_AttributeError,
"'%s' object has no attribute '%U'",
Py_TYPE(self)->tp_name, attr_name);
#else
PyErr_Restore(exc_type, exc_value, exc_traceback);
#endif
drgn_error_destroy(err);
return NULL;
} else if (err->code == DRGN_ERROR_LOOKUP) {
PyErr_SetString(PyExc_AttributeError, err->message);
drgn_error_destroy(err);
} else {
set_drgn_error(err);
}
}
out:
#if !GETATTR_SUPPRESS
Py_XDECREF(exc_traceback);
Py_XDECREF(exc_value);
Py_DECREF(exc_type);
#endif
#undef GETATTR_SUPPRESS
return (PyObject *)res;
}
static Py_ssize_t DrgnObject_length(DrgnObject *self)
{
struct drgn_type *underlying_type;
uint64_t length;
underlying_type = drgn_underlying_type(self->obj.type);
if (drgn_type_kind(underlying_type) != DRGN_TYPE_ARRAY ||
!drgn_type_is_complete(underlying_type)) {
set_error_type_name("'%s' has no len()",
drgn_object_qualified_type(&self->obj));
return -1;
}
length = drgn_type_length(underlying_type);
if (length > PY_SSIZE_T_MAX) {
PyErr_SetString(PyExc_OverflowError, "length is too large");
return -1;
}
return length;
}
static DrgnObject *DrgnObject_subscript_impl(DrgnObject *self,
int64_t index)
{
struct drgn_error *err;
DrgnObject *res;
res = DrgnObject_alloc(DrgnObject_prog(self));
if (!res)
return NULL;
err = drgn_object_subscript(&res->obj, &self->obj, index);
if (err) {
Py_DECREF(res);
return set_drgn_error(err);
}
return res;
}
static DrgnObject *DrgnObject_subscript(DrgnObject *self, PyObject *key)
{
struct index_arg index = { .is_signed = true };
if (!index_converter(key, &index))
return NULL;
return DrgnObject_subscript_impl(self, index.svalue);
}
static ObjectIterator *DrgnObject_iter(DrgnObject *self)
{
struct drgn_type *underlying_type;
ObjectIterator *it;
underlying_type = drgn_underlying_type(self->obj.type);
if (drgn_type_kind(underlying_type) != DRGN_TYPE_ARRAY ||
!drgn_type_is_complete(underlying_type)) {
set_error_type_name("'%s' is not iterable",
drgn_object_qualified_type(&self->obj));
return NULL;
}
it = (ObjectIterator *)ObjectIterator_type.tp_alloc(&ObjectIterator_type,
0);
if (!it)
return NULL;
it->obj = self;
Py_INCREF(self);
it->length = drgn_type_length(underlying_type);
return it;
}
static int add_to_dir(PyObject *dir, struct drgn_type *type)
{
struct drgn_error *err;
type = drgn_underlying_type(type);
if (!drgn_type_has_members(type))
return 0;
struct drgn_type_member *members = drgn_type_members(type);
size_t num_members = drgn_type_num_members(type);
for (size_t i = 0; i < num_members; i++) {
struct drgn_type_member *member;
member = &members[i];
if (member->name) {
PyObject *str = PyUnicode_FromString(member->name);
if (!str)
return -1;
if (PyList_Append(dir, str) == -1) {
Py_DECREF(str);
return -1;
}
Py_DECREF(str);
} else {
struct drgn_qualified_type member_type;
err = drgn_member_type(member, &member_type, NULL);
if (err) {
set_drgn_error(err);
return -1;
}
if (add_to_dir(dir, member_type.type) == -1)
return -1;
}
}
return 0;
}
static PyObject *DrgnObject_dir(DrgnObject *self)
{
_Py_IDENTIFIER(__dir__);
PyObject *method, *dir;
struct drgn_type *type;
method = _PyObject_GetAttrId((PyObject *)Py_TYPE(self)->tp_base,
&PyId___dir__);
if (!method)
return NULL;
dir = PyObject_CallFunctionObjArgs(method, self, NULL);
Py_DECREF(method);
if (!dir)
return NULL;
type = drgn_underlying_type(self->obj.type);
if (drgn_type_kind(type) == DRGN_TYPE_POINTER)
type = drgn_type_type(type).type;
if (add_to_dir(dir, type) == -1) {
Py_DECREF(dir);
return NULL;
}
return dir;
}
static PyGetSetDef DrgnObject_getset[] = {
{"prog_", (getter)DrgnObject_get_prog, NULL, drgn_Object_prog__DOC},
{"type_", (getter)DrgnObject_get_type, NULL, drgn_Object_type__DOC},
{"absent_", (getter)DrgnObject_get_absent, NULL,
drgn_Object_absent__DOC},
{"address_", (getter)DrgnObject_get_address, NULL,
drgn_Object_address__DOC},
{"byteorder_", (getter)DrgnObject_get_byteorder, NULL,
drgn_Object_byteorder__DOC},
{"bit_offset_", (getter)DrgnObject_get_bit_offset, NULL,
drgn_Object_bit_offset__DOC},
{"bit_field_size_", (getter)DrgnObject_get_bit_field_size, NULL,
drgn_Object_bit_field_size__DOC},
{},
};
static PyMethodDef DrgnObject_methods[] = {
{"__getitem__", (PyCFunction)DrgnObject_subscript,
METH_O | METH_COEXIST, drgn_Object___getitem___DOC},
{"value_", (PyCFunction)DrgnObject_value, METH_NOARGS,
drgn_Object_value__DOC},
{"string_", (PyCFunction)DrgnObject_string, METH_NOARGS,
drgn_Object_string__DOC},
{"member_", (PyCFunction)DrgnObject_member,
METH_VARARGS | METH_KEYWORDS, drgn_Object_member__DOC},
{"address_of_", (PyCFunction)DrgnObject_address_of, METH_NOARGS,
drgn_Object_address_of__DOC},
{"read_", (PyCFunction)DrgnObject_read, METH_NOARGS,
drgn_Object_read__DOC},
{"format_", (PyCFunction)DrgnObject_format,
METH_VARARGS | METH_KEYWORDS, drgn_Object_format__DOC},
{"__round__", (PyCFunction)DrgnObject_round,
METH_VARARGS | METH_KEYWORDS},
{"__trunc__", (PyCFunction)DrgnObject_trunc, METH_NOARGS},
{"__floor__", (PyCFunction)DrgnObject_floor, METH_NOARGS},
{"__ceil__", (PyCFunction)DrgnObject_ceil, METH_NOARGS},
{"__dir__", (PyCFunction)DrgnObject_dir, METH_NOARGS,
"dir() implementation which includes structure, union, and class members."},
{},
};
static PyNumberMethods DrgnObject_as_number = {
.nb_add = (binaryfunc)DrgnObject_add,
.nb_subtract = (binaryfunc)DrgnObject_sub,
.nb_multiply = (binaryfunc)DrgnObject_mul,
.nb_remainder = (binaryfunc)DrgnObject_mod,
.nb_negative = (unaryfunc)DrgnObject_neg,
.nb_positive = (unaryfunc)DrgnObject_pos,
.nb_bool = (inquiry)DrgnObject_bool,
.nb_invert = (unaryfunc)DrgnObject_not,
.nb_lshift = (binaryfunc)DrgnObject_lshift,
.nb_rshift = (binaryfunc)DrgnObject_rshift,
.nb_and = (binaryfunc)DrgnObject_and,
.nb_xor = (binaryfunc)DrgnObject_xor,
.nb_or = (binaryfunc)DrgnObject_or,
.nb_int = (unaryfunc)DrgnObject_int,
.nb_float = (unaryfunc)DrgnObject_float,
.nb_true_divide = (binaryfunc)DrgnObject_div,
.nb_index = (unaryfunc)DrgnObject_index,
};
static PyMappingMethods DrgnObject_as_mapping = {
.mp_length = (lenfunc)DrgnObject_length,
.mp_subscript = (binaryfunc)DrgnObject_subscript,
};
PyTypeObject DrgnObject_type = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "_drgn.Object",
.tp_basicsize = sizeof(DrgnObject),
.tp_dealloc = (destructor)DrgnObject_dealloc,
.tp_repr = (reprfunc)DrgnObject_repr,
.tp_as_number = &DrgnObject_as_number,
.tp_as_mapping = &DrgnObject_as_mapping,
.tp_str = (reprfunc)DrgnObject_str,
.tp_getattro = (getattrofunc)DrgnObject_getattro,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_doc = drgn_Object_DOC,
.tp_richcompare = DrgnObject_richcompare,
.tp_iter = (getiterfunc)DrgnObject_iter,
.tp_methods = DrgnObject_methods,
.tp_getset = DrgnObject_getset,
.tp_new = (newfunc)DrgnObject_new,
};
PyObject *DrgnObject_NULL(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *keywords[] = {"prog", "type", NULL};
PyObject *prog_obj, *type_obj;
PyObject *a, *k, *ret;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO:NULL", keywords,
&prog_obj, &type_obj))
return NULL;
a = Py_BuildValue("OO", prog_obj, type_obj);
if (!a)
return NULL;
k = Py_BuildValue("{s:i}", "value", 0);
if (!k) {
Py_DECREF(a);
return NULL;
}
ret = PyObject_Call((PyObject *)&DrgnObject_type, a, k);
Py_DECREF(k);
Py_DECREF(a);
return ret;
}
DrgnObject *cast(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *keywords[] = {"type", "obj", NULL};
struct drgn_error *err;
struct drgn_qualified_type qualified_type;
PyObject *type_obj;
DrgnObject *obj, *res;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO!:cast", keywords,
&type_obj, &DrgnObject_type, &obj))
return NULL;
if (Program_type_arg(DrgnObject_prog(obj), type_obj, false,
&qualified_type) == -1)
return NULL;
res = DrgnObject_alloc(DrgnObject_prog(obj));
if (!res)
return NULL;
err = drgn_object_cast(&res->obj, qualified_type, &obj->obj);
if (err) {
Py_DECREF(res);
return set_drgn_error(err);
}
return res;
}
DrgnObject *reinterpret(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *keywords[] = {"type", "obj", "byteorder", NULL};
struct drgn_error *err;
PyObject *type_obj;
struct drgn_qualified_type qualified_type;
struct byteorder_arg byteorder = {
.allow_none = true,
.is_none = true,
.value = DRGN_PROGRAM_ENDIAN,
};
DrgnObject *obj, *res;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO!|O&:reinterpret",
keywords, &type_obj, &DrgnObject_type,
&obj, byteorder_converter,
&byteorder))
return NULL;
if (Program_type_arg(DrgnObject_prog(obj), type_obj, false,
&qualified_type) == -1)
return NULL;
res = DrgnObject_alloc(DrgnObject_prog(obj));
if (!res)
return NULL;
err = drgn_object_reinterpret(&res->obj, qualified_type,
byteorder.value, &obj->obj);
if (err) {
Py_DECREF(res);
return set_drgn_error(err);
}
return res;
}
DrgnObject *DrgnObject_container_of(PyObject *self, PyObject *args,
PyObject *kwds)
{
static char *keywords[] = {"ptr", "type", "member", NULL};
struct drgn_error *err;
DrgnObject *obj, *res;
PyObject *type_obj;
struct drgn_qualified_type qualified_type;
const char *member_designator;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!Os:container_of",
keywords, &DrgnObject_type, &obj,
&type_obj, &member_designator))
return NULL;
if (Program_type_arg(DrgnObject_prog(obj), type_obj, false,
&qualified_type) == -1)
return NULL;
res = DrgnObject_alloc(DrgnObject_prog(obj));
if (!res)
return NULL;
err = drgn_object_container_of(&res->obj, &obj->obj, qualified_type,
member_designator);
if (err) {
Py_DECREF(res);
return set_drgn_error(err);
}
return res;
}
static void ObjectIterator_dealloc(ObjectIterator *self)
{
Py_DECREF(self->obj);
Py_TYPE(self)->tp_free((PyObject *)self);
}
static DrgnObject *ObjectIterator_next(ObjectIterator *self)
{
if (self->index >= self->length)
return NULL;
return DrgnObject_subscript_impl(self->obj, self->index++);
}
static PyObject *ObjectIterator_length_hint(ObjectIterator *self)
{
return PyLong_FromUnsignedLongLong(self->length);
}
static PyMethodDef ObjectIterator_methods[] = {
{"__length_hint__", (PyCFunction)ObjectIterator_length_hint,
METH_NOARGS},
{},
};
PyTypeObject ObjectIterator_type = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "_drgn._ObjectIterator",
.tp_basicsize = sizeof(ObjectIterator),
.tp_dealloc = (destructor)ObjectIterator_dealloc,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_iter = PyObject_SelfIter,
.tp_iternext = (iternextfunc)ObjectIterator_next,
.tp_methods = ObjectIterator_methods,
};