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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <mdb/mdb_modapi.h> 30 31 #include <pthread.h> 32 #include <stddef.h> 33 34 #include <libuutil.h> 35 #include <libuutil_impl.h> 36 37 /*ARGSUSED*/ 38 static int 39 uutil_status(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 40 { 41 pthread_t uu_panic_thread = 0; 42 43 if ((flags & DCMD_ADDRSPEC) || argc != 0) 44 return (DCMD_USAGE); 45 46 if (mdb_readvar(&uu_panic_thread, "uu_panic_thread") == -1) { 47 mdb_warn("unable to read uu_panic_thread"); 48 } 49 50 if (uu_panic_thread != 0) { 51 mdb_printf("thread %d uu_panicked\n", uu_panic_thread); 52 } 53 54 return (DCMD_OK); 55 } 56 57 /*ARGSUSED*/ 58 static int 59 uutil_listpool(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 60 { 61 uu_list_pool_t ulp; 62 63 if (!(flags & DCMD_ADDRSPEC)) { 64 if (mdb_walk_dcmd("uu_list_pool", "uu_list_pool", argc, 65 argv) == -1) { 66 mdb_warn("can't walk uu_list_pool"); 67 return (DCMD_ERR); 68 } 69 return (DCMD_OK); 70 } 71 72 if (argc != 0) 73 return (DCMD_USAGE); 74 75 if (DCMD_HDRSPEC(flags)) 76 mdb_printf("%-?s %-30s %?s %5s\n", 77 "ADDR", "NAME", "COMPARE", "FLAGS"); 78 79 if (mdb_vread(&ulp, sizeof (uu_list_pool_t), addr) == -1) { 80 mdb_warn("failed to read uu_list_pool\n"); 81 return (DCMD_ERR); 82 } 83 84 mdb_printf("%0?p %-30s %08x %c\n", addr, ulp.ulp_name, ulp.ulp_cmp, 85 ulp.ulp_debug ? 'D' : ' '); 86 87 return (DCMD_OK); 88 } 89 90 /*ARGSUSED*/ 91 static int 92 uutil_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 93 { 94 uu_list_t ul; 95 96 if (!(flags & DCMD_ADDRSPEC) || argc != 0) 97 return (DCMD_USAGE); 98 99 if (mdb_vread(&ul, sizeof (uu_list_t), addr) == -1) { 100 mdb_warn("failed to read uu_list\n"); 101 return (DCMD_ERR); 102 } 103 104 if (DCMD_HDRSPEC(flags)) 105 mdb_printf("%-?s %-?s %-?s %6s %5s\n", 106 "ADDR", "POOL", "PARENT", "NODES", "FLAGS"); 107 108 mdb_printf("%0?p %0?p %0?p %6u %c%c\n", 109 addr, ul.ul_pool, UU_PTR_DECODE(ul.ul_parent_enc), 110 ul.ul_numnodes, ul.ul_sorted ? 'S' : ' ', ul.ul_debug? 'D' : ' '); 111 112 return (DCMD_OK); 113 } 114 115 typedef struct uutil_listpool_walk { 116 uintptr_t ulpw_final; 117 uintptr_t ulpw_current; 118 } uutil_listpool_walk_t; 119 120 int 121 uutil_listpool_walk_init(mdb_walk_state_t *wsp) 122 { 123 uu_list_pool_t null_lpool; 124 uutil_listpool_walk_t *ulpw; 125 GElf_Sym sym; 126 127 bzero(&null_lpool, sizeof (uu_list_pool_t)); 128 129 if (mdb_lookup_by_obj("libuutil.so.1", "uu_null_lpool", &sym) == 130 -1) { 131 mdb_warn("failed to find 'uu_null_lpool'\n"); 132 return (WALK_ERR); 133 } 134 135 if (mdb_vread(&null_lpool, sym.st_size, (uintptr_t)sym.st_value) == 136 -1) { 137 mdb_warn("failed to read data from 'uu_null_lpool' address\n"); 138 return (WALK_ERR); 139 } 140 141 ulpw = mdb_alloc(sizeof (uutil_listpool_walk_t), UM_SLEEP); 142 143 ulpw->ulpw_final = (uintptr_t)null_lpool.ulp_prev; 144 ulpw->ulpw_current = (uintptr_t)null_lpool.ulp_next; 145 wsp->walk_data = ulpw; 146 147 return (WALK_NEXT); 148 } 149 150 int 151 uutil_listpool_walk_step(mdb_walk_state_t *wsp) 152 { 153 uu_list_pool_t ulp; 154 uutil_listpool_walk_t *ulpw = wsp->walk_data; 155 int status; 156 157 if (mdb_vread(&ulp, sizeof (uu_list_pool_t), 158 ulpw->ulpw_current) == -1) { 159 mdb_warn("failed to read uu_list_pool %x", ulpw->ulpw_current); 160 return (WALK_ERR); 161 } 162 163 status = wsp->walk_callback(ulpw->ulpw_current, &ulp, wsp->walk_cbdata); 164 165 if (ulpw->ulpw_current == ulpw->ulpw_final) 166 return (WALK_DONE); 167 168 ulpw->ulpw_current = (uintptr_t)ulp.ulp_next; 169 170 return (status); 171 } 172 173 void 174 uutil_listpool_walk_fini(mdb_walk_state_t *wsp) 175 { 176 uutil_listpool_walk_t *ulpw = wsp->walk_data; 177 mdb_free(ulpw, sizeof (uutil_listpool_walk_t)); 178 } 179 180 typedef struct uutil_list_walk { 181 uintptr_t ulw_final; 182 uintptr_t ulw_current; 183 } uutil_list_walk_t; 184 185 int 186 uutil_list_walk_init(mdb_walk_state_t *wsp) 187 { 188 uutil_list_walk_t *ulw; 189 uu_list_pool_t ulp; 190 191 if (mdb_vread(&ulp, sizeof (uu_list_pool_t), wsp->walk_addr) == -1) { 192 mdb_warn("failed to read uu_list_pool_t at given address\n"); 193 return (WALK_ERR); 194 } 195 196 if (UU_LIST_PTR(ulp.ulp_null_list.ul_next_enc) == 197 &((uu_list_pool_t *)wsp->walk_addr)->ulp_null_list) 198 return (WALK_DONE); 199 200 ulw = mdb_alloc(sizeof (uutil_list_walk_t), UM_SLEEP); 201 202 ulw->ulw_final = (uintptr_t)UU_LIST_PTR(ulp.ulp_null_list.ul_prev_enc); 203 ulw->ulw_current = 204 (uintptr_t)UU_LIST_PTR(ulp.ulp_null_list.ul_next_enc); 205 wsp->walk_data = ulw; 206 207 return (WALK_NEXT); 208 } 209 210 int 211 uutil_list_walk_step(mdb_walk_state_t *wsp) 212 { 213 uu_list_t ul; 214 uutil_list_walk_t *ulw = wsp->walk_data; 215 int status; 216 217 if (mdb_vread(&ul, sizeof (uu_list_t), ulw->ulw_current) == -1) { 218 mdb_warn("failed to read uu_list %x", ulw->ulw_current); 219 return (WALK_ERR); 220 } 221 222 status = wsp->walk_callback(ulw->ulw_current, &ul, wsp->walk_cbdata); 223 224 if (ulw->ulw_current == ulw->ulw_final) 225 return (WALK_DONE); 226 227 ulw->ulw_current = (uintptr_t)UU_LIST_PTR(ul.ul_next_enc); 228 229 return (status); 230 } 231 232 void 233 uutil_list_walk_fini(mdb_walk_state_t *wsp) 234 { 235 uutil_list_walk_t *ulw = wsp->walk_data; 236 mdb_free(ulw, sizeof (uutil_list_walk_t)); 237 } 238 239 typedef struct uutil_list_node_walk { 240 size_t ulnw_offset; 241 uintptr_t ulnw_final; 242 uintptr_t ulnw_current; 243 void *ulnw_buf; 244 size_t ulnw_bufsz; 245 } uutil_list_node_walk_t; 246 247 int 248 uutil_list_node_walk_init(mdb_walk_state_t *wsp) 249 { 250 uutil_list_node_walk_t *ulnw; 251 uu_list_t ul; 252 uu_list_pool_t ulp; 253 254 if (mdb_vread(&ul, sizeof (uu_list_t), wsp->walk_addr) == -1) { 255 mdb_warn("failed to read uu_list_t at given address\n"); 256 return (WALK_ERR); 257 } 258 259 if (mdb_vread(&ulp, sizeof (uu_list_pool_t), (uintptr_t)ul.ul_pool) == 260 -1) { 261 mdb_warn("failed to read supporting uu_list_pool_t\n"); 262 return (WALK_ERR); 263 } 264 265 ulnw = mdb_alloc(sizeof (uutil_list_node_walk_t), UM_SLEEP); 266 267 ulnw->ulnw_offset = ul.ul_offset; 268 ulnw->ulnw_final = wsp->walk_addr + offsetof(uu_list_t, ul_null_node); 269 ulnw->ulnw_current = (uintptr_t)ul.ul_null_node.uln_next; 270 ulnw->ulnw_buf = mdb_alloc(ulp.ulp_objsize, UM_SLEEP); 271 ulnw->ulnw_bufsz = ulp.ulp_objsize; 272 273 wsp->walk_data = ulnw; 274 275 return (WALK_NEXT); 276 } 277 278 int 279 uutil_list_node_walk_step(mdb_walk_state_t *wsp) 280 { 281 uu_list_node_impl_t uln; 282 uutil_list_node_walk_t *ulnw = wsp->walk_data; 283 int status; 284 uintptr_t diff; 285 286 if (ulnw->ulnw_current == ulnw->ulnw_final) 287 return (WALK_DONE); 288 289 if (mdb_vread(&uln, sizeof (uu_list_node_impl_t), ulnw->ulnw_current) == 290 -1) { 291 mdb_warn("failed to read uu_list_node %x", ulnw->ulnw_current); 292 return (WALK_ERR); 293 } 294 295 diff = ulnw->ulnw_current - ulnw->ulnw_offset; 296 297 if (mdb_vread(ulnw->ulnw_buf, ulnw->ulnw_bufsz, diff) == -1) { 298 mdb_warn("failed to read enclosing structure %x", diff); 299 return (WALK_ERR); 300 } 301 /* 302 * Correct for offset; we return the address of the included structure. 303 */ 304 status = wsp->walk_callback(diff, ulnw->ulnw_buf, wsp->walk_cbdata); 305 306 ulnw->ulnw_current = (uintptr_t)uln.uln_next; 307 308 return (status); 309 } 310 311 void 312 uutil_list_node_walk_fini(mdb_walk_state_t *wsp) 313 { 314 uutil_list_node_walk_t *ulnw = wsp->walk_data; 315 316 mdb_free(ulnw->ulnw_buf, ulnw->ulnw_bufsz); 317 mdb_free(ulnw, sizeof (uutil_list_node_walk_t)); 318 } 319 320 static const mdb_dcmd_t dcmds[] = { 321 { "uutil_status", NULL, "libuutil status summary", uutil_status }, 322 { "uu_list_pool", NULL, "display uu_list_pool information", 323 uutil_listpool }, 324 { "uu_list", NULL, "display uu_list information", 325 uutil_list }, 326 { NULL } 327 }; 328 329 static const mdb_walker_t walkers[] = { 330 { "uu_list_pool", "walk uu_list_pools", 331 uutil_listpool_walk_init, uutil_listpool_walk_step, 332 uutil_listpool_walk_fini }, 333 { "uu_list", "given a uu_list_pool, walk its uu_lists", 334 uutil_list_walk_init, uutil_list_walk_step, 335 uutil_list_walk_fini }, 336 { "uu_list_node", 337 "given a uu_list, walk its nodes, returning container addr", 338 uutil_list_node_walk_init, uutil_list_node_walk_step, 339 uutil_list_node_walk_fini }, 340 { NULL } 341 }; 342 343 static const mdb_modinfo_t modinfo = { 344 MDB_API_VERSION, dcmds, walkers 345 }; 346 347 const mdb_modinfo_t * 348 _mdb_init(void) 349 { 350 return (&modinfo); 351 } 352