1# SPDX-License-Identifier: GPL-2.0 2# 3# Radix Tree Parser 4# 5# Copyright (c) 2016 Linaro Ltd 6# Copyright (c) 2023 Broadcom 7# 8# Authors: 9# Kieran Bingham <[email protected]> 10# Florian Fainelli <[email protected]> 11 12import gdb 13 14from linux import utils 15from linux import constants 16 17radix_tree_root_type = utils.CachedType("struct xarray") 18radix_tree_node_type = utils.CachedType("struct xa_node") 19 20def is_internal_node(node): 21 long_type = utils.get_long_type() 22 return ((node.cast(long_type) & constants.LX_RADIX_TREE_ENTRY_MASK) == constants.LX_RADIX_TREE_INTERNAL_NODE) 23 24def entry_to_node(node): 25 long_type = utils.get_long_type() 26 node_type = node.type 27 indirect_ptr = node.cast(long_type) & ~constants.LX_RADIX_TREE_INTERNAL_NODE 28 return indirect_ptr.cast(radix_tree_node_type.get_type().pointer()) 29 30def node_maxindex(node): 31 return (constants.LX_RADIX_TREE_MAP_SIZE << node['shift']) - 1 32 33def lookup(root, index): 34 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)) 39 40 node = root['xa_head'] 41 if node == 0: 42 return None 43 44 if not (is_internal_node(node)): 45 if (index > 0): 46 return None 47 return node 48 49 node = entry_to_node(node) 50 maxindex = node_maxindex(node) 51 52 if (index > maxindex): 53 return None 54 55 shift = node['shift'] + constants.LX_RADIX_TREE_MAP_SHIFT 56 57 while True: 58 offset = (index >> node['shift']) & constants.LX_RADIX_TREE_MAP_MASK 59 slot = node['slots'][offset] 60 61 if slot == 0: 62 return None 63 64 node = slot.cast(node.type.pointer()).dereference() 65 if node == 0: 66 return None 67 68 shift -= constants.LX_RADIX_TREE_MAP_SHIFT 69 if (shift <= 0): 70 break 71 72 return node 73 74class LxRadixTree(gdb.Function): 75 """ Lookup and return a node from a RadixTree. 76 77$lx_radix_tree_lookup(root_node [, index]): Return the node at the given index. 78If index is omitted, the root node is dereference and returned.""" 79 80 def __init__(self): 81 super(LxRadixTree, self).__init__("lx_radix_tree_lookup") 82 83 def invoke(self, root, index=0): 84 result = lookup(root, index) 85 if result is None: 86 raise gdb.GdbError("No entry in tree at index {}".format(index)) 87 88 return result 89 90LxRadixTree() 91