mapletree.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  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. import gdb
  10. from linux import utils
  11. from linux import constants
  12. from linux import xarray
  13. maple_tree_root_type = utils.CachedType("struct maple_tree")
  14. maple_node_type = utils.CachedType("struct maple_node")
  15. maple_enode_type = utils.CachedType("void")
  16. maple_dense = 0
  17. maple_leaf_64 = 1
  18. maple_range_64 = 2
  19. maple_arange_64 = 3
  20. class Mas(object):
  21. ma_active = 0
  22. ma_start = 1
  23. ma_root = 2
  24. ma_none = 3
  25. ma_pause = 4
  26. ma_overflow = 5
  27. ma_underflow = 6
  28. ma_error = 7
  29. def __init__(self, mt, first, end):
  30. if mt.type == maple_tree_root_type.get_type().pointer():
  31. self.tree = mt.dereference()
  32. elif mt.type != maple_tree_root_type.get_type():
  33. raise gdb.GdbError("must be {} not {}"
  34. .format(maple_tree_root_type.get_type().pointer(), mt.type))
  35. self.tree = mt
  36. self.index = first
  37. self.last = end
  38. self.node = None
  39. self.status = self.ma_start
  40. self.min = 0
  41. self.max = -1
  42. def is_start(self):
  43. # mas_is_start()
  44. return self.status == self.ma_start
  45. def is_ptr(self):
  46. # mas_is_ptr()
  47. return self.status == self.ma_root
  48. def is_none(self):
  49. # mas_is_none()
  50. return self.status == self.ma_none
  51. def root(self):
  52. # mas_root()
  53. return self.tree['ma_root'].cast(maple_enode_type.get_type().pointer())
  54. def start(self):
  55. # mas_start()
  56. if self.is_start() is False:
  57. return None
  58. self.min = 0
  59. self.max = ~0
  60. while True:
  61. self.depth = 0
  62. root = self.root()
  63. if xarray.xa_is_node(root):
  64. self.depth = 0
  65. self.status = self.ma_active
  66. self.node = mte_safe_root(root)
  67. self.offset = 0
  68. if mte_dead_node(self.node) is True:
  69. continue
  70. return None
  71. self.node = None
  72. # Empty tree
  73. if root is None:
  74. self.status = self.ma_none
  75. self.offset = constants.LX_MAPLE_NODE_SLOTS
  76. return None
  77. # Single entry tree
  78. self.status = self.ma_root
  79. self.offset = constants.LX_MAPLE_NODE_SLOTS
  80. if self.index != 0:
  81. return None
  82. return root
  83. return None
  84. def reset(self):
  85. # mas_reset()
  86. self.status = self.ma_start
  87. self.node = None
  88. def mte_safe_root(node):
  89. if node.type != maple_enode_type.get_type().pointer():
  90. raise gdb.GdbError("{} must be {} not {}"
  91. .format(mte_safe_root.__name__, maple_enode_type.get_type().pointer(), node.type))
  92. ulong_type = utils.get_ulong_type()
  93. indirect_ptr = node.cast(ulong_type) & ~0x2
  94. val = indirect_ptr.cast(maple_enode_type.get_type().pointer())
  95. return val
  96. def mte_node_type(entry):
  97. ulong_type = utils.get_ulong_type()
  98. val = None
  99. if entry.type == maple_enode_type.get_type().pointer():
  100. val = entry.cast(ulong_type)
  101. elif entry.type == ulong_type:
  102. val = entry
  103. else:
  104. raise gdb.GdbError("{} must be {} not {}"
  105. .format(mte_node_type.__name__, maple_enode_type.get_type().pointer(), entry.type))
  106. return (val >> 0x3) & 0xf
  107. def ma_dead_node(node):
  108. if node.type != maple_node_type.get_type().pointer():
  109. raise gdb.GdbError("{} must be {} not {}"
  110. .format(ma_dead_node.__name__, maple_node_type.get_type().pointer(), node.type))
  111. ulong_type = utils.get_ulong_type()
  112. parent = node['parent']
  113. indirect_ptr = node['parent'].cast(ulong_type) & ~constants.LX_MAPLE_NODE_MASK
  114. return indirect_ptr == node
  115. def mte_to_node(enode):
  116. ulong_type = utils.get_ulong_type()
  117. if enode.type == maple_enode_type.get_type().pointer():
  118. indirect_ptr = enode.cast(ulong_type)
  119. elif enode.type == ulong_type:
  120. indirect_ptr = enode
  121. else:
  122. raise gdb.GdbError("{} must be {} not {}"
  123. .format(mte_to_node.__name__, maple_enode_type.get_type().pointer(), enode.type))
  124. indirect_ptr = indirect_ptr & ~constants.LX_MAPLE_NODE_MASK
  125. return indirect_ptr.cast(maple_node_type.get_type().pointer())
  126. def mte_dead_node(enode):
  127. if enode.type != maple_enode_type.get_type().pointer():
  128. raise gdb.GdbError("{} must be {} not {}"
  129. .format(mte_dead_node.__name__, maple_enode_type.get_type().pointer(), enode.type))
  130. node = mte_to_node(enode)
  131. return ma_dead_node(node)
  132. def ma_is_leaf(tp):
  133. result = tp < maple_range_64
  134. return tp < maple_range_64
  135. def mt_pivots(t):
  136. if t == maple_dense:
  137. return 0
  138. elif t == maple_leaf_64 or t == maple_range_64:
  139. return constants.LX_MAPLE_RANGE64_SLOTS - 1
  140. elif t == maple_arange_64:
  141. return constants.LX_MAPLE_ARANGE64_SLOTS - 1
  142. def ma_pivots(node, t):
  143. if node.type != maple_node_type.get_type().pointer():
  144. raise gdb.GdbError("{}: must be {} not {}"
  145. .format(ma_pivots.__name__, maple_node_type.get_type().pointer(), node.type))
  146. if t == maple_arange_64:
  147. return node['ma64']['pivot']
  148. elif t == maple_leaf_64 or t == maple_range_64:
  149. return node['mr64']['pivot']
  150. else:
  151. return None
  152. def ma_slots(node, tp):
  153. if node.type != maple_node_type.get_type().pointer():
  154. raise gdb.GdbError("{}: must be {} not {}"
  155. .format(ma_slots.__name__, maple_node_type.get_type().pointer(), node.type))
  156. if tp == maple_arange_64:
  157. return node['ma64']['slot']
  158. elif tp == maple_range_64 or tp == maple_leaf_64:
  159. return node['mr64']['slot']
  160. elif tp == maple_dense:
  161. return node['slot']
  162. else:
  163. return None
  164. def mt_slot(mt, slots, offset):
  165. ulong_type = utils.get_ulong_type()
  166. return slots[offset].cast(ulong_type)
  167. def mtree_lookup_walk(mas):
  168. ulong_type = utils.get_ulong_type()
  169. n = mas.node
  170. while True:
  171. node = mte_to_node(n)
  172. tp = mte_node_type(n)
  173. pivots = ma_pivots(node, tp)
  174. end = mt_pivots(tp)
  175. offset = 0
  176. while True:
  177. if pivots[offset] >= mas.index:
  178. break
  179. if offset >= end:
  180. break
  181. offset += 1
  182. slots = ma_slots(node, tp)
  183. n = mt_slot(mas.tree, slots, offset)
  184. if ma_dead_node(node) is True:
  185. mas.reset()
  186. return None
  187. break
  188. if ma_is_leaf(tp) is True:
  189. break
  190. return n
  191. def mtree_load(mt, index):
  192. ulong_type = utils.get_ulong_type()
  193. # MT_STATE(...)
  194. mas = Mas(mt, index, index)
  195. entry = None
  196. while True:
  197. entry = mas.start()
  198. if mas.is_none():
  199. return None
  200. if mas.is_ptr():
  201. if index != 0:
  202. entry = None
  203. return entry
  204. entry = mtree_lookup_walk(mas)
  205. if entry is None and mas.is_start():
  206. continue
  207. else:
  208. break
  209. if xarray.xa_is_zero(entry):
  210. return None
  211. return entry