def test_array(self): segment = bytearray() for i in range(10): segment.extend(i.to_bytes(4, "little")) self.add_memory_segment(segment, virt_addr=0xFFFF0000) obj = Object(self.prog, "int [5]", address=0xFFFF0000) self.assertEqual(obj.value_(), [0, 1, 2, 3, 4]) self.assertEqual(sizeof(obj), 20) obj = Object(self.prog, "int [2][5]", address=0xFFFF0000) self.assertEqual(obj.value_(), [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]) obj = Object(self.prog, "int [2][2][2]", address=0xFFFF0000) self.assertEqual(obj.value_(), [[[0, 1], [2, 3]], [[4, 5], [6, 7]]])
def test_float(self): obj = Object(self.prog, "double", value=3.14) self.assertIs(obj.prog_, self.prog) self.assertIdentical(obj.type_, self.prog.type("double")) self.assertFalse(obj.absent_) self.assertIsNone(obj.address_) self.assertEqual(obj.value_(), 3.14) self.assertEqual(repr(obj), "Object(prog, 'double', value=3.14)") obj = Object(self.prog, "double", value=-100.0) self.assertIdentical(Object(self.prog, "double", value=-100), obj) self.assertRaisesRegex( TypeError, "'double' value must be number", Object, self.prog, "double", value={}, ) self.assertEqual(Object(self.prog, "double", value=math.e).value_(), math.e) self.assertEqual( Object(self.prog, "float", value=math.e).value_(), struct.unpack("f", struct.pack("f", math.e))[0], )
def test_read_float(self): pi32 = struct.unpack("f", struct.pack("f", math.pi))[0] for bit_size in [32, 64]: for bit_offset in range(8): for byteorder in ["little", "big"]: if bit_size == 64: fmt = "<d" expected = math.pi else: fmt = "<f" expected = pi32 tmp = int.from_bytes(struct.pack(fmt, math.pi), "little") if byteorder == "little": tmp <<= bit_offset else: tmp <<= (8 - bit_size - bit_offset) % 8 buf = tmp.to_bytes((bit_size + bit_offset + 7) // 8, byteorder) prog = mock_program(segments=[MockMemorySegment(buf, 0)]) obj = Object( prog, prog.float_type( "double" if bit_size == 64 else "float", bit_size // 8, byteorder, ), address=0, bit_offset=bit_offset, ) self.assertEqual(obj.value_(), expected)
def is_a_nulls(pos: Object) -> bool: """ Return whether a a pointer is a nulls marker. :param pos: ``struct hlist_nulls_node *`` """ return bool(pos.value_() & 1)
def print_flow_act(acts): nlattr = acts.actions[0] nla_type = nlattr.nla_type if nla_type == prog['OVS_ACTION_ATTR_OUTPUT']: addr = nlattr.address_of_().value_() + prog.type('struct nlattr').size port = Object(prog, 'int', address=addr) print("\toutput port: %d" % port.value_())
def _slub_get_freelist(freelist: Object, freelist_set: Set[int]) -> None: # In SLUB, the freelist is a linked list with the next pointer # located at ptr + slab_cache->offset. ptr = freelist.value_() while ptr: freelist_set.add(ptr) ptr = prog.read_word(ptr + freelist_offset)
def test_unsigned(self): obj = Object(self.prog, "unsigned int", value=2 ** 32 - 1) self.assertIs(obj.prog_, self.prog) self.assertIdentical(obj.type_, self.prog.type("unsigned int")) self.assertFalse(obj.absent_) self.assertIsNone(obj.address_) self.assertIsNone(obj.bit_offset_) self.assertIsNone(obj.bit_field_size_) self.assertEqual(obj.value_(), 2 ** 32 - 1) self.assertEqual(repr(obj), "Object(prog, 'unsigned int', value=4294967295)") self.assertIdentical(Object(self.prog, "unsigned int", value=-1), obj) self.assertIdentical(Object(self.prog, "unsigned int", value=2 ** 64 - 1), obj) self.assertIdentical(Object(self.prog, "unsigned int", value=2 ** 65 - 1), obj) self.assertIdentical( Object(self.prog, "unsigned int", value=2 ** 32 - 1 + 0.9), obj ) self.assertRaisesRegex( TypeError, "'unsigned int' value must be number", Object, self.prog, "unsigned int", value="foo", ) obj = Object(self.prog, "unsigned int", value=24, 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, 'unsigned int', value=8, bit_field_size=4)" ) value = 12345678912345678989 for bit_size in range(1, 65): self.assertEqual( Object( self.prog, "unsigned long long", value=value, bit_field_size=bit_size, ).value_(), value & ((1 << bit_size) - 1), )
def RB_EMPTY_NODE(node: Object) -> bool: """ Return whether a red-black tree node is empty, i.e., not inserted in a tree. :param node: ``struct rb_node *`` """ return node.__rb_parent_color.value_() == node.value_()
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_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 print_mod_hdr_key(key): actions = key.actions num_actions = key.num_actions for j in range(num_actions): p = Object(prog, 'void *', address=actions.value_()) p = p.value_() l = socket.ntohl(p & 0xffffffff) h = socket.ntohl((p & 0xffffffff00000000) >> 32) parse_pedit(l, h) actions = actions + 8
def test_pointer_typedef(self): obj = Object( self.prog, self.prog.typedef_type("INTP", self.prog.type("int *")), value=0xFFFF0000, ) self.assertFalse(obj.absent_) self.assertIsNone(obj.address_) self.assertEqual(obj.value_(), 0xFFFF0000) self.assertEqual(repr(obj), "Object(prog, 'INTP', value=0xffff0000)")
def per_cpu_ptr(ptr: Object, cpu: IntegerLike) -> Object: """ Return the per-CPU pointer for a given CPU. :param ptr: ``type __percpu *`` :param cpu: CPU number. :return: ``type *`` """ offset = ptr.prog_["__per_cpu_offset"][cpu].value_() return Object(ptr.prog_, ptr.type_, value=ptr.value_() + offset)
def name_to_address(name): (status, output) = subprocess.getstatusoutput("grep -w " + name + " /proc/kallsyms | awk '{print $1}'") print("%d, %s" % (status, output)) if status: return 0 t = int(output, 16) p = Object(prog, 'void *', address=t) return p.value_()
def test_struct(self): self.add_memory_segment( ( (99).to_bytes(4, "little") + (-1).to_bytes(4, "little", signed=True) + (12345).to_bytes(4, "little") + (0).to_bytes(4, "little") ), virt_addr=0xFFFF0000, ) self.types.append(self.point_type) obj = Object(self.prog, "struct point", address=0xFFFF0000) self.assertEqual(obj.value_(), {"x": 99, "y": -1}) self.assertEqual(sizeof(obj), 8) type_ = self.prog.struct_type( "foo", 16, ( TypeMember(self.point_type, "point"), TypeMember( self.prog.struct_type( None, 8, ( TypeMember(self.prog.int_type("int", 4, True), "bar"), TypeMember(self.prog.int_type("int", 4, True), "baz", 32), ), ), None, 64, ), ), ) obj = Object(self.prog, type_, address=0xFFFF0000) self.assertEqual( obj.value_(), {"point": {"x": 99, "y": -1}, "bar": 12345, "baz": 0} )
def per_cpu_ptr(ptr: Object, cpu: IntegerLike) -> Object: """ Return the per-CPU pointer for a given CPU. >>> prog["init_net"].loopback_dev.pcpu_refcnt (int *)0x2c980 >>> per_cpu_ptr(prog["init_net"].loopback_dev.pcpu_refcnt, 7) *(int *)0xffff925e3ddec980 = 4 :param ptr: Per-CPU pointer, i.e., ``type __percpu *``. For global variables, it's usually easier to use :func:`per_cpu()`. :param cpu: CPU number. :return: ``type *`` object. """ offset = ptr.prog_["__per_cpu_offset"][cpu].value_() return Object(ptr.prog_, ptr.type_, value=ptr.value_() + offset)
def test_compound_offset(self): value = {"n": 23, "x": 100, "y": -5} obj = Object( self.prog, self.prog.struct_type( None, 12, ( TypeMember(self.prog.int_type("int", 4, True), "n"), TypeMember(self.point_type, None, 32), ), ), value, ) self.assertEqual(obj.value_(), value) self.assertIdentical(obj.x, Object(self.prog, "int", value=100)) self.assertIdentical(obj.y, Object(self.prog, "int", value=-5))
def print_hmap(hmap_addr, struct_name, member): objs = [] buckets = hmap_addr.buckets.value_() n = hmap_addr.n.value_() if n == 0: return objs # print("\n=== %s: buckets: %x, n: %d ===" % (struct_name, buckets, n)) i = 0 while 1: p = Object(prog, 'void *', address=buckets) if p.value_() == 0: buckets = buckets + 8 continue data = container_of(p, "struct " + struct_name, member) objs.append(data) i += 1 if i == n: return objs next = data.member_(member).next while next.value_() != 0: data = container_of(next, "struct " + struct_name, member) objs.append(data) i += 1 if i == n: return objs next = data.member_(member).next buckets = buckets + 8 return objs
def test_read_unsigned(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) prog = mock_program(segments=[MockMemorySegment(buf, 0)]) obj = Object( prog, prog.int_type("unsigned long long", 8, False, byteorder), address=0, bit_field_size=bit_size, bit_offset=bit_offset, ) self.assertEqual(obj.value_(), value & ((1 << bit_size) - 1))
def for_each_onslab_object_in_slab(slab: drgn.Object) -> Iterable[drgn.Object]: assert sdb.type_canonical_name(slab.type_) == 'struct spl_kmem_slab *' cache = slab.sks_cache sks_size = spl_aligned_slab_size(cache) spl_obj_size = spl_aligned_obj_size(cache) for i in range(slab.sks_objs.value_()): obj = sdb.create_object('void *', slab.value_() + sks_size + (i * spl_obj_size)) # # If the sko_list of the object is empty, it means that # this object is not part of the slab's internal free list # and therefore it is allocated. NOTE: sko_list in the # actual code is not a list, but a link on a list. Thus, # the check below is not checking whether the "object # list" is empty for this slab, but rather whether the # link is part of any list. # sko = sko_from_obj(cache, obj) assert sko.sko_magic.value_() == 0x20202020 # SKO_MAGIC if linked_lists.is_list_empty(sko.sko_list): yield obj
def _slub_get_freelist(freelist: Object, freelist_set: Set[int]) -> None: ptr = freelist.value_() while ptr: freelist_set.add(ptr) ptr = _freelist_dereference(ptr + freelist_offset)
release = address_to_name(hex(release)) # print("flow_block_cb release: %s" % release) cb_priv = Object(prog, 'struct mlx5e_rep_indr_block_priv', address=cb.cb_priv.value_()) # print("mlx5e_rep_indr_block_priv %lx" % cb_priv.address_of_()) # print(cb_priv) else: for cb in list_for_each_entry('struct tcf_block_cb', block.cb_list.address_of_(), 'list'): print(cb) func = cb.cb.value_() func = address_to_name(hex(func)) print("tcf_block_cb cb: %s" % func) # ofed 4.7, cb is mlx5e_rep_indr_setup_block_cb priv = cb.cb_priv priv = Object(prog, 'struct mlx5e_rep_indr_block_priv', address=priv.value_()) # print(priv) # on ofed 4.6, priv is the pointer of struct mlx5e_priv print("\n%20s ingress_sched_data %20x\n" % (name, addr)) chain_list_addr = block.chain_list.address_of_() for chain in list_for_each_entry('struct tcf_chain', chain_list_addr, 'list'): if (chain.value_() == 0): print("chain 0, continue") continue print("tcf_chain %lx" % chain.value_()) print("tcf_block %lx" % chain.block.value_()) print("chain index: %d, 0x%x" % (chain.index, chain.index)) print("chain refcnt: %d" % (chain.refcnt))
def print_chain_mapping(item): print("mapping_item %lx" % item, end='\t') print("cnt: %d" % item.cnt, end='\t') print("id (chain_mapping): %d" % item.id, end='\t') data = Object(prog, 'int *', address=item.data.address_of_()) print("data (chain): 0x%x" % data.value_())
def test_compound(self): obj = Object(self.prog, self.point_type, value={"x": 100, "y": -5}) self.assertIdentical(obj.x, Object(self.prog, "int", value=100)) self.assertIdentical(obj.y, Object(self.prog, "int", value=-5)) self.assertIdentical( Object(self.prog, self.point_type, value={}), Object(self.prog, self.point_type, value={"x": 0, "y": 0}), ) value = { "a": {"x": 1, "y": 2}, "b": {"x": 3, "y": 4}, } obj = Object(self.prog, self.line_segment_type, value=value) self.assertIdentical( obj.a, Object(self.prog, self.point_type, value={"x": 1, "y": 2}) ) self.assertIdentical( obj.b, Object(self.prog, self.point_type, value={"x": 3, "y": 4}) ) self.assertEqual(obj.value_(), value) invalid_struct = self.prog.struct_type( "foo", 4, ( TypeMember(self.prog.int_type("short", 2, True), "a"), # Straddles the end of the structure. TypeMember(self.prog.int_type("int", 4, True), "b", 16), # Beyond the end of the structure. TypeMember(self.prog.int_type("int", 4, True), "c", 32), ), ) Object(self.prog, invalid_struct, value={"a": 0}) self.assertRaisesRegex( OutOfBoundsError, "out of bounds of value", Object, self.prog, invalid_struct, value={"a": 0, "b": 4}, ) self.assertRaisesRegex( OutOfBoundsError, "out of bounds of value", Object, self.prog, invalid_struct, value={"a": 0, "c": 4}, ) self.assertRaisesRegex( TypeError, "must be dictionary or mapping", Object, self.prog, self.point_type, value=1, ) self.assertRaisesRegex( TypeError, "member key must be string", Object, self.prog, self.point_type, value={0: 0}, ) self.assertRaisesRegex( TypeError, "must be number", Object, self.prog, self.point_type, value={"x": []}, ) self.assertRaisesRegex( LookupError, "has no member 'z'", Object, self.prog, self.point_type, value={"z": 999}, )
def _entry_to_node(node: Object, internal_node: int) -> Object: return Object(node.prog_, node.type_, value=node.value_() & ~internal_node)
def _is_internal_node(node: Object, internal_node: int) -> bool: return (node.value_() & _RADIX_TREE_ENTRY_MASK) == internal_node
def test_pointer(self): obj = Object(self.prog, "int *", value=0xFFFF0000) self.assertFalse(obj.absent_) self.assertIsNone(obj.address_) self.assertEqual(obj.value_(), 0xFFFF0000) self.assertEqual(repr(obj), "Object(prog, 'int *', value=0xffff0000)")
#!/usr/local/bin/drgn -k from drgn.helpers.linux import * from drgn import Object import time import sys import os sys.path.append("..") import lib gen = prog['init_net'].gen id = prog['tcf_action_net_id'] print("tcf_action_net_id: %d" % id) ptr = gen.ptr[id] tcf_action_net = Object(prog, 'struct tcf_action_net', address=ptr.value_()) print("tcf_action_net %lx" % tcf_action_net.address_of_()) for cb in list_for_each_entry('struct tcf_action_egdev_cb', tcf_action_net.egdev_list.address_of_(), 'list'): print(cb) func = cb.cb.value_() func = lib.address_to_name(hex(func)) print(func) priv = cb.cb_priv priv = Object(prog, 'struct mlx5e_priv', address=priv.value_()) print(priv.netdev.name.string_().decode())
address=cb.cb_priv.value_()) # print("mlx5e_rep_indr_block_priv %lx" % cb_priv.address_of_()) # print(cb_priv) else: for cb in list_for_each_entry('struct tcf_block_cb', block.cb_list.address_of_(), 'list'): print(cb) func = cb.cb.value_() func = address_to_name(hex(func)) print("tcf_block_cb cb: %s" % func) # ofed 4.7, cb is mlx5e_rep_indr_setup_block_cb priv = cb.cb_priv priv = Object(prog, 'struct mlx5e_rep_indr_block_priv', address=priv.value_()) # print(priv) # on ofed 4.6, priv is the pointer of struct mlx5e_priv chain_list_addr = block.chain_list.address_of_() for chain in list_for_each_entry('struct tcf_chain', chain_list_addr, 'list'): if (chain.value_() == 0): print("chain 0, continue") continue print("tcf_chain %lx, index: %d, %x, refcnt: %d, action_refcnt: %d" % \ (chain, chain.index, chain.index, chain.refcnt, chain.action_refcnt)) tcf_proto = chain.filter_chain while True: print(" tcf_proto %lx, protocol %x, prio %x" % \
def sko_from_obj(cache: drgn.Object, obj: drgn.Object) -> drgn.Object: assert sdb.type_canonical_name(cache.type_) == 'struct spl_kmem_cache *' cache_obj_align = cache.skc_obj_align.value_() return sdb.create_object( 'spl_kmem_obj_t *', obj.value_() + p2.p2roundup(object_size(cache), cache_obj_align))