History

scripts/gdb: add rb tree iterating utilities

Implement gdb functions for rb_first(), rb_last(), rb_next(), and rb_prev(). These can be useful to iterate through the kernel's red-black trees. [swboyd@chromium.org: v2] Link: http://lkml.kernel.org/r/20190329220844.38234-4-swboyd@chromium.org Link: http://lkml.kernel.org/r/20190325184522.260535-4-swboyd@chromium.org Signed-off-by: Stephen Boyd <swboyd@chromium.org> Cc: Douglas Anderson <dianders@chromium.org> Cc: Nikolay Borisov <n.borisov.lkml@gmail.com> Cc: Kieran Bingham <kbingham@kernel.org> Cc: Jan Kiszka <jan.kiszka@siemens.com> Cc: Jackie Liu <liuyun01@kylinos.cn> Cc: Jason Wessel <jason.wessel@windriver.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Stephen Boyd committed 7 years ago

Commit 449ca0c1 parent 90cf83d2 files · +178 −0Browse files

Showing the changes to scripts (2 of 2 files). Show all

Unified · Split

2 files
  1. scripts/gdb/linux/rbtree.py +177 −0
  2. scripts/gdb/vmlinux-gdb.py +1 −0
scripts/gdb/linux/rbtree.py+177−0
@@ -0,0 +1,177 @@
1+# SPDX-License-Identifier: GPL-2.0
2+#
3+# Copyright 2019 Google LLC.
4+
5+import gdb
6+
7+from linux import utils
8+
9+rb_root_type = utils.CachedType("struct rb_root")
10+rb_node_type = utils.CachedType("struct rb_node")
11+
12+
13+def rb_first(root):
14+ if root.type == rb_root_type.get_type():
15+ node = node.address.cast(rb_root_type.get_type().pointer())
16+ elif root.type != rb_root_type.get_type().pointer():
17+ raise gdb.GdbError("Must be struct rb_root not {}".format(root.type))
18+
19+ node = root['rb_node']
20+ if node is 0:
21+ return None
22+
23+ while node['rb_left']:
24+ node = node['rb_left']
25+
26+ return node
27+
28+
29+def rb_last(root):
30+ if root.type == rb_root_type.get_type():
31+ node = node.address.cast(rb_root_type.get_type().pointer())
32+ elif root.type != rb_root_type.get_type().pointer():
33+ raise gdb.GdbError("Must be struct rb_root not {}".format(root.type))
34+
35+ node = root['rb_node']
36+ if node is 0:
37+ return None
38+
39+ while node['rb_right']:
40+ node = node['rb_right']
41+
42+ return node
43+
44+
45+def rb_parent(node):
46+ parent = gdb.Value(node['__rb_parent_color'] & ~3)
47+ return parent.cast(rb_node_type.get_type().pointer())
48+
49+
50+def rb_empty_node(node):
51+ return node['__rb_parent_color'] == node.address
52+
53+
54+def rb_next(node):
55+ if node.type == rb_node_type.get_type():
56+ node = node.address.cast(rb_node_type.get_type().pointer())
57+ elif node.type != rb_node_type.get_type().pointer():
58+ raise gdb.GdbError("Must be struct rb_node not {}".format(node.type))
59+
60+ if rb_empty_node(node):
61+ return None
62+
63+ if node['rb_right']:
64+ node = node['rb_right']
65+ while node['rb_left']:
66+ node = node['rb_left']
67+ return node
68+
69+ parent = rb_parent(node)
70+ while parent and node == parent['rb_right']:
71+ node = parent
72+ parent = rb_parent(node)
73+
74+ return parent
75+
76+
77+def rb_prev(node):
78+ if node.type == rb_node_type.get_type():
79+ node = node.address.cast(rb_node_type.get_type().pointer())
80+ elif node.type != rb_node_type.get_type().pointer():
81+ raise gdb.GdbError("Must be struct rb_node not {}".format(node.type))
82+
83+ if rb_empty_node(node):
84+ return None
85+
86+ if node['rb_left']:
87+ node = node['rb_left']
88+ while node['rb_right']:
89+ node = node['rb_right']
90+ return node.dereference()
91+
92+ parent = rb_parent(node)
93+ while parent and node == parent['rb_left'].dereference():
94+ node = parent
95+ parent = rb_parent(node)
96+
97+ return parent
98+
99+
100+class LxRbFirst(gdb.Function):
101+ """Lookup and return a node from an RBTree
102+
103+$lx_rb_first(root): Return the node at the given index.
104+If index is omitted, the root node is dereferenced and returned."""
105+
106+ def __init__(self):
107+ super(LxRbFirst, self).__init__("lx_rb_first")
108+
109+ def invoke(self, root):
110+ result = rb_first(root)
111+ if result is None:
112+ raise gdb.GdbError("No entry in tree")
113+
114+ return result
115+
116+
117+LxRbFirst()
118+
119+
120+class LxRbLast(gdb.Function):
121+ """Lookup and return a node from an RBTree.
122+
123+$lx_rb_last(root): Return the node at the given index.
124+If index is omitted, the root node is dereferenced and returned."""
125+
126+ def __init__(self):
127+ super(LxRbLast, self).__init__("lx_rb_last")
128+
129+ def invoke(self, root):
130+ result = rb_last(root)
131+ if result is None:
132+ raise gdb.GdbError("No entry in tree")
133+
134+ return result
135+
136+
137+LxRbLast()
138+
139+
140+class LxRbNext(gdb.Function):
141+ """Lookup and return a node from an RBTree.
142+
143+$lx_rb_next(node): Return the node at the given index.
144+If index is omitted, the root node is dereferenced and returned."""
145+
146+ def __init__(self):
147+ super(LxRbNext, self).__init__("lx_rb_next")
148+
149+ def invoke(self, node):
150+ result = rb_next(node)
151+ if result is None:
152+ raise gdb.GdbError("No entry in tree")
153+
154+ return result
155+
156+
157+LxRbNext()
158+
159+
160+class LxRbPrev(gdb.Function):
161+ """Lookup and return a node from an RBTree.
162+
163+$lx_rb_prev(node): Return the node at the given index.
164+If index is omitted, the root node is dereferenced and returned."""
165+
166+ def __init__(self):
167+ super(LxRbPrev, self).__init__("lx_rb_prev")
168+
169+ def invoke(self, node):
170+ result = rb_prev(node)
171+ if result is None:
172+ raise gdb.GdbError("No entry in tree")
173+
174+ return result
175+
176+
177+LxRbPrev()
scripts/gdb/vmlinux-gdb.py+1−0
@@ -30,5 +30,6 @@ else: · 29 unmodified lines
3030 import linux.config
3131 import linux.cpus
3232 import linux.lists
33+ import linux.rbtree
3334 import linux.proc
3435 import linux.constants