1*789Sahrens /* 2*789Sahrens * CDDL HEADER START 3*789Sahrens * 4*789Sahrens * The contents of this file are subject to the terms of the 5*789Sahrens * Common Development and Distribution License, Version 1.0 only 6*789Sahrens * (the "License"). You may not use this file except in compliance 7*789Sahrens * with the License. 8*789Sahrens * 9*789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*789Sahrens * or http://www.opensolaris.org/os/licensing. 11*789Sahrens * See the License for the specific language governing permissions 12*789Sahrens * and limitations under the License. 13*789Sahrens * 14*789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 15*789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*789Sahrens * If applicable, add the following below this CDDL HEADER, with the 17*789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 18*789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 19*789Sahrens * 20*789Sahrens * CDDL HEADER END 21*789Sahrens */ 22*789Sahrens /* 23*789Sahrens * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*789Sahrens * Use is subject to license terms. 25*789Sahrens */ 26*789Sahrens 27*789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 28*789Sahrens 29*789Sahrens #include <sys/avl.h> 30*789Sahrens 31*789Sahrens #include <mdb/mdb_modapi.h> 32*789Sahrens 33*789Sahrens struct aw_info { 34*789Sahrens void *aw_buff; /* buffer to hold the tree's data structure */ 35*789Sahrens avl_tree_t aw_tree; /* copy of avl_tree_t being walked */ 36*789Sahrens }; 37*789Sahrens 38*789Sahrens /* 39*789Sahrens * common code used to find the addr of the the leftmost child below 40*789Sahrens * an AVL node 41*789Sahrens */ 42*789Sahrens static uintptr_t 43*789Sahrens avl_leftmostchild(uintptr_t addr, void * buff, size_t offset, size_t size) 44*789Sahrens { 45*789Sahrens avl_node_t *node = (avl_node_t *)((uintptr_t)buff + offset); 46*789Sahrens 47*789Sahrens for (;;) { 48*789Sahrens addr -= offset; 49*789Sahrens if (mdb_vread(buff, size, addr) == -1) { 50*789Sahrens mdb_warn("read of avl_node_t failed: %p", addr); 51*789Sahrens return ((uintptr_t)-1L); 52*789Sahrens } 53*789Sahrens if (node->avl_child[0] == NULL) 54*789Sahrens break; 55*789Sahrens addr = (uintptr_t)node->avl_child[0]; 56*789Sahrens } 57*789Sahrens return (addr); 58*789Sahrens } 59*789Sahrens 60*789Sahrens /* 61*789Sahrens * initialize a forward walk thru an avl tree. 62*789Sahrens */ 63*789Sahrens int 64*789Sahrens avl_walk_init(mdb_walk_state_t *wsp) 65*789Sahrens { 66*789Sahrens struct aw_info *aw; 67*789Sahrens avl_tree_t *tree; 68*789Sahrens uintptr_t addr; 69*789Sahrens 70*789Sahrens /* 71*789Sahrens * allocate the AVL walk data 72*789Sahrens */ 73*789Sahrens wsp->walk_data = aw = mdb_zalloc(sizeof (struct aw_info), UM_SLEEP); 74*789Sahrens 75*789Sahrens /* 76*789Sahrens * get an mdb copy of the avl_tree_t being walked 77*789Sahrens */ 78*789Sahrens tree = &aw->aw_tree; 79*789Sahrens if (mdb_vread(tree, sizeof (avl_tree_t), wsp->walk_addr) == -1) { 80*789Sahrens mdb_warn("read of avl_tree_t failed: %p", wsp->walk_addr); 81*789Sahrens goto error; 82*789Sahrens } 83*789Sahrens if (tree->avl_size < tree->avl_offset + sizeof (avl_node_t)) { 84*789Sahrens mdb_warn("invalid avl_tree_t at %p, avl_size:%d, avl_offset:%d", 85*789Sahrens wsp->walk_addr, tree->avl_size, tree->avl_offset); 86*789Sahrens goto error; 87*789Sahrens } 88*789Sahrens 89*789Sahrens /* 90*789Sahrens * allocate a buffer to hold the mdb copy of tree's structs 91*789Sahrens * "node" always points at the avl_node_t field inside the struct 92*789Sahrens */ 93*789Sahrens aw->aw_buff = mdb_zalloc(tree->avl_size, UM_SLEEP); 94*789Sahrens 95*789Sahrens /* 96*789Sahrens * get the first avl_node_t address, use same algorithm 97*789Sahrens * as avl_start() -- leftmost child in tree from root 98*789Sahrens */ 99*789Sahrens addr = (uintptr_t)tree->avl_root; 100*789Sahrens if (addr == NULL) { 101*789Sahrens wsp->walk_addr = NULL; 102*789Sahrens return (WALK_NEXT); 103*789Sahrens } 104*789Sahrens addr = avl_leftmostchild(addr, aw->aw_buff, tree->avl_offset, 105*789Sahrens tree->avl_size); 106*789Sahrens if (addr == (uintptr_t)-1L) 107*789Sahrens goto error; 108*789Sahrens 109*789Sahrens wsp->walk_addr = addr; 110*789Sahrens return (WALK_NEXT); 111*789Sahrens 112*789Sahrens error: 113*789Sahrens if (aw->aw_buff != NULL) 114*789Sahrens mdb_free(aw->aw_buff, sizeof (tree->avl_size)); 115*789Sahrens mdb_free(aw, sizeof (struct aw_info)); 116*789Sahrens return (WALK_ERR); 117*789Sahrens } 118*789Sahrens 119*789Sahrens /* 120*789Sahrens * At each step, visit (callback) the current node, then move to the next 121*789Sahrens * in the AVL tree. Uses the same algorithm as avl_walk(). 122*789Sahrens */ 123*789Sahrens int 124*789Sahrens avl_walk_step(mdb_walk_state_t *wsp) 125*789Sahrens { 126*789Sahrens struct aw_info *aw; 127*789Sahrens size_t offset; 128*789Sahrens size_t size; 129*789Sahrens uintptr_t addr; 130*789Sahrens avl_node_t *node; 131*789Sahrens int status; 132*789Sahrens int was_child; 133*789Sahrens 134*789Sahrens /* 135*789Sahrens * don't walk past the end of the tree! 136*789Sahrens */ 137*789Sahrens addr = wsp->walk_addr; 138*789Sahrens if (addr == NULL) 139*789Sahrens return (WALK_DONE); 140*789Sahrens 141*789Sahrens aw = (struct aw_info *)wsp->walk_data; 142*789Sahrens size = aw->aw_tree.avl_size; 143*789Sahrens offset = aw->aw_tree.avl_offset; 144*789Sahrens node = (avl_node_t *)((uintptr_t)aw->aw_buff + offset); 145*789Sahrens 146*789Sahrens /* 147*789Sahrens * must read the current node for the call back to use 148*789Sahrens */ 149*789Sahrens if (mdb_vread(aw->aw_buff, size, addr) == -1) { 150*789Sahrens mdb_warn("read of avl_node_t failed: %p", addr); 151*789Sahrens return (WALK_ERR); 152*789Sahrens } 153*789Sahrens 154*789Sahrens /* 155*789Sahrens * do the call back 156*789Sahrens */ 157*789Sahrens status = wsp->walk_callback(addr, aw->aw_buff, wsp->walk_cbdata); 158*789Sahrens if (status != WALK_NEXT) 159*789Sahrens return (status); 160*789Sahrens 161*789Sahrens /* 162*789Sahrens * move to the next node.... 163*789Sahrens * note we read in new nodes, so the pointer to the buffer is fixed 164*789Sahrens */ 165*789Sahrens 166*789Sahrens /* 167*789Sahrens * if the node has a right child then go to it and then all the way 168*789Sahrens * thru as many left children as possible 169*789Sahrens */ 170*789Sahrens addr = (uintptr_t)node->avl_child[1]; 171*789Sahrens if (addr != NULL) { 172*789Sahrens addr = avl_leftmostchild(addr, aw->aw_buff, offset, size); 173*789Sahrens if (addr == (uintptr_t)-1L) 174*789Sahrens return (WALK_ERR); 175*789Sahrens 176*789Sahrens /* 177*789Sahrens * othewise return to parent nodes, stopping if we ever return from 178*789Sahrens * a left child 179*789Sahrens */ 180*789Sahrens } else { 181*789Sahrens for (;;) { 182*789Sahrens was_child = AVL_XCHILD(node); 183*789Sahrens addr = (uintptr_t)AVL_XPARENT(node); 184*789Sahrens if (addr == NULL) 185*789Sahrens break; 186*789Sahrens addr -= offset; 187*789Sahrens if (was_child == 0) /* stop on return from left child */ 188*789Sahrens break; 189*789Sahrens if (mdb_vread(aw->aw_buff, size, addr) == -1) { 190*789Sahrens mdb_warn("read of avl_node_t failed: %p", addr); 191*789Sahrens return (WALK_ERR); 192*789Sahrens } 193*789Sahrens } 194*789Sahrens } 195*789Sahrens 196*789Sahrens wsp->walk_addr = addr; 197*789Sahrens return (WALK_NEXT); 198*789Sahrens } 199*789Sahrens 200*789Sahrens /* 201*789Sahrens * Release the memory allocated for the walk 202*789Sahrens */ 203*789Sahrens void 204*789Sahrens avl_walk_fini(mdb_walk_state_t *wsp) 205*789Sahrens { 206*789Sahrens struct aw_info *aw; 207*789Sahrens 208*789Sahrens aw = (struct aw_info *)wsp->walk_data; 209*789Sahrens 210*789Sahrens if (aw == NULL) 211*789Sahrens return; 212*789Sahrens 213*789Sahrens if (aw->aw_buff != NULL) 214*789Sahrens mdb_free(aw->aw_buff, aw->aw_tree.avl_size); 215*789Sahrens 216*789Sahrens mdb_free(aw, sizeof (struct aw_info)); 217*789Sahrens } 218