diff options
Diffstat (limited to 'usr/src/cmd/mdb/common/modules/genunix/avl.c')
-rw-r--r-- | usr/src/cmd/mdb/common/modules/genunix/avl.c | 110 |
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); } } |