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