summaryrefslogtreecommitdiff
path: root/usr/src/cmd/mdb/common/modules/genunix/avl.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/mdb/common/modules/genunix/avl.c')
-rw-r--r--usr/src/cmd/mdb/common/modules/genunix/avl.c110
1 files changed, 89 insertions, 21 deletions
diff --git a/usr/src/cmd/mdb/common/modules/genunix/avl.c b/usr/src/cmd/mdb/common/modules/genunix/avl.c
index b10856cfc3..444af78fa1 100644
--- a/usr/src/cmd/mdb/common/modules/genunix/avl.c
+++ b/usr/src/cmd/mdb/common/modules/genunix/avl.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -31,8 +30,12 @@
#include <mdb/mdb_modapi.h>
struct aw_info {
- void *aw_buff; /* buffer to hold the tree's data structure */
+ void *aw_buff; /* buffer to hold tree element */
avl_tree_t aw_tree; /* copy of avl_tree_t being walked */
+ uintptr_t aw_end; /* last node in specified range */
+ const char *aw_elem_name;
+ int (*aw_elem_check)(void *, uintptr_t, void *);
+ void *aw_elem_check_arg;
};
/*
@@ -40,14 +43,15 @@ struct aw_info {
* an AVL node
*/
static uintptr_t
-avl_leftmostchild(uintptr_t addr, void * buff, size_t offset, size_t size)
+avl_leftmostchild(uintptr_t addr, void *buff, size_t offset, size_t size,
+ const char *elem_name)
{
avl_node_t *node = (avl_node_t *)((uintptr_t)buff + offset);
for (;;) {
addr -= offset;
if (mdb_vread(buff, size, addr) == -1) {
- mdb_warn("read of avl_node_t failed: %p", addr);
+ mdb_warn("failed to read %s at %#lx", elem_name, addr);
return ((uintptr_t)-1L);
}
if (node->avl_child[0] == NULL)
@@ -59,14 +63,32 @@ avl_leftmostchild(uintptr_t addr, void * buff, size_t offset, size_t size)
/*
* initialize a forward walk thru an avl tree.
+ *
+ * begin and end optionally specify objects other than the first and last
+ * objects in the tree; either or both may be NULL (defaulting to first and
+ * last).
+ *
+ * avl_name and element_name specify command-specific labels other than
+ * "avl_tree_t" and "tree element" for use in error messages.
+ *
+ * element_check() returns -1, 1, or 0: abort the walk with an error, stop
+ * without an error, or allow the normal callback; arg is an optional user
+ * argument to element_check().
*/
int
-avl_walk_init(mdb_walk_state_t *wsp)
+avl_walk_init_range(mdb_walk_state_t *wsp, uintptr_t begin, uintptr_t end,
+ const char *avl_name, const char *element_name,
+ int (*element_check)(void *, uintptr_t, void *), void *arg)
{
struct aw_info *aw;
avl_tree_t *tree;
uintptr_t addr;
+ if (avl_name == NULL)
+ avl_name = "avl_tree_t";
+ if (element_name == NULL)
+ element_name = "tree element";
+
/*
* allocate the AVL walk data
*/
@@ -77,7 +99,7 @@ avl_walk_init(mdb_walk_state_t *wsp)
*/
tree = &aw->aw_tree;
if (mdb_vread(tree, sizeof (avl_tree_t), wsp->walk_addr) == -1) {
- mdb_warn("read of avl_tree_t failed: %p", wsp->walk_addr);
+ mdb_warn("failed to read %s at %#lx", avl_name, wsp->walk_addr);
goto error;
}
if (tree->avl_size < tree->avl_offset + sizeof (avl_node_t)) {
@@ -91,22 +113,30 @@ avl_walk_init(mdb_walk_state_t *wsp)
* "node" always points at the avl_node_t field inside the struct
*/
aw->aw_buff = mdb_zalloc(tree->avl_size, UM_SLEEP);
+ aw->aw_end = (end == NULL ? NULL : end + tree->avl_offset);
+ aw->aw_elem_name = element_name;
+ aw->aw_elem_check = element_check;
+ aw->aw_elem_check_arg = arg;
/*
* get the first avl_node_t address, use same algorithm
* as avl_start() -- leftmost child in tree from root
*/
- addr = (uintptr_t)tree->avl_root;
- if (addr == NULL) {
- wsp->walk_addr = NULL;
- return (WALK_NEXT);
+ if (begin == NULL) {
+ addr = (uintptr_t)tree->avl_root;
+ if (addr == NULL) {
+ wsp->walk_addr = NULL;
+ return (WALK_NEXT);
+ }
+ addr = avl_leftmostchild(addr, aw->aw_buff, tree->avl_offset,
+ tree->avl_size, aw->aw_elem_name);
+ if (addr == (uintptr_t)-1L)
+ goto error;
+ wsp->walk_addr = addr;
+ } else {
+ wsp->walk_addr = begin + tree->avl_offset;
}
- addr = avl_leftmostchild(addr, aw->aw_buff, tree->avl_offset,
- tree->avl_size);
- if (addr == (uintptr_t)-1L)
- goto error;
- wsp->walk_addr = addr;
return (WALK_NEXT);
error:
@@ -116,6 +146,29 @@ error:
return (WALK_ERR);
}
+int
+avl_walk_init(mdb_walk_state_t *wsp)
+{
+ return (avl_walk_init_range(wsp, NULL, NULL, NULL, NULL, NULL, NULL));
+}
+
+int
+avl_walk_init_named(mdb_walk_state_t *wsp,
+ const char *avl_name, const char *element_name)
+{
+ return (avl_walk_init_range(wsp, NULL, NULL, avl_name, element_name,
+ NULL, NULL));
+}
+
+int
+avl_walk_init_checked(mdb_walk_state_t *wsp,
+ const char *avl_name, const char *element_name,
+ int (*element_check)(void *, uintptr_t, void *), void *arg)
+{
+ return (avl_walk_init_range(wsp, NULL, NULL, avl_name, element_name,
+ element_check, arg));
+}
+
/*
* At each step, visit (callback) the current node, then move to the next
* in the AVL tree. Uses the same algorithm as avl_walk().
@@ -139,6 +192,10 @@ avl_walk_step(mdb_walk_state_t *wsp)
return (WALK_DONE);
aw = (struct aw_info *)wsp->walk_data;
+
+ if (aw->aw_end != NULL && wsp->walk_addr == aw->aw_end)
+ return (WALK_DONE);
+
size = aw->aw_tree.avl_size;
offset = aw->aw_tree.avl_offset;
node = (avl_node_t *)((uintptr_t)aw->aw_buff + offset);
@@ -147,10 +204,19 @@ avl_walk_step(mdb_walk_state_t *wsp)
* must read the current node for the call back to use
*/
if (mdb_vread(aw->aw_buff, size, addr) == -1) {
- mdb_warn("read of avl_node_t failed: %p", addr);
+ mdb_warn("failed to read %s at %#lx", aw->aw_elem_name, addr);
return (WALK_ERR);
}
+ if (aw->aw_elem_check != NULL) {
+ int rc = aw->aw_elem_check(aw->aw_buff, addr,
+ aw->aw_elem_check_arg);
+ if (rc == -1)
+ return (WALK_ERR);
+ else if (rc == 1)
+ return (WALK_DONE);
+ }
+
/*
* do the call back
*/
@@ -169,7 +235,8 @@ avl_walk_step(mdb_walk_state_t *wsp)
*/
addr = (uintptr_t)node->avl_child[1];
if (addr != NULL) {
- addr = avl_leftmostchild(addr, aw->aw_buff, offset, size);
+ addr = avl_leftmostchild(addr, aw->aw_buff, offset, size,
+ aw->aw_elem_name);
if (addr == (uintptr_t)-1L)
return (WALK_ERR);
@@ -187,7 +254,8 @@ avl_walk_step(mdb_walk_state_t *wsp)
if (was_child == 0) /* stop on return from left child */
break;
if (mdb_vread(aw->aw_buff, size, addr) == -1) {
- mdb_warn("read of avl_node_t failed: %p", addr);
+ mdb_warn("failed to read %s at %#lx",
+ aw->aw_elem_name, addr);
return (WALK_ERR);
}
}