コード例 #1
0
ファイル: cgroup.py プロジェクト: osandov/drgn
def css_next_descendant_pre(pos: Object, root: Object) -> Object:
    """
    Get the next pre-order descendant (or ``NULL`` if there is none) of the
    given css root starting from the given position (``NULL`` to initiate
    traversal).

    :param pos: ``struct cgroup_subsys_state *``
    :param root: ``struct cgroup_subsys_state *``
    :return: ``struct cgroup_subsys_state *``
    """
    # If first iteration, visit root.
    if not pos:
        return root

    # Visit the first child if exists.
    null = NULL(pos.prog_, "struct cgroup_subsys_state *")
    next_ = css_next_child(null, pos)
    if next_:
        return next_

    # No child, visit my or the closest ancestor's next sibling.
    while pos != root:
        next_ = css_next_child(pos, pos.parent)
        if next_:
            return next_
        pos = pos.parent

    return NULL(root.prog_, "struct cgroup_subsys_state *")
コード例 #2
0
ファイル: test_rbtree.py プロジェクト: osandov/drgn
 def test_rb_next(self):
     for i in range(self.num_entries - 1):
         self.assertEqual(rb_next(self.node(i)), self.node(i + 1))
     self.assertEqual(
         rb_next(self.node(self.num_entries - 1)),
         NULL(self.prog, "struct rb_node *"),
     )
コード例 #3
0
ファイル: user.py プロジェクト: sravyamks/drgn
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 *")
コード例 #4
0
ファイル: rbtree.py プロジェクト: cneira/drgn
def rb_next(node):
    """
    .. c:function:: struct rb_node *rb_next(struct rb_node *node)

    Return the next node (in sort order) after a red-black node, or a ``NULL``
    object if the node is the last node in the tree or is empty.
    """
    node = node.read_()

    if RB_EMPTY_NODE(node):
        return NULL(node.prog_, node.type_)

    next = node.rb_right.read_()
    if next:
        node = next
        while True:
            next = node.rb_left.read_()
            if not next:
                return node
            node = next

    parent = rb_parent(node).read_()
    while parent and node == parent.rb_right:
        node = parent
        parent = rb_parent(node).read_()
    return parent
コード例 #5
0
ファイル: pid.py プロジェクト: nathandialpad/drgn
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 *')
コード例 #6
0
def rb_find(
    type: Union[str, Type],
    root: Object,
    member: str,
    key: KeyType,
    cmp: Callable[[KeyType, Object], int],
) -> Object:
    """
    Find an entry in a red-black tree given a key and a comparator function.

    Note that this function does not have an analogue in the Linux kernel
    source code, as tree searches are all open-coded.

    :param type: Entry type.
    :param root: ``struct rb_root *``
    :param member: Name of ``struct rb_node`` member in entry type.
    :param key: Key to find.
    :param cmp: Callback taking key and entry that returns < 0 if the key is
        less than the entry, > 0 if the key is greater than the entry, and 0 if
        the key matches the entry.
    :return: ``type *`` found entry, or ``NULL`` if not found.
    """
    prog = root.prog_
    type = prog.type(type)
    node = root.rb_node.read_()
    while node:
        entry = container_of(node, type, member)
        ret = cmp(key, entry)
        if ret < 0:
            node = node.rb_left.read_()
        elif ret > 0:
            node = node.rb_right.read_()
        else:
            return entry
    return NULL(prog, prog.pointer_type(type))
コード例 #7
0
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
コード例 #8
0
ファイル: cgroup.py プロジェクト: osandov/drgn
def css_next_child(pos: Object, parent: Object) -> Object:
    """
    Get the next child (or ``NULL`` if there is none) of the given parent
    starting from the given position (``NULL`` to initiate traversal).

    :param pos: ``struct cgroup_subsys_state *``
    :param parent: ``struct cgroup_subsys_state *``
    :return: ``struct cgroup_subsys_state *``
    """
    if not pos:
        next_ = container_of(
            parent.children.next, "struct cgroup_subsys_state", "sibling"
        )
    elif not (pos.flags & pos.prog_["CSS_RELEASED"]):
        next_ = container_of(pos.sibling.next, "struct cgroup_subsys_state", "sibling")
    else:
        serial_nr = pos.serial_nr.value_()  # Read once and cache.
        for next_ in list_for_each_entry(
            "struct cgroup_subsys_state", parent.children.address_of_(), "sibling"
        ):
            if next_.serial_nr > serial_nr:
                break

    if next_.sibling.address_of_() != parent.children.address_of_():
        return next_
    return NULL(next_.prog_, "struct cgroup_subsys_state *")
コード例 #9
0
ファイル: user.py プロジェクト: shiloong/drgn
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 *")
コード例 #10
0
def _css_for_each_impl(next_fn, css):
    pos = NULL(css.prog_, "struct cgroup_subsys_state *")
    while True:
        pos = next_fn(pos, css)
        if not pos:
            break
        if pos.flags & pos.prog_["CSS_ONLINE"]:
            yield pos
コード例 #11
0
ファイル: pid.py プロジェクト: nathandialpad/drgn
def pid_task(pid, pid_type):
    """
    .. c:function:: struct task_struct *pid_task(struct pid *pid, enum pid_type pid_type)

    Return the ``struct task_struct *`` containing the given ``struct pid *``
    of the given type.
    """
    if not pid:
        return NULL(pid.prog_, 'struct task_struct *')
    first = pid.tasks[0].first
    if not first:
        return NULL(pid.prog_, 'struct task_struct *')
    try:
        return container_of(first, 'struct task_struct',
                            f'pid_links[{int(pid_type)}]')
    except LookupError:
        return container_of(first, 'struct task_struct',
                            f'pids[{int(pid_type)}].node')
コード例 #12
0
def _css_for_each_impl(next_fn: Callable[[Object, Object], Object],
                       css: Object) -> Iterator[Object]:
    pos = NULL(css.prog_, "struct cgroup_subsys_state *")
    while True:
        pos = next_fn(pos, css)
        if not pos:
            break
        if pos.flags & pos.prog_["CSS_ONLINE"]:
            yield pos
コード例 #13
0
def cgroup_parent(cgrp):
    """
    .. c:function:: struct cgroup *cgroup_parent(struct cgroup *cgrp)

    Return the parent cgroup of the given cgroup if it exists, ``NULL``
    otherwise.
    """
    parent_css = cgrp.self.parent
    if parent_css:
        return container_of(parent_css, "struct cgroup", "self")
    return NULL(cgrp.prog_, "struct cgroup *")
コード例 #14
0
ファイル: cgroup.py プロジェクト: osandov/drgn
def cgroup_parent(cgrp: Object) -> Object:
    """
    Return the parent cgroup of the given cgroup if it exists, ``NULL``
    otherwise.

    :param cgrp: ``struct cgroup *``
    :return: ``struct cgroup *``
    """
    parent_css = cgrp.self.parent
    if parent_css:
        return container_of(parent_css, "struct cgroup", "self")
    return NULL(cgrp.prog_, "struct cgroup *")
コード例 #15
0
ファイル: list.py プロジェクト: cneira/drgn
def list_first_entry_or_null(head, type, member):
    """
    .. c:function:: type *list_first_entry_or_null(struct list_head *head, type, member)

    Return the first entry in a list or ``NULL`` if the list is empty.

    See also :func:`list_first_entry()`.
    """
    head = head.read_()
    pos = head.next.read_()
    if pos == head:
        return NULL(head.prog_, head.prog_.pointer_type(type))
    else:
        return container_of(pos, type, member)
コード例 #16
0
ファイル: test_rbtree.py プロジェクト: osandov/drgn
    def test_rb_find(self):
        def cmp(key, obj):
            value = obj.value.value_()
            return key - value

        for i in range(self.num_entries):
            self.assertEqual(
                rb_find("struct drgn_test_rb_entry", self.root, "node", i,
                        cmp),
                self.entry(i),
            )
        self.assertEqual(
            rb_find("struct drgn_test_rb_entry", self.root, "node",
                    self.num_entries, cmp),
            NULL(self.prog, "struct drgn_test_rb_entry *"),
        )
コード例 #17
0
ファイル: test_list.py プロジェクト: osandov/drgn
 def test_list_first_entry_or_null(self):
     self.assertEqual(
         list_first_entry_or_null(self.empty, "struct drgn_test_list_entry",
                                  "node"),
         NULL(self.prog, "struct drgn_test_list_entry *"),
     )
     self.assertEqual(
         list_first_entry_or_null(self.full, "struct drgn_test_list_entry",
                                  "node"),
         self.entry(0),
     )
     self.assertEqual(
         list_first_entry_or_null(self.singular,
                                  "struct drgn_test_list_entry", "node"),
         self.singular_entry,
     )
コード例 #18
0
ファイル: list.py プロジェクト: osandov/drgn
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)
コード例 #19
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 *")
コード例 #20
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 *")
コード例 #21
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 *")
コード例 #22
0
ファイル: test_rbtree.py プロジェクト: osandov/drgn
 def test_rb_prev(self):
     for i in range(1, self.num_entries):
         self.assertEqual(rb_prev(self.node(i)), self.node(i - 1))
     self.assertEqual(rb_prev(self.node(0)),
                      NULL(self.prog, "struct rb_node *"))
コード例 #23
0
 def test_cgroup_parent(self):
     self.assertEqual(cgroup_parent(self.child_cgroup), self.parent_cgroup)
     self.assertEqual(cgroup_parent(self.parent_cgroup), self.root_cgroup)
     self.assertEqual(cgroup_parent(self.root_cgroup),
                      NULL(self.prog, "struct cgroup *"))