Skip to content

Commit

Permalink
scripts/gdb: add rb tree iterating utilities
Browse files Browse the repository at this point in the history
Implement gdb functions for rb_first(), rb_last(), rb_next(), and
rb_prev().  These can be useful to iterate through the kernel's
red-black trees.

[[email protected]: v2]
  Link: http://lkml.kernel.org/r/[email protected]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Stephen Boyd <[email protected]>
Cc: Douglas Anderson <[email protected]>
Cc: Nikolay Borisov <[email protected]>
Cc: Kieran Bingham <[email protected]>
Cc: Jan Kiszka <[email protected]>
Cc: Jackie Liu <[email protected]>
Cc: Jason Wessel <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
bebarino authored and torvalds committed May 15, 2019
1 parent 90cf83d commit 449ca0c
Show file tree
Hide file tree
Showing 2 changed files with 178 additions and 0 deletions.
177 changes: 177 additions & 0 deletions scripts/gdb/linux/rbtree.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
# 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_first(root):
if root.type == rb_root_type.get_type():
node = node.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 is 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 = node.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 is 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()
1 change: 1 addition & 0 deletions scripts/gdb/vmlinux-gdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@
import linux.config
import linux.cpus
import linux.lists
import linux.rbtree
import linux.proc
import linux.constants

0 comments on commit 449ca0c

Please sign in to comment.