summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--scripts/gdb/linux/radixtree.py66
1 files changed, 40 insertions, 26 deletions
diff --git a/scripts/gdb/linux/radixtree.py b/scripts/gdb/linux/radixtree.py
index bc2954e45c32..8ce9936dfa50 100644
--- a/scripts/gdb/linux/radixtree.py
+++ b/scripts/gdb/linux/radixtree.py
@@ -27,6 +27,24 @@ def entry_to_node(node):
indirect_ptr = node.cast(long_type) & ~constants.LX_RADIX_TREE_INTERNAL_NODE
return indirect_ptr.cast(radix_tree_node_type.get_type().pointer())
+def is_node(entry):
+ # Like xa_is_node(): internal entries below 4096 are sibling, retry
+ # or zero entries rather than pointers to a struct xa_node.
+ ulong_type = utils.get_ulong_type()
+ return is_internal_node(entry) and entry.cast(ulong_type) > 4096
+
+def is_sibling(entry):
+ # Like xa_is_sibling(): a multi-index entry occupies several slots,
+ # and all but the first hold a sibling entry that encodes the offset
+ # of the first one.
+ ulong_type = utils.get_ulong_type()
+ return is_internal_node(entry) and entry.cast(ulong_type) < \
+ xa_mk_internal(constants.LX_RADIX_TREE_MAP_SIZE - 1)
+
+def sibling_offset(entry):
+ ulong_type = utils.get_ulong_type()
+ return int(entry.cast(ulong_type)) >> 2
+
def node_maxindex(node):
return (constants.LX_RADIX_TREE_MAP_SIZE << node['shift']) - 1
@@ -40,39 +58,35 @@ def resolve_root(root):
def lookup(root, index):
root = resolve_root(root)
- node = root['xa_head']
- if node == 0:
- return None
+ entry = root['xa_head']
- if not (is_internal_node(node)):
- if (index > 0):
+ if is_node(entry):
+ node = entry_to_node(entry)
+ if index > node_maxindex(node):
return None
- return node
- node = entry_to_node(node)
- maxindex = node_maxindex(node)
-
- if (index > maxindex):
- return None
-
- shift = node['shift'] + constants.LX_RADIX_TREE_MAP_SHIFT
-
- while True:
- offset = (index >> node['shift']) & constants.LX_RADIX_TREE_MAP_MASK
- slot = node['slots'][offset]
+ # Walk down the tree like xas_load() does.
+ while True:
+ offset = (index >> node['shift']) & constants.LX_RADIX_TREE_MAP_MASK
+ entry = node['slots'][offset]
- if slot == 0:
- return None
+ while is_sibling(entry):
+ entry = node['slots'][sibling_offset(entry)]
+ if node['shift'] and is_node(entry):
+ # xas_descend() turns this into a retry entry.
+ return None
- node = slot.cast(node.type.pointer()).dereference()
- if node == 0:
- return None
+ if not is_node(entry) or node['shift'] == 0:
+ break
+ node = entry_to_node(entry)
+ elif index > 0:
+ return None
- shift -= constants.LX_RADIX_TREE_MAP_SHIFT
- if (shift <= 0):
- break
+ # Empty slots and retry or zero entries hold no data.
+ if entry == 0 or is_internal_node(entry):
+ return None
- return node
+ return entry
def descend(parent, index):
offset = (index >> int(parent["shift"])) & constants.LX_RADIX_TREE_MAP_MASK