Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

scripts/gdb/radix-tree: add lx-radix-tree-command

Patch series "scripts/gdb/symbols: make BPF debug info available to GDB",
v2.

This series greatly simplifies debugging BPF progs when using QEMU gdbstub
by providing symbol names, sizes, and line numbers to GDB.

Patch 1 adds radix tree iteration, which is necessary for parsing
prog_idr. Patch 2 is the actual implementation; its description contains
some details on how to use this.


This patch (of 2):

Add a function and a command to iterate over radix tree contents.
Duplicate the C implementation in Python, but drop support for tagging.

Link: https://lkml.kernel.org/r/20251106124600.86736-1-iii@linux.ibm.com
Link: https://lkml.kernel.org/r/20251106124600.86736-2-iii@linux.ibm.com
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
Cc: Alexander Gordeev <agordeev@linux.ibm.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andrii Nakryiko <andrii@kernel.org>
Cc: Daniel Borkman <daniel@iogearbox.net>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Jan Kiszka <jan.kiszka@siemens.com>
Cc: Kieran Bingham <kbingham@kernel.org>
Cc: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Ilya Leoshkevich and committed by
Andrew Morton
caa71919 c9dddd98

+132 -7
+132 -7
scripts/gdb/linux/radixtree.py
··· 30 30 def node_maxindex(node): 31 31 return (constants.LX_RADIX_TREE_MAP_SIZE << node['shift']) - 1 32 32 33 - def lookup(root, index): 33 + def resolve_root(root): 34 + if root.type == radix_tree_root_type.get_type(): 35 + return root 34 36 if root.type == radix_tree_root_type.get_type().pointer(): 35 - node = root.dereference() 36 - elif root.type != radix_tree_root_type.get_type(): 37 - raise gdb.GdbError("must be {} not {}" 38 - .format(radix_tree_root_type.get_type(), root.type)) 37 + return root.dereference() 38 + raise gdb.GdbError("must be {} not {}" 39 + .format(radix_tree_root_type.get_type(), root.type)) 39 40 41 + def lookup(root, index): 42 + root = resolve_root(root) 40 43 node = root['xa_head'] 41 44 if node == 0: 42 45 return None ··· 74 71 75 72 return node 76 73 77 - class LxRadixTree(gdb.Function): 74 + def descend(parent, index): 75 + offset = (index >> int(parent["shift"])) & constants.LX_RADIX_TREE_MAP_MASK 76 + return offset, parent["slots"][offset] 77 + 78 + def load_root(root): 79 + node = root["xa_head"] 80 + nodep = node 81 + 82 + if is_internal_node(node): 83 + node = entry_to_node(node) 84 + maxindex = node_maxindex(node) 85 + return int(node["shift"]) + constants.LX_RADIX_TREE_MAP_SHIFT, \ 86 + nodep, maxindex 87 + 88 + return 0, nodep, 0 89 + 90 + class RadixTreeIter: 91 + def __init__(self, start): 92 + self.index = 0 93 + self.next_index = start 94 + self.node = None 95 + 96 + def xa_mk_internal(v): 97 + return (v << 2) | 2 98 + 99 + LX_XA_RETRY_ENTRY = xa_mk_internal(256) 100 + LX_RADIX_TREE_RETRY = LX_XA_RETRY_ENTRY 101 + 102 + def next_chunk(root, iter): 103 + mask = (1 << (utils.get_ulong_type().sizeof * 8)) - 1 104 + 105 + index = iter.next_index 106 + if index == 0 and iter.index != 0: 107 + return None 108 + 109 + restart = True 110 + while restart: 111 + restart = False 112 + 113 + _, child, maxindex = load_root(root) 114 + if index > maxindex: 115 + return None 116 + if not child: 117 + return None 118 + 119 + if not is_internal_node(child): 120 + iter.index = index 121 + iter.next_index = (maxindex + 1) & mask 122 + iter.node = None 123 + return root["xa_head"].address 124 + 125 + while True: 126 + node = entry_to_node(child) 127 + offset, child = descend(node, index) 128 + 129 + if not child: 130 + while True: 131 + offset += 1 132 + if offset >= constants.LX_RADIX_TREE_MAP_SIZE: 133 + break 134 + slot = node["slots"][offset] 135 + if slot: 136 + break 137 + index &= ~node_maxindex(node) 138 + index = (index + (offset << int(node["shift"]))) & mask 139 + if index == 0: 140 + return None 141 + if offset == constants.LX_RADIX_TREE_MAP_SIZE: 142 + restart = True 143 + break 144 + child = node["slots"][offset] 145 + 146 + if not child: 147 + restart = True 148 + break 149 + if child == LX_XA_RETRY_ENTRY: 150 + break 151 + if not node["shift"] or not is_internal_node(child): 152 + break 153 + 154 + iter.index = (index & ~node_maxindex(node)) | offset 155 + iter.next_index = ((index | node_maxindex(node)) + 1) & mask 156 + iter.node = node 157 + 158 + return node["slots"][offset].address 159 + 160 + def next_slot(slot, iter): 161 + mask = (1 << (utils.get_ulong_type().sizeof * 8)) - 1 162 + for _ in range(iter.next_index - iter.index - 1): 163 + slot += 1 164 + iter.index = (iter.index + 1) & mask 165 + if slot.dereference(): 166 + return slot 167 + return None 168 + 169 + def for_each_slot(root, start=0): 170 + iter = RadixTreeIter(start) 171 + slot = None 172 + while True: 173 + if not slot: 174 + slot = next_chunk(root, iter) 175 + if not slot: 176 + break 177 + yield iter.index, slot 178 + slot = next_slot(slot, iter) 179 + 180 + class LxRadixTreeLookup(gdb.Function): 78 181 """ Lookup and return a node from a RadixTree. 79 182 80 183 $lx_radix_tree_lookup(root_node [, index]): Return the node at the given index. 81 184 If index is omitted, the root node is dereference and returned.""" 82 185 83 186 def __init__(self): 84 - super(LxRadixTree, self).__init__("lx_radix_tree_lookup") 187 + super(LxRadixTreeLookup, self).__init__("lx_radix_tree_lookup") 85 188 86 189 def invoke(self, root, index=0): 87 190 result = lookup(root, index) ··· 196 87 197 88 return result 198 89 90 + class LxRadixTree(gdb.Command): 91 + """Show all values stored in a RadixTree.""" 92 + 93 + def __init__(self): 94 + super(LxRadixTree, self).__init__("lx-radix-tree", gdb.COMMAND_DATA, 95 + gdb.COMPLETE_NONE) 96 + 97 + def invoke(self, argument, from_tty): 98 + args = gdb.string_to_argv(argument) 99 + if len(args) != 1: 100 + raise gdb.GdbError("Usage: lx-radix-tree ROOT") 101 + root = gdb.parse_and_eval(args[0]) 102 + for index, slot in for_each_slot(root): 103 + gdb.write("[{}] = {}\n".format(index, slot.dereference())) 104 + 199 105 LxRadixTree() 106 + LxRadixTreeLookup()