libdrgn: python: add PyLong_From* and PyLong_As* wrappers for stdint.h types

It feels icky to write code that, for example, passes a uint64_t to
PyLong_FromUnsignedLongLong(). In practice it's fine, but it's much
nicer to have conversion functions specifically for the stdint.h types.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
This commit is contained in:
Omar Sandoval 2022-12-05 16:06:22 -08:00
parent 7180304c88
commit 73fea86792
8 changed files with 70 additions and 54 deletions

View File

@ -39,6 +39,33 @@
#define DRGNPY_PUBLIC __attribute__((__visibility__("default")))
// PyLong_From* and PyLong_As* for stdint.h types. These use _Generic for
// slightly more type safety (e.g., so you can't pass an int64_t to
// PyLong_FromUint64()).
#if ULONG_MAX == UINT64_MAX
#define PyLong_FromUint64(v) _Generic((v), uint64_t: PyLong_FromUnsignedLong)(v)
#define PyLong_AsUint64(obj) ((uint64_t)PyLong_AsUnsignedLong(obj))
#define PyLong_AsUint64Mask(obj) ((uint64_t)PyLong_AsUnsignedLongMask(obj))
#elif ULLONG_MAX == UINT64_MAX
#define PyLong_FromUint64(v) _Generic((v), uint64_t: PyLong_FromUnsignedLongLong)(v)
#define PyLong_AsUint64(obj) ((uint64_t)PyLong_AsUnsignedLongLong(obj))
#define PyLong_AsUint64Mask(obj) ((uint64_t)PyLong_AsUnsignedLongLongMask(obj))
#endif
#if LONG_MIN == INT64_MIN && LONG_MAX == INT64_MAX
#define PyLong_FromInt64(v) _Generic((v), int64_t: PyLong_FromLong)(v)
#define PyLong_AsInt64(obj) ((int64_t)PyLong_AsLong(obj))
#elif LLONG_MIN == INT64_MIN && LLONG_MAX == INT64_MAX
#define PyLong_FromInt64(v) _Generic((v), int64_t: PyLong_FromLongLong)(v)
#define PyLong_AsInt64(obj) ((int64_t)PyLong_AsLongLong(obj))
#endif
#if ULONG_MAX >= UINT32_MAX
#define PyLong_FromUint32(v) _Generic((v), uint32_t: PyLong_FromUnsignedLong)(v)
#define PyLong_FromUint16(v) _Generic((v), uint16_t: PyLong_FromUnsignedLong)(v)
#define PyLong_FromUint8(v) _Generic((v), uint8_t: PyLong_FromUnsignedLong)(v)
#endif
#define Py_RETURN_BOOL(cond) do { \
if (cond) \
Py_RETURN_TRUE; \

View File

@ -16,7 +16,7 @@ PyObject *drgnpy_linux_helper_direct_mapping_offset(PyObject *self, PyObject *ar
err = linux_helper_direct_mapping_offset(&((Program *)arg)->prog, &ret);
if (err)
return set_drgn_error(err);
return PyLong_FromUnsignedLongLong(ret);
return PyLong_FromUint64(ret);
}
PyObject *drgnpy_linux_helper_read_vm(PyObject *self, PyObject *args,
@ -114,7 +114,7 @@ PyObject *drgnpy_linux_helper_task_cpu(PyObject *self, PyObject *args,
err = linux_helper_task_cpu(&task->obj, &cpu);
if (err)
return set_drgn_error(err);
return PyLong_FromUnsignedLongLong(cpu);
return PyLong_FromUint64(cpu);
}
DrgnObject *drgnpy_linux_helper_radix_tree_lookup(PyObject *self,
@ -311,7 +311,7 @@ PyObject *drgnpy_linux_helper_kaslr_offset(PyObject *self, PyObject *args,
if (!(prog->prog.flags & DRGN_PROGRAM_IS_LINUX_KERNEL))
return PyErr_Format(PyExc_ValueError, "not Linux kernel");
return PyLong_FromUnsignedLongLong(prog->prog.vmcoreinfo.kaslr_offset);
return PyLong_FromUint64(prog->prog.vmcoreinfo.kaslr_offset);
}
PyObject *drgnpy_linux_helper_pgtable_l5_enabled(PyObject *self, PyObject *args,

View File

@ -70,7 +70,6 @@ static PyObject *sizeof_(PyObject *self, PyObject *arg)
{
struct drgn_error *err;
uint64_t size;
if (PyObject_TypeCheck(arg, &DrgnType_type)) {
err = drgn_type_sizeof(((DrgnType *)arg)->type, &size);
} else if (PyObject_TypeCheck(arg, &DrgnObject_type)) {
@ -82,7 +81,7 @@ static PyObject *sizeof_(PyObject *self, PyObject *arg)
}
if (err)
return set_drgn_error(err);
return PyLong_FromUnsignedLongLong(size);
return PyLong_FromUint64(size);
}
static PyObject *offsetof_(PyObject *self, PyObject *args, PyObject *kwds)
@ -99,7 +98,7 @@ static PyObject *offsetof_(PyObject *self, PyObject *args, PyObject *kwds)
err = drgn_type_offsetof(type->type, member, &offset);
if (err)
return set_drgn_error(err);
return PyLong_FromUnsignedLongLong(offset);
return PyLong_FromUint64(offset);
}
static PyMethodDef drgn_methods[] = {

View File

@ -18,19 +18,16 @@ static int DrgnObject_literal(struct drgn_object *res, PyObject *literal)
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;
bool is_negative = Py_SIZE(literal) < 0;
if (is_negative) {
literal = PyNumber_Negative(literal);
if (!literal)
return -1;
}
uvalue = PyLong_AsUnsignedLongLong(literal);
uint64_t uvalue = PyLong_AsUint64(literal);
if (is_negative)
Py_DECREF(literal);
if (uvalue == (unsigned long long)-1 && PyErr_Occurred())
if (uvalue == (uint64_t)-1 && PyErr_Occurred())
return -1;
err = drgn_object_integer_literal(res, uvalue);
if (!err && is_negative)
@ -214,9 +211,9 @@ static int serialize_py_object(struct drgn_program *prog, char *buf,
int64_t svalue;
uint64_t uvalue;
} tmp;
tmp.uvalue = PyLong_AsUnsignedLongLongMask(long_obj);
tmp.uvalue = PyLong_AsUint64Mask(long_obj);
Py_DECREF(long_obj);
if (tmp.uvalue == (unsigned long long)-1 && PyErr_Occurred())
if (tmp.uvalue == (uint64_t)-1 && PyErr_Occurred())
return -1;
if (type->encoding == DRGN_OBJECT_ENCODING_SIGNED) {
tmp.svalue = truncate_signed(tmp.svalue,
@ -438,10 +435,9 @@ static DrgnObject *DrgnObject_new(PyTypeObject *subtype, PyObject *args,
long_obj = PyNumber_Long(value_obj);
if (!long_obj)
goto err;
tmp.uvalue = PyLong_AsUnsignedLongLongMask(long_obj);
tmp.uvalue = PyLong_AsUint64Mask(long_obj);
Py_DECREF(long_obj);
if (tmp.uvalue == (unsigned long long)-1 &&
PyErr_Occurred())
if (tmp.uvalue == (uint64_t)-1 && PyErr_Occurred())
goto err;
if (encoding == DRGN_OBJECT_ENCODING_SIGNED) {
err = drgn_object_set_signed(&obj->obj,
@ -641,22 +637,20 @@ static PyObject *DrgnObject_value_impl(struct drgn_object *obj)
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);
return PyLong_FromInt64(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);
return PyLong_FromUint64(uvalue);
}
case DRGN_OBJECT_ENCODING_FLOAT: {
double fvalue;
@ -1017,7 +1011,7 @@ static PyObject *DrgnObject_get_absent(DrgnObject *self, void *arg)
static PyObject *DrgnObject_get_address(DrgnObject *self, void *arg)
{
if (self->obj.kind == DRGN_OBJECT_REFERENCE)
return PyLong_FromUnsignedLongLong(self->obj.address);
return PyLong_FromUint64(self->obj.address);
else
Py_RETURN_NONE;
}
@ -1026,7 +1020,7 @@ 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);
return PyLong_FromUint8(self->obj.bit_offset);
case DRGN_OBJECT_VALUE:
case DRGN_OBJECT_ABSENT:
Py_RETURN_NONE;
@ -1036,7 +1030,7 @@ static PyObject *DrgnObject_get_bit_offset(DrgnObject *self, void *arg)
static PyObject *DrgnObject_get_bit_field_size(DrgnObject *self, void *arg)
{
if (self->obj.is_bit_field)
return PyLong_FromUnsignedLongLong(self->obj.bit_size);
return PyLong_FromUint64(self->obj.bit_size);
else
Py_RETURN_NONE;
}
@ -1166,10 +1160,10 @@ static PyObject *DrgnObject_int(DrgnObject *self)
switch (self->obj.encoding) {
case DRGN_OBJECT_ENCODING_SIGNED:
ret = PyLong_FromLongLong(value->svalue);
ret = PyLong_FromInt64(value->svalue);
break;
case DRGN_OBJECT_ENCODING_UNSIGNED:
ret = PyLong_FromUnsignedLongLong(value->uvalue);
ret = PyLong_FromUint64(value->uvalue);
break;
case DRGN_OBJECT_ENCODING_FLOAT:
ret = PyLong_FromDouble(value->fvalue);
@ -1235,10 +1229,10 @@ static PyObject *DrgnObject_index(DrgnObject *self)
switch (self->obj.encoding) {
case DRGN_OBJECT_ENCODING_SIGNED:
ret = PyLong_FromLongLong(value->svalue);
ret = PyLong_FromInt64(value->svalue);
break;
case DRGN_OBJECT_ENCODING_UNSIGNED:
ret = PyLong_FromUnsignedLongLong(value->uvalue);
ret = PyLong_FromUint64(value->uvalue);
break;
default:
UNREACHABLE();
@ -1328,10 +1322,10 @@ static PyObject *DrgnObject_##func(DrgnObject *self) \
\
switch (self->obj.encoding) { \
case DRGN_OBJECT_ENCODING_SIGNED: \
ret = PyLong_FromLongLong(value->svalue); \
ret = PyLong_FromInt64(value->svalue); \
break; \
case DRGN_OBJECT_ENCODING_UNSIGNED: \
ret = PyLong_FromUnsignedLongLong(value->uvalue); \
ret = PyLong_FromUint64(value->uvalue); \
break; \
case DRGN_OBJECT_ENCODING_FLOAT: \
ret = PyLong_FromDouble(func(value->fvalue)); \
@ -1834,7 +1828,7 @@ static DrgnObject *ObjectIterator_next(ObjectIterator *self)
static PyObject *ObjectIterator_length_hint(ObjectIterator *self)
{
return PyLong_FromUnsignedLongLong(self->length);
return PyLong_FromUint64(self->length);
}
static PyMethodDef ObjectIterator_methods[] = {

View File

@ -248,7 +248,7 @@ static PyObject *StackFrame_register(StackFrame *self, PyObject *arg)
"register value is not known");
return NULL;
}
return PyLong_FromUnsignedLongLong(value);
return PyLong_FromUint64(value);
}
static PyObject *StackFrame_registers(StackFrame *self)
@ -266,7 +266,7 @@ static PyObject *StackFrame_registers(StackFrame *self)
if (!drgn_stack_frame_register(self->trace->trace, self->i, reg,
&value))
continue;
PyObject *value_obj = PyLong_FromUnsignedLongLong(value);
PyObject *value_obj = PyLong_FromUint64(value);
if (!value_obj) {
Py_DECREF(dict);
return NULL;
@ -312,7 +312,7 @@ static PyObject *StackFrame_get_pc(StackFrame *self, void *arg)
{
uint64_t pc;
if (drgn_stack_frame_pc(self->trace->trace, self->i, &pc)) {
return PyLong_FromUnsignedLongLong(pc);
return PyLong_FromUint64(pc);
} else {
PyErr_SetString(PyExc_LookupError,
"program counter is not known");
@ -324,7 +324,7 @@ static PyObject *StackFrame_get_sp(StackFrame *self, void *arg)
{
uint64_t sp;
if (drgn_stack_frame_sp(self->trace->trace, self->i, &sp)) {
return PyLong_FromUnsignedLongLong(sp);
return PyLong_FromUint64(sp);
} else {
PyErr_SetString(PyExc_LookupError,
"stack pointer is not known");

View File

@ -41,12 +41,12 @@ static PyObject *Symbol_get_name(Symbol *self, void *arg)
static PyObject *Symbol_get_address(Symbol *self, void *arg)
{
return PyLong_FromUnsignedLongLong(drgn_symbol_address(self->sym));
return PyLong_FromUint64(drgn_symbol_address(self->sym));
}
static PyObject *Symbol_get_size(Symbol *self, void *arg)
{
return PyLong_FromUnsignedLongLong(drgn_symbol_size(self->sym));
return PyLong_FromUint64(drgn_symbol_size(self->sym));
}
static PyObject *Symbol_get_binding(Symbol *self, void *arg)

View File

@ -38,7 +38,7 @@ static void Thread_dealloc(Thread *self)
static PyObject *Thread_get_tid(Thread *self)
{
return PyLong_FromUnsignedLong(self->thread.tid);
return PyLong_FromUint32(self->thread.tid);
}
static DrgnObject *Thread_get_object(Thread *self)

View File

@ -117,7 +117,7 @@ static PyObject *DrgnType_get_size(DrgnType *self)
}
if (!drgn_type_is_complete(self->type))
Py_RETURN_NONE;
return PyLong_FromUnsignedLongLong(drgn_type_size(self->type));
return PyLong_FromUint64(drgn_type_size(self->type));
}
static PyObject *DrgnType_get_length(DrgnType *self)
@ -128,7 +128,7 @@ static PyObject *DrgnType_get_length(DrgnType *self)
drgn_type_kind_str(self->type));
}
if (drgn_type_is_complete(self->type))
return PyLong_FromUnsignedLongLong(drgn_type_length(self->type));
return PyLong_FromUint64(drgn_type_length(self->type));
else
Py_RETURN_NONE;
}
@ -196,7 +196,7 @@ static TypeMember *TypeMember_wrap(PyObject *parent,
Py_INCREF(Py_None);
py_member->name = Py_None;
}
py_member->bit_offset = PyLong_FromUnsignedLongLong(bit_offset);
py_member->bit_offset = PyLong_FromUint64(bit_offset);
if (!py_member->bit_offset)
goto err;
return py_member;
@ -1081,17 +1081,15 @@ static void TypeMember_dealloc(TypeMember *self)
static PyObject *TypeMember_get_offset(TypeMember *self, void *arg)
{
unsigned long long bit_offset;
bit_offset = PyLong_AsUnsignedLongLong(self->bit_offset);
if (bit_offset == (unsigned long long)-1 && PyErr_Occurred())
uint64_t bit_offset = PyLong_AsUint64(self->bit_offset);
if (bit_offset == (uint64_t)-1 && PyErr_Occurred())
return NULL;
if (bit_offset % 8) {
PyErr_SetString(PyExc_ValueError,
"member is not byte-aligned");
return NULL;
}
return PyLong_FromUnsignedLongLong(bit_offset / 8);
return PyLong_FromUint64(bit_offset / 8);
}
static PyObject *TypeMember_get_bit_field_size(TypeMember *self, void *arg)
@ -1100,7 +1098,7 @@ static PyObject *TypeMember_get_bit_field_size(TypeMember *self, void *arg)
if (!object)
return NULL;
if (object->obj.is_bit_field)
return PyLong_FromUnsignedLongLong(object->obj.bit_size);
return PyLong_FromUint64(object->obj.bit_size);
else
Py_RETURN_NONE;
}
@ -1633,9 +1631,8 @@ static int unpack_member(struct drgn_compound_type_builder *builder,
return -1;
}
unsigned long long bit_offset =
PyLong_AsUnsignedLongLong(member->bit_offset);
if (bit_offset == (unsigned long long)-1 && PyErr_Occurred())
uint64_t bit_offset = PyLong_AsUint64(member->bit_offset);
if (bit_offset == (uint64_t)-1 && PyErr_Occurred())
return -1;
union drgn_lazy_object object;
@ -1878,14 +1875,13 @@ static int unpack_enumerator(struct drgn_enum_type_builder *builder,
struct drgn_error *err;
if (is_signed) {
long long svalue = PyLong_AsLongLong(enumerator->value);
int64_t svalue = PyLong_AsInt64(enumerator->value);
if (svalue == -1 && PyErr_Occurred())
return -1;
err = drgn_enum_type_builder_add_signed(builder, name, svalue);
} else {
unsigned long long uvalue =
PyLong_AsUnsignedLongLong(enumerator->value);
if (uvalue == (unsigned long long)-1 && PyErr_Occurred())
uint64_t uvalue = PyLong_AsUint64(enumerator->value);
if (uvalue == (uint64_t)-1 && PyErr_Occurred())
return -1;
err = drgn_enum_type_builder_add_unsigned(builder, name,
uvalue);