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 #include <mdb/mdb_modapi.h> 28 29 #include <pthread.h> 30 #include <stddef.h> 31 32 #include <libuutil.h> 33 #include <libuutil_impl.h> 34 35 /*ARGSUSED*/ 36 static int 37 uutil_status(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 38 { 39 pthread_t uu_panic_thread = 0; 40 41 if ((flags & DCMD_ADDRSPEC) || argc != 0) 42 return (DCMD_USAGE); 43 44 if (mdb_readvar(&uu_panic_thread, "uu_panic_thread") == -1) { 45 mdb_warn("unable to read uu_panic_thread"); 46 } 47 48 if (uu_panic_thread != 0) { 49 mdb_printf("thread %d uu_panicked\n", uu_panic_thread); 50 } 51 52 return (DCMD_OK); 53 } 54 55 /*ARGSUSED*/ 56 static int 57 uutil_listpool(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 58 { 59 uu_list_pool_t ulp; 60 61 if (!(flags & DCMD_ADDRSPEC)) { 62 if (mdb_walk_dcmd("uu_list_pool", "uu_list_pool", argc, 63 argv) == -1) { 64 mdb_warn("can't walk uu_list_pool"); 65 return (DCMD_ERR); 66 } 67 return (DCMD_OK); 68 } 69 70 if (argc != 0) 71 return (DCMD_USAGE); 72 73 if (DCMD_HDRSPEC(flags)) 74 mdb_printf("%-?s %-30s %?s %5s\n", 75 "ADDR", "NAME", "COMPARE", "FLAGS"); 76 77 if (mdb_vread(&ulp, sizeof (uu_list_pool_t), addr) == -1) { 78 mdb_warn("failed to read uu_list_pool\n"); 79 return (DCMD_ERR); 80 } 81 82 mdb_printf("%0?p %-30s %08x %c\n", addr, ulp.ulp_name, ulp.ulp_cmp, 83 ulp.ulp_debug ? 'D' : ' '); 84 85 return (DCMD_OK); 86 } 87 88 /*ARGSUSED*/ 89 static int 90 uutil_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 91 { 92 uu_list_t ul; 93 94 if (!(flags & DCMD_ADDRSPEC) || argc != 0) 95 return (DCMD_USAGE); 96 97 if (mdb_vread(&ul, sizeof (uu_list_t), addr) == -1) { 98 mdb_warn("failed to read uu_list\n"); 99 return (DCMD_ERR); 100 } 101 102 if (DCMD_HDRSPEC(flags)) 103 mdb_printf("%-?s %-?s %-?s %6s %5s\n", 104 "ADDR", "POOL", "PARENT", "NODES", "FLAGS"); 105 106 mdb_printf("%0?p %0?p %0?p %6u %c%c\n", 107 addr, ul.ul_pool, UU_PTR_DECODE(ul.ul_parent_enc), 108 ul.ul_numnodes, ul.ul_sorted ? 'S' : ' ', ul.ul_debug? 'D' : ' '); 109 110 return (DCMD_OK); 111 } 112 113 typedef struct uutil_listpool_walk { 114 uintptr_t ulpw_final; 115 uintptr_t ulpw_current; 116 } uutil_listpool_walk_t; 117 118 int 119 uutil_listpool_walk_init(mdb_walk_state_t *wsp) 120 { 121 uu_list_pool_t null_lpool; 122 uutil_listpool_walk_t *ulpw; 123 GElf_Sym sym; 124 125 bzero(&null_lpool, sizeof (uu_list_pool_t)); 126 127 if (mdb_lookup_by_obj("libuutil.so.1", "uu_null_lpool", &sym) == 128 -1) { 129 mdb_warn("failed to find 'uu_null_lpool'\n"); 130 return (WALK_ERR); 131 } 132 133 if (mdb_vread(&null_lpool, sym.st_size, (uintptr_t)sym.st_value) == 134 -1) { 135 mdb_warn("failed to read data from 'uu_null_lpool' address\n"); 136 return (WALK_ERR); 137 } 138 139 ulpw = mdb_alloc(sizeof (uutil_listpool_walk_t), UM_SLEEP); 140 141 ulpw->ulpw_final = (uintptr_t)null_lpool.ulp_prev; 142 ulpw->ulpw_current = (uintptr_t)null_lpool.ulp_next; 143 wsp->walk_data = ulpw; 144 145 return (WALK_NEXT); 146 } 147 148 int 149 uutil_listpool_walk_step(mdb_walk_state_t *wsp) 150 { 151 uu_list_pool_t ulp; 152 uutil_listpool_walk_t *ulpw = wsp->walk_data; 153 int status; 154 155 if (mdb_vread(&ulp, sizeof (uu_list_pool_t), 156 ulpw->ulpw_current) == -1) { 157 mdb_warn("failed to read uu_list_pool %x", ulpw->ulpw_current); 158 return (WALK_ERR); 159 } 160 161 status = wsp->walk_callback(ulpw->ulpw_current, &ulp, wsp->walk_cbdata); 162 163 if (ulpw->ulpw_current == ulpw->ulpw_final) 164 return (WALK_DONE); 165 166 ulpw->ulpw_current = (uintptr_t)ulp.ulp_next; 167 168 return (status); 169 } 170 171 void 172 uutil_listpool_walk_fini(mdb_walk_state_t *wsp) 173 { 174 uutil_listpool_walk_t *ulpw = wsp->walk_data; 175 mdb_free(ulpw, sizeof (uutil_listpool_walk_t)); 176 } 177 178 typedef struct uutil_list_walk { 179 uintptr_t ulw_final; 180 uintptr_t ulw_current; 181 } uutil_list_walk_t; 182 183 int 184 uutil_list_walk_init(mdb_walk_state_t *wsp) 185 { 186 uutil_list_walk_t *ulw; 187 uu_list_pool_t ulp; 188 189 if (mdb_vread(&ulp, sizeof (uu_list_pool_t), wsp->walk_addr) == -1) { 190 mdb_warn("failed to read uu_list_pool_t at given address\n"); 191 return (WALK_ERR); 192 } 193 194 if (UU_LIST_PTR(ulp.ulp_null_list.ul_next_enc) == 195 &((uu_list_pool_t *)wsp->walk_addr)->ulp_null_list) 196 return (WALK_DONE); 197 198 ulw = mdb_alloc(sizeof (uutil_list_walk_t), UM_SLEEP); 199 200 ulw->ulw_final = (uintptr_t)UU_LIST_PTR(ulp.ulp_null_list.ul_prev_enc); 201 ulw->ulw_current = 202 (uintptr_t)UU_LIST_PTR(ulp.ulp_null_list.ul_next_enc); 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)UU_LIST_PTR(ul.ul_next_enc); 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