13323Scindi /* 23323Scindi * CDDL HEADER START 33323Scindi * 43323Scindi * The contents of this file are subject to the terms of the 53323Scindi * Common Development and Distribution License (the "License"). 63323Scindi * You may not use this file except in compliance with the License. 73323Scindi * 83323Scindi * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93323Scindi * or http://www.opensolaris.org/os/licensing. 103323Scindi * See the License for the specific language governing permissions 113323Scindi * and limitations under the License. 123323Scindi * 133323Scindi * When distributing Covered Code, include this CDDL HEADER in each 143323Scindi * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153323Scindi * If applicable, add the following below this CDDL HEADER, with the 163323Scindi * fields enclosed by brackets "[]" replaced with your own identifying 173323Scindi * information: Portions Copyright [yyyy] [name of copyright owner] 183323Scindi * 193323Scindi * CDDL HEADER END 203323Scindi */ 213323Scindi 223323Scindi /* 234087Scindi * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 243323Scindi * Use is subject to license terms. 253323Scindi */ 263323Scindi #pragma ident "%Z%%M% %I% %E% SMI" 273323Scindi 283323Scindi #include <sys/mdb_modapi.h> 293323Scindi #include <libelf.h> 303323Scindi #include <sys/fm/protocol.h> 313323Scindi #include <topo_mod.h> 323323Scindi #include <topo_tree.h> 333323Scindi #include <topo_module.h> 34*4198Seschrock #include <stddef.h> 353323Scindi 363323Scindi 373323Scindi /* 383323Scindi * We use this to keep track of which bucket we're in while walking 393323Scindi * the modhash and we also cache the length of the hash 403323Scindi */ 413323Scindi static topo_modhash_t tmh; 423323Scindi static uint_t hash_idx; 433323Scindi 443323Scindi static uintptr_t curr_pg; 453323Scindi static uint_t is_root; 463323Scindi static uint_t verbose; 473323Scindi static char *pgrp; 483323Scindi static char *tgt_scheme; 493323Scindi static char parent[255]; 503323Scindi 513323Scindi /* 523323Scindi * This structure is used by the topo_nodehash walker instances to 533323Scindi * keep track of where they're at in the node hash 543323Scindi */ 553323Scindi typedef struct tnwalk_state { 563323Scindi uint_t hash_idx; 573323Scindi topo_nodehash_t hash; 583323Scindi topo_nodehash_t *curr_hash; 593323Scindi } tnwalk_state_t; 603323Scindi 613323Scindi 623323Scindi static char *stab_lvls[] = {"Internal", "", "Private", "Obsolete", "External", 633323Scindi "Unstable", "Evolving", "Stable", "Standard", "Max"}; 643323Scindi 653323Scindi /*ARGSUSED*/ 663323Scindi static int 673323Scindi topo_handle(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 683323Scindi { 693323Scindi char uuid[36], root[36], plat[36], isa[36], machine[36], product[36]; 703323Scindi topo_hdl_t th; 713323Scindi 723323Scindi /* 733323Scindi * Read in the structure and then read in all of the string fields from 743323Scindi * the target's addr space 753323Scindi */ 763323Scindi if (mdb_vread(&th, sizeof (th), addr) != sizeof (th)) { 773323Scindi mdb_warn("failed to read topo_hdl_t at %p", addr); 783323Scindi return (DCMD_ERR); 793323Scindi } 803323Scindi 813323Scindi if (mdb_readstr(uuid, sizeof (uuid), (uintptr_t)th.th_uuid) < 0) { 823323Scindi (void) mdb_snprintf(uuid, sizeof (uuid), "<%p>", th.th_uuid); 833323Scindi } 843323Scindi if (mdb_readstr(root, sizeof (root), (uintptr_t)th.th_rootdir) < 0) { 853323Scindi (void) mdb_snprintf(root, sizeof (root), "<%p>", th.th_rootdir); 863323Scindi } 873323Scindi if (mdb_readstr(plat, sizeof (plat), (uintptr_t)th.th_platform) < 0) { 883323Scindi (void) mdb_snprintf(plat, sizeof (plat), "<%p>", 893323Scindi th.th_platform); 903323Scindi } 913323Scindi if (mdb_readstr(isa, sizeof (isa), (uintptr_t)th.th_isa) < 0) { 923323Scindi (void) mdb_snprintf(isa, sizeof (isa), "<%p>", th.th_isa); 933323Scindi } 943323Scindi if (mdb_readstr(machine, sizeof (machine), (uintptr_t)th.th_machine) 953323Scindi < 0) { 963323Scindi 973323Scindi (void) mdb_snprintf(machine, sizeof (machine), "<%p>", 983323Scindi th.th_machine); 993323Scindi } 1003323Scindi if (mdb_readstr(product, sizeof (product), (uintptr_t)th.th_product) 1013323Scindi < 0) { 1023323Scindi 1033323Scindi (void) mdb_snprintf(product, sizeof (product), "<%p>", 1043323Scindi th.th_product); 1053323Scindi } 1063323Scindi 1073323Scindi /* 1083323Scindi * Dump it all out in a nice pretty format and keep it to 80 chars wide 1093323Scindi */ 1103323Scindi if (DCMD_HDRSPEC(flags)) { 1113323Scindi mdb_printf("%<u>%-12s %-36s %-30s%</u>\n", "FIELD", "VALUE", 1123323Scindi "DESCR"); 1133323Scindi } 1143323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "th_lock", th.th_lock, 1153323Scindi "Mutex lock protecting handle"); 1163323Scindi mdb_printf("%-12s %-36s %-30s\n", "th_uuid", uuid, 1173323Scindi "UUID of the topology snapshot"); 1183323Scindi mdb_printf("%-12s %-36s %-30s\n", "th_rootdir", root, 1193323Scindi "Root directory of plugin paths"); 1203323Scindi mdb_printf("%-12s %-36s %-30s\n", "th_platform", plat, "Platform name"); 1213323Scindi mdb_printf("%-12s %-36s %-30s\n", "th_isa", isa, "ISA name"); 1223323Scindi mdb_printf("%-12s %-36s %-30s\n", "th_machine", machine, 1233323Scindi "Machine name"); 1243323Scindi mdb_printf("%-12s %-36s %-30s\n", "th_product", product, 1253323Scindi "Product name"); 1263323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "th_di", th.th_di, 1273323Scindi "Handle to the root of the devinfo tree"); 1283323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "th_pi", th.th_pi, 1293323Scindi "Handle to the root of the PROM tree"); 1303323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "th_modhash", th.th_modhash, 1313323Scindi "Module hash"); 1323323Scindi mdb_printf("%-12s %-36s %-30s\n", "th_trees", "", 1333323Scindi "Scheme-specific topo tree list"); 1343323Scindi mdb_printf(" %-12s 0x%-34p %-30s\n", "l_prev", th.th_trees.l_prev, 135*4198Seschrock ""); 1363323Scindi mdb_printf(" %-12s 0x%-34p %-30s\n", "l_next", th.th_trees.l_next, 137*4198Seschrock ""); 1383323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "th_alloc", th.th_alloc, 1393323Scindi "Allocators"); 1403323Scindi mdb_printf("%-12s %-36d %-30s\n", "tm_ernno", th.th_errno, "errno"); 1413323Scindi mdb_printf("%-12s %-36d %-30s\n", "tm_debug", th.th_debug, 1423323Scindi "Debug mask"); 1433323Scindi mdb_printf("%-12s %-36d %-30s\n", "tm_dbout", th.th_dbout, 1443323Scindi "Debug channel"); 1453323Scindi 1463323Scindi return (DCMD_OK); 1473323Scindi } 1483323Scindi 1493323Scindi 1503323Scindi /*ARGSUSED*/ 1513323Scindi static int 1523323Scindi topo_module(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1533323Scindi { 1543323Scindi char name[36], path[36], root[36]; 1553323Scindi topo_mod_t tm; 1563323Scindi 1573323Scindi /* 1583323Scindi * Read in the structure and then read in all of the string fields from 1593323Scindi * the target's addr space 1603323Scindi */ 1613323Scindi if (mdb_vread(&tm, sizeof (tm), addr) != sizeof (tm)) { 1623323Scindi mdb_warn("failed to read topo_mod_t at %p", addr); 1633323Scindi return (DCMD_ERR); 1643323Scindi } 1653323Scindi 1663323Scindi if (mdb_readstr(name, sizeof (name), (uintptr_t)tm.tm_name) < 0) { 1673323Scindi (void) mdb_snprintf(name, sizeof (name), "<%p>", tm.tm_name); 1683323Scindi } 1693323Scindi if (mdb_readstr(path, sizeof (path), (uintptr_t)tm.tm_path) < 0) { 1703323Scindi (void) mdb_snprintf(path, sizeof (path), "<%p>", tm.tm_path); 1713323Scindi } 1723323Scindi if (mdb_readstr(root, sizeof (root), (uintptr_t)tm.tm_rootdir) < 0) { 1733323Scindi (void) mdb_snprintf(root, sizeof (root), "<%p>", tm.tm_rootdir); 1743323Scindi } 1753323Scindi 1763323Scindi /* 1773323Scindi * Dump it all out in a nice pretty format and keep it to 80 chars wide 1783323Scindi */ 1793323Scindi if (DCMD_HDRSPEC(flags)) { 1803323Scindi mdb_printf("%<u>%-12s %-36s %-30s%</u>\n", 181*4198Seschrock "FIELD", "VALUE", "DESCR"); 1823323Scindi } 1833323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tm_lock", tm.tm_lock, 184*4198Seschrock "Lock for tm_cv/owner/flags/refs"); 1853323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tm_cv", tm.tm_cv, 186*4198Seschrock "Module condition variable"); 1873323Scindi mdb_printf("%-12s %-36s %-30s\n", "tm_busy", tm.tm_busy, 188*4198Seschrock "Busy indicator"); 1893323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tm_next", tm.tm_next, 190*4198Seschrock "Next module in hash chain"); 1913323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tm_hdl", tm.tm_hdl, 192*4198Seschrock "Topo handle for this module"); 1933323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tm_alloc", tm.tm_alloc, 194*4198Seschrock "Allocators"); 1953323Scindi mdb_printf("%-12s %-36s %-30s\n", "tm_name", name, 196*4198Seschrock "Basename of module"); 1973323Scindi mdb_printf("%-12s %-36s %-30s\n", "tm_path", path, 198*4198Seschrock "Full pathname of module"); 1993323Scindi mdb_printf("%-12s %-36s %-30s\n", "tm_rootdir", root, 200*4198Seschrock "Relative root directory of module"); 2013323Scindi mdb_printf("%-12s %-36u %-30s\n", "tm_refs", tm.tm_refs, 202*4198Seschrock "Module reference count"); 2033323Scindi mdb_printf("%-12s %-36u %-30s\n", "tm_flags", tm.tm_flags, 204*4198Seschrock "Module flags"); 2053323Scindi if (TOPO_MOD_INIT & tm.tm_flags) { 2063323Scindi mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_MOD_INIT", 207*4198Seschrock "Module init completed"); 2083323Scindi } 2093323Scindi if (TOPO_MOD_FINI & tm.tm_flags) { 2103323Scindi mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_MOD_FINI", 211*4198Seschrock "Module fini completed"); 2123323Scindi } 2133323Scindi if (TOPO_MOD_REG & tm.tm_flags) { 2143323Scindi mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_MOD_REG", 215*4198Seschrock "Module registered"); 2163323Scindi } 2173323Scindi if (TOPO_MOD_UNREG & tm.tm_flags) { 2183323Scindi mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_MOD_UNREG", 219*4198Seschrock "Module unregistered"); 2203323Scindi } 2213323Scindi 2223323Scindi mdb_printf("%-12s %-36u %-30s\n", "tm_debug", tm.tm_debug, 223*4198Seschrock "Debug printf mask"); 2243323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tm_data", tm.tm_data, 225*4198Seschrock "Private rtld/builtin data"); 2263323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tm_mops", tm.tm_mops, 227*4198Seschrock "Module class ops vector"); 2283323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tm_info", tm.tm_info, 229*4198Seschrock "Module info registered with handle"); 2303323Scindi mdb_printf("%-12s %-36d %-30s\n", "tm_ernno", tm.tm_errno, 231*4198Seschrock "Module errno"); 2323323Scindi 2333323Scindi return (DCMD_OK); 2343323Scindi } 2353323Scindi 2363323Scindi 2373323Scindi /*ARGSUSED*/ 2383323Scindi static int 2393323Scindi topo_node(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2403323Scindi { 2413323Scindi char name[36]; 2423323Scindi tnode_t tn; 2433323Scindi 2443323Scindi if (!addr) 2453323Scindi return (DCMD_ERR); 2463323Scindi 2473323Scindi /* 2483323Scindi * Read in the structure and then read in all of the string fields from 2493323Scindi * the target's addr space 2503323Scindi */ 2513323Scindi if (mdb_vread(&tn, sizeof (tn), addr) != sizeof (tn)) { 2523323Scindi mdb_warn("failed to read tnode_t at %p", addr); 2533323Scindi return (DCMD_ERR); 2543323Scindi } 2553323Scindi 2563323Scindi if (mdb_readstr(name, sizeof (name), (uintptr_t)tn.tn_name) < 0) { 2573323Scindi (void) mdb_snprintf(name, sizeof (name), "<%p>", tn.tn_name); 2583323Scindi } 2593323Scindi 2603323Scindi /* 2613323Scindi * Dump it all out in a nice pretty format and keep it to 80 chars wide 2623323Scindi */ 2633323Scindi if (DCMD_HDRSPEC(flags)) { 2643323Scindi mdb_printf("%<u>%-12s %-36s %-30s%</u>\n", 2653323Scindi "FIELD", "VALUE", "DESCR"); 2663323Scindi } 2673323Scindi 268*4198Seschrock mdb_printf("%-12s 0x%-34p %-30s\n", "tn_lock", 269*4198Seschrock addr + offsetof(tnode_t, tn_lock), 270*4198Seschrock "Lock protecting node members"); 2713323Scindi mdb_printf("%-12s %-36s %-30s\n", "tn_name", name, 272*4198Seschrock "Node name"); 2733323Scindi mdb_printf("%-12s %-36d %-30s\n", "tn_instance", tn.tn_instance, 274*4198Seschrock "Node instance"); 2753323Scindi mdb_printf("%-12s %-36d %-30s\n", "tn_state", tn.tn_state, 276*4198Seschrock "Node state"); 2773323Scindi if (TOPO_NODE_INIT & tn.tn_state) { 2783323Scindi mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_NODE_INIT", ""); 2793323Scindi } 2803323Scindi if (TOPO_NODE_ROOT & tn.tn_state) { 2813323Scindi mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_NODE_ROOT", ""); 2823323Scindi } 2833323Scindi if (TOPO_NODE_BOUND & tn.tn_state) { 2843323Scindi mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_NODE_BOUND", ""); 2853323Scindi } 2863323Scindi if (TOPO_NODE_LINKED & tn.tn_state) { 2873323Scindi mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_NODE_LINKED", ""); 2883323Scindi } 2893323Scindi mdb_printf("%-12s %-36d %-30s\n", "tn_fflags", tn.tn_fflags, 290*4198Seschrock "FMRI flags"); 2913323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tn_parent", tn.tn_parent, 292*4198Seschrock "Node parent"); 2933323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tn_phash", tn.tn_phash, 294*4198Seschrock "Parent hash bucket"); 2953323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tn_hdl", tn.tn_hdl, 296*4198Seschrock "Topo handle"); 2973323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tn_enum", tn.tn_enum, 298*4198Seschrock "Enumerator module"); 2993323Scindi mdb_printf("%-12s %-36s %-30s\n", "tn_children", "", 300*4198Seschrock "Hash table of child nodes"); 301*4198Seschrock mdb_printf(" %-12s 0x%-34p\n", "l_prev", tn.tn_children.l_prev); 302*4198Seschrock mdb_printf(" %-12s 0x%-34p\n", "l_next", tn.tn_children.l_next); 3033323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tn_pgroups", &(tn.tn_pgroups), 304*4198Seschrock "Property group list"); 3053323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tn_methods", &(tn.tn_methods), 306*4198Seschrock "Registered method list"); 3073323Scindi mdb_printf("%-12s 0x%-34p %-30s\n", "tn_priv", tn.tn_priv, 308*4198Seschrock "Private enumerator data"); 3093323Scindi mdb_printf("%-12s %-36d %-30s\n", "tn_refs", tn.tn_refs, 310*4198Seschrock "Node reference count"); 3113323Scindi 3123323Scindi return (DCMD_OK); 3133323Scindi } 3143323Scindi 3153323Scindi /*ARGSUSED*/ 3163323Scindi static int 3173323Scindi find_tree_root(uintptr_t addr, const void *data, void *arg) 3183323Scindi { 3193323Scindi ttree_t *tree = (ttree_t *)data; 3203323Scindi char scheme[36]; 3213323Scindi 3223323Scindi if (mdb_readstr(scheme, sizeof (scheme), (uintptr_t)tree->tt_scheme) 3233323Scindi < 0) { 3243323Scindi (void) mdb_snprintf(scheme, sizeof (scheme), "<%p>", 3253323Scindi tree->tt_scheme); 3263323Scindi } 3273323Scindi 3283323Scindi if (strncmp(tgt_scheme, scheme, 36) == 0) { 3293323Scindi *((tnode_t **)arg) = tree->tt_root; 3303323Scindi return (WALK_DONE); 3313323Scindi } 3323323Scindi return (WALK_NEXT); 3333323Scindi } 3343323Scindi 3354087Scindi static void 3364087Scindi dump_propmethod(uintptr_t addr) 3374087Scindi { 3384087Scindi topo_propmethod_t pm; 3394087Scindi 3404087Scindi if (mdb_vread(&pm, sizeof (pm), addr) != sizeof (pm)) { 3414087Scindi mdb_warn("failed to read topo_propmethod at %p", addr); 3424087Scindi return; 3434087Scindi } 3444087Scindi 3454087Scindi mdb_printf(" method: %-32s version: %-16s args: %p\n", 3464087Scindi pm.tpm_name, pm.tpm_version, pm.tpm_args); 3474087Scindi } 3483323Scindi 3493323Scindi /* 3503323Scindi * Dump the given property value. For the actual property values 3513323Scindi * we dump a pointer to the nvlist which can be decoded using the ::nvlist 3523323Scindi * dcmd from the libnvpair MDB module 3533323Scindi */ 3543323Scindi /*ARGSUSED*/ 3553323Scindi static int 3563323Scindi dump_propval(uintptr_t addr, const void *data, void *arg) 3573323Scindi { 3583323Scindi topo_proplist_t *plistp = (topo_proplist_t *)data; 3593323Scindi topo_propval_t pval; 3603323Scindi char name[32], *type; 3613323Scindi 3623323Scindi if (mdb_vread(&pval, sizeof (pval), (uintptr_t)plistp->tp_pval) 3633323Scindi != sizeof (pval)) { 3643323Scindi 3653323Scindi mdb_warn("failed to read topo_propval_t at %p", 3663323Scindi plistp->tp_pval); 3673323Scindi return (WALK_ERR); 3683323Scindi } 3693323Scindi if (mdb_readstr(name, sizeof (name), (uintptr_t)pval.tp_name) < 0) { 3703323Scindi (void) mdb_snprintf(name, sizeof (name), "<%p>", pval.tp_name); 3713323Scindi } 3723323Scindi switch (pval.tp_type) { 3733323Scindi case TOPO_TYPE_BOOLEAN: type = "boolean"; break; 3743323Scindi case TOPO_TYPE_INT32: type = "int32"; break; 3753323Scindi case TOPO_TYPE_UINT32: type = "uint32"; break; 3763323Scindi case TOPO_TYPE_INT64: type = "int64"; break; 3773323Scindi case TOPO_TYPE_UINT64: type = "uint64"; break; 3783323Scindi case TOPO_TYPE_STRING: type = "string"; break; 3793323Scindi case TOPO_TYPE_FMRI: type = "fmri"; break; 3803323Scindi case TOPO_TYPE_INT32_ARRAY: type = "int32[]"; break; 3813323Scindi case TOPO_TYPE_UINT32_ARRAY: type = "uint32[]"; break; 3823323Scindi case TOPO_TYPE_INT64_ARRAY: type = "int64[]"; break; 3833323Scindi case TOPO_TYPE_UINT64_ARRAY: type = "uint64[]"; break; 3843323Scindi case TOPO_TYPE_STRING_ARRAY: type = "string[]"; break; 3853323Scindi case TOPO_TYPE_FMRI_ARRAY: type = "fmri[]"; break; 3863323Scindi default: type = "unknown type"; 3873323Scindi } 3883323Scindi mdb_printf(" %-32s %-16s value: %p\n", name, type, pval.tp_val); 3894087Scindi 3904087Scindi if (pval.tp_method != NULL) 3914087Scindi dump_propmethod((uintptr_t)pval.tp_method); 3924087Scindi 3933323Scindi return (WALK_NEXT); 3943323Scindi } 3953323Scindi 3963323Scindi 3973323Scindi /* 3983323Scindi * Dumps the contents of the property group. 3993323Scindi */ 4003323Scindi /*ARGSUSED*/ 4013323Scindi static int 4023323Scindi dump_pgroup(uintptr_t addr, const void *data, void *arg) 4033323Scindi { 4043323Scindi topo_pgroup_t *pgp = (topo_pgroup_t *)data; 4053323Scindi topo_ipgroup_info_t ipg; 4063323Scindi char buf[32]; 4073323Scindi 4083323Scindi if (mdb_vread(&ipg, sizeof (ipg), (uintptr_t)pgp->tpg_info) 4093323Scindi != sizeof (ipg)) { 4103323Scindi 4113323Scindi mdb_warn("failed to read topo_ipgroup_info_t at %p", 4123323Scindi pgp->tpg_info); 4133323Scindi return (WALK_ERR); 4143323Scindi } 4153323Scindi if (mdb_readstr(buf, sizeof (buf), (uintptr_t)ipg.tpi_name) < 0) { 4163323Scindi mdb_warn("failed to read string at %p", ipg.tpi_name); 4173323Scindi return (WALK_ERR); 4183323Scindi } 4193323Scindi /* 4203323Scindi * If this property group is the one we're interested in or if the user 4213323Scindi * specified the "all" property group, we'll dump it 4223323Scindi */ 4233323Scindi if ((strncmp(pgrp, buf, sizeof (buf)) == 0) || 4243323Scindi (strncmp(pgrp, "all", sizeof (buf)) == 0)) { 4253323Scindi 4263323Scindi mdb_printf(" group: %-32s version: %d, stability: %s/%s\n", 4273323Scindi buf, ipg.tpi_version, stab_lvls[ipg.tpi_namestab], 4283323Scindi stab_lvls[ipg.tpi_datastab]); 4293323Scindi 4303323Scindi (void) mdb_pwalk("topo_proplist", dump_propval, NULL, curr_pg); 4313323Scindi } 4323323Scindi return (WALK_NEXT); 4333323Scindi } 4343323Scindi 4353323Scindi 4363323Scindi /* 4373323Scindi * Recursive function to dump the specified node and all of it's children 4383323Scindi */ 4393323Scindi /*ARGSUSED*/ 4403323Scindi static int 4413323Scindi dump_tnode(uintptr_t addr, const void *data, void *arg) 4423323Scindi { 4433323Scindi tnode_t node; 4443323Scindi char pname[255], buf[80], old_pname[255]; 4453323Scindi 4463323Scindi if (!addr) { 4473323Scindi return (WALK_NEXT); 4483323Scindi } 4493323Scindi 4503323Scindi if (mdb_vread(&node, sizeof (node), addr) != sizeof (node)) { 4513323Scindi mdb_warn("failed to read tnode_t at %p", addr); 4523323Scindi return (WALK_ERR); 4533323Scindi } 4543323Scindi if (mdb_readstr(buf, sizeof (buf), (uintptr_t)node.tn_name) < 0) { 4553323Scindi (void) mdb_snprintf(buf, sizeof (buf), "<%p>", 4563323Scindi node.tn_name); 4573323Scindi } 4583323Scindi 4593323Scindi if (is_root) { 4603323Scindi mdb_snprintf(pname, sizeof (pname), "%s", parent); 4613323Scindi is_root = 0; 4623323Scindi } else { 4633323Scindi mdb_snprintf(pname, sizeof (pname), "%s/%s=%u", 4643323Scindi parent, buf, node.tn_instance); 4653323Scindi 4663323Scindi if (verbose) 4673323Scindi mdb_printf("%s\n tnode_t: %p\n", pname, addr); 4683323Scindi else 4693323Scindi mdb_printf("%s\n", pname); 4703323Scindi } 4713323Scindi mdb_snprintf(old_pname, sizeof (old_pname), "%s", parent); 4723323Scindi mdb_snprintf(parent, sizeof (parent), "%s", pname); 4733323Scindi 4743323Scindi if (pgrp) 4753323Scindi (void) mdb_pwalk("topo_pgroup", dump_pgroup, NULL, addr); 4763323Scindi 4773323Scindi (void) mdb_pwalk("topo_nodehash", dump_tnode, NULL, addr); 4783323Scindi mdb_snprintf(parent, sizeof (parent), "%s", old_pname); 4793323Scindi 4803323Scindi return (WALK_NEXT); 4813323Scindi } 4823323Scindi 4833323Scindi 4843323Scindi /* 4853323Scindi * Given a topo_hdl_t *, the topo dcmd dumps the topo tree. The format of the 4863323Scindi * output is modeled after fmtopo. Like fmtopo, by default, we'll dump the 4873323Scindi * "hc" scheme tree. The user can optionally specify a different tree via the 4883323Scindi * "-s <scheme>" option. 4893323Scindi * 4903323Scindi * Specifying the "-v" option provides more verbose output. Currently it 4913323Scindi * outputs the tnode_t * addr for each node, which is useful if you want to 4923323Scindi * dump it with the topo_node dcmd. 4933323Scindi * 4943323Scindi * The functionality of the "-P" option is similar to fmtopo. 4953323Scindi */ 4963323Scindi /*ARGSUSED*/ 4973323Scindi static int 4983323Scindi fmtopo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 4993323Scindi { 5003323Scindi char product[36], *opt_s = NULL, *opt_P = NULL; 5013323Scindi topo_hdl_t th; 5023323Scindi tnode_t *tree_root; 5033323Scindi uint_t opt_v = FALSE; 5043323Scindi char *def_scheme = "hc"; 5053323Scindi 5063323Scindi if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &opt_v, 5073323Scindi 's', MDB_OPT_STR, &opt_s, 'P', MDB_OPT_STR, &opt_P, NULL) 5083323Scindi != argc) { 5093323Scindi return (DCMD_USAGE); 5103323Scindi } 5113323Scindi 5123323Scindi if (opt_s) { 5133323Scindi tgt_scheme = opt_s; 5143323Scindi } else { 5153323Scindi tgt_scheme = def_scheme; 5163323Scindi } 5173323Scindi 5183323Scindi pgrp = opt_P; 5193323Scindi verbose = opt_v; 5203323Scindi is_root = 1; 5213323Scindi 5223323Scindi /* 5233323Scindi * Read in the topo_handle and some of its string fields from 5243323Scindi * the target's addr space 5253323Scindi */ 5263323Scindi if (mdb_vread(&th, sizeof (th), addr) != sizeof (th)) { 5273323Scindi mdb_warn("failed to read topo_hdl_t at %p", addr); 5283323Scindi return (DCMD_ERR); 5293323Scindi } 5303323Scindi 5313323Scindi if (mdb_readstr(product, sizeof (product), (uintptr_t)th.th_product) 5323323Scindi < 0) { 5333323Scindi 5343323Scindi (void) mdb_snprintf(product, sizeof (product), "<%p>", 5353323Scindi th.th_product); 5363323Scindi } 5373323Scindi 5383323Scindi mdb_snprintf(parent, sizeof (parent), 5393323Scindi "%s://:product-id=%s", tgt_scheme, product); 5403323Scindi 5413323Scindi /* 5423323Scindi * Walk the list of topo trees, looking for the one that is for the 5433323Scindi * scheme we're interested in. 5443323Scindi */ 5453323Scindi tree_root = NULL; 5463323Scindi mdb_pwalk("topo_tree", find_tree_root, &tree_root, addr); 5473323Scindi 5483323Scindi if (! tree_root) { 5493323Scindi mdb_warn("failed to find a topo tree for scheme %s\n", 5503323Scindi tgt_scheme); 5513323Scindi return (DCMD_ERR); 5523323Scindi } 5533323Scindi 5543323Scindi return (dump_tnode((uintptr_t)tree_root, NULL, NULL)); 5553323Scindi } 5563323Scindi 5573323Scindi 5583323Scindi static int 5593323Scindi ttree_walk_init(mdb_walk_state_t *wsp) 5603323Scindi { 5613323Scindi topo_hdl_t th; 5623323Scindi 5633323Scindi if (wsp->walk_addr == NULL) { 5643323Scindi mdb_warn("NULL topo_hdl_t passed in"); 5653323Scindi return (WALK_ERR); 5663323Scindi } 5673323Scindi 5683323Scindi if (mdb_vread(&th, sizeof (th), wsp->walk_addr) != sizeof (th)) { 5693323Scindi mdb_warn("failed to read topo_hdl_t at %p", wsp->walk_addr); 5703323Scindi return (WALK_ERR); 5713323Scindi } 5723323Scindi 5733323Scindi wsp->walk_addr = (uintptr_t)th.th_trees.l_next; 5743323Scindi wsp->walk_data = mdb_alloc(sizeof (ttree_t), UM_SLEEP); 5753323Scindi 5763323Scindi return (WALK_NEXT); 5773323Scindi } 5783323Scindi 5793323Scindi 5803323Scindi static int 5813323Scindi ttree_walk_step(mdb_walk_state_t *wsp) 5823323Scindi { 5833323Scindi int rv; 5843323Scindi ttree_t *tree; 5853323Scindi 5863323Scindi if (wsp->walk_addr == NULL) 5873323Scindi return (WALK_DONE); 5883323Scindi 5893323Scindi if (mdb_vread(wsp->walk_data, sizeof (ttree_t), wsp->walk_addr) 5903323Scindi != sizeof (ttree_t)) { 5913323Scindi 5923323Scindi mdb_warn("failed to read ttree_t at %p", wsp->walk_addr); 5933323Scindi return (WALK_ERR); 5943323Scindi } 5953323Scindi 5963323Scindi rv = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 5973323Scindi wsp->walk_cbdata); 5983323Scindi 5993323Scindi tree = (ttree_t *)wsp->walk_data; 6003323Scindi wsp->walk_addr = (uintptr_t)tree->tt_list.l_next; 6013323Scindi 6023323Scindi return (rv); 6033323Scindi } 6043323Scindi 6053323Scindi 6063323Scindi static void 6073323Scindi ttree_walk_fini(mdb_walk_state_t *wsp) 6083323Scindi { 6093323Scindi mdb_free(wsp->walk_data, sizeof (ttree_t)); 6103323Scindi } 6113323Scindi 6123323Scindi 6133323Scindi static int 6143323Scindi tmod_walk_init(mdb_walk_state_t *wsp) 6153323Scindi { 6163323Scindi topo_hdl_t th; 6173323Scindi 6183323Scindi if (wsp->walk_addr == NULL) { 6193323Scindi mdb_warn("NULL topo_hdl_t passed in"); 6203323Scindi return (WALK_ERR); 6213323Scindi } 6223323Scindi 6233323Scindi if (mdb_vread(&th, sizeof (th), wsp->walk_addr) != sizeof (th)) { 6243323Scindi mdb_warn("failed to read topo_hdl_t at %p", wsp->walk_addr); 6253323Scindi return (WALK_ERR); 6263323Scindi } 6273323Scindi 6283323Scindi if (mdb_vread(&tmh, sizeof (topo_modhash_t), (uintptr_t)th.th_modhash) 6293323Scindi == -1) { 6303323Scindi 6313323Scindi mdb_warn("failed to read topo_modhash_t at %p", wsp->walk_addr); 6323323Scindi return (WALK_DONE); 6333323Scindi } 6343323Scindi 6353323Scindi hash_idx = 0; 6363323Scindi 6373323Scindi if (mdb_vread(&(wsp->walk_addr), sizeof (uintptr_t *), 6383323Scindi (uintptr_t)(tmh.mh_hash)) != sizeof (tnode_t *)) { 6393323Scindi 6403323Scindi mdb_warn("failed to read %u bytes at %p", sizeof (tnode_t *), 6413323Scindi tmh.mh_hash); 6423323Scindi return (WALK_ERR); 6433323Scindi } 6443323Scindi 6453323Scindi wsp->walk_data = mdb_alloc(sizeof (topo_mod_t), UM_SLEEP); 6463323Scindi 6473323Scindi return (WALK_NEXT); 6483323Scindi } 6493323Scindi 6503323Scindi 6513323Scindi static int 6523323Scindi tmod_walk_step(mdb_walk_state_t *wsp) 6533323Scindi { 6543323Scindi int rv; 6553323Scindi topo_mod_t *tm; 6563323Scindi 6573323Scindi if (wsp->walk_addr == NULL) 6583323Scindi return (WALK_DONE); 6593323Scindi 6603323Scindi if (mdb_vread(wsp->walk_data, sizeof (topo_mod_t), wsp->walk_addr) 6613323Scindi == -1) { 6623323Scindi 6633323Scindi mdb_warn("failed to read topo_mod_t at %p", wsp->walk_addr); 6643323Scindi return (WALK_DONE); 6653323Scindi } 6663323Scindi 6673323Scindi rv = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 6683323Scindi wsp->walk_cbdata); 6693323Scindi 6703323Scindi tm = (topo_mod_t *)wsp->walk_data; 6713323Scindi 6723323Scindi if (tm->tm_next) 6733323Scindi wsp->walk_addr = (uintptr_t)tm->tm_next; 6743323Scindi else if (++hash_idx < tmh.mh_hashlen) 6753323Scindi if (mdb_vread(&(wsp->walk_addr), sizeof (uintptr_t *), 6763323Scindi (uintptr_t)(tmh.mh_hash+hash_idx)) != sizeof (tnode_t *)) { 6773323Scindi 6783323Scindi mdb_warn("failed to read %u bytes at %p", 6793323Scindi sizeof (tnode_t *), tmh.mh_hash+hash_idx); 6803323Scindi return (DCMD_ERR); 6813323Scindi } 6823323Scindi else 6833323Scindi wsp->walk_addr = NULL; 6843323Scindi 6853323Scindi return (rv); 6863323Scindi } 6873323Scindi 6883323Scindi static void 6893323Scindi tmod_walk_fini(mdb_walk_state_t *wsp) 6903323Scindi { 6913323Scindi mdb_free(wsp->walk_data, sizeof (topo_mod_t)); 6923323Scindi } 6933323Scindi 6943323Scindi 6953323Scindi static int 6963323Scindi tpg_walk_init(mdb_walk_state_t *wsp) 6973323Scindi { 6983323Scindi tnode_t node; 6993323Scindi 7003323Scindi if (wsp->walk_addr == NULL) { 7013323Scindi mdb_warn("NULL tnode_t passed in"); 7023323Scindi return (WALK_ERR); 7033323Scindi } 7043323Scindi 7053323Scindi if (mdb_vread(&node, sizeof (node), wsp->walk_addr) != sizeof (node)) { 7063323Scindi mdb_warn("failed to read tnode_t at %p", wsp->walk_addr); 7073323Scindi return (WALK_ERR); 7083323Scindi } 7093323Scindi 7103323Scindi wsp->walk_addr = (uintptr_t)node.tn_pgroups.l_next; 7113323Scindi wsp->walk_data = mdb_alloc(sizeof (topo_pgroup_t), UM_SLEEP); 7123323Scindi 7133323Scindi return (WALK_NEXT); 7143323Scindi } 7153323Scindi 7163323Scindi 7173323Scindi static int 7183323Scindi tpg_walk_step(mdb_walk_state_t *wsp) 7193323Scindi { 7203323Scindi int rv; 7213323Scindi topo_pgroup_t *tpgp; 7223323Scindi 7233323Scindi if (wsp->walk_addr == NULL) 7243323Scindi return (WALK_DONE); 7253323Scindi 7263323Scindi if (mdb_vread(wsp->walk_data, sizeof (topo_pgroup_t), wsp->walk_addr) 7273323Scindi == -1) { 7283323Scindi 7293323Scindi mdb_warn("failed to read topo_pgroup_t at %p", wsp->walk_addr); 7303323Scindi return (WALK_DONE); 7313323Scindi } 7323323Scindi 7333323Scindi curr_pg = wsp->walk_addr; 7343323Scindi rv = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 7353323Scindi wsp->walk_cbdata); 7363323Scindi 7373323Scindi tpgp = (topo_pgroup_t *)wsp->walk_data; 7383323Scindi wsp->walk_addr = (uintptr_t)tpgp->tpg_list.l_next; 7393323Scindi 7403323Scindi return (rv); 7413323Scindi } 7423323Scindi 7433323Scindi 7443323Scindi static void 7453323Scindi tpg_walk_fini(mdb_walk_state_t *wsp) 7463323Scindi { 7473323Scindi mdb_free(wsp->walk_data, sizeof (topo_pgroup_t)); 7483323Scindi } 7493323Scindi 7503323Scindi 7513323Scindi static int 7523323Scindi tpl_walk_init(mdb_walk_state_t *wsp) 7533323Scindi { 7543323Scindi topo_pgroup_t pg; 7553323Scindi 7563323Scindi if (wsp->walk_addr == NULL) { 7573323Scindi mdb_warn("NULL topo_pgroup_t passed in"); 7583323Scindi return (WALK_ERR); 7593323Scindi } 7603323Scindi 7613323Scindi if (mdb_vread(&pg, sizeof (pg), wsp->walk_addr) != sizeof (pg)) { 7623323Scindi mdb_warn("failed to read topo_pgroup_t at %p", wsp->walk_addr); 7633323Scindi return (WALK_ERR); 7643323Scindi } 7653323Scindi 7663323Scindi wsp->walk_addr = (uintptr_t)pg.tpg_pvals.l_next; 7673323Scindi wsp->walk_data = mdb_alloc(sizeof (topo_proplist_t), UM_SLEEP); 7683323Scindi 7693323Scindi return (WALK_NEXT); 7703323Scindi } 7713323Scindi 7723323Scindi 7733323Scindi static int 7743323Scindi tpl_walk_step(mdb_walk_state_t *wsp) 7753323Scindi { 7763323Scindi int rv; 7773323Scindi topo_proplist_t *plp; 7783323Scindi 7793323Scindi if (wsp->walk_addr == NULL) 7803323Scindi return (WALK_DONE); 7813323Scindi 7823323Scindi if (mdb_vread(wsp->walk_data, sizeof (topo_proplist_t), wsp->walk_addr) 7833323Scindi == -1) { 7843323Scindi 7853323Scindi mdb_warn("failed to read topo_proplist_t at %p", 7863323Scindi wsp->walk_addr); 7873323Scindi return (WALK_DONE); 7883323Scindi } 7893323Scindi plp = (topo_proplist_t *)wsp->walk_data; 7903323Scindi 7913323Scindi rv = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 7923323Scindi wsp->walk_cbdata); 7933323Scindi 7943323Scindi wsp->walk_addr = (uintptr_t)plp->tp_list.l_next; 7953323Scindi 7963323Scindi return (rv); 7973323Scindi } 7983323Scindi 7993323Scindi 8003323Scindi static void 8013323Scindi tpl_walk_fini(mdb_walk_state_t *wsp) 8023323Scindi { 8033323Scindi mdb_free(wsp->walk_data, sizeof (topo_proplist_t)); 8043323Scindi } 8053323Scindi 8063323Scindi 8073323Scindi static int 8083323Scindi tnh_walk_init(mdb_walk_state_t *wsp) 8093323Scindi { 8103323Scindi tnode_t node; 8113323Scindi tnwalk_state_t *state; 8123323Scindi 8133323Scindi if (wsp->walk_addr == NULL) { 8143323Scindi mdb_warn("NULL tnode_t passed in"); 8153323Scindi return (WALK_ERR); 8163323Scindi } 8173323Scindi 8183323Scindi if (mdb_vread(&node, sizeof (node), wsp->walk_addr) != sizeof (node)) { 8193323Scindi mdb_warn("failed to read tnode_t at %p", wsp->walk_addr); 8203323Scindi return (WALK_ERR); 8213323Scindi } 8223323Scindi 8233323Scindi state = mdb_zalloc(sizeof (tnwalk_state_t), UM_SLEEP); 8243323Scindi 8253323Scindi state->curr_hash = (topo_nodehash_t *)node.tn_children.l_next; 8263323Scindi state->hash_idx = 0; 8273323Scindi wsp->walk_data = state; 8283323Scindi 8293323Scindi return (WALK_NEXT); 8303323Scindi } 8313323Scindi 8323323Scindi 8333323Scindi static int 8343323Scindi tnh_walk_step(mdb_walk_state_t *wsp) 8353323Scindi { 8363323Scindi tnwalk_state_t *state = wsp->walk_data; 8373323Scindi int rv, i = state->hash_idx++; 8383323Scindi tnode_t *npp; 8393323Scindi 8403323Scindi if (state->curr_hash == NULL) 8413323Scindi return (WALK_DONE); 8423323Scindi 8433323Scindi if (mdb_vread(&(state->hash), sizeof (topo_nodehash_t), 8443323Scindi (uintptr_t)state->curr_hash) != sizeof (topo_nodehash_t)) { 8453323Scindi 8463323Scindi mdb_warn("failed to read topo_nodehash_t at %p", 8473323Scindi (uintptr_t)state->curr_hash); 8483323Scindi return (WALK_ERR); 8493323Scindi } 8503323Scindi 8513323Scindi if (mdb_vread(&npp, sizeof (tnode_t *), 8523323Scindi (uintptr_t)(state->hash.th_nodearr+i)) != sizeof (tnode_t *)) { 8533323Scindi 8543323Scindi mdb_warn("failed to read %u bytes at %p", sizeof (tnode_t *), 8553323Scindi state->hash.th_nodearr+i); 8563323Scindi return (WALK_ERR); 8573323Scindi } 8583323Scindi wsp->walk_addr = (uintptr_t)npp; 8593323Scindi 8603323Scindi rv = wsp->walk_callback(wsp->walk_addr, state, wsp->walk_cbdata); 8613323Scindi 8623323Scindi if (state->hash_idx >= state->hash.th_arrlen) { 8633323Scindi /* 8643323Scindi * move on to the next child hash bucket 8653323Scindi */ 8663323Scindi state->curr_hash = 8673323Scindi (topo_nodehash_t *)(state->hash.th_list.l_next); 8683323Scindi state->hash_idx = 0; 8693323Scindi } 8703323Scindi 8713323Scindi return (rv); 8723323Scindi } 8733323Scindi 8743323Scindi 8753323Scindi static void 8763323Scindi tnh_walk_fini(mdb_walk_state_t *wsp) 8773323Scindi { 8783323Scindi mdb_free(wsp->walk_data, sizeof (tnwalk_state_t)); 8793323Scindi } 8803323Scindi 8813323Scindi 8823323Scindi static const mdb_dcmd_t dcmds[] = { 8833323Scindi { "topo_handle", "", "print contents of a topo handle", topo_handle, 8843323Scindi NULL }, 8853323Scindi { "topo_module", "", "print contents of a topo module handle", 8863323Scindi topo_module, NULL }, 8873323Scindi { "topo_node", "", "print contents of a topo node", topo_node, NULL }, 8883323Scindi { "fmtopo", "[-P <pgroup>][-s <scheme>][-v]", 8893323Scindi "print topology of the given handle", fmtopo, NULL }, 8903323Scindi { NULL } 8913323Scindi }; 8923323Scindi 8933323Scindi static const mdb_walker_t walkers[] = { 8943323Scindi { "topo_tree", "walk the tree list for a given topo handle", 8953323Scindi ttree_walk_init, ttree_walk_step, ttree_walk_fini, NULL }, 8963323Scindi { "topo_module", "walk the module hash for a given topo handle", 8973323Scindi tmod_walk_init, tmod_walk_step, tmod_walk_fini, NULL }, 8983323Scindi { "topo_pgroup", "walk the property groups for a given topo node", 8993323Scindi tpg_walk_init, tpg_walk_step, tpg_walk_fini, NULL }, 9003323Scindi { "topo_proplist", "walk the property list for a given property group", 9013323Scindi tpl_walk_init, tpl_walk_step, tpl_walk_fini, NULL }, 9023323Scindi { "topo_nodehash", "walk the child nodehash for a given topo node", 9033323Scindi tnh_walk_init, tnh_walk_step, tnh_walk_fini, NULL }, 9043323Scindi { NULL } 9053323Scindi }; 9063323Scindi 9073323Scindi static const mdb_modinfo_t modinfo = { 9083323Scindi MDB_API_VERSION, dcmds, walkers 9093323Scindi }; 9103323Scindi 9113323Scindi const mdb_modinfo_t * 9123323Scindi _mdb_init(void) 9133323Scindi { 9143323Scindi return (&modinfo); 9153323Scindi } 916