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