Пример #1
0
 def test_hlist_for_each_entry(self):
     self.assertEqual(
         list(
             hlist_for_each_entry("struct drgn_test_hlist_entry",
                                  self.empty, "node")),
         [],
     )
     self.assertEqual(
         list(
             hlist_for_each_entry("struct drgn_test_hlist_entry", self.full,
                                  "node")),
         [self.entry(i) for i in range(self.num_entries)],
     )
Пример #2
0
def find_user(prog: Program, uid: Union[Object, IntegerLike]) -> Object:
    """
    Return the user structure with the given UID.

    :param uid: ``kuid_t`` object or integer.
    :return: ``struct user_state *``
    """
    try:
        uidhashentry = prog.cache["uidhashentry"]
    except KeyError:
        uidhash_table = prog["uidhash_table"]
        uidhash_sz = len(uidhash_table)
        uidhash_bits = uidhash_sz.bit_length() - 1
        uidhash_mask = uidhash_sz - 1

        def uidhashentry(uid: int) -> Object:
            hash = ((uid >> uidhash_bits) + uid) & uidhash_mask
            return uidhash_table + hash

        prog.cache["uidhashentry"] = uidhashentry

    uid = _kuid_val(uid)
    for user in hlist_for_each_entry("struct user_struct", uidhashentry(uid),
                                     "uidhash_node"):
        if user.uid.val == uid:
            return user
    return NULL(prog, "struct user_struct *")
Пример #3
0
def for_each_pid(prog_or_ns):
    """
    .. c:function:: for_each_pid(struct pid_namespace *ns)

    Iterate over all of the PIDs in the given namespace. If given a
    :class:`Program` instead, the initial PID namespace is used.

    :return: Iterator of ``struct pid *`` objects.
    """
    if isinstance(prog_or_ns, Program):
        prog = prog_or_ns
        ns = prog_or_ns['init_pid_ns'].address_of_()
    else:
        prog = prog_or_ns.prog_
        ns = prog_or_ns
    if hasattr(ns, 'idr'):
        for nr, entry in idr_for_each(ns.idr):
            yield cast('struct pid *', entry)
    else:
        pid_hash = prog['pid_hash']
        for i in range(1 << prog['pidhash_shift'].value_()):
            for upid in hlist_for_each_entry('struct upid',
                                             pid_hash[i].address_of_(),
                                             'pid_chain'):
                if upid.ns == ns:
                    yield container_of(upid, 'struct pid',
                                       f'numbers[{int(ns.level)}]')
Пример #4
0
 def _call(self, objs: Iterable[drgn.Object]) -> Iterable[drgn.Object]:
     sname = get_valid_struct_name(self, self.args.struct_name)
     for obj in objs:
         try:
             yield from hlist_for_each_entry(sname, obj, self.args.member)
         except LookupError as err:
             raise sdb.CommandError(self.name, str(err))
Пример #5
0
def for_each_pid(prog_or_ns: Union[Program, Object]) -> Iterator[Object]:
    """
    Iterate over all PIDs in a namespace.

    :param prog_or_ns: ``struct pid_namespace *`` to iterate over, or
        :class:`Program` to iterate over initial PID namespace.
    :return: Iterator of ``struct pid *`` objects.
    """
    if isinstance(prog_or_ns, Program):
        prog = prog_or_ns
        ns = prog_or_ns["init_pid_ns"].address_of_()
    else:
        prog = prog_or_ns.prog_
        ns = prog_or_ns
    if hasattr(ns, "idr"):
        for nr, entry in idr_for_each(ns.idr):
            yield cast("struct pid *", entry)
    else:
        pid_hash = prog["pid_hash"]
        for i in range(1 << prog["pidhash_shift"].value_()):
            for upid in hlist_for_each_entry("struct upid",
                                             pid_hash[i].address_of_(),
                                             "pid_chain"):
                if upid.ns == ns:
                    yield container_of(upid, "struct pid",
                                       f"numbers[{int(ns.level)}]")
Пример #6
0
def find_user(prog, uid):
    """
    .. c:function:: struct user_struct *find_user(kuid_t uid)

    Return the user structure with the given UID, which may be a ``kuid_t`` or
    an integer.
    """
    try:
        uidhashentry = prog.cache["uidhashentry"]
    except KeyError:
        uidhash_table = prog["uidhash_table"]
        uidhash_sz = len(uidhash_table)
        uidhash_bits = uidhash_sz.bit_length() - 1
        uidhash_mask = uidhash_sz - 1

        def uidhashentry(uid):
            hash = ((uid >> uidhash_bits) + uid) & uidhash_mask
            return uidhash_table + hash

        prog.cache["uidhashentry"] = uidhashentry

    uid = _kuid_val(uid)
    for user in hlist_for_each_entry(
        "struct user_struct", uidhashentry(uid), "uidhash_node"
    ):
        if user.uid.val == uid:
            return user
    return NULL(prog, "struct user_struct *")
Пример #7
0
def find_pid(prog_or_ns, nr):
    """
    .. c:function:: struct pid *find_pid(struct pid_namespace *ns, int nr)

    Return the ``struct pid *`` for the given PID number in the given
    namespace. If given a :class:`Program` instead, the initial PID namespace
    is used.
    """
    if isinstance(prog_or_ns, Program):
        prog = prog_or_ns
        ns = prog_or_ns['init_pid_ns'].address_of_()
    else:
        prog = prog_or_ns.prog_
        ns = prog_or_ns
    if hasattr(ns, 'idr'):
        return cast('struct pid *', idr_find(ns.idr, nr))
    else:
        # We could implement pid_hashfn() and only search that bucket, but it's
        # different for 32-bit and 64-bit systems, and it has changed at least
        # once, in v4.7. Searching the whole hash table is slower but
        # foolproof.
        pid_hash = prog['pid_hash']
        for i in range(1 << prog['pidhash_shift'].value_()):
            for upid in hlist_for_each_entry('struct upid',
                                             pid_hash[i].address_of_(),
                                             'pid_chain'):
                if upid.nr == nr and upid.ns == ns:
                    return container_of(upid, 'struct pid',
                                        f'numbers[{ns.level.value_()}]')
        return NULL(prog, 'struct pid *')
Пример #8
0
Файл: fs.py Проект: osandov/drgn
def inode_paths(inode: Object) -> Iterator[bytes]:
    """
    Return an iterator over all of the paths of an inode from the root of its
    filesystem.

    :param inode: ``struct inode *``
    """
    return (dentry_path(dentry) for dentry in hlist_for_each_entry(
        "struct dentry", inode.i_dentry.address_of_(), "d_u.d_alias"))
Пример #9
0
def for_each_user(prog: Program) -> Iterator[Object]:
    """
    Iterate over all users in the system.

    :return: Iterator of ``struct user_struct *`` objects.
    """
    for hash_entry in prog["uidhash_table"]:
        for user in hlist_for_each_entry("struct user_struct", hash_entry,
                                         "uidhash_node"):
            yield user
Пример #10
0
def inode_paths(inode):
    """
    .. c:function:: inode_paths(struct inode *inode)

    Return an iterator over all of the paths of an inode from the root of its
    filesystem.

    :rtype: Iterator[bytes]
    """
    return (dentry_path(dentry) for dentry in hlist_for_each_entry(
        'struct dentry', inode.i_dentry.address_of_(), 'd_u.d_alias'))
Пример #11
0
def qdisc_lookup(dev: Object, major: IntegerLike) -> Object:
    """
    Get a Qdisc from a device and a major handle number.  It is worth noting
    that conventionally handles are hexadecimal, e.g. ``10:`` in a ``tc``
    command means major handle 0x10.

    :param dev: ``struct net_device *``
    :param major: Qdisc major handle number.
    :return: ``struct Qdisc *`` (``NULL`` if not found)
    """
    major = operator.index(major) << 16

    roots = [dev.qdisc]
    if dev.ingress_queue:
        roots.append(dev.ingress_queue.qdisc_sleeping)

    # Since Linux kernel commit 59cc1f61f09c ("net: sched: convert qdisc linked
    # list to hashtable") (in v4.7), a device's child Qdiscs are maintained in
    # a hashtable in its struct net_device. Before that, they are maintained in
    # a linked list in their root Qdisc.
    use_hashtable = dev.prog_.type("struct net_device").has_member(
        "qdisc_hash")

    for root in roots:
        if root.handle == major:
            return root

        if use_hashtable:
            for head in root.dev_queue.dev.qdisc_hash:
                for qdisc in hlist_for_each_entry("struct Qdisc",
                                                  head.address_of_(), "hash"):
                    if qdisc.handle == major:
                        return qdisc
        else:
            for qdisc in list_for_each_entry("struct Qdisc",
                                             root.list.address_of_(), "list"):
                if qdisc.handle == major:
                    return qdisc

    return NULL(dev.prog_, "struct Qdisc *")
Пример #12
0
def netdev_get_by_name(prog_or_net: Union[Program, Object],
                       name: Union[str, bytes]) -> Object:
    """
    Get the network device with the given interface name.

    :param prog_or_net: ``struct net *`` containing the device, or
        :class:`Program` to use the initial network namespace.
    :param name: Network interface name.
    :return: ``struct net_device *`` (``NULL`` if not found)
    """
    if isinstance(prog_or_net, Program):
        prog_or_net = prog_or_net["init_net"]
    if isinstance(name, str):
        name = name.encode()

    # Since Linux kernel commit ff92741270bf ("net: introduce name_node struct
    # to be used in hashlist") (in v5.5), the device name hash table contains
    # struct netdev_name_node entries. Before that, it contained the struct
    # net_device directly.
    try:
        entry_type = prog_or_net.prog_.type("struct netdev_name_node")
        member = "hlist"
        entry_is_name_node = True
    except LookupError:
        entry_type = prog_or_net.prog_.type("struct net_device")
        member = "name_hlist"
        entry_is_name_node = False

    for i in range(_NETDEV_HASHENTRIES):
        head = prog_or_net.dev_name_head[i]
        for entry in hlist_for_each_entry(entry_type, head, member):
            if entry.name.string_() == name:
                if entry_is_name_node:
                    return entry.dev
                else:
                    return entry

    return NULL(prog_or_net.prog_, "struct net_device *")
Пример #13
0
def netdev_get_by_index(prog_or_net: Union[Program, Object],
                        ifindex: IntegerLike) -> Object:
    """
    Get the network device with the given interface index number.

    :param prog_or_net: ``struct net *`` containing the device, or
        :class:`Program` to use the initial network namespace.
    :param ifindex: Network interface index number.
    :return: ``struct net_device *`` (``NULL`` if not found)
    """
    if isinstance(prog_or_net, Program):
        prog_or_net = prog_or_net["init_net"]
    if isinstance(ifindex, Object):
        ifindex = ifindex.read_()

    head = prog_or_net.dev_index_head[operator.index(ifindex)
                                      & (_NETDEV_HASHENTRIES - 1)]
    for netdev in hlist_for_each_entry("struct net_device", head,
                                       "index_hlist"):
        if netdev.ifindex == ifindex:
            return netdev

    return NULL(prog_or_net.prog_, "struct net_device *")
Пример #14
0
 def walk(self, obj: drgn.Object) -> Iterable[drgn.Object]:
     yield from hlist_for_each_entry(" ".join(self.args.type), obj,
                                     self.args.member)