File Index
Files and directories
Sign in
FILE

mapletree.py

File preview with syntax highlighting.

linux-6.19.14/scripts/gdb/linux/mapletree.py PYTHON
  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
~/ Read-only file preview.