Skip to content

Commit 51f75d7

Browse files
committed
drgn.helpers.linux.device: add for_each_registered_{chr,blk}dev()
1 parent 7dda3ea commit 51f75d7

File tree

2 files changed

+92
-1
lines changed

2 files changed

+92
-1
lines changed

drgn/helpers/linux/device.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,17 @@
1010
"""
1111

1212
import operator
13+
from typing import Iterator, Tuple
1314

14-
from drgn import IntegerLike
15+
from drgn import IntegerLike, Object, Program, cast
16+
from drgn.helpers.common.prog import takes_program_or_default
1517

1618
__all__ = (
1719
"MAJOR",
1820
"MINOR",
1921
"MKDEV",
22+
"for_each_registered_blkdev",
23+
"for_each_registered_chrdev",
2024
)
2125

2226

@@ -51,3 +55,33 @@ def MKDEV(major: IntegerLike, minor: IntegerLike) -> int:
5155
:param minor: Device minor ID.
5256
"""
5357
return (operator.index(major) << _MINORBITS) | operator.index(minor)
58+
59+
60+
@takes_program_or_default
61+
def for_each_registered_chrdev(
62+
prog: Program,
63+
) -> Iterator[Tuple[int, int, bytes, Object]]:
64+
cdev_map_probes = prog["cdev_map"].probes
65+
for cd in prog["chrdevs"]:
66+
while cd := cd.read_():
67+
major = cd.major.value_()
68+
dev = MKDEV(major, cd.baseminor)
69+
cdev = cd.cdev.read_()
70+
if not cdev:
71+
probe = cdev_map_probes[major].read_()
72+
while next := probe.next.read_():
73+
if probe.dev.value_() == dev:
74+
cdev = cast("struct cdev *", probe.data)
75+
break
76+
probe = next
77+
78+
yield dev, cd.minorct.value_(), cd.name.string_(), cdev
79+
cd = cd.next
80+
81+
82+
@takes_program_or_default
83+
def for_each_registered_blkdev(prog: Program) -> Iterator[Tuple[int, bytes]]:
84+
for name in prog["major_names"]:
85+
while name := name.read_():
86+
yield name.major.value_(), name.name.string_()
87+
name = name.next
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
# SPDX-License-Identifier: LGPL-2.1-or-later
3+
4+
5+
from drgn.helpers.linux.device import (
6+
MAJOR,
7+
for_each_registered_blkdev,
8+
for_each_registered_chrdev,
9+
)
10+
from tests.linux_kernel import LinuxKernelTestCase
11+
12+
13+
class TestDevice(LinuxKernelTestCase):
14+
def test_for_each_registered_chrdev(self):
15+
expected = []
16+
with open("/proc/devices", "rb") as f:
17+
ignore = True
18+
for line in f:
19+
line = line.rstrip(b"\n")
20+
if line == b"Character devices:":
21+
ignore = False
22+
elif ignore:
23+
pass
24+
elif not line:
25+
break
26+
else:
27+
tokens = line.split(maxsplit=1)
28+
expected.append((int(tokens[0]), tokens[1]))
29+
30+
self.assertCountEqual(
31+
[
32+
(MAJOR(dev), name)
33+
for dev, _, name, _ in for_each_registered_chrdev(self.prog)
34+
],
35+
expected,
36+
)
37+
38+
def test_for_each_registered_blkdev(self):
39+
expected = []
40+
with open("/proc/devices", "rb") as f:
41+
ignore = True
42+
for line in f:
43+
line = line.rstrip(b"\n")
44+
if line == b"Block devices:":
45+
ignore = False
46+
elif ignore:
47+
pass
48+
elif not line:
49+
break
50+
else:
51+
tokens = line.split(maxsplit=1)
52+
expected.append((int(tokens[0]), tokens[1]))
53+
54+
self.assertCountEqual(
55+
[(major, name) for major, name in for_each_registered_blkdev(self.prog)],
56+
expected,
57+
)

0 commit comments

Comments
 (0)