forked from mirrors/linux
		
	Add inorder iteration function for rbtree usage.
This is a preparation patch for the next patch to fix the gdb mounts
issue.
Link: https://lkml.kernel.org/r/20240723064902.124154-3-kuan-ying.lee@canonical.com
Fixes: 2eea9ce431 ("mounts: keep list of mounts in an rbtree")
Signed-off-by: Kuan-Ying Lee <kuan-ying.lee@canonical.com>
Cc: Jan Kiszka <jan.kiszka@siemens.com>
Cc: Kieran Bingham <kbingham@kernel.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
		
	
			
		
			
				
	
	
		
			189 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			189 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# 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()
 |