| # SPDX-License-Identifier: GPL-2.0 | |
| # | |
| # Copyright 2019 Google LLC. | |
| import gdb | |
| from linux import utils | |
| rb_root_type = utils.CachedType("struct rb_root") | |
| rb_node_type = utils.CachedType("struct rb_node") | |
| def rb_inorder_for_each(root): | |
| def inorder(node): | |
| if node: | |
| yield from inorder(node['rb_left']) | |
| yield node | |
| yield from inorder(node['rb_right']) | |
| yield from inorder(root['rb_node']) | |
| def rb_inorder_for_each_entry(root, gdbtype, member): | |
| for node in rb_inorder_for_each(root): | |
| yield utils.container_of(node, gdbtype, member) | |
| def rb_first(root): | |
| if root.type == rb_root_type.get_type(): | |
| node = root.address.cast(rb_root_type.get_type().pointer()) | |
| elif root.type != rb_root_type.get_type().pointer(): | |
| raise gdb.GdbError("Must be struct rb_root not {}".format(root.type)) | |
| node = root['rb_node'] | |
| if node == 0: | |
| return None | |
| while node['rb_left']: | |
| node = node['rb_left'] | |
| return node | |
| def rb_last(root): | |
| if root.type == rb_root_type.get_type(): | |
| node = root.address.cast(rb_root_type.get_type().pointer()) | |
| elif root.type != rb_root_type.get_type().pointer(): | |
| raise gdb.GdbError("Must be struct rb_root not {}".format(root.type)) | |
| node = root['rb_node'] | |
| if node == 0: | |
| return None | |
| while node['rb_right']: | |
| node = node['rb_right'] | |
| return node | |
| def rb_parent(node): | |
| parent = gdb.Value(node['__rb_parent_color'] & ~3) | |
| return parent.cast(rb_node_type.get_type().pointer()) | |
| def rb_empty_node(node): | |
| return node['__rb_parent_color'] == node.address | |
| def rb_next(node): | |
| if node.type == rb_node_type.get_type(): | |
| node = node.address.cast(rb_node_type.get_type().pointer()) | |
| elif node.type != rb_node_type.get_type().pointer(): | |
| raise gdb.GdbError("Must be struct rb_node not {}".format(node.type)) | |
| if rb_empty_node(node): | |
| return None | |
| if node['rb_right']: | |
| node = node['rb_right'] | |
| while node['rb_left']: | |
| node = node['rb_left'] | |
| return node | |
| parent = rb_parent(node) | |
| while parent and node == parent['rb_right']: | |
| node = parent | |
| parent = rb_parent(node) | |
| return parent | |
| def rb_prev(node): | |
| if node.type == rb_node_type.get_type(): | |
| node = node.address.cast(rb_node_type.get_type().pointer()) | |
| elif node.type != rb_node_type.get_type().pointer(): | |
| raise gdb.GdbError("Must be struct rb_node not {}".format(node.type)) | |
| if rb_empty_node(node): | |
| return None | |
| if node['rb_left']: | |
| node = node['rb_left'] | |
| while node['rb_right']: | |
| node = node['rb_right'] | |
| return node.dereference() | |
| parent = rb_parent(node) | |
| while parent and node == parent['rb_left'].dereference(): | |
| node = parent | |
| parent = rb_parent(node) | |
| return parent | |
| class LxRbFirst(gdb.Function): | |
| """Lookup and return a node from an RBTree | |
| $lx_rb_first(root): Return the node at the given index. | |
| If index is omitted, the root node is dereferenced and returned.""" | |
| def __init__(self): | |
| super(LxRbFirst, self).__init__("lx_rb_first") | |
| def invoke(self, root): | |
| result = rb_first(root) | |
| if result is None: | |
| raise gdb.GdbError("No entry in tree") | |
| return result | |
| LxRbFirst() | |
| class LxRbLast(gdb.Function): | |
| """Lookup and return a node from an RBTree. | |
| $lx_rb_last(root): Return the node at the given index. | |
| If index is omitted, the root node is dereferenced and returned.""" | |
| def __init__(self): | |
| super(LxRbLast, self).__init__("lx_rb_last") | |
| def invoke(self, root): | |
| result = rb_last(root) | |
| if result is None: | |
| raise gdb.GdbError("No entry in tree") | |
| return result | |
| LxRbLast() | |
| class LxRbNext(gdb.Function): | |
| """Lookup and return a node from an RBTree. | |
| $lx_rb_next(node): Return the node at the given index. | |
| If index is omitted, the root node is dereferenced and returned.""" | |
| def __init__(self): | |
| super(LxRbNext, self).__init__("lx_rb_next") | |
| def invoke(self, node): | |
| result = rb_next(node) | |
| if result is None: | |
| raise gdb.GdbError("No entry in tree") | |
| return result | |
| LxRbNext() | |
| class LxRbPrev(gdb.Function): | |
| """Lookup and return a node from an RBTree. | |
| $lx_rb_prev(node): Return the node at the given index. | |
| If index is omitted, the root node is dereferenced and returned.""" | |
| def __init__(self): | |
| super(LxRbPrev, self).__init__("lx_rb_prev") | |
| def invoke(self, node): | |
| result = rb_prev(node) | |
| if result is None: | |
| raise gdb.GdbError("No entry in tree") | |
| return result | |
| LxRbPrev() |