radixtree.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  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 <kieran.bingham@linaro.org>
  10. #
  11. # This work is licensed under the terms of the GNU GPL version 2.
  12. #
  13. import gdb
  14. from linux import utils
  15. from linux import constants
  16. radix_tree_root_type = utils.CachedType("struct radix_tree_root")
  17. radix_tree_node_type = utils.CachedType("struct radix_tree_node")
  18. def is_indirect_ptr(node):
  19. long_type = utils.get_long_type()
  20. return (node.cast(long_type) & constants.LX_RADIX_TREE_INDIRECT_PTR)
  21. def indirect_to_ptr(node):
  22. long_type = utils.get_long_type()
  23. node_type = node.type
  24. indirect_ptr = node.cast(long_type) & ~constants.LX_RADIX_TREE_INDIRECT_PTR
  25. return indirect_ptr.cast(node_type)
  26. def maxindex(height):
  27. height = height & constants.LX_RADIX_TREE_HEIGHT_MASK
  28. return gdb.parse_and_eval("height_to_maxindex["+str(height)+"]")
  29. def lookup(root, index):
  30. if root.type == radix_tree_root_type.get_type().pointer():
  31. root = root.dereference()
  32. elif root.type != radix_tree_root_type.get_type():
  33. raise gdb.GdbError("Must be struct radix_tree_root not {}"
  34. .format(root.type))
  35. node = root['rnode']
  36. if node is 0:
  37. return None
  38. if not (is_indirect_ptr(node)):
  39. if (index > 0):
  40. return None
  41. return node
  42. node = indirect_to_ptr(node)
  43. height = node['path'] & constants.LX_RADIX_TREE_HEIGHT_MASK
  44. if (index > maxindex(height)):
  45. return None
  46. shift = (height-1) * constants.LX_RADIX_TREE_MAP_SHIFT
  47. while True:
  48. new_index = (index >> shift) & constants.LX_RADIX_TREE_MAP_MASK
  49. slot = node['slots'][new_index]
  50. node = slot.cast(node.type.pointer()).dereference()
  51. if node is 0:
  52. return None
  53. shift -= constants.LX_RADIX_TREE_MAP_SHIFT
  54. height -= 1
  55. if (height <= 0):
  56. break
  57. return node
  58. class LxRadixTree(gdb.Function):
  59. """ Lookup and return a node from a RadixTree.
  60. $lx_radix_tree_lookup(root_node [, index]): Return the node at the given index.
  61. If index is omitted, the root node is dereferenced and returned."""
  62. def __init__(self):
  63. super(LxRadixTree, self).__init__("lx_radix_tree_lookup")
  64. def invoke(self, root, index=0):
  65. result = lookup(root, index)
  66. if result is None:
  67. raise gdb.GdbError("No entry in tree at index {}".format(index))
  68. return result
  69. LxRadixTree()