def test_multiple_inputs(): line = 'count' objs = [ drgn.Object(MOCK_PROGRAM, 'void *', value=0), drgn.Object(MOCK_PROGRAM, 'int', value=0xfffff), drgn.Object(MOCK_PROGRAM, 'unsigned long *', value=0xdeadbeef), ] ret = invoke(MOCK_PROGRAM, objs, line) assert len(ret) == 1 assert ret[0].value_() == 3
def test_multi_void_ptr_input_value_match_lt(): line = 'filter obj < 1' objs = [ drgn.Object(MOCK_PROGRAM, 'void *', value=0), drgn.Object(MOCK_PROGRAM, 'void *', value=1), drgn.Object(MOCK_PROGRAM, 'void *', value=2), ] ret = invoke(MOCK_PROGRAM, objs, line) assert len(ret) == 1 assert ret[0].value_() == 0 assert ret[0].type_ == MOCK_PROGRAM.type('void *')
def test_multiple_piped(): line = 'echo' objs = [ drgn.Object(MOCK_PROGRAM, 'void *', value=0), drgn.Object(MOCK_PROGRAM, 'int', value=1), ] ret = invoke(MOCK_PROGRAM, objs, line) assert len(ret) == 2 assert ret[0].value_() == 0 assert ret[0].type_ == MOCK_PROGRAM.type('void *') assert ret[1].value_() == 1 assert ret[1].type_ == MOCK_PROGRAM.type('int')
def test_multi_void_ptr_input_value_match_ne() -> None: line = 'filter "obj != 1"' objs = [ drgn.Object(MOCK_PROGRAM, 'void *', value=0), drgn.Object(MOCK_PROGRAM, 'void *', value=1), drgn.Object(MOCK_PROGRAM, 'void *', value=2), ] ret = invoke(MOCK_PROGRAM, objs, line) assert len(ret) == 2 assert ret[0].value_() == 0 assert sdb.type_equals(ret[0].type_, MOCK_PROGRAM.type('void *')) assert ret[1].value_() == 2 assert sdb.type_equals(ret[1].type_, MOCK_PROGRAM.type('void *'))
def _call_one(self, obj: drgn.Object) -> Iterable[drgn.Object]: try: sum_ = drgn_percpu.percpu_counter_sum(obj) except AttributeError as err: raise sdb.CommandError(self.name, "input is not a percpu_counter") from err yield drgn.Object(sdb.get_prog(), type="s64", value=sum_)
def test_single_void_ptr_input_value_no_match(): line = 'filter obj == 1' objs = [drgn.Object(MOCK_PROGRAM, 'void *', value=0)] ret = invoke(MOCK_PROGRAM, objs, line) assert not ret
def call(self, objs: Iterable[drgn.Object]) -> Iterable[drgn.Object]: try: for obj in objs: lhs = eval(self.lhs_code, {'__builtins__': None}, {'obj': obj}) rhs = eval(self.rhs_code, {'__builtins__': None}, {'obj': obj}) if not isinstance(lhs, drgn.Object): raise sdb.CommandInvalidInputError( self.name, "left hand side has unsupported type ({})".format( type(lhs).__name__)) if isinstance(rhs, str): lhs = lhs.string_().decode("utf-8") elif isinstance(rhs, int): rhs = drgn.Object(self.prog, type=lhs.type_, value=rhs) elif isinstance(rhs, bool): pass elif isinstance(rhs, drgn.Object): pass else: raise sdb.CommandInvalidInputError( self.name, "right hand side has unsupported type ({})".format( type(rhs).__name__)) if eval("lhs {} rhs".format(self.compare), {'__builtins__': None}, { 'lhs': lhs, 'rhs': rhs }): yield obj except (AttributeError, TypeError, ValueError) as err: raise sdb.CommandError(self.name, str(err))
def test_single_input(): line = 'count' objs = [drgn.Object(MOCK_PROGRAM, 'void *', value=0)] ret = invoke(MOCK_PROGRAM, objs, line) assert len(ret) == 1 assert ret[0].value_() == 1
def walk(self, obj: drgn.Object) -> Iterable[drgn.Object]: offset = int(obj.list_offset) first_node = obj.list_head.address_of_() node = first_node.next while node != first_node: yield drgn.Object(self.prog, type="void *", value=int(node) - offset) node = node.next
def test_single_void_ptr_input_value_match(): line = 'filter obj == 0' objs = [drgn.Object(MOCK_PROGRAM, 'void *', value=0)] ret = invoke(MOCK_PROGRAM, objs, line) assert len(ret) == 1 assert ret[0].value_() == 0 assert ret[0].type_ == MOCK_PROGRAM.type('void *')
def test_test_piped_int(): line = 'echo' objs = [drgn.Object(MOCK_PROGRAM, 'int', value=1)] ret = invoke(MOCK_PROGRAM, objs, line) assert len(ret) == 1 assert ret[0].value_() == 1 assert ret[0].type_ == MOCK_PROGRAM.type('int')
def test_piped_input(): line = 'echo' objs = [drgn.Object(MOCK_PROGRAM, 'void *', value=0)] ret = invoke(MOCK_PROGRAM, objs, line) assert len(ret) == 1 assert ret[0].value_() == 0 assert ret[0].type_ == MOCK_PROGRAM.type('void *')
def test_piped_and_args_combo(): line = 'echo 0 1' objs = [ drgn.Object(MOCK_PROGRAM, 'void *', value=0), drgn.Object(MOCK_PROGRAM, 'int', value=1), ] ret = invoke(MOCK_PROGRAM, objs, line) assert len(ret) == 4 assert ret[0].value_() == 0 assert ret[0].type_ == MOCK_PROGRAM.type('void *') assert ret[1].value_() == 1 assert ret[1].type_ == MOCK_PROGRAM.type('int') assert ret[2].value_() == 0 assert ret[2].type_ == MOCK_PROGRAM.type('void *') assert ret[3].value_() == 1 assert ret[3].type_ == MOCK_PROGRAM.type('void *')
def test_array_member_index(): line = 'addr global_struct | member ts_array[0]' objs = [] ret = invoke(MOCK_PROGRAM, objs, line) assert len(ret) == 1 assert ret[0] == drgn.Object(MOCK_PROGRAM, MOCK_PROGRAM.type('int'), value=0x0f0f0f0f)
def test_char_array_input_string_match(): line = 'filter obj == "foo"' objs = [drgn.Object(MOCK_PROGRAM, 'char [4]', value=b"foo")] ret = invoke(MOCK_PROGRAM, objs, line) assert len(ret) == 1 assert ret[0].value_() == [102, 111, 111, 0] assert ret[0].string_() == b'foo' assert ret[0].type_ == MOCK_PROGRAM.type('char [4]')
def call(self, objs: Iterable[drgn.Object]) -> Iterable[drgn.Object]: for obj in objs: yield obj for addr in self.args.addrs: try: value_ = int(addr, 0) except ValueError: raise sdb.CommandInvalidInputError(self.name, addr) yield drgn.Object(self.prog, "void *", value=value_)
def test_one_member(): line = 'addr global_struct | member ts_int' objs = [] ret = invoke(MOCK_PROGRAM, objs, line) assert len(ret) == 1 assert ret[0] == drgn.Object(MOCK_PROGRAM, MOCK_PROGRAM.type('int'), value=1)
def test_multiple_members(): line = 'addr global_struct | member ts_int ts_voidp' objs = [] ret = invoke(MOCK_PROGRAM, objs, line) assert len(ret) == 2 assert ret[0] == drgn.Object(MOCK_PROGRAM, MOCK_PROGRAM.type('int'), value=1) assert ret[1] == MOCK_PROGRAM['global_int'].address_of_()
def test_multi_echo_combo(): line = 'echo 2 3 | echo 4' objs = [ drgn.Object(MOCK_PROGRAM, 'void *', value=0), drgn.Object(MOCK_PROGRAM, 'int', value=1), ] ret = invoke(MOCK_PROGRAM, objs, line) assert len(ret) == 5 assert ret[0].value_() == 0 assert ret[0].type_ == MOCK_PROGRAM.type('void *') assert ret[1].value_() == 1 assert ret[1].type_ == MOCK_PROGRAM.type('int') assert ret[2].value_() == 2 assert ret[2].type_ == MOCK_PROGRAM.type('void *') assert ret[3].value_() == 3 assert ret[3].type_ == MOCK_PROGRAM.type('void *') assert ret[4].value_() == 4 assert ret[4].type_ == MOCK_PROGRAM.type('void *')
def _helper(self, node: drgn.Object, offset: int) -> Iterable[drgn.Object]: if node == drgn.NULL(sdb.prog, node.type_): return lchild = node.avl_child[0] yield from self._helper(lchild, offset) obj = drgn.Object(sdb.prog, type="void *", value=int(node) - offset) yield obj rchild = node.avl_child[1] yield from self._helper(rchild, offset)
def cache_get_free_pointer(cache: drgn.Object, p: drgn.Object) -> drgn.Object: """ Get the next pointer in the freelist. Note, that this function assumes that CONFIG_SLAB_FREELIST_HARDENED is set in the target """ assert sdb.type_canonical_name(cache.type_) == 'struct kmem_cache *' assert sdb.type_canonical_name(p.type_) == 'void *' hardened_ptr = p + cache.offset.value_() # # We basically do what `freelist_dereference()` and # `freelist_ptr()` do in the kernel source: # # ptr <- (void *)*(unsigned long *)(hardened_ptr) # intermediate_ulong = drgn.Object(sdb.get_prog(), type='unsigned long', address=hardened_ptr.value_()) ptr = drgn.Object(sdb.get_prog(), type='void *', value=intermediate_ulong.value_()) # # ptr_addr <- (unsigned long)hardened_ptr # ptr_addr = drgn.Object(sdb.get_prog(), type='unsigned long', value=hardened_ptr.value_()) # # return (void *)((unsigned long)ptr ^ cache->random ^ ptr_addr) # ptr_as_ulong = drgn.Object(sdb.get_prog(), type='unsigned long', value=ptr.value_()) clean_ptr_val = ptr_as_ulong.value_() clean_ptr_val ^= cache.random.value_() clean_ptr_val ^= ptr_addr.value_() return drgn.Object(sdb.get_prog(), type='void *', value=clean_ptr_val)
def test_multi_void_ptr_input_value_match_ne(): line = 'filter obj != 1' objs = [ drgn.Object(MOCK_PROGRAM, 'void *', value=0), drgn.Object(MOCK_PROGRAM, 'void *', value=1), drgn.Object(MOCK_PROGRAM, 'void *', value=2), ] # # This throws an error for all the wrong reasons. The operator this # test is attempting to use is "!=", and due to a bug in the lexer # used within "invoke", this operator does not reach the "filter" # command. Instead, the lexer sees the "!" character and split the # string into the following parts: # # 1. filter obj # 2. = 1 # # As a result, the "filter" command fails because it doesn't see a # comparison operator as input to it. # with pytest.raises(sdb.CommandInvalidInputError): invoke(MOCK_PROGRAM, objs, line)
def mock_object_find(prog: drgn.Program, name: str, flags: drgn.FindObjectFlags, filename: Optional[str]) -> Optional[drgn.Object]: assert filename is None assert flags == drgn.FindObjectFlags.ANY mock_objects = { 'global_int': (int_type, 0xffffffffc0a8aee0), 'global_void_ptr': (voidp_type, 0xffff88d26353c108), 'global_struct': (struct_type, global_struct_addr), } if name in mock_objects: type_, addr = mock_objects[name] return drgn.Object(prog, type=type_, address=addr) return None
def walk(self, blkcg, q_id, parent_path): if not self.include_dying and \ not (blkcg.css.flags.value_() & prog['CSS_ONLINE'].value_()): return name = BlkgIterator.blkcg_name(blkcg) path = parent_path + '/' + name if parent_path else name blkg = drgn.Object(prog, 'struct blkcg_gq', address=radix_tree_lookup(blkcg.blkg_tree, q_id)) if not blkg.address_: return self.blkgs.append((path if path else '/', blkg)) for c in list_for_each_entry('struct blkcg', blkcg.css.children.address_of_(), 'css.sibling'): self.walk(c, q_id, path)
def _call(self, objs: Iterable[drgn.Object]) -> Iterable[drgn.Object]: for obj in objs: # # We canonicalize the type just in case it is a typedef # to a pointer (e.g. typedef char* char_p). # obj_type = type_canonicalize(obj.type_) if obj_type.kind != drgn.TypeKind.POINTER: raise CommandError( self.name, f"'{obj.type_.type_name()}' is not a valid pointer type") if obj_type.type.type_name() == 'void': raise CommandError(self.name, "cannot dereference a void pointer") yield drgn.Object(get_prog(), type=obj.type_.type, address=obj.value_())
def create_object(type_: Union[str, drgn.Type], val: Any) -> drgn.Object: global prog return drgn.Object(prog, type_, value=val)
if args.cgroup: for r in args.cgroup: if re_str is None: re_str = r else: re_str += '|' + r filter_re = re.compile(re_str) if re_str else None # Locate the roots q_id = None root_iocg = None ioc = None for i, ptr in radix_tree_for_each(blkcg_root.blkg_tree.address_of_()): blkg = drgn.Object(prog, 'struct blkcg_gq', address=ptr) try: if devname == blkg.q.kobj.parent.name.string_().decode('utf-8'): q_id = blkg.q.id.value_() if blkg.pd[plid]: root_iocg = container_of(blkg.pd[plid], 'struct ioc_gq', 'pd') ioc = root_iocg.ioc break except: pass if ioc is None: err(f'Could not find ioc for {devname}') if interval == 0: sys.exit(0)
def call(self, objs: Iterable[drgn.Object]) -> Iterable[drgn.Object]: yield drgn.Object(sdb.prog, type='unsigned long long', value=sum(1 for _ in objs))
def resolve_for_address(prog: drgn.Program, arg: str) -> drgn.Object: if is_hex(arg): return drgn.Object(prog, "void *", value=int(arg, 16)) return prog[arg].address_of_()
def test_char_array_input_object_match() -> None: line = 'filter "obj == obj"' objs = [drgn.Object(MOCK_PROGRAM, 'char [4]', value=b"foo")] with pytest.raises(sdb.CommandError): invoke(MOCK_PROGRAM, objs, line)