mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-23 01:33:06 +00:00
libdrgn: python: add sizeof()
It's annoying to do obj.type_.size, and that doesn't even work for every type. Add sizeof() that does the right thing whether it's given a Type or Object.
This commit is contained in:
parent
12b0214b4d
commit
b8c657d760
@ -1282,6 +1282,16 @@ can be used just like types obtained from :meth:`Program.type()`.
|
||||
Miscellaneous
|
||||
-------------
|
||||
|
||||
.. function:: sizeof(type_or_obj)
|
||||
|
||||
Get the size of a :class:`Type` or :class:`Object` in bytes.
|
||||
|
||||
:param type_or_obj: Entity to get the size of.
|
||||
:type type_or_obj: Type or Object
|
||||
:rtype: int
|
||||
:raises TypeError: if the type does not have a size (e.g., because it is
|
||||
incomplete or void)
|
||||
|
||||
.. autofunction:: execscript
|
||||
|
||||
Exceptions
|
||||
|
@ -79,6 +79,7 @@ from _drgn import (
|
||||
program_from_kernel,
|
||||
program_from_pid,
|
||||
reinterpret,
|
||||
sizeof,
|
||||
struct_type,
|
||||
typedef_type,
|
||||
union_type,
|
||||
@ -121,6 +122,7 @@ __all__ = [
|
||||
'program_from_kernel',
|
||||
'program_from_pid',
|
||||
'reinterpret',
|
||||
'sizeof',
|
||||
'struct_type',
|
||||
'typedef_type',
|
||||
'union_type',
|
||||
|
@ -104,8 +104,15 @@ def main() -> None:
|
||||
from drgn.internal.rlcompleter import Completer
|
||||
|
||||
init_globals['drgn'] = drgn
|
||||
drgn_globals = ['cast', 'container_of', 'execscript', 'NULL', 'Object',
|
||||
'reinterpret']
|
||||
drgn_globals = [
|
||||
'NULL',
|
||||
'Object',
|
||||
'cast',
|
||||
'container_of',
|
||||
'execscript',
|
||||
'reinterpret',
|
||||
'sizeof',
|
||||
]
|
||||
for attr in drgn_globals:
|
||||
init_globals[attr] = getattr(drgn, attr)
|
||||
init_globals['__name__'] = '__main__'
|
||||
|
@ -1423,7 +1423,7 @@ LIBDRGN_PUBLIC struct drgn_error *
|
||||
drgn_object_sizeof(const struct drgn_object *obj, uint64_t *ret)
|
||||
{
|
||||
if (obj->is_bit_field) {
|
||||
return drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT,
|
||||
return drgn_error_create(DRGN_ERROR_TYPE,
|
||||
"cannot get size of bit field");
|
||||
}
|
||||
return drgn_type_sizeof(obj->type, ret);
|
||||
|
@ -50,11 +50,31 @@ static PyObject *filename_matches(PyObject *self, PyObject *args,
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
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)) {
|
||||
err = drgn_object_sizeof(&((DrgnObject *)arg)->obj, &size);
|
||||
} else {
|
||||
return PyErr_Format(PyExc_TypeError,
|
||||
"expected Type or Object, not %s",
|
||||
Py_TYPE(arg)->tp_name);
|
||||
}
|
||||
if (err)
|
||||
return set_drgn_error(err);
|
||||
return PyLong_FromUnsignedLongLong(size);
|
||||
}
|
||||
|
||||
static PyMethodDef drgn_methods[] = {
|
||||
{"filename_matches", (PyCFunction)filename_matches,
|
||||
METH_VARARGS | METH_KEYWORDS, drgn_filename_matches_DOC},
|
||||
{"NULL", (PyCFunction)DrgnObject_NULL, METH_VARARGS | METH_KEYWORDS,
|
||||
drgn_NULL_DOC},
|
||||
{"sizeof", (PyCFunction)sizeof_, METH_O, drgn_sizeof_DOC},
|
||||
{"cast", (PyCFunction)cast, METH_VARARGS | METH_KEYWORDS,
|
||||
drgn_cast_DOC},
|
||||
{"reinterpret", (PyCFunction)reinterpret, METH_VARARGS | METH_KEYWORDS,
|
||||
|
@ -16,6 +16,7 @@ from drgn import (
|
||||
int_type,
|
||||
pointer_type,
|
||||
reinterpret,
|
||||
sizeof,
|
||||
struct_type,
|
||||
typedef_type,
|
||||
union_type,
|
||||
@ -116,6 +117,7 @@ class TestReference(ObjectTestCase):
|
||||
self.assertEqual(obj.byteorder_, 'big')
|
||||
self.assertEqual(obj.value_(), -402456576)
|
||||
self.assertEqual(repr(obj), "Object(prog, 'int', address=0xffff0000, byteorder='big')")
|
||||
self.assertEqual(sizeof(obj), 4)
|
||||
|
||||
obj = Object(prog, 'unsigned int', address=0xffff0000,
|
||||
bit_field_size=4)
|
||||
@ -123,6 +125,7 @@ class TestReference(ObjectTestCase):
|
||||
self.assertEqual(obj.bit_field_size_, 4)
|
||||
self.assertEqual(obj.value_(), 8)
|
||||
self.assertEqual(repr(obj), "Object(prog, 'unsigned int', address=0xffff0000, bit_field_size=4)")
|
||||
self.assertRaises(TypeError, sizeof, obj)
|
||||
|
||||
obj = Object(prog, 'unsigned int', address=0xffff0000,
|
||||
bit_field_size=4, bit_offset=4)
|
||||
@ -182,7 +185,7 @@ class TestReference(ObjectTestCase):
|
||||
byteorder=byteorder)
|
||||
self.assertEqual(obj.value_(), expected)
|
||||
|
||||
def test_read_struct(self):
|
||||
def test_struct(self):
|
||||
segment = ((99).to_bytes(4, 'little') +
|
||||
(-1).to_bytes(4, 'little', signed=True) +
|
||||
(12345).to_bytes(4, 'little') +
|
||||
@ -193,6 +196,7 @@ class TestReference(ObjectTestCase):
|
||||
|
||||
obj = Object(prog, 'struct point', address=0xffff0000)
|
||||
self.assertEqual(obj.value_(), {'x': 99, 'y': -1})
|
||||
self.assertEqual(sizeof(obj), 8)
|
||||
|
||||
type_ = struct_type('foo', 16, (
|
||||
(point_type, 'point'),
|
||||
@ -205,7 +209,7 @@ class TestReference(ObjectTestCase):
|
||||
self.assertEqual(obj.value_(),
|
||||
{'point': {'x': 99, 'y': -1}, 'bar': 12345, 'baz': 0})
|
||||
|
||||
def test_read_array(self):
|
||||
def test_array(self):
|
||||
segment = bytearray()
|
||||
for i in range(10):
|
||||
segment.extend(i.to_bytes(4, 'little'))
|
||||
@ -215,6 +219,7 @@ class TestReference(ObjectTestCase):
|
||||
|
||||
obj = Object(prog, 'int [5]', address=0xffff0000)
|
||||
self.assertEqual(obj.value_(), [0, 1, 2, 3, 4])
|
||||
self.assertEqual(sizeof(obj), 20)
|
||||
|
||||
obj = Object(prog, 'int [2][5]', address=0xffff0000)
|
||||
self.assertEqual(obj.value_(), [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]])
|
||||
@ -235,6 +240,7 @@ class TestReference(ObjectTestCase):
|
||||
obj.value_)
|
||||
self.assertRaisesRegex(TypeError, 'cannot read object with void type',
|
||||
obj.read_)
|
||||
self.assertRaises(TypeError, sizeof, obj)
|
||||
|
||||
def test_function(self):
|
||||
obj = Object(self.prog,
|
||||
@ -251,6 +257,7 @@ class TestReference(ObjectTestCase):
|
||||
self.assertRaisesRegex(TypeError,
|
||||
'cannot read object with function type',
|
||||
obj.read_)
|
||||
self.assertRaises(TypeError, sizeof, obj)
|
||||
|
||||
def test_incomplete(self):
|
||||
# It's valid to create references with incomplete type, but not to read
|
||||
@ -262,6 +269,7 @@ class TestReference(ObjectTestCase):
|
||||
self.assertRaisesRegex(TypeError,
|
||||
'cannot read object with incomplete structure type',
|
||||
obj.read_)
|
||||
self.assertRaises(TypeError, sizeof, obj)
|
||||
|
||||
obj = Object(self.prog, union_type('foo'), address=0)
|
||||
self.assertRaisesRegex(TypeError, 'cannot read object with incomplete union type',
|
||||
|
@ -12,6 +12,7 @@ from drgn import (
|
||||
function_type,
|
||||
int_type,
|
||||
pointer_type,
|
||||
sizeof,
|
||||
struct_type,
|
||||
typedef_type,
|
||||
union_type,
|
||||
@ -43,6 +44,7 @@ class TestType(unittest.TestCase):
|
||||
self.assertNotEqual(t, int_type('int', 4, False))
|
||||
|
||||
self.assertEqual(repr(t), "int_type(name='int', size=4, is_signed=True)")
|
||||
self.assertEqual(sizeof(t), 4)
|
||||
|
||||
self.assertRaises(TypeError, int_type, None, 4, True)
|
||||
|
||||
@ -62,6 +64,7 @@ class TestType(unittest.TestCase):
|
||||
self.assertNotEqual(t, bool_type('_Bool', 2))
|
||||
|
||||
self.assertEqual(repr(t), "bool_type(name='_Bool', size=1)")
|
||||
self.assertEqual(sizeof(t), 1)
|
||||
|
||||
self.assertRaises(TypeError, bool_type, None, 1)
|
||||
|
||||
@ -78,6 +81,7 @@ class TestType(unittest.TestCase):
|
||||
self.assertNotEqual(t, float_type('float', 8))
|
||||
|
||||
self.assertEqual(repr(t), "float_type(name='float', size=4)")
|
||||
self.assertEqual(sizeof(t), 4)
|
||||
|
||||
self.assertRaises(TypeError, float_type, None, 4)
|
||||
|
||||
@ -96,6 +100,7 @@ class TestType(unittest.TestCase):
|
||||
self.assertNotEqual(t, complex_type('double _Complex', 16, float_type('float', 4)))
|
||||
|
||||
self.assertEqual(repr(t), "complex_type(name='double _Complex', size=16, type=float_type(name='double', size=8))")
|
||||
self.assertEqual(sizeof(t), 16)
|
||||
|
||||
self.assertRaises(TypeError, complex_type, None, 16, float_type('double', 8))
|
||||
self.assertRaises(TypeError, complex_type, 'double _Complex', 16, None)
|
||||
@ -161,6 +166,7 @@ class TestType(unittest.TestCase):
|
||||
self.assertNotEqual(t, struct_type('point'))
|
||||
|
||||
self.assertEqual(repr(t), "struct_type(tag='point', size=8, members=((int_type(name='int', size=4, is_signed=True), 'x', 0, 0), (int_type(name='int', size=4, is_signed=True), 'y', 32, 0)))")
|
||||
self.assertEqual(sizeof(t), 8)
|
||||
|
||||
t = struct_type(None, 8, (
|
||||
(int_type('int', 4, True), 'x', 0),
|
||||
@ -287,6 +293,7 @@ class TestType(unittest.TestCase):
|
||||
self.assertNotEqual(t, union_type('option'))
|
||||
|
||||
self.assertEqual(repr(t), "union_type(tag='option', size=4, members=((int_type(name='int', size=4, is_signed=True), 'x', 0, 0), (int_type(name='unsigned int', size=4, is_signed=False), 'y', 0, 0)))")
|
||||
self.assertEqual(sizeof(t), 4)
|
||||
|
||||
t = union_type(None, 4, (
|
||||
(int_type('int', 4, True), 'x'),
|
||||
@ -399,6 +406,7 @@ class TestType(unittest.TestCase):
|
||||
|
||||
self.assertEqual(repr(t),
|
||||
"enum_type(tag='color', type=int_type(name='unsigned int', size=4, is_signed=False), enumerators=(('RED', 0), ('GREEN', 1), ('BLUE', 2)))")
|
||||
self.assertEqual(sizeof(t), 4)
|
||||
|
||||
t = enum_type('color', None, None)
|
||||
self.assertEqual(t.kind, TypeKind.ENUM)
|
||||
@ -477,6 +485,7 @@ class TestType(unittest.TestCase):
|
||||
'INT', int_type('int', 4, True, Qualifiers.CONST)))
|
||||
|
||||
self.assertEqual(repr(t), "typedef_type(name='INT', type=int_type(name='int', size=4, is_signed=True))")
|
||||
self.assertEqual(sizeof(t), 4)
|
||||
|
||||
t = typedef_type('VOID', void_type())
|
||||
self.assertFalse(t.is_complete())
|
||||
@ -511,6 +520,7 @@ class TestType(unittest.TestCase):
|
||||
self.assertNotEqual(t, pointer_type(8, void_type(Qualifiers.CONST)))
|
||||
|
||||
self.assertEqual(repr(t), "pointer_type(size=8, type=int_type(name='int', size=4, is_signed=True))")
|
||||
self.assertEqual(sizeof(t), 8)
|
||||
|
||||
self.assertRaises(TypeError, pointer_type, None,
|
||||
int_type('int', 4, True))
|
||||
@ -535,6 +545,7 @@ class TestType(unittest.TestCase):
|
||||
self.assertNotEqual(t, array_type(10, void_type(Qualifiers.CONST)))
|
||||
|
||||
self.assertEqual(repr(t), "array_type(length=10, type=int_type(name='int', size=4, is_signed=True))")
|
||||
self.assertEqual(sizeof(t), 40)
|
||||
|
||||
t = array_type(0, int_type('int', 4, True))
|
||||
self.assertEqual(t.kind, TypeKind.ARRAY)
|
||||
@ -584,6 +595,7 @@ class TestType(unittest.TestCase):
|
||||
void_type(), ((int_type('int', 4, True), 'n'),), True))
|
||||
|
||||
self.assertEqual(repr(t), "function_type(type=void_type(), parameters=((int_type(name='int', size=4, is_signed=True), 'n'),), is_variadic=False)")
|
||||
self.assertRaises(TypeError, sizeof, t)
|
||||
|
||||
self.assertFalse(function_type(void_type(), (), False).is_variadic)
|
||||
self.assertTrue(function_type(void_type(), (), True).is_variadic)
|
||||
|
Loading…
Reference in New Issue
Block a user