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