diff options
Diffstat (limited to 'scripts/gdb/linux/radixtree.py')
| -rw-r--r-- | scripts/gdb/linux/radixtree.py | 90 | 
1 files changed, 90 insertions, 0 deletions
| diff --git a/scripts/gdb/linux/radixtree.py b/scripts/gdb/linux/radixtree.py new file mode 100644 index 000000000000..074543ac763d --- /dev/null +++ b/scripts/gdb/linux/radixtree.py @@ -0,0 +1,90 @@ +# SPDX-License-Identifier: GPL-2.0 +# +#  Radix Tree Parser +# +# Copyright (c) 2016 Linaro Ltd +# Copyright (c) 2023 Broadcom +# +# Authors: +#  Kieran Bingham <kieran.bingham@linaro.org> +#  Florian Fainelli <f.fainelli@gmail.com> + +import gdb + +from linux import utils +from linux import constants + +radix_tree_root_type = utils.CachedType("struct xarray") +radix_tree_node_type = utils.CachedType("struct xa_node") + +def is_internal_node(node): +    long_type = utils.get_long_type() +    return ((node.cast(long_type) & constants.LX_RADIX_TREE_ENTRY_MASK) == constants.LX_RADIX_TREE_INTERNAL_NODE) + +def entry_to_node(node): +    long_type = utils.get_long_type() +    node_type = node.type +    indirect_ptr = node.cast(long_type) & ~constants.LX_RADIX_TREE_INTERNAL_NODE +    return indirect_ptr.cast(radix_tree_node_type.get_type().pointer()) + +def node_maxindex(node): +    return (constants.LX_RADIX_TREE_MAP_SIZE << node['shift']) - 1 + +def lookup(root, index): +    if root.type == radix_tree_root_type.get_type().pointer(): +        node = root.dereference() +    elif root.type != radix_tree_root_type.get_type(): +        raise gdb.GdbError("must be {} not {}" +                           .format(radix_tree_root_type.get_type(), root.type)) + +    node = root['xa_head'] +    if node == 0: +        return None + +    if not (is_internal_node(node)): +        if (index > 0): +            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] + +        if slot == 0: +            return None + +        node = slot.cast(node.type.pointer()).dereference() +        if node == 0: +            return None + +        shift -= constants.LX_RADIX_TREE_MAP_SHIFT +        if (shift <= 0): +            break + +    return node + +class LxRadixTree(gdb.Function): +    """ Lookup and return a node from a RadixTree. + +$lx_radix_tree_lookup(root_node [, index]): Return the node at the given index. +If index is omitted, the root node is dereference and returned.""" + +    def __init__(self): +        super(LxRadixTree, self).__init__("lx_radix_tree_lookup") + +    def invoke(self, root, index=0): +        result = lookup(root, index) +        if result is None: +            raise gdb.GdbError("No entry in tree at index {}".format(index)) + +        return result + +LxRadixTree() | 
