History

scripts/gdb: fix interrupts.py after maple tree conversion

In commit 721255b9826b ("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.

Florian Fainelli committed 1 year ago

Commit a02b0cd1 parent ea9b77f4 files · +293 −6Browse files

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

Unified · Split

4 files
  1. scripts/gdb/linux/constants.py.in +7 −0
  2. scripts/gdb/linux/interrupts.py +6 −6
  3. scripts/gdb/linux/mapletree.py +252 −0
  4. scripts/gdb/linux/xarray.py +28 −0
scripts/gdb/linux/constants.py.in+7−0
@@ -20,6 +20,7 @@ · 19 unmodified lines
20#include <linux/of_fdt.h>20#include <linux/of_fdt.h>
21#include <linux/page_ext.h>21#include <linux/page_ext.h>
22#include <linux/radix-tree.h>22#include <linux/radix-tree.h>
23#include <linux/maple_tree.h>
23#include <linux/slab.h>24#include <linux/slab.h>
24#include <linux/threads.h>25#include <linux/threads.h>
25#include <linux/vmalloc.h>26#include <linux/vmalloc.h>
@@ -93,6 +94,12 @@ LX_GDBPARSED(RADIX_TREE_MAP_SIZE) · 67 unmodified lines
93LX_GDBPARSED(RADIX_TREE_MAP_SHIFT)94LX_GDBPARSED(RADIX_TREE_MAP_SHIFT)
94LX_GDBPARSED(RADIX_TREE_MAP_MASK)95LX_GDBPARSED(RADIX_TREE_MAP_MASK)
95 96
97/* linux/maple_tree.h */
98LX_VALUE(MAPLE_NODE_SLOTS)
99LX_VALUE(MAPLE_RANGE64_SLOTS)
100LX_VALUE(MAPLE_ARANGE64_SLOTS)
101LX_GDBPARSED(MAPLE_NODE_MASK)
102
96/* linux/vmalloc.h */103/* linux/vmalloc.h */
97LX_VALUE(VM_IOREMAP)104LX_VALUE(VM_IOREMAP)
98LX_VALUE(VM_ALLOC)105LX_VALUE(VM_ALLOC)
scripts/gdb/linux/interrupts.py+6−6
@@ -7,7 +7,7 @@ import gdb · 6 unmodified lines
7from linux import constants7from linux import constants
8from linux import cpus8from linux import cpus
9from linux import utils9from linux import utils
10from linux import radixtree10from linux import mapletree
11 11
12irq_desc_type = utils.CachedType("struct irq_desc")12irq_desc_type = utils.CachedType("struct irq_desc")
13 13
@@ -23,12 +23,12 @@ def irqd_is_level(desc): · 9 unmodified lines
23def show_irq_desc(prec, irq):23def show_irq_desc(prec, irq):
24 text = ""24 text = ""
25 25
26 desc = radixtree.lookup(gdb.parse_and_eval("&irq_desc_tree"), irq)26 desc = mapletree.mtree_load(gdb.parse_and_eval("&sparse_irqs"), irq)
27 if desc is None:27 if desc is None:
28 return text28 return text
29 29
30 desc = desc.cast(irq_desc_type.get_type())30 desc = desc.cast(irq_desc_type.get_type().pointer())
31 if desc is None:31 if desc == 0:
32 return text32 return text
33 33
34 if irq_settings_is_hidden(desc):34 if irq_settings_is_hidden(desc):
@@ -221,8 +221,8 @@ class LxInterruptList(gdb.Command): · 186 unmodified lines
221 gdb.write("CPU%-8d" % cpu)221 gdb.write("CPU%-8d" % cpu)
222 gdb.write("\n")222 gdb.write("\n")
223 223
224 if utils.gdb_eval_or_none("&irq_desc_tree") is None:224 if utils.gdb_eval_or_none("&sparse_irqs") is None:
225 return225 raise gdb.GdbError("Unable to find the sparse IRQ tree, is CONFIG_SPARSE_IRQ enabled?")
226 226
227 for irq in range(nr_irqs):227 for irq in range(nr_irqs):
228 gdb.write(show_irq_desc(prec, irq))228 gdb.write(show_irq_desc(prec, irq))
scripts/gdb/linux/mapletree.py+252−0
@@ -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 <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
scripts/gdb/linux/xarray.py+28−0
@@ -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 <florian.fainelli@broadcom.com>
9
10import gdb
11
12from linux import utils
13from linux import constants
14
15def xa_is_internal(entry):
16 ulong_type = utils.get_ulong_type()
17 return ((entry.cast(ulong_type) & 3) == 2)
18
19def xa_mk_internal(v):
20 return ((v << 2) | 2)
21
22def xa_is_zero(entry):
23 ulong_type = utils.get_ulong_type()
24 return entry.cast(ulong_type) == xa_mk_internal(257)
25
26def xa_is_node(entry):
27 ulong_type = utils.get_ulong_type()
28 return xa_is_internal(entry) and (entry.cast(ulong_type) > 4096)