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 2004 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, ul.ul_parent, ul.ul_numnodes, 110 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 uu_list_t null_list; 189 uutil_list_walk_t *ulw; 190 uu_list_pool_t ulp; 191 192 bzero(&null_list, sizeof (uu_list_t)); 193 194 if (mdb_vread(&ulp, sizeof (uu_list_pool_t), wsp->walk_addr) == -1) { 195 mdb_warn("failed to read uu_list_pool_t at given address\n"); 196 return (WALK_ERR); 197 } 198 199 ulw = mdb_alloc(sizeof (uutil_list_walk_t), UM_SLEEP); 200 201 ulw->ulw_final = (uintptr_t)ulp.ulp_null_list.ul_prev; 202 ulw->ulw_current = (uintptr_t)ulp.ulp_null_list.ul_next; 203 wsp->walk_data = ulw; 204 205 return (WALK_NEXT); 206 } 207 208 int 209 uutil_list_walk_step(mdb_walk_state_t *wsp) 210 { 211 uu_list_t ul; 212 uutil_list_walk_t *ulw = wsp->walk_data; 213 int status; 214 215 if (mdb_vread(&ul, sizeof (uu_list_t), ulw->ulw_current) == -1) { 216 mdb_warn("failed to read uu_list %x", ulw->ulw_current); 217 return (WALK_ERR); 218 } 219 220 status = wsp->walk_callback(ulw->ulw_current, &ul, wsp->walk_cbdata); 221 222 if (ulw->ulw_current == ulw->ulw_final) 223 return (WALK_DONE); 224 225 ulw->ulw_current = (uintptr_t)ul.ul_next; 226 227 return (status); 228 } 229 230 void 231 uutil_list_walk_fini(mdb_walk_state_t *wsp) 232 { 233 uutil_list_walk_t *ulw = wsp->walk_data; 234 mdb_free(ulw, sizeof (uutil_list_walk_t)); 235 } 236 237 typedef struct uutil_list_node_walk { 238 size_t ulnw_offset; 239 uintptr_t ulnw_final; 240 uintptr_t ulnw_current; 241 void *ulnw_buf; 242 size_t ulnw_bufsz; 243 } uutil_list_node_walk_t; 244 245 int 246 uutil_list_node_walk_init(mdb_walk_state_t *wsp) 247 { 248 uutil_list_node_walk_t *ulnw; 249 uu_list_t ul; 250 uu_list_pool_t ulp; 251 252 if (mdb_vread(&ul, sizeof (uu_list_t), wsp->walk_addr) == -1) { 253 mdb_warn("failed to read uu_list_t at given address\n"); 254 return (WALK_ERR); 255 } 256 257 if (mdb_vread(&ulp, sizeof (uu_list_pool_t), (uintptr_t)ul.ul_pool) == 258 -1) { 259 mdb_warn("failed to read supporting uu_list_pool_t\n"); 260 return (WALK_ERR); 261 } 262 263 ulnw = mdb_alloc(sizeof (uutil_list_node_walk_t), UM_SLEEP); 264 265 ulnw->ulnw_offset = ul.ul_offset; 266 ulnw->ulnw_final = wsp->walk_addr + offsetof(uu_list_t, ul_null_node); 267 ulnw->ulnw_current = (uintptr_t)ul.ul_null_node.uln_next; 268 ulnw->ulnw_buf = mdb_alloc(ulp.ulp_objsize, UM_SLEEP); 269 ulnw->ulnw_bufsz = ulp.ulp_objsize; 270 271 wsp->walk_data = ulnw; 272 273 return (WALK_NEXT); 274 } 275 276 int 277 uutil_list_node_walk_step(mdb_walk_state_t *wsp) 278 { 279 uu_list_node_impl_t uln; 280 uutil_list_node_walk_t *ulnw = wsp->walk_data; 281 int status; 282 uintptr_t diff; 283 284 if (ulnw->ulnw_current == ulnw->ulnw_final) 285 return (WALK_DONE); 286 287 if (mdb_vread(&uln, sizeof (uu_list_node_impl_t), ulnw->ulnw_current) == 288 -1) { 289 mdb_warn("failed to read uu_list_node %x", ulnw->ulnw_current); 290 return (WALK_ERR); 291 } 292 293 diff = ulnw->ulnw_current - ulnw->ulnw_offset; 294 295 if (mdb_vread(ulnw->ulnw_buf, ulnw->ulnw_bufsz, diff) == -1) { 296 mdb_warn("failed to read enclosing structure %x", diff); 297 return (WALK_ERR); 298 } 299 /* 300 * Correct for offset; we return the address of the included structure. 301 */ 302 status = wsp->walk_callback(diff, ulnw->ulnw_buf, wsp->walk_cbdata); 303 304 ulnw->ulnw_current = (uintptr_t)uln.uln_next; 305 306 return (status); 307 } 308 309 void 310 uutil_list_node_walk_fini(mdb_walk_state_t *wsp) 311 { 312 uutil_list_node_walk_t *ulnw = wsp->walk_data; 313 314 mdb_free(ulnw->ulnw_buf, ulnw->ulnw_bufsz); 315 mdb_free(ulnw, sizeof (uutil_list_node_walk_t)); 316 } 317 318 static const mdb_dcmd_t dcmds[] = { 319 { "uutil_status", NULL, "libuutil status summary", uutil_status }, 320 { "uu_list_pool", NULL, "display uu_list_pool information", 321 uutil_listpool }, 322 { "uu_list", NULL, "display uu_list information", 323 uutil_list }, 324 { NULL } 325 }; 326 327 static const mdb_walker_t walkers[] = { 328 { "uu_list_pool", "walk uu_list_pools", 329 uutil_listpool_walk_init, uutil_listpool_walk_step, 330 uutil_listpool_walk_fini }, 331 { "uu_list", "given a uu_list_pool, walk its uu_lists", 332 uutil_list_walk_init, uutil_list_walk_step, 333 uutil_list_walk_fini }, 334 { "uu_list_node", 335 "given a uu_list, walk its nodes, returning container addr", 336 uutil_list_node_walk_init, uutil_list_node_walk_step, 337 uutil_list_node_walk_fini }, 338 { NULL } 339 }; 340 341 static const mdb_modinfo_t modinfo = { 342 MDB_API_VERSION, dcmds, walkers 343 }; 344 345 const mdb_modinfo_t * 346 _mdb_init(void) 347 { 348 return (&modinfo); 349 } 350