1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <mdb/mdb_modapi.h> 29 30 typedef struct combined_walk { 31 int (*cw_init)(mdb_walk_state_t *); 32 int (*cw_step)(mdb_walk_state_t *); 33 void (*cw_fini)(mdb_walk_state_t *); 34 struct combined_walk *cw_next; 35 void *cw_data; 36 boolean_t cw_initialized; 37 } combined_walk_t; 38 39 typedef struct combined_walk_data { 40 uintptr_t cwd_initial_walk_addr; /* to init each walk */ 41 combined_walk_t *cwd_current_walk; 42 combined_walk_t *cwd_final_walk; /* tail pointer */ 43 } combined_walk_data_t; 44 45 /* 46 * Initialize a combined walk to 47 * A) present a single concatenated series of elements from different 48 * structures, or 49 * B) select from several possible walks at runtime. 50 * Multiple walks are done in the same order passed to combined_walk_add(). Each 51 * walk is initialized with the same wsp->walk_addr. 52 */ 53 void 54 combined_walk_init(mdb_walk_state_t *wsp) 55 { 56 combined_walk_data_t *cwd; 57 58 cwd = mdb_alloc(sizeof (combined_walk_data_t), UM_SLEEP); 59 60 cwd->cwd_initial_walk_addr = wsp->walk_addr; 61 cwd->cwd_current_walk = cwd->cwd_final_walk = NULL; 62 wsp->walk_data = cwd; 63 } 64 65 static void 66 combined_walk_append(combined_walk_data_t *cwd, combined_walk_t *cw) 67 { 68 if (cwd->cwd_final_walk == NULL) { 69 cwd->cwd_current_walk = cwd->cwd_final_walk = cw; 70 } else { 71 cwd->cwd_final_walk->cw_next = cw; 72 cwd->cwd_final_walk = cw; 73 } 74 } 75 76 static combined_walk_t * 77 combined_walk_remove_current(combined_walk_data_t *cwd) 78 { 79 combined_walk_t *cw = cwd->cwd_current_walk; 80 if (cw == NULL) { 81 return (NULL); 82 } 83 if (cw == cwd->cwd_final_walk) { 84 cwd->cwd_final_walk = cw->cw_next; 85 } 86 cwd->cwd_current_walk = cw->cw_next; 87 cw->cw_next = NULL; 88 return (cw); 89 } 90 91 void 92 combined_walk_add(mdb_walk_state_t *wsp, 93 int (*walk_init)(mdb_walk_state_t *), 94 int (*walk_step)(mdb_walk_state_t *), 95 void (*walk_fini)(mdb_walk_state_t *)) 96 { 97 combined_walk_data_t *cwd = wsp->walk_data; 98 combined_walk_t *cw; 99 100 cw = mdb_alloc(sizeof (combined_walk_t), UM_SLEEP); 101 102 cw->cw_init = walk_init; 103 cw->cw_step = walk_step; 104 cw->cw_fini = walk_fini; 105 cw->cw_next = NULL; 106 cw->cw_data = NULL; 107 cw->cw_initialized = B_FALSE; 108 109 combined_walk_append(cwd, cw); 110 } 111 112 int 113 combined_walk_step(mdb_walk_state_t *wsp) 114 { 115 combined_walk_data_t *cwd = wsp->walk_data; 116 combined_walk_t *cw = cwd->cwd_current_walk; 117 int status; 118 119 if (cw == NULL) { 120 return (WALK_DONE); 121 } 122 123 if (cw->cw_initialized) { 124 wsp->walk_data = cw->cw_data; 125 } else { 126 wsp->walk_addr = cwd->cwd_initial_walk_addr; 127 status = cw->cw_init(wsp); 128 cw->cw_data = wsp->walk_data; 129 cw->cw_initialized = B_TRUE; 130 if (status != WALK_NEXT) { 131 wsp->walk_data = cwd; 132 return (status); 133 } 134 } 135 136 status = cw->cw_step(wsp); 137 138 if (status == WALK_DONE) { 139 (void) combined_walk_remove_current(cwd); 140 cw->cw_fini(wsp); 141 mdb_free(cw, sizeof (combined_walk_t)); 142 wsp->walk_data = cwd; 143 return (combined_walk_step(wsp)); 144 } 145 146 wsp->walk_data = cwd; 147 return (status); 148 } 149 150 void 151 combined_walk_fini(mdb_walk_state_t *wsp) 152 { 153 combined_walk_data_t *cwd = wsp->walk_data; 154 combined_walk_t *cw; 155 156 while ((cw = combined_walk_remove_current(cwd)) != NULL) { 157 if (cw->cw_initialized) { 158 wsp->walk_data = cw->cw_data; 159 cw->cw_fini(wsp); 160 } 161 mdb_free(cw, sizeof (combined_walk_t)); 162 } 163 164 mdb_free(cwd, sizeof (combined_walk_data_t)); 165 } 166