1# 2# gdb helper commands and functions for Linux kernel debugging 3# 4# Radix Tree Parser 5# 6# Copyright (c) 2016 Linaro Ltd 7# 8# Authors: 9# Kieran Bingham <[email protected]> 10# 11# This work is licensed under the terms of the GNU GPL version 2. 12# 13 14import gdb 15 16from linux import utils 17from linux import constants 18 19radix_tree_root_type = utils.CachedType("struct radix_tree_root") 20radix_tree_node_type = utils.CachedType("struct radix_tree_node") 21 22 23def is_indirect_ptr(node): 24 long_type = utils.get_long_type() 25 return (node.cast(long_type) & constants.LX_RADIX_TREE_INDIRECT_PTR) 26 27 28def indirect_to_ptr(node): 29 long_type = utils.get_long_type() 30 node_type = node.type 31 indirect_ptr = node.cast(long_type) & ~constants.LX_RADIX_TREE_INDIRECT_PTR 32 return indirect_ptr.cast(node_type) 33 34 35def maxindex(height): 36 height = height & constants.LX_RADIX_TREE_HEIGHT_MASK 37 return gdb.parse_and_eval("height_to_maxindex["+str(height)+"]") 38 39 40def lookup(root, index): 41 if root.type == radix_tree_root_type.get_type().pointer(): 42 root = root.dereference() 43 elif root.type != radix_tree_root_type.get_type(): 44 raise gdb.GdbError("Must be struct radix_tree_root not {}" 45 .format(root.type)) 46 47 node = root['rnode'] 48 if node is 0: 49 return None 50 51 if not (is_indirect_ptr(node)): 52 if (index > 0): 53 return None 54 return node 55 56 node = indirect_to_ptr(node) 57 58 height = node['path'] & constants.LX_RADIX_TREE_HEIGHT_MASK 59 if (index > maxindex(height)): 60 return None 61 62 shift = (height-1) * constants.LX_RADIX_TREE_MAP_SHIFT 63 64 while True: 65 new_index = (index >> shift) & constants.LX_RADIX_TREE_MAP_MASK 66 slot = node['slots'][new_index] 67 68 node = slot.cast(node.type.pointer()).dereference() 69 if node is 0: 70 return None 71 72 shift -= constants.LX_RADIX_TREE_MAP_SHIFT 73 height -= 1 74 75 if (height <= 0): 76 break 77 78 return node 79 80 81class LxRadixTree(gdb.Function): 82 """ Lookup and return a node from a RadixTree. 83 84$lx_radix_tree_lookup(root_node [, index]): Return the node at the given index. 85If index is omitted, the root node is dereferenced and returned.""" 86 87 def __init__(self): 88 super(LxRadixTree, self).__init__("lx_radix_tree_lookup") 89 90 def invoke(self, root, index=0): 91 result = lookup(root, index) 92 if result is None: 93 raise gdb.GdbError("No entry in tree at index {}".format(index)) 94 95 return result 96 97LxRadixTree() 98