Skip to content

Commit 6dc8f0a

Browse files
committed
TEMPORARY: reintroduce Python implementations of linux helpers so we can test against them
1 parent 8d870ac commit 6dc8f0a

File tree

4 files changed

+159
-1
lines changed

4 files changed

+159
-1
lines changed

drgn/helpers/linux/idr.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,32 @@
1111
IDRs were not based on radix trees.
1212
"""
1313

14+
from typing import Iterator, Tuple
15+
1416
from _drgn import (
1517
_linux_helper_idr_find as idr_find,
1618
_linux_helper_idr_for_each as idr_for_each,
1719
)
20+
from drgn import Object
21+
from drgn.helpers.linux.radixtree import old_radix_tree_for_each
1822

1923
__all__ = (
2024
"idr_find",
2125
"idr_for_each",
26+
"old_idr_for_each",
2227
)
28+
29+
30+
def old_idr_for_each(idr: Object) -> Iterator[Tuple[int, Object]]:
31+
"""
32+
Iterate over all of the entries in an IDR.
33+
34+
:param idr: ``struct idr *``
35+
:return: Iterator of (index, ``void *``) tuples.
36+
"""
37+
try:
38+
base = idr.idr_base.value_()
39+
except AttributeError:
40+
base = 0
41+
for index, entry in old_radix_tree_for_each(idr.idr_rt.address_of_()):
42+
yield index + base, entry

drgn/helpers/linux/pid.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,71 @@
99
IDs and processes.
1010
"""
1111

12+
from typing import Iterator, Union
13+
1214
from _drgn import (
1315
_linux_helper_find_pid as find_pid,
1416
_linux_helper_find_task as find_task,
1517
_linux_helper_pid_task as pid_task,
1618
_linux_helper_for_each_task as for_each_task,
1719
_linux_helper_for_each_pid as for_each_pid,
1820
)
21+
from drgn import Object, Program, cast, container_of
22+
from drgn.helpers.linux.idr import old_idr_for_each
23+
from drgn.helpers.linux.list import hlist_for_each_entry
1924

2025
__all__ = (
2126
"find_pid",
2227
"find_task",
2328
"for_each_pid",
2429
"for_each_task",
2530
"pid_task",
31+
"old_for_each_pid",
32+
"old_for_each_task",
2633
)
34+
35+
36+
def old_for_each_pid(prog_or_ns: Union[Program, Object]) -> Iterator[Object]:
37+
"""
38+
Iterate over all PIDs in a namespace.
39+
40+
:param prog_or_ns: ``struct pid_namespace *`` to iterate over, or
41+
:class:`Program` to iterate over initial PID namespace.
42+
:return: Iterator of ``struct pid *`` objects.
43+
"""
44+
if isinstance(prog_or_ns, Program):
45+
prog = prog_or_ns
46+
ns = prog_or_ns["init_pid_ns"].address_of_()
47+
else:
48+
prog = prog_or_ns.prog_
49+
ns = prog_or_ns
50+
if hasattr(ns, "idr"):
51+
for nr, entry in old_idr_for_each(ns.idr):
52+
yield cast("struct pid *", entry)
53+
else:
54+
pid_hash = prog["pid_hash"]
55+
for i in range(1 << prog["pidhash_shift"].value_()):
56+
for upid in hlist_for_each_entry(
57+
"struct upid", pid_hash[i].address_of_(), "pid_chain"
58+
):
59+
if upid.ns == ns:
60+
yield container_of(upid, "struct pid", f"numbers[{int(ns.level)}]")
61+
62+
63+
def old_for_each_task(prog_or_ns: Union[Program, Object]) -> Iterator[Object]:
64+
"""
65+
Iterate over all of the tasks visible in a namespace.
66+
67+
:param prog_or_ns: ``struct pid_namespace *`` to iterate over, or
68+
:class:`Program` to iterate over initial PID namespace.
69+
:return: Iterator of ``struct task_struct *`` objects.
70+
"""
71+
if isinstance(prog_or_ns, Program):
72+
prog = prog_or_ns
73+
else:
74+
prog = prog_or_ns.prog_
75+
PIDTYPE_PID = prog["PIDTYPE_PID"].value_()
76+
for pid in old_for_each_pid(prog_or_ns):
77+
task = pid_task(pid, PIDTYPE_PID)
78+
if task:
79+
yield task

drgn/helpers/linux/radixtree.py

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,58 @@
99
radix trees from :linux:`include/linux/radix-tree.h`.
1010
"""
1111

12+
from typing import Iterator, Tuple
13+
1214
from _drgn import (
1315
_linux_helper_radix_tree_lookup as radix_tree_lookup,
1416
_linux_helper_radix_tree_for_each as radix_tree_for_each,
1517
)
18+
from drgn import Object, cast
19+
20+
__all__ = (
21+
"radix_tree_for_each",
22+
"radix_tree_lookup",
23+
"old_radix_tree_for_each",
24+
)
25+
26+
_RADIX_TREE_ENTRY_MASK = 3
27+
28+
29+
def _is_internal_node(node: Object, internal_node: int) -> bool:
30+
return (node.value_() & _RADIX_TREE_ENTRY_MASK) == internal_node
31+
32+
33+
def _entry_to_node(node: Object, internal_node: int) -> Object:
34+
return Object(node.prog_, node.type_, value=node.value_() & ~internal_node)
35+
36+
37+
def _radix_tree_root_node(root: Object) -> Tuple[Object, int]:
38+
try:
39+
node = root.xa_head
40+
except AttributeError:
41+
return root.rnode.read_(), 1
42+
else:
43+
return cast("struct xa_node *", node).read_(), 2
44+
45+
46+
def old_radix_tree_for_each(root: Object) -> Iterator[Tuple[int, Object]]:
47+
"""
48+
Iterate over all of the entries in a radix tree.
49+
50+
:param root: ``struct radix_tree_root *``
51+
:return: Iterator of (index, ``void *``) tuples.
52+
"""
53+
node, RADIX_TREE_INTERNAL_NODE = _radix_tree_root_node(root)
54+
55+
def aux(node: Object, index: int) -> Iterator[Tuple[int, Object]]:
56+
if _is_internal_node(node, RADIX_TREE_INTERNAL_NODE):
57+
parent = _entry_to_node(node, RADIX_TREE_INTERNAL_NODE)
58+
for i, slot in enumerate(parent.slots):
59+
yield from aux(
60+
cast(parent.type_, slot).read_(),
61+
index + (i << parent.shift.value_()),
62+
)
63+
elif node:
64+
yield index, cast("void *", node)
1665

17-
__all__ = ("radix_tree_for_each", "radix_tree_lookup")
66+
yield from aux(node, 0)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
# SPDX-License-Identifier: GPL-3.0-or-later
3+
4+
from drgn.helpers.linux.pid import (
5+
for_each_pid,
6+
for_each_task,
7+
old_for_each_pid,
8+
old_for_each_task,
9+
)
10+
from drgn.helpers.linux.idr import idr_for_each, old_idr_for_each
11+
from drgn.helpers.linux.radixtree import radix_tree_for_each, old_radix_tree_for_each
12+
from tests.helpers.linux import LinuxHelperTestCase
13+
14+
15+
class TestCHelpers(LinuxHelperTestCase):
16+
def verify_iterators_match(self, old_iter, other_iter, arg):
17+
self.assertTrue(sum(1 for _ in old_iter(arg)) >= 100)
18+
self.assertTrue(all(x == y for x, y in zip(old_iter(arg), other_iter(arg))))
19+
20+
def test_for_each_task(self):
21+
self.verify_iterators_match(old_for_each_task, for_each_task, self.prog)
22+
23+
def test_for_each_pid(self):
24+
self.verify_iterators_match(old_for_each_pid, for_each_pid, self.prog)
25+
26+
def test_idr_for_each(self):
27+
if hasattr(self.prog["init_pid_ns"], "idr"):
28+
idr = self.prog["init_pid_ns"].idr
29+
self.verify_iterators_match(old_idr_for_each, idr_for_each, idr)
30+
31+
def test_radix_tree_for_each(self):
32+
if hasattr(self.prog["init_pid_ns"], "idr"):
33+
root = self.prog["init_pid_ns"].idr.idr_rt.address_of_()
34+
self.verify_iterators_match(
35+
old_radix_tree_for_each, radix_tree_for_each, root
36+
)

0 commit comments

Comments
 (0)