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 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/mdb_modapi.h> 29 #include <libelf.h> 30 #include <sys/fm/protocol.h> 31 #include <topo_mod.h> 32 #include <topo_tree.h> 33 #include <topo_module.h> 34 35 36 /* 37 * We use this to keep track of which bucket we're in while walking 38 * the modhash and we also cache the length of the hash 39 */ 40 static topo_modhash_t tmh; 41 static uint_t hash_idx; 42 43 static uintptr_t curr_pg; 44 static uint_t is_root; 45 static uint_t verbose; 46 static char *pgrp; 47 static char *tgt_scheme; 48 static char parent[255]; 49 50 /* 51 * This structure is used by the topo_nodehash walker instances to 52 * keep track of where they're at in the node hash 53 */ 54 typedef struct tnwalk_state { 55 uint_t hash_idx; 56 topo_nodehash_t hash; 57 topo_nodehash_t *curr_hash; 58 } tnwalk_state_t; 59 60 61 static char *stab_lvls[] = {"Internal", "", "Private", "Obsolete", "External", 62 "Unstable", "Evolving", "Stable", "Standard", "Max"}; 63 64 /*ARGSUSED*/ 65 static int 66 topo_handle(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 67 { 68 char uuid[36], root[36], plat[36], isa[36], machine[36], product[36]; 69 topo_hdl_t th; 70 71 /* 72 * Read in the structure and then read in all of the string fields from 73 * the target's addr space 74 */ 75 if (mdb_vread(&th, sizeof (th), addr) != sizeof (th)) { 76 mdb_warn("failed to read topo_hdl_t at %p", addr); 77 return (DCMD_ERR); 78 } 79 80 if (mdb_readstr(uuid, sizeof (uuid), (uintptr_t)th.th_uuid) < 0) { 81 (void) mdb_snprintf(uuid, sizeof (uuid), "<%p>", th.th_uuid); 82 } 83 if (mdb_readstr(root, sizeof (root), (uintptr_t)th.th_rootdir) < 0) { 84 (void) mdb_snprintf(root, sizeof (root), "<%p>", th.th_rootdir); 85 } 86 if (mdb_readstr(plat, sizeof (plat), (uintptr_t)th.th_platform) < 0) { 87 (void) mdb_snprintf(plat, sizeof (plat), "<%p>", 88 th.th_platform); 89 } 90 if (mdb_readstr(isa, sizeof (isa), (uintptr_t)th.th_isa) < 0) { 91 (void) mdb_snprintf(isa, sizeof (isa), "<%p>", th.th_isa); 92 } 93 if (mdb_readstr(machine, sizeof (machine), (uintptr_t)th.th_machine) 94 < 0) { 95 96 (void) mdb_snprintf(machine, sizeof (machine), "<%p>", 97 th.th_machine); 98 } 99 if (mdb_readstr(product, sizeof (product), (uintptr_t)th.th_product) 100 < 0) { 101 102 (void) mdb_snprintf(product, sizeof (product), "<%p>", 103 th.th_product); 104 } 105 106 /* 107 * Dump it all out in a nice pretty format and keep it to 80 chars wide 108 */ 109 if (DCMD_HDRSPEC(flags)) { 110 mdb_printf("%<u>%-12s %-36s %-30s%</u>\n", "FIELD", "VALUE", 111 "DESCR"); 112 } 113 mdb_printf("%-12s 0x%-34p %-30s\n", "th_lock", th.th_lock, 114 "Mutex lock protecting handle"); 115 mdb_printf("%-12s %-36s %-30s\n", "th_uuid", uuid, 116 "UUID of the topology snapshot"); 117 mdb_printf("%-12s %-36s %-30s\n", "th_rootdir", root, 118 "Root directory of plugin paths"); 119 mdb_printf("%-12s %-36s %-30s\n", "th_platform", plat, "Platform name"); 120 mdb_printf("%-12s %-36s %-30s\n", "th_isa", isa, "ISA name"); 121 mdb_printf("%-12s %-36s %-30s\n", "th_machine", machine, 122 "Machine name"); 123 mdb_printf("%-12s %-36s %-30s\n", "th_product", product, 124 "Product name"); 125 mdb_printf("%-12s 0x%-34p %-30s\n", "th_di", th.th_di, 126 "Handle to the root of the devinfo tree"); 127 mdb_printf("%-12s 0x%-34p %-30s\n", "th_pi", th.th_pi, 128 "Handle to the root of the PROM tree"); 129 mdb_printf("%-12s 0x%-34p %-30s\n", "th_modhash", th.th_modhash, 130 "Module hash"); 131 mdb_printf("%-12s %-36s %-30s\n", "th_trees", "", 132 "Scheme-specific topo tree list"); 133 mdb_printf(" %-12s 0x%-34p %-30s\n", "l_prev", th.th_trees.l_prev, 134 ""); 135 mdb_printf(" %-12s 0x%-34p %-30s\n", "l_next", th.th_trees.l_next, 136 ""); 137 mdb_printf("%-12s 0x%-34p %-30s\n", "th_alloc", th.th_alloc, 138 "Allocators"); 139 mdb_printf("%-12s %-36d %-30s\n", "tm_ernno", th.th_errno, "errno"); 140 mdb_printf("%-12s %-36d %-30s\n", "tm_debug", th.th_debug, 141 "Debug mask"); 142 mdb_printf("%-12s %-36d %-30s\n", "tm_dbout", th.th_dbout, 143 "Debug channel"); 144 145 return (DCMD_OK); 146 } 147 148 149 /*ARGSUSED*/ 150 static int 151 topo_module(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 152 { 153 char name[36], path[36], root[36]; 154 topo_mod_t tm; 155 156 /* 157 * Read in the structure and then read in all of the string fields from 158 * the target's addr space 159 */ 160 if (mdb_vread(&tm, sizeof (tm), addr) != sizeof (tm)) { 161 mdb_warn("failed to read topo_mod_t at %p", addr); 162 return (DCMD_ERR); 163 } 164 165 if (mdb_readstr(name, sizeof (name), (uintptr_t)tm.tm_name) < 0) { 166 (void) mdb_snprintf(name, sizeof (name), "<%p>", tm.tm_name); 167 } 168 if (mdb_readstr(path, sizeof (path), (uintptr_t)tm.tm_path) < 0) { 169 (void) mdb_snprintf(path, sizeof (path), "<%p>", tm.tm_path); 170 } 171 if (mdb_readstr(root, sizeof (root), (uintptr_t)tm.tm_rootdir) < 0) { 172 (void) mdb_snprintf(root, sizeof (root), "<%p>", tm.tm_rootdir); 173 } 174 175 /* 176 * Dump it all out in a nice pretty format and keep it to 80 chars wide 177 */ 178 if (DCMD_HDRSPEC(flags)) { 179 mdb_printf("%<u>%-12s %-36s %-30s%</u>\n", 180 "FIELD", "VALUE", "DESCR"); 181 } 182 mdb_printf("%-12s 0x%-34p %-30s\n", "tm_lock", tm.tm_lock, 183 "Lock for tm_cv/owner/flags/refs"); 184 mdb_printf("%-12s 0x%-34p %-30s\n", "tm_cv", tm.tm_cv, 185 "Module condition variable"); 186 mdb_printf("%-12s %-36s %-30s\n", "tm_busy", tm.tm_busy, 187 "Busy indicator"); 188 mdb_printf("%-12s 0x%-34p %-30s\n", "tm_next", tm.tm_next, 189 "Next module in hash chain"); 190 mdb_printf("%-12s 0x%-34p %-30s\n", "tm_hdl", tm.tm_hdl, 191 "Topo handle for this module"); 192 mdb_printf("%-12s 0x%-34p %-30s\n", "tm_alloc", tm.tm_alloc, 193 "Allocators"); 194 mdb_printf("%-12s %-36s %-30s\n", "tm_name", name, 195 "Basename of module"); 196 mdb_printf("%-12s %-36s %-30s\n", "tm_path", path, 197 "Full pathname of module"); 198 mdb_printf("%-12s %-36s %-30s\n", "tm_rootdir", root, 199 "Relative root directory of module"); 200 mdb_printf("%-12s %-36u %-30s\n", "tm_refs", tm.tm_refs, 201 "Module reference count"); 202 mdb_printf("%-12s %-36u %-30s\n", "tm_flags", tm.tm_flags, 203 "Module flags"); 204 if (TOPO_MOD_INIT & tm.tm_flags) { 205 mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_MOD_INIT", 206 "Module init completed"); 207 } 208 if (TOPO_MOD_FINI & tm.tm_flags) { 209 mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_MOD_FINI", 210 "Module fini completed"); 211 } 212 if (TOPO_MOD_REG & tm.tm_flags) { 213 mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_MOD_REG", 214 "Module registered"); 215 } 216 if (TOPO_MOD_UNREG & tm.tm_flags) { 217 mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_MOD_UNREG", 218 "Module unregistered"); 219 } 220 221 mdb_printf("%-12s %-36u %-30s\n", "tm_debug", tm.tm_debug, 222 "Debug printf mask"); 223 mdb_printf("%-12s 0x%-34p %-30s\n", "tm_data", tm.tm_data, 224 "Private rtld/builtin data"); 225 mdb_printf("%-12s 0x%-34p %-30s\n", "tm_mops", tm.tm_mops, 226 "Module class ops vector"); 227 mdb_printf("%-12s 0x%-34p %-30s\n", "tm_info", tm.tm_info, 228 "Module info registered with handle"); 229 mdb_printf("%-12s %-36d %-30s\n", "tm_ernno", tm.tm_errno, 230 "Module errno"); 231 232 return (DCMD_OK); 233 } 234 235 236 /*ARGSUSED*/ 237 static int 238 topo_node(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 239 { 240 char name[36]; 241 tnode_t tn; 242 243 if (!addr) 244 return (DCMD_ERR); 245 246 /* 247 * Read in the structure and then read in all of the string fields from 248 * the target's addr space 249 */ 250 if (mdb_vread(&tn, sizeof (tn), addr) != sizeof (tn)) { 251 mdb_warn("failed to read tnode_t at %p", addr); 252 return (DCMD_ERR); 253 } 254 255 if (mdb_readstr(name, sizeof (name), (uintptr_t)tn.tn_name) < 0) { 256 (void) mdb_snprintf(name, sizeof (name), "<%p>", tn.tn_name); 257 } 258 259 /* 260 * Dump it all out in a nice pretty format and keep it to 80 chars wide 261 */ 262 if (DCMD_HDRSPEC(flags)) { 263 mdb_printf("%<u>%-12s %-36s %-30s%</u>\n", 264 "FIELD", "VALUE", "DESCR"); 265 } 266 267 mdb_printf("%-12s 0x%-34p %-30s\n", "tn_lock", tn.tn_lock, 268 "Mutex lock protecting node members"); 269 mdb_printf("%-12s %-36s %-30s\n", "tn_name", name, 270 "Node name"); 271 mdb_printf("%-12s %-36d %-30s\n", "tn_instance", tn.tn_instance, 272 "Node instance"); 273 mdb_printf("%-12s %-36d %-30s\n", "tn_state", tn.tn_state, 274 "Node state"); 275 if (TOPO_NODE_INIT & tn.tn_state) { 276 mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_NODE_INIT", ""); 277 } 278 if (TOPO_NODE_ROOT & tn.tn_state) { 279 mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_NODE_ROOT", ""); 280 } 281 if (TOPO_NODE_BOUND & tn.tn_state) { 282 mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_NODE_BOUND", ""); 283 } 284 if (TOPO_NODE_LINKED & tn.tn_state) { 285 mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_NODE_LINKED", ""); 286 } 287 mdb_printf("%-12s %-36d %-30s\n", "tn_fflags", tn.tn_fflags, 288 "FMRI flags"); 289 mdb_printf("%-12s 0x%-34p %-30s\n", "tn_parent", tn.tn_parent, 290 "Node parent"); 291 mdb_printf("%-12s 0x%-34p %-30s\n", "tn_phash", tn.tn_phash, 292 "Parent hash bucket"); 293 mdb_printf("%-12s 0x%-34p %-30s\n", "tn_hdl", tn.tn_hdl, 294 "Topo handle"); 295 mdb_printf("%-12s 0x%-34p %-30s\n", "tn_enum", tn.tn_enum, 296 "Enumerator module"); 297 mdb_printf("%-12s %-36s %-30s\n", "tn_children", "", 298 "Hash table of child nodes"); 299 mdb_printf(" %-12s 0x%-34p %-30s\n", "l_prev", tn.tn_children.l_prev, 300 ""); 301 mdb_printf(" %-12s 0x%-34p %-30s\n", "l_next", tn.tn_children.l_next, 302 ""); 303 mdb_printf("%-12s 0x%-34p %-30s\n", "tn_pgroups", &(tn.tn_pgroups), 304 "Property group list"); 305 mdb_printf("%-12s 0x%-34p %-30s\n", "tn_methods", &(tn.tn_methods), 306 "Registered method list"); 307 mdb_printf("%-12s 0x%-34p %-30s\n", "tn_priv", tn.tn_priv, 308 "Private enumerator data"); 309 mdb_printf("%-12s %-36d %-30s\n", "tn_refs", tn.tn_refs, 310 "Node reference count"); 311 312 return (DCMD_OK); 313 } 314 315 /*ARGSUSED*/ 316 static int 317 find_tree_root(uintptr_t addr, const void *data, void *arg) 318 { 319 ttree_t *tree = (ttree_t *)data; 320 char scheme[36]; 321 322 if (mdb_readstr(scheme, sizeof (scheme), (uintptr_t)tree->tt_scheme) 323 < 0) { 324 (void) mdb_snprintf(scheme, sizeof (scheme), "<%p>", 325 tree->tt_scheme); 326 } 327 328 if (strncmp(tgt_scheme, scheme, 36) == 0) { 329 *((tnode_t **)arg) = tree->tt_root; 330 return (WALK_DONE); 331 } 332 return (WALK_NEXT); 333 } 334 335 336 /* 337 * Dump the given property value. For the actual property values 338 * we dump a pointer to the nvlist which can be decoded using the ::nvlist 339 * dcmd from the libnvpair MDB module 340 */ 341 /*ARGSUSED*/ 342 static int 343 dump_propval(uintptr_t addr, const void *data, void *arg) 344 { 345 topo_proplist_t *plistp = (topo_proplist_t *)data; 346 topo_propval_t pval; 347 char name[32], *type; 348 349 if (mdb_vread(&pval, sizeof (pval), (uintptr_t)plistp->tp_pval) 350 != sizeof (pval)) { 351 352 mdb_warn("failed to read topo_propval_t at %p", 353 plistp->tp_pval); 354 return (WALK_ERR); 355 } 356 if (mdb_readstr(name, sizeof (name), (uintptr_t)pval.tp_name) < 0) { 357 (void) mdb_snprintf(name, sizeof (name), "<%p>", pval.tp_name); 358 } 359 switch (pval.tp_type) { 360 case TOPO_TYPE_BOOLEAN: type = "boolean"; break; 361 case TOPO_TYPE_INT32: type = "int32"; break; 362 case TOPO_TYPE_UINT32: type = "uint32"; break; 363 case TOPO_TYPE_INT64: type = "int64"; break; 364 case TOPO_TYPE_UINT64: type = "uint64"; break; 365 case TOPO_TYPE_STRING: type = "string"; break; 366 case TOPO_TYPE_FMRI: type = "fmri"; break; 367 case TOPO_TYPE_INT32_ARRAY: type = "int32[]"; break; 368 case TOPO_TYPE_UINT32_ARRAY: type = "uint32[]"; break; 369 case TOPO_TYPE_INT64_ARRAY: type = "int64[]"; break; 370 case TOPO_TYPE_UINT64_ARRAY: type = "uint64[]"; break; 371 case TOPO_TYPE_STRING_ARRAY: type = "string[]"; break; 372 case TOPO_TYPE_FMRI_ARRAY: type = "fmri[]"; break; 373 default: type = "unknown type"; 374 } 375 mdb_printf(" %-32s %-16s value: %p\n", name, type, pval.tp_val); 376 return (WALK_NEXT); 377 } 378 379 380 /* 381 * Dumps the contents of the property group. 382 */ 383 /*ARGSUSED*/ 384 static int 385 dump_pgroup(uintptr_t addr, const void *data, void *arg) 386 { 387 topo_pgroup_t *pgp = (topo_pgroup_t *)data; 388 topo_ipgroup_info_t ipg; 389 char buf[32]; 390 391 if (mdb_vread(&ipg, sizeof (ipg), (uintptr_t)pgp->tpg_info) 392 != sizeof (ipg)) { 393 394 mdb_warn("failed to read topo_ipgroup_info_t at %p", 395 pgp->tpg_info); 396 return (WALK_ERR); 397 } 398 if (mdb_readstr(buf, sizeof (buf), (uintptr_t)ipg.tpi_name) < 0) { 399 mdb_warn("failed to read string at %p", ipg.tpi_name); 400 return (WALK_ERR); 401 } 402 /* 403 * If this property group is the one we're interested in or if the user 404 * specified the "all" property group, we'll dump it 405 */ 406 if ((strncmp(pgrp, buf, sizeof (buf)) == 0) || 407 (strncmp(pgrp, "all", sizeof (buf)) == 0)) { 408 409 mdb_printf(" group: %-32s version: %d, stability: %s/%s\n", 410 buf, ipg.tpi_version, stab_lvls[ipg.tpi_namestab], 411 stab_lvls[ipg.tpi_datastab]); 412 413 (void) mdb_pwalk("topo_proplist", dump_propval, NULL, curr_pg); 414 } 415 return (WALK_NEXT); 416 } 417 418 419 /* 420 * Recursive function to dump the specified node and all of it's children 421 */ 422 /*ARGSUSED*/ 423 static int 424 dump_tnode(uintptr_t addr, const void *data, void *arg) 425 { 426 tnode_t node; 427 char pname[255], buf[80], old_pname[255]; 428 429 if (!addr) { 430 return (WALK_NEXT); 431 } 432 433 if (mdb_vread(&node, sizeof (node), addr) != sizeof (node)) { 434 mdb_warn("failed to read tnode_t at %p", addr); 435 return (WALK_ERR); 436 } 437 if (mdb_readstr(buf, sizeof (buf), (uintptr_t)node.tn_name) < 0) { 438 (void) mdb_snprintf(buf, sizeof (buf), "<%p>", 439 node.tn_name); 440 } 441 442 if (is_root) { 443 mdb_snprintf(pname, sizeof (pname), "%s", parent); 444 is_root = 0; 445 } else { 446 mdb_snprintf(pname, sizeof (pname), "%s/%s=%u", 447 parent, buf, node.tn_instance); 448 449 if (verbose) 450 mdb_printf("%s\n tnode_t: %p\n", pname, addr); 451 else 452 mdb_printf("%s\n", pname); 453 } 454 mdb_snprintf(old_pname, sizeof (old_pname), "%s", parent); 455 mdb_snprintf(parent, sizeof (parent), "%s", pname); 456 457 if (pgrp) 458 (void) mdb_pwalk("topo_pgroup", dump_pgroup, NULL, addr); 459 460 (void) mdb_pwalk("topo_nodehash", dump_tnode, NULL, addr); 461 mdb_snprintf(parent, sizeof (parent), "%s", old_pname); 462 463 return (WALK_NEXT); 464 } 465 466 467 /* 468 * Given a topo_hdl_t *, the topo dcmd dumps the topo tree. The format of the 469 * output is modeled after fmtopo. Like fmtopo, by default, we'll dump the 470 * "hc" scheme tree. The user can optionally specify a different tree via the 471 * "-s <scheme>" option. 472 * 473 * Specifying the "-v" option provides more verbose output. Currently it 474 * outputs the tnode_t * addr for each node, which is useful if you want to 475 * dump it with the topo_node dcmd. 476 * 477 * The functionality of the "-P" option is similar to fmtopo. 478 */ 479 /*ARGSUSED*/ 480 static int 481 fmtopo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 482 { 483 char product[36], *opt_s = NULL, *opt_P = NULL; 484 topo_hdl_t th; 485 tnode_t *tree_root; 486 uint_t opt_v = FALSE; 487 char *def_scheme = "hc"; 488 489 if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &opt_v, 490 's', MDB_OPT_STR, &opt_s, 'P', MDB_OPT_STR, &opt_P, NULL) 491 != argc) { 492 return (DCMD_USAGE); 493 } 494 495 if (opt_s) { 496 tgt_scheme = opt_s; 497 } else { 498 tgt_scheme = def_scheme; 499 } 500 501 pgrp = opt_P; 502 verbose = opt_v; 503 is_root = 1; 504 505 /* 506 * Read in the topo_handle and some of its string fields from 507 * the target's addr space 508 */ 509 if (mdb_vread(&th, sizeof (th), addr) != sizeof (th)) { 510 mdb_warn("failed to read topo_hdl_t at %p", addr); 511 return (DCMD_ERR); 512 } 513 514 if (mdb_readstr(product, sizeof (product), (uintptr_t)th.th_product) 515 < 0) { 516 517 (void) mdb_snprintf(product, sizeof (product), "<%p>", 518 th.th_product); 519 } 520 521 mdb_snprintf(parent, sizeof (parent), 522 "%s://:product-id=%s", tgt_scheme, product); 523 524 /* 525 * Walk the list of topo trees, looking for the one that is for the 526 * scheme we're interested in. 527 */ 528 tree_root = NULL; 529 mdb_pwalk("topo_tree", find_tree_root, &tree_root, addr); 530 531 if (! tree_root) { 532 mdb_warn("failed to find a topo tree for scheme %s\n", 533 tgt_scheme); 534 return (DCMD_ERR); 535 } 536 537 return (dump_tnode((uintptr_t)tree_root, NULL, NULL)); 538 } 539 540 541 static int 542 ttree_walk_init(mdb_walk_state_t *wsp) 543 { 544 topo_hdl_t th; 545 546 if (wsp->walk_addr == NULL) { 547 mdb_warn("NULL topo_hdl_t passed in"); 548 return (WALK_ERR); 549 } 550 551 if (mdb_vread(&th, sizeof (th), wsp->walk_addr) != sizeof (th)) { 552 mdb_warn("failed to read topo_hdl_t at %p", wsp->walk_addr); 553 return (WALK_ERR); 554 } 555 556 wsp->walk_addr = (uintptr_t)th.th_trees.l_next; 557 wsp->walk_data = mdb_alloc(sizeof (ttree_t), UM_SLEEP); 558 559 return (WALK_NEXT); 560 } 561 562 563 static int 564 ttree_walk_step(mdb_walk_state_t *wsp) 565 { 566 int rv; 567 ttree_t *tree; 568 569 if (wsp->walk_addr == NULL) 570 return (WALK_DONE); 571 572 if (mdb_vread(wsp->walk_data, sizeof (ttree_t), wsp->walk_addr) 573 != sizeof (ttree_t)) { 574 575 mdb_warn("failed to read ttree_t at %p", wsp->walk_addr); 576 return (WALK_ERR); 577 } 578 579 rv = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 580 wsp->walk_cbdata); 581 582 tree = (ttree_t *)wsp->walk_data; 583 wsp->walk_addr = (uintptr_t)tree->tt_list.l_next; 584 585 return (rv); 586 } 587 588 589 static void 590 ttree_walk_fini(mdb_walk_state_t *wsp) 591 { 592 mdb_free(wsp->walk_data, sizeof (ttree_t)); 593 } 594 595 596 static int 597 tmod_walk_init(mdb_walk_state_t *wsp) 598 { 599 topo_hdl_t th; 600 601 if (wsp->walk_addr == NULL) { 602 mdb_warn("NULL topo_hdl_t passed in"); 603 return (WALK_ERR); 604 } 605 606 if (mdb_vread(&th, sizeof (th), wsp->walk_addr) != sizeof (th)) { 607 mdb_warn("failed to read topo_hdl_t at %p", wsp->walk_addr); 608 return (WALK_ERR); 609 } 610 611 if (mdb_vread(&tmh, sizeof (topo_modhash_t), (uintptr_t)th.th_modhash) 612 == -1) { 613 614 mdb_warn("failed to read topo_modhash_t at %p", wsp->walk_addr); 615 return (WALK_DONE); 616 } 617 618 hash_idx = 0; 619 620 if (mdb_vread(&(wsp->walk_addr), sizeof (uintptr_t *), 621 (uintptr_t)(tmh.mh_hash)) != sizeof (tnode_t *)) { 622 623 mdb_warn("failed to read %u bytes at %p", sizeof (tnode_t *), 624 tmh.mh_hash); 625 return (WALK_ERR); 626 } 627 628 wsp->walk_data = mdb_alloc(sizeof (topo_mod_t), UM_SLEEP); 629 630 return (WALK_NEXT); 631 } 632 633 634 static int 635 tmod_walk_step(mdb_walk_state_t *wsp) 636 { 637 int rv; 638 topo_mod_t *tm; 639 640 if (wsp->walk_addr == NULL) 641 return (WALK_DONE); 642 643 if (mdb_vread(wsp->walk_data, sizeof (topo_mod_t), wsp->walk_addr) 644 == -1) { 645 646 mdb_warn("failed to read topo_mod_t at %p", wsp->walk_addr); 647 return (WALK_DONE); 648 } 649 650 rv = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 651 wsp->walk_cbdata); 652 653 tm = (topo_mod_t *)wsp->walk_data; 654 655 if (tm->tm_next) 656 wsp->walk_addr = (uintptr_t)tm->tm_next; 657 else if (++hash_idx < tmh.mh_hashlen) 658 if (mdb_vread(&(wsp->walk_addr), sizeof (uintptr_t *), 659 (uintptr_t)(tmh.mh_hash+hash_idx)) != sizeof (tnode_t *)) { 660 661 mdb_warn("failed to read %u bytes at %p", 662 sizeof (tnode_t *), tmh.mh_hash+hash_idx); 663 return (DCMD_ERR); 664 } 665 else 666 wsp->walk_addr = NULL; 667 668 return (rv); 669 } 670 671 static void 672 tmod_walk_fini(mdb_walk_state_t *wsp) 673 { 674 mdb_free(wsp->walk_data, sizeof (topo_mod_t)); 675 } 676 677 678 static int 679 tpg_walk_init(mdb_walk_state_t *wsp) 680 { 681 tnode_t node; 682 683 if (wsp->walk_addr == NULL) { 684 mdb_warn("NULL tnode_t passed in"); 685 return (WALK_ERR); 686 } 687 688 if (mdb_vread(&node, sizeof (node), wsp->walk_addr) != sizeof (node)) { 689 mdb_warn("failed to read tnode_t at %p", wsp->walk_addr); 690 return (WALK_ERR); 691 } 692 693 wsp->walk_addr = (uintptr_t)node.tn_pgroups.l_next; 694 wsp->walk_data = mdb_alloc(sizeof (topo_pgroup_t), UM_SLEEP); 695 696 return (WALK_NEXT); 697 } 698 699 700 static int 701 tpg_walk_step(mdb_walk_state_t *wsp) 702 { 703 int rv; 704 topo_pgroup_t *tpgp; 705 706 if (wsp->walk_addr == NULL) 707 return (WALK_DONE); 708 709 if (mdb_vread(wsp->walk_data, sizeof (topo_pgroup_t), wsp->walk_addr) 710 == -1) { 711 712 mdb_warn("failed to read topo_pgroup_t at %p", wsp->walk_addr); 713 return (WALK_DONE); 714 } 715 716 curr_pg = wsp->walk_addr; 717 rv = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 718 wsp->walk_cbdata); 719 720 tpgp = (topo_pgroup_t *)wsp->walk_data; 721 wsp->walk_addr = (uintptr_t)tpgp->tpg_list.l_next; 722 723 return (rv); 724 } 725 726 727 static void 728 tpg_walk_fini(mdb_walk_state_t *wsp) 729 { 730 mdb_free(wsp->walk_data, sizeof (topo_pgroup_t)); 731 } 732 733 734 static int 735 tpl_walk_init(mdb_walk_state_t *wsp) 736 { 737 topo_pgroup_t pg; 738 739 if (wsp->walk_addr == NULL) { 740 mdb_warn("NULL topo_pgroup_t passed in"); 741 return (WALK_ERR); 742 } 743 744 if (mdb_vread(&pg, sizeof (pg), wsp->walk_addr) != sizeof (pg)) { 745 mdb_warn("failed to read topo_pgroup_t at %p", wsp->walk_addr); 746 return (WALK_ERR); 747 } 748 749 wsp->walk_addr = (uintptr_t)pg.tpg_pvals.l_next; 750 wsp->walk_data = mdb_alloc(sizeof (topo_proplist_t), UM_SLEEP); 751 752 return (WALK_NEXT); 753 } 754 755 756 static int 757 tpl_walk_step(mdb_walk_state_t *wsp) 758 { 759 int rv; 760 topo_proplist_t *plp; 761 762 if (wsp->walk_addr == NULL) 763 return (WALK_DONE); 764 765 if (mdb_vread(wsp->walk_data, sizeof (topo_proplist_t), wsp->walk_addr) 766 == -1) { 767 768 mdb_warn("failed to read topo_proplist_t at %p", 769 wsp->walk_addr); 770 return (WALK_DONE); 771 } 772 plp = (topo_proplist_t *)wsp->walk_data; 773 774 rv = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 775 wsp->walk_cbdata); 776 777 wsp->walk_addr = (uintptr_t)plp->tp_list.l_next; 778 779 return (rv); 780 } 781 782 783 static void 784 tpl_walk_fini(mdb_walk_state_t *wsp) 785 { 786 mdb_free(wsp->walk_data, sizeof (topo_proplist_t)); 787 } 788 789 790 static int 791 tnh_walk_init(mdb_walk_state_t *wsp) 792 { 793 tnode_t node; 794 tnwalk_state_t *state; 795 796 if (wsp->walk_addr == NULL) { 797 mdb_warn("NULL tnode_t passed in"); 798 return (WALK_ERR); 799 } 800 801 if (mdb_vread(&node, sizeof (node), wsp->walk_addr) != sizeof (node)) { 802 mdb_warn("failed to read tnode_t at %p", wsp->walk_addr); 803 return (WALK_ERR); 804 } 805 806 state = mdb_zalloc(sizeof (tnwalk_state_t), UM_SLEEP); 807 808 state->curr_hash = (topo_nodehash_t *)node.tn_children.l_next; 809 state->hash_idx = 0; 810 wsp->walk_data = state; 811 812 return (WALK_NEXT); 813 } 814 815 816 static int 817 tnh_walk_step(mdb_walk_state_t *wsp) 818 { 819 tnwalk_state_t *state = wsp->walk_data; 820 int rv, i = state->hash_idx++; 821 tnode_t *npp; 822 823 if (state->curr_hash == NULL) 824 return (WALK_DONE); 825 826 if (mdb_vread(&(state->hash), sizeof (topo_nodehash_t), 827 (uintptr_t)state->curr_hash) != sizeof (topo_nodehash_t)) { 828 829 mdb_warn("failed to read topo_nodehash_t at %p", 830 (uintptr_t)state->curr_hash); 831 return (WALK_ERR); 832 } 833 834 if (mdb_vread(&npp, sizeof (tnode_t *), 835 (uintptr_t)(state->hash.th_nodearr+i)) != sizeof (tnode_t *)) { 836 837 mdb_warn("failed to read %u bytes at %p", sizeof (tnode_t *), 838 state->hash.th_nodearr+i); 839 return (WALK_ERR); 840 } 841 wsp->walk_addr = (uintptr_t)npp; 842 843 rv = wsp->walk_callback(wsp->walk_addr, state, wsp->walk_cbdata); 844 845 if (state->hash_idx >= state->hash.th_arrlen) { 846 /* 847 * move on to the next child hash bucket 848 */ 849 state->curr_hash = 850 (topo_nodehash_t *)(state->hash.th_list.l_next); 851 state->hash_idx = 0; 852 } 853 854 return (rv); 855 } 856 857 858 static void 859 tnh_walk_fini(mdb_walk_state_t *wsp) 860 { 861 mdb_free(wsp->walk_data, sizeof (tnwalk_state_t)); 862 } 863 864 865 static const mdb_dcmd_t dcmds[] = { 866 { "topo_handle", "", "print contents of a topo handle", topo_handle, 867 NULL }, 868 { "topo_module", "", "print contents of a topo module handle", 869 topo_module, NULL }, 870 { "topo_node", "", "print contents of a topo node", topo_node, NULL }, 871 { "fmtopo", "[-P <pgroup>][-s <scheme>][-v]", 872 "print topology of the given handle", fmtopo, NULL }, 873 { NULL } 874 }; 875 876 static const mdb_walker_t walkers[] = { 877 { "topo_tree", "walk the tree list for a given topo handle", 878 ttree_walk_init, ttree_walk_step, ttree_walk_fini, NULL }, 879 { "topo_module", "walk the module hash for a given topo handle", 880 tmod_walk_init, tmod_walk_step, tmod_walk_fini, NULL }, 881 { "topo_pgroup", "walk the property groups for a given topo node", 882 tpg_walk_init, tpg_walk_step, tpg_walk_fini, NULL }, 883 { "topo_proplist", "walk the property list for a given property group", 884 tpl_walk_init, tpl_walk_step, tpl_walk_fini, NULL }, 885 { "topo_nodehash", "walk the child nodehash for a given topo node", 886 tnh_walk_init, tnh_walk_step, tnh_walk_fini, NULL }, 887 { NULL } 888 }; 889 890 static const mdb_modinfo_t modinfo = { 891 MDB_API_VERSION, dcmds, walkers 892 }; 893 894 const mdb_modinfo_t * 895 _mdb_init(void) 896 { 897 return (&modinfo); 898 } 899