def rb_prev(node: Object) -> Object: """ Return the previous node (in sort order) before a red-black node, or ``NULL`` if the node is the first node in the tree or is empty. :param node: ``struct rb_node *`` :return: ``struct rb_node *`` """ node = node.read_() if RB_EMPTY_NODE(node): return NULL(node.prog_, node.type_) next = node.rb_left.read_() if next: node = next while True: next = node.rb_right.read_() if not next: return node node = next parent = rb_parent(node).read_() while parent and node == parent.rb_left: node = parent parent = rb_parent(node).read_() return parent
def list_empty(head: Object) -> bool: """ Return whether a list is empty. :param head: ``struct list_head *`` """ head = head.read_() return head.next == head
def list_is_singular(head: Object) -> bool: """ Return whether a list has only one element. :param head: ``struct list_head *`` """ head = head.read_() next = head.next return next != head and next == head.prev
def list_for_each_reverse(head: Object) -> Iterator[Object]: """ Iterate over all of the nodes in a list in reverse order. :param head: ``struct list_head *`` :return: Iterator of ``struct list_head *`` objects. """ head = head.read_() pos = head.prev.read_() while pos != head: yield pos pos = pos.prev.read_()
def test_cast_primitive_value(self): obj = Object(self.prog, "long", value=2 ** 32 + 1) self.assertIdentical(cast("int", obj), Object(self.prog, "int", value=1)) self.assertIdentical( cast("int", obj.read_()), Object(self.prog, "int", value=1) ) self.assertIdentical( cast("const int", Object(self.prog, "int", value=1)), Object(self.prog, "const int", value=1), ) self.assertRaisesRegex( TypeError, "cannot cast to 'struct point'", cast, self.point_type, Object(self.prog, "int", value=1), )
def test_address_of(self): obj = Object(self.prog, "int", address=0xFFFF0000) self.assertIdentical( obj.address_of_(), Object(self.prog, "int *", value=0xFFFF0000) ) obj = obj.read_() self.assertRaisesRegex( ValueError, "cannot take address of value", obj.address_of_ ) obj = Object(self.prog, "int", address=0xFFFF0000, bit_field_size=4) self.assertRaisesRegex( ValueError, "cannot take address of bit field", obj.address_of_ ) obj = Object(self.prog, "int", address=0xFFFF0000, bit_offset=4) self.assertRaisesRegex( ValueError, "cannot take address of bit field", obj.address_of_ )
def test_read_struct_bit_offset(self): value = 12345678912345678989 for bit_size in range(1, 65): for bit_offset in range(8): size = (bit_size + bit_offset + 7) // 8 size_mask = (1 << (8 * size)) - 1 for byteorder in ["little", "big"]: if byteorder == "little": tmp = value << bit_offset else: tmp = value << (8 - bit_size - bit_offset) % 8 tmp &= size_mask buf = tmp.to_bytes(size, byteorder) + b"\0" prog = mock_program(segments=[MockMemorySegment(buf, 0)]) obj = Object( prog, prog.struct_type( None, (bit_offset + bit_size + 7) // 8, ( TypeMember( Object( prog, prog.int_type( "unsigned long long", 8, False, byteorder, ), bit_field_size=bit_size, ), "x", bit_offset=bit_offset, ), ), ), address=0, ) self.assertEqual(obj.x.value_(), value & ((1 << bit_size) - 1)) self.assertEqual( obj.x.read_().value_(), value & ((1 << bit_size) - 1) ) self.assertEqual( obj.read_().x.value_(), value & ((1 << bit_size) - 1) )
def list_first_entry_or_null(head: Object, type: Union[str, Type], member: str) -> Object: """ Return the first entry in a list or ``NULL`` if the list is empty. See also :func:`list_first_entry()`. :param head: ``struct list_head *`` :param type: Entry type. :param member: Name of list node member in entry type. :return: ``type *`` """ head = head.read_() pos = head.next.read_() if pos == head: return NULL(head.prog_, head.prog_.pointer_type(head.prog_.type(type))) else: return container_of(pos, type, member)
def test_signed(self): obj = Object(self.prog, "int", value=-4) self.assertIs(obj.prog_, self.prog) self.assertIdentical(obj.type_, self.prog.type("int")) self.assertFalse(obj.absent_) self.assertIsNone(obj.address_) self.assertIsNone(obj.bit_offset_) self.assertIsNone(obj.bit_field_size_) self.assertEqual(obj.value_(), -4) self.assertEqual(repr(obj), "Object(prog, 'int', value=-4)") self.assertIdentical(obj.read_(), obj) self.assertIdentical(Object(self.prog, "int", value=2 ** 32 - 4), obj) self.assertIdentical(Object(self.prog, "int", value=2 ** 64 - 4), obj) self.assertIdentical(Object(self.prog, "int", value=2 ** 128 - 4), obj) self.assertIdentical(Object(self.prog, "int", value=-4.6), obj) self.assertRaisesRegex( TypeError, "'int' value must be number", Object, self.prog, "int", value=b"asdf", ) obj = Object(self.prog, "int", value=8, bit_field_size=4) self.assertIsNone(obj.bit_offset_) self.assertEqual(obj.bit_field_size_, 4) self.assertEqual(obj.value_(), -8) self.assertEqual(repr(obj), "Object(prog, 'int', value=-8, bit_field_size=4)") value = 12345678912345678989 for bit_size in range(1, 65): tmp = value & ((1 << bit_size) - 1) mask = 1 << (bit_size - 1) tmp = (tmp ^ mask) - mask self.assertEqual( Object( self.prog, "long", value=value, bit_field_size=bit_size ).value_(), tmp, )
def test_basic(self): self.add_memory_segment((1000).to_bytes(4, "little"), virt_addr=0xFFFF0000) obj = Object(self.prog, "int", address=0xFFFF0000) self.assertIs(obj.prog_, self.prog) self.assertIdentical(obj.type_, self.prog.type("int")) self.assertFalse(obj.absent_) self.assertEqual(obj.address_, 0xFFFF0000) self.assertEqual(obj.bit_offset_, 0) self.assertIsNone(obj.bit_field_size_) self.assertEqual(obj.value_(), 1000) self.assertEqual(repr(obj), "Object(prog, 'int', address=0xffff0000)") self.assertIdentical(obj.read_(), Object(self.prog, "int", value=1000)) obj = Object( self.prog, self.prog.int_type("sbe32", 4, True, "big"), address=0xFFFF0000 ) self.assertEqual(obj.value_(), -402456576) obj = Object(self.prog, "unsigned int", address=0xFFFF0000, bit_field_size=4) self.assertEqual(obj.bit_offset_, 0) 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( self.prog, "unsigned int", address=0xFFFF0000, bit_field_size=4, bit_offset=4, ) self.assertEqual(obj.bit_offset_, 4) self.assertEqual(obj.bit_field_size_, 4) self.assertEqual(obj.value_(), 14) self.assertEqual( repr(obj), "Object(prog, 'unsigned int', address=0xffff0000, bit_offset=4, bit_field_size=4)", )
def test_member(self): reference = Object(self.prog, self.point_type, address=0xFFFF0000) unnamed_reference = Object( self.prog, self.prog.struct_type( "point", 8, ( TypeMember( self.prog.struct_type(None, 8, self.point_type.members), None ), ), ), address=0xFFFF0000, ) ptr = Object( self.prog, self.prog.pointer_type(self.point_type), value=0xFFFF0000 ) for obj in [reference, unnamed_reference, ptr]: self.assertIdentical( obj.member_("x"), Object(self.prog, "int", address=0xFFFF0000) ) self.assertIdentical(obj.member_("x"), obj.x) self.assertIdentical( obj.member_("y"), Object(self.prog, "int", address=0xFFFF0004) ) self.assertIdentical(obj.member_("y"), obj.y) self.assertRaisesRegex( LookupError, "'struct point' has no member 'z'", obj.member_, "z" ) self.assertRaisesRegex( AttributeError, "'struct point' has no member 'z'", getattr, obj, "z" ) obj = reference.read_() self.assertIdentical(obj.x, Object(self.prog, "int", value=0)) self.assertIdentical(obj.y, Object(self.prog, "int", value=1)) obj = Object(self.prog, "int", value=1) self.assertRaisesRegex( TypeError, "'int' is not a structure, union, or class", obj.member_, "x" ) self.assertRaisesRegex(AttributeError, "no attribute", getattr, obj, "x")
def validate_list_for_each(head: Object) -> Iterator[Object]: """ Like :func:`list_for_each()`, but validates the list like :func:`validate_list()` while iterating. :param head: ``struct list_head *`` :raises ValidationError: if the list is invalid """ head = head.read_() pos = head.next.read_() while pos != head: yield pos next = pos.next.read_() next_prev = next.prev.read_() if next_prev != pos: raise ValidationError( f"{pos.format_(dereference=False, symbolize=False)}" f" next {next.format_(dereference=False, symbolize=False, type_name=False)}" f" has prev {next_prev.format_(dereference=False, symbolize=False, type_name=False)}" ) pos = next
def test_subscript(self): arr = Object(self.prog, "int [4]", address=0xFFFF0000) incomplete_arr = Object(self.prog, "int []", address=0xFFFF0000) ptr = Object(self.prog, "int *", value=0xFFFF0000) for obj in [arr, incomplete_arr, ptr]: for i in range(5): self.assertIdentical( obj[i], Object(self.prog, "int", address=0xFFFF0000 + 4 * i) ) if i < 4: self.assertIdentical( obj[i].read_(), Object(self.prog, "int", value=i) ) else: self.assertRaises(FaultError, obj[i].read_) obj = arr.read_() for i in range(4): self.assertIdentical(obj[i], Object(self.prog, "int", value=i)) self.assertRaisesRegex(OutOfBoundsError, "out of bounds", obj.__getitem__, 4) obj = Object(self.prog, "int", value=0) self.assertRaises(TypeError, obj.__getitem__, 0)