Source code for crash.types.rbtree

# -*- coding: utf-8 -*-
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:

from typing import Optional, Iterable

import gdb

from crash.util import container_of
from crash.util.symbols import Types
from crash.exceptions import ArgumentTypeError, UnexpectedGDBTypeError

[docs] class TreeError(Exception): pass
[docs] class CorruptTreeError(TreeError): pass
types = Types(['struct rb_root', 'struct rb_node']) def _rb_left_deepest_node(node: gdb.Value) -> Optional[gdb.Value]: while int(node) != 0: if int(node['rb_left']) != 0: node = node['rb_left'] elif int(node['rb_right']) != 0: node = node['rb_right'] else: return node return None def _rb_parent(node: gdb.Value) -> Optional[gdb.Value]: addr = int(node['__rb_parent_color']) addr &= ~0x3 if addr == 0: return None return gdb.Value(addr).cast(node.type) def _rb_next_postorder(node: gdb.Value) -> Optional[gdb.Value]: if int(node) == 0: return None parent = _rb_parent(node) if (parent is not None and int(node) == int(parent['rb_left']) and int(parent['rb_right']) != 0): return _rb_left_deepest_node(parent['rb_right']) return parent
[docs] def rbtree_postorder_for_each(root: gdb.Value) -> Iterable[gdb.Value]: """ Iterate over nodes of a rooted RB tree in post-order fashion Args: root: The tree to iterate. The value must be of type ``struct rb_root`` or ``struct rb_root *``. Yields: gdb.Value: The next node of the tree. The value is of type ``struct rb_node``. Raises: :obj:`.CorruptTreeError`: the list is corrupted """ if not isinstance(root, gdb.Value): raise ArgumentTypeError('root', root, gdb.Value) if root.type == types.rb_root_type.pointer(): root = root.dereference() elif root.type != types.rb_root_type: raise UnexpectedGDBTypeError('root', root, types.rb_root_type) if root.type is not types.rb_root_type: types.override('struct rb_root', root.type) if int(root.address) == 0: raise CorruptTreeError("root is NULL pointer") node = _rb_left_deepest_node(root['rb_node']) while node is not None: yield node.dereference() node = _rb_next_postorder(node)
[docs] def rbtree_postorder_for_each_entry(root: gdb.Value, gdbtype: gdb.Type, member: str) -> Iterable[gdb.Value]: """ Iterate over nodes of a rooted RB tree in post-order fashion and yield each node's containing object Args: root: The tree to iterate. The value must be of type ``struct rb_root`` or ``struct rb_root *``. gdbtype: The type of the containing object member: The name of the member in the containing object that corresponds to the rb_node Yields: gdb.Value: The next node of the tree. The value is of the specified type. Raises: :obj:`.CorruptTreeError`: the list is corrupted """ for node in rbtree_postorder_for_each(root): yield container_of(node, gdbtype, member)