Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1# SPDX-License-Identifier: GPL-2.0
2#
3# Maple tree helpers
4#
5# Copyright (c) 2025 Broadcom
6#
7# Authors:
8# Florian Fainelli <florian.fainelli@broadcom.com>
9
10import gdb
11
12from linux import utils
13from linux import constants
14from linux import xarray
15
16maple_tree_root_type = utils.CachedType("struct maple_tree")
17maple_node_type = utils.CachedType("struct maple_node")
18maple_enode_type = utils.CachedType("void")
19
20maple_dense = 0
21maple_leaf_64 = 1
22maple_range_64 = 2
23maple_arange_64 = 3
24
25class Mas(object):
26 ma_active = 0
27 ma_start = 1
28 ma_root = 2
29 ma_none = 3
30 ma_pause = 4
31 ma_overflow = 5
32 ma_underflow = 6
33 ma_error = 7
34
35 def __init__(self, mt, first, end):
36 if mt.type == maple_tree_root_type.get_type().pointer():
37 self.tree = mt.dereference()
38 elif mt.type != maple_tree_root_type.get_type():
39 raise gdb.GdbError("must be {} not {}"
40 .format(maple_tree_root_type.get_type().pointer(), mt.type))
41 self.tree = mt
42 self.index = first
43 self.last = end
44 self.node = None
45 self.status = self.ma_start
46 self.min = 0
47 self.max = -1
48
49 def is_start(self):
50 # mas_is_start()
51 return self.status == self.ma_start
52
53 def is_ptr(self):
54 # mas_is_ptr()
55 return self.status == self.ma_root
56
57 def is_none(self):
58 # mas_is_none()
59 return self.status == self.ma_none
60
61 def root(self):
62 # mas_root()
63 return self.tree['ma_root'].cast(maple_enode_type.get_type().pointer())
64
65 def start(self):
66 # mas_start()
67 if self.is_start() is False:
68 return None
69
70 self.min = 0
71 self.max = ~0
72
73 while True:
74 self.depth = 0
75 root = self.root()
76 if xarray.xa_is_node(root):
77 self.depth = 0
78 self.status = self.ma_active
79 self.node = mte_safe_root(root)
80 self.offset = 0
81 if mte_dead_node(self.node) is True:
82 continue
83
84 return None
85
86 self.node = None
87 # Empty tree
88 if root is None:
89 self.status = self.ma_none
90 self.offset = constants.LX_MAPLE_NODE_SLOTS
91 return None
92
93 # Single entry tree
94 self.status = self.ma_root
95 self.offset = constants.LX_MAPLE_NODE_SLOTS
96
97 if self.index != 0:
98 return None
99
100 return root
101
102 return None
103
104 def reset(self):
105 # mas_reset()
106 self.status = self.ma_start
107 self.node = None
108
109def mte_safe_root(node):
110 if node.type != maple_enode_type.get_type().pointer():
111 raise gdb.GdbError("{} must be {} not {}"
112 .format(mte_safe_root.__name__, maple_enode_type.get_type().pointer(), node.type))
113 ulong_type = utils.get_ulong_type()
114 indirect_ptr = node.cast(ulong_type) & ~0x2
115 val = indirect_ptr.cast(maple_enode_type.get_type().pointer())
116 return val
117
118def mte_node_type(entry):
119 ulong_type = utils.get_ulong_type()
120 val = None
121 if entry.type == maple_enode_type.get_type().pointer():
122 val = entry.cast(ulong_type)
123 elif entry.type == ulong_type:
124 val = entry
125 else:
126 raise gdb.GdbError("{} must be {} not {}"
127 .format(mte_node_type.__name__, maple_enode_type.get_type().pointer(), entry.type))
128 return (val >> 0x3) & 0xf
129
130def ma_dead_node(node):
131 if node.type != maple_node_type.get_type().pointer():
132 raise gdb.GdbError("{} must be {} not {}"
133 .format(ma_dead_node.__name__, maple_node_type.get_type().pointer(), node.type))
134 ulong_type = utils.get_ulong_type()
135 parent = node['parent']
136 indirect_ptr = node['parent'].cast(ulong_type) & ~constants.LX_MAPLE_NODE_MASK
137 return indirect_ptr == node
138
139def mte_to_node(enode):
140 ulong_type = utils.get_ulong_type()
141 if enode.type == maple_enode_type.get_type().pointer():
142 indirect_ptr = enode.cast(ulong_type)
143 elif enode.type == ulong_type:
144 indirect_ptr = enode
145 else:
146 raise gdb.GdbError("{} must be {} not {}"
147 .format(mte_to_node.__name__, maple_enode_type.get_type().pointer(), enode.type))
148 indirect_ptr = indirect_ptr & ~constants.LX_MAPLE_NODE_MASK
149 return indirect_ptr.cast(maple_node_type.get_type().pointer())
150
151def mte_dead_node(enode):
152 if enode.type != maple_enode_type.get_type().pointer():
153 raise gdb.GdbError("{} must be {} not {}"
154 .format(mte_dead_node.__name__, maple_enode_type.get_type().pointer(), enode.type))
155 node = mte_to_node(enode)
156 return ma_dead_node(node)
157
158def ma_is_leaf(tp):
159 result = tp < maple_range_64
160 return tp < maple_range_64
161
162def mt_pivots(t):
163 if t == maple_dense:
164 return 0
165 elif t == maple_leaf_64 or t == maple_range_64:
166 return constants.LX_MAPLE_RANGE64_SLOTS - 1
167 elif t == maple_arange_64:
168 return constants.LX_MAPLE_ARANGE64_SLOTS - 1
169
170def ma_pivots(node, t):
171 if node.type != maple_node_type.get_type().pointer():
172 raise gdb.GdbError("{}: must be {} not {}"
173 .format(ma_pivots.__name__, maple_node_type.get_type().pointer(), node.type))
174 if t == maple_arange_64:
175 return node['ma64']['pivot']
176 elif t == maple_leaf_64 or t == maple_range_64:
177 return node['mr64']['pivot']
178 else:
179 return None
180
181def ma_slots(node, tp):
182 if node.type != maple_node_type.get_type().pointer():
183 raise gdb.GdbError("{}: must be {} not {}"
184 .format(ma_slots.__name__, maple_node_type.get_type().pointer(), node.type))
185 if tp == maple_arange_64:
186 return node['ma64']['slot']
187 elif tp == maple_range_64 or tp == maple_leaf_64:
188 return node['mr64']['slot']
189 elif tp == maple_dense:
190 return node['slot']
191 else:
192 return None
193
194def mt_slot(mt, slots, offset):
195 ulong_type = utils.get_ulong_type()
196 return slots[offset].cast(ulong_type)
197
198def mtree_lookup_walk(mas):
199 ulong_type = utils.get_ulong_type()
200 n = mas.node
201
202 while True:
203 node = mte_to_node(n)
204 tp = mte_node_type(n)
205 pivots = ma_pivots(node, tp)
206 end = mt_pivots(tp)
207 offset = 0
208 while True:
209 if pivots[offset] >= mas.index:
210 break
211 if offset >= end:
212 break
213 offset += 1
214
215 slots = ma_slots(node, tp)
216 n = mt_slot(mas.tree, slots, offset)
217 if ma_dead_node(node) is True:
218 mas.reset()
219 return None
220 break
221
222 if ma_is_leaf(tp) is True:
223 break
224
225 return n
226
227def mtree_load(mt, index):
228 ulong_type = utils.get_ulong_type()
229 # MT_STATE(...)
230 mas = Mas(mt, index, index)
231 entry = None
232
233 while True:
234 entry = mas.start()
235 if mas.is_none():
236 return None
237
238 if mas.is_ptr():
239 if index != 0:
240 entry = None
241 return entry
242
243 entry = mtree_lookup_walk(mas)
244 if entry is None and mas.is_start():
245 continue
246 else:
247 break
248
249 if xarray.xa_is_zero(entry):
250 return None
251
252 return entry