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