Skip to content

Commit a02b0cd

Browse files
ffainelliakpm00
authored andcommitted
scripts/gdb: fix interrupts.py after maple tree conversion
In commit 721255b ("genirq: Use a maple tree for interrupt descriptor management"), the irq_desc_tree was replaced with a sparse_irqs tree using a maple tree structure. Since the script looked for the irq_desc_tree symbol which is no longer available, no interrupts would be printed and the script output would not be useful anymore. In addition to looking up the correct symbol (sparse_irqs), a new module (mapletree.py) is added whose mtree_load() implementation is largely copied after the C version and uses the same variable and intermediate function names wherever possible to ensure that both the C and Python version be updated in the future. This restores the scripts' output to match that of /proc/interrupts. Link: https://lkml.kernel.org/r/[email protected] Fixes: 721255b ("genirq: Use a maple tree for interrupt descriptor management") Signed-off-by: Florian Fainelli <[email protected]> Cc: Jan Kiszka <[email protected]> Cc: Kieran Bingham <[email protected]> Cc: Shanker Donthineni <[email protected]> Cc: Thomas Gleinxer <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent ea9b77f commit a02b0cd

File tree

4 files changed

+293
-6
lines changed

4 files changed

+293
-6
lines changed

scripts/gdb/linux/constants.py.in

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/of_fdt.h>
2121
#include <linux/page_ext.h>
2222
#include <linux/radix-tree.h>
23+
#include <linux/maple_tree.h>
2324
#include <linux/slab.h>
2425
#include <linux/threads.h>
2526
#include <linux/vmalloc.h>
@@ -93,6 +94,12 @@ LX_GDBPARSED(RADIX_TREE_MAP_SIZE)
9394
LX_GDBPARSED(RADIX_TREE_MAP_SHIFT)
9495
LX_GDBPARSED(RADIX_TREE_MAP_MASK)
9596

97+
/* linux/maple_tree.h */
98+
LX_VALUE(MAPLE_NODE_SLOTS)
99+
LX_VALUE(MAPLE_RANGE64_SLOTS)
100+
LX_VALUE(MAPLE_ARANGE64_SLOTS)
101+
LX_GDBPARSED(MAPLE_NODE_MASK)
102+
96103
/* linux/vmalloc.h */
97104
LX_VALUE(VM_IOREMAP)
98105
LX_VALUE(VM_ALLOC)

scripts/gdb/linux/interrupts.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from linux import constants
88
from linux import cpus
99
from linux import utils
10-
from linux import radixtree
10+
from linux import mapletree
1111

1212
irq_desc_type = utils.CachedType("struct irq_desc")
1313

@@ -23,12 +23,12 @@ def irqd_is_level(desc):
2323
def show_irq_desc(prec, irq):
2424
text = ""
2525

26-
desc = radixtree.lookup(gdb.parse_and_eval("&irq_desc_tree"), irq)
26+
desc = mapletree.mtree_load(gdb.parse_and_eval("&sparse_irqs"), irq)
2727
if desc is None:
2828
return text
2929

30-
desc = desc.cast(irq_desc_type.get_type())
31-
if desc is None:
30+
desc = desc.cast(irq_desc_type.get_type().pointer())
31+
if desc == 0:
3232
return text
3333

3434
if irq_settings_is_hidden(desc):
@@ -221,8 +221,8 @@ def invoke(self, arg, from_tty):
221221
gdb.write("CPU%-8d" % cpu)
222222
gdb.write("\n")
223223

224-
if utils.gdb_eval_or_none("&irq_desc_tree") is None:
225-
return
224+
if utils.gdb_eval_or_none("&sparse_irqs") is None:
225+
raise gdb.GdbError("Unable to find the sparse IRQ tree, is CONFIG_SPARSE_IRQ enabled?")
226226

227227
for irq in range(nr_irqs):
228228
gdb.write(show_irq_desc(prec, irq))

scripts/gdb/linux/mapletree.py

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
#
3+
# Maple tree helpers
4+
#
5+
# Copyright (c) 2025 Broadcom
6+
#
7+
# Authors:
8+
# Florian Fainelli <[email protected]>
9+
10+
import gdb
11+
12+
from linux import utils
13+
from linux import constants
14+
from linux import xarray
15+
16+
maple_tree_root_type = utils.CachedType("struct maple_tree")
17+
maple_node_type = utils.CachedType("struct maple_node")
18+
maple_enode_type = utils.CachedType("void")
19+
20+
maple_dense = 0
21+
maple_leaf_64 = 1
22+
maple_range_64 = 2
23+
maple_arange_64 = 3
24+
25+
class 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+
109+
def 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+
118+
def 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+
130+
def 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+
139+
def 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+
151+
def 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+
158+
def ma_is_leaf(tp):
159+
result = tp < maple_range_64
160+
return tp < maple_range_64
161+
162+
def 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+
170+
def 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+
181+
def 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+
194+
def mt_slot(mt, slots, offset):
195+
ulong_type = utils.get_ulong_type()
196+
return slots[offset].cast(ulong_type)
197+
198+
def 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+
227+
def 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

scripts/gdb/linux/xarray.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
#
3+
# Xarray helpers
4+
#
5+
# Copyright (c) 2025 Broadcom
6+
#
7+
# Authors:
8+
# Florian Fainelli <[email protected]>
9+
10+
import gdb
11+
12+
from linux import utils
13+
from linux import constants
14+
15+
def xa_is_internal(entry):
16+
ulong_type = utils.get_ulong_type()
17+
return ((entry.cast(ulong_type) & 3) == 2)
18+
19+
def xa_mk_internal(v):
20+
return ((v << 2) | 2)
21+
22+
def xa_is_zero(entry):
23+
ulong_type = utils.get_ulong_type()
24+
return entry.cast(ulong_type) == xa_mk_internal(257)
25+
26+
def xa_is_node(entry):
27+
ulong_type = utils.get_ulong_type()
28+
return xa_is_internal(entry) and (entry.cast(ulong_type) > 4096)

0 commit comments

Comments
 (0)