xref: /onnv-gate/usr/src/cmd/mdb/common/modules/libtopo/libtopo.c (revision 5068:06d88145c7f7)
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>
344198Seschrock #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 	}
114*5068Srobj 	mdb_printf("%-12s 0x%-34p %-30s\n", "th_lock",
115*5068Srobj 	    addr + offsetof(topo_hdl_t, th_lock),
1163323Scindi 	    "Mutex lock protecting handle");
1173323Scindi 	mdb_printf("%-12s %-36s %-30s\n", "th_uuid", uuid,
1183323Scindi 	    "UUID of the topology snapshot");
1193323Scindi 	mdb_printf("%-12s %-36s %-30s\n", "th_rootdir", root,
1203323Scindi 	    "Root directory of plugin paths");
1213323Scindi 	mdb_printf("%-12s %-36s %-30s\n", "th_platform", plat, "Platform name");
1223323Scindi 	mdb_printf("%-12s %-36s %-30s\n", "th_isa", isa, "ISA name");
1233323Scindi 	mdb_printf("%-12s %-36s %-30s\n", "th_machine", machine,
1243323Scindi 	    "Machine name");
1253323Scindi 	mdb_printf("%-12s %-36s %-30s\n", "th_product", product,
1263323Scindi 	    "Product name");
1273323Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "th_di", th.th_di,
1283323Scindi 	    "Handle to the root of the devinfo tree");
1293323Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "th_pi", th.th_pi,
1303323Scindi 	    "Handle to the root of the PROM tree");
1313323Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "th_modhash", th.th_modhash,
1323323Scindi 	    "Module hash");
1333323Scindi 	mdb_printf("%-12s %-36s %-30s\n", "th_trees", "",
1343323Scindi 	    "Scheme-specific topo tree list");
1353323Scindi 	mdb_printf("  %-12s 0x%-34p %-30s\n", "l_prev", th.th_trees.l_prev,
1364198Seschrock 	    "");
1373323Scindi 	mdb_printf("  %-12s 0x%-34p %-30s\n", "l_next", th.th_trees.l_next,
1384198Seschrock 	    "");
1393323Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "th_alloc", th.th_alloc,
1403323Scindi 	    "Allocators");
1413323Scindi 	mdb_printf("%-12s %-36d %-30s\n", "tm_ernno", th.th_errno, "errno");
1423323Scindi 	mdb_printf("%-12s %-36d %-30s\n", "tm_debug", th.th_debug,
1433323Scindi 	    "Debug mask");
1443323Scindi 	mdb_printf("%-12s %-36d %-30s\n", "tm_dbout", th.th_dbout,
1453323Scindi 	    "Debug channel");
1463323Scindi 
1473323Scindi 	return (DCMD_OK);
1483323Scindi }
1493323Scindi 
1503323Scindi 
1513323Scindi /*ARGSUSED*/
1523323Scindi static int
1533323Scindi topo_module(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1543323Scindi {
1553323Scindi 	char name[36], path[36], root[36];
1563323Scindi 	topo_mod_t tm;
1573323Scindi 
1583323Scindi 	/*
1593323Scindi 	 * Read in the structure and then read in all of the string fields from
1603323Scindi 	 * the target's addr space
1613323Scindi 	 */
1623323Scindi 	if (mdb_vread(&tm, sizeof (tm), addr) != sizeof (tm)) {
1633323Scindi 		mdb_warn("failed to read topo_mod_t at %p", addr);
1643323Scindi 		return (DCMD_ERR);
1653323Scindi 	}
1663323Scindi 
1673323Scindi 	if (mdb_readstr(name, sizeof (name), (uintptr_t)tm.tm_name) < 0) {
1683323Scindi 		(void) mdb_snprintf(name, sizeof (name), "<%p>", tm.tm_name);
1693323Scindi 	}
1703323Scindi 	if (mdb_readstr(path, sizeof (path), (uintptr_t)tm.tm_path) < 0) {
1713323Scindi 		(void) mdb_snprintf(path, sizeof (path), "<%p>", tm.tm_path);
1723323Scindi 	}
1733323Scindi 	if (mdb_readstr(root, sizeof (root), (uintptr_t)tm.tm_rootdir) < 0) {
1743323Scindi 		(void) mdb_snprintf(root, sizeof (root), "<%p>", tm.tm_rootdir);
1753323Scindi 	}
1763323Scindi 
1773323Scindi 	/*
1783323Scindi 	 * Dump it all out in a nice pretty format and keep it to 80 chars wide
1793323Scindi 	 */
1803323Scindi 	if (DCMD_HDRSPEC(flags)) {
1813323Scindi 		mdb_printf("%<u>%-12s %-36s %-30s%</u>\n",
1824198Seschrock 		    "FIELD", "VALUE", "DESCR");
1833323Scindi 	}
184*5068Srobj 	mdb_printf("%-12s 0x%-34p %-30s\n", "tm_lock",
185*5068Srobj 	    addr + offsetof(topo_mod_t, tm_lock),
1864198Seschrock 	    "Lock for tm_cv/owner/flags/refs");
187*5068Srobj 	mdb_printf("%-12s 0x%-34p %-30s\n", "tm_cv",
188*5068Srobj 	    addr + offsetof(topo_mod_t, tm_cv),
1894198Seschrock 	    "Module condition variable");
1903323Scindi 	mdb_printf("%-12s %-36s %-30s\n", "tm_busy", tm.tm_busy,
1914198Seschrock 	    "Busy indicator");
1923323Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tm_next", tm.tm_next,
1934198Seschrock 	    "Next module in hash chain");
1943323Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tm_hdl", tm.tm_hdl,
1954198Seschrock 	    "Topo handle for this module");
1963323Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tm_alloc", tm.tm_alloc,
1974198Seschrock 	    "Allocators");
1983323Scindi 	mdb_printf("%-12s %-36s %-30s\n", "tm_name", name,
1994198Seschrock 	    "Basename of module");
2003323Scindi 	mdb_printf("%-12s %-36s %-30s\n", "tm_path", path,
2014198Seschrock 	    "Full pathname of module");
2023323Scindi 	mdb_printf("%-12s %-36s %-30s\n", "tm_rootdir", root,
2034198Seschrock 	    "Relative root directory of module");
2043323Scindi 	mdb_printf("%-12s %-36u %-30s\n", "tm_refs", tm.tm_refs,
2054198Seschrock 	    "Module reference count");
2063323Scindi 	mdb_printf("%-12s %-36u %-30s\n", "tm_flags", tm.tm_flags,
2074198Seschrock 	    "Module flags");
2083323Scindi 	if (TOPO_MOD_INIT & tm.tm_flags) {
2093323Scindi 		mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_MOD_INIT",
2104198Seschrock 		    "Module init completed");
2113323Scindi 	}
2123323Scindi 	if (TOPO_MOD_FINI & tm.tm_flags) {
2133323Scindi 		mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_MOD_FINI",
2144198Seschrock 		    "Module fini completed");
2153323Scindi 	}
2163323Scindi 	if (TOPO_MOD_REG & tm.tm_flags) {
2173323Scindi 		mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_MOD_REG",
2184198Seschrock 		    "Module registered");
2193323Scindi 	}
2203323Scindi 	if (TOPO_MOD_UNREG & tm.tm_flags) {
2213323Scindi 		mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_MOD_UNREG",
2224198Seschrock 		    "Module unregistered");
2233323Scindi 	}
2243323Scindi 
2253323Scindi 	mdb_printf("%-12s %-36u %-30s\n", "tm_debug", tm.tm_debug,
2264198Seschrock 	    "Debug printf mask");
2273323Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tm_data", tm.tm_data,
2284198Seschrock 	    "Private rtld/builtin data");
2293323Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tm_mops", tm.tm_mops,
2304198Seschrock 	    "Module class ops vector");
2313323Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tm_info", tm.tm_info,
2324198Seschrock 	    "Module info registered with handle");
2333323Scindi 	mdb_printf("%-12s %-36d %-30s\n", "tm_ernno", tm.tm_errno,
2344198Seschrock 	    "Module errno");
2353323Scindi 
2363323Scindi 	return (DCMD_OK);
2373323Scindi }
2383323Scindi 
2393323Scindi 
2403323Scindi /*ARGSUSED*/
2413323Scindi static int
2423323Scindi topo_node(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2433323Scindi {
2443323Scindi 	char name[36];
2453323Scindi 	tnode_t tn;
2463323Scindi 
2473323Scindi 	if (!addr)
2483323Scindi 		return (DCMD_ERR);
2493323Scindi 
2503323Scindi 	/*
2513323Scindi 	 * Read in the structure and then read in all of the string fields from
2523323Scindi 	 * the target's addr space
2533323Scindi 	 */
2543323Scindi 	if (mdb_vread(&tn, sizeof (tn), addr) != sizeof (tn)) {
2553323Scindi 		mdb_warn("failed to read tnode_t at %p", addr);
2563323Scindi 		return (DCMD_ERR);
2573323Scindi 	}
2583323Scindi 
2593323Scindi 	if (mdb_readstr(name, sizeof (name), (uintptr_t)tn.tn_name) < 0) {
2603323Scindi 		(void) mdb_snprintf(name, sizeof (name), "<%p>", tn.tn_name);
2613323Scindi 	}
2623323Scindi 
2633323Scindi 	/*
2643323Scindi 	 * Dump it all out in a nice pretty format and keep it to 80 chars wide
2653323Scindi 	 */
2663323Scindi 	if (DCMD_HDRSPEC(flags)) {
2673323Scindi 		mdb_printf("%<u>%-12s %-36s %-30s%</u>\n",
2683323Scindi 		"FIELD", "VALUE", "DESCR");
2693323Scindi 	}
2703323Scindi 
2714198Seschrock 	mdb_printf("%-12s 0x%-34p %-30s\n", "tn_lock",
2724198Seschrock 	    addr + offsetof(tnode_t, tn_lock),
2734198Seschrock 	    "Lock protecting node members");
2743323Scindi 	mdb_printf("%-12s %-36s %-30s\n", "tn_name", name,
2754198Seschrock 	    "Node name");
2763323Scindi 	mdb_printf("%-12s %-36d %-30s\n", "tn_instance", tn.tn_instance,
2774198Seschrock 	    "Node instance");
2783323Scindi 	mdb_printf("%-12s %-36d %-30s\n", "tn_state", tn.tn_state,
2794198Seschrock 	    "Node state");
2803323Scindi 	if (TOPO_NODE_INIT & tn.tn_state) {
2813323Scindi 		mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_NODE_INIT", "");
2823323Scindi 	}
2833323Scindi 	if (TOPO_NODE_ROOT & tn.tn_state) {
2843323Scindi 		mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_NODE_ROOT", "");
2853323Scindi 	}
2863323Scindi 	if (TOPO_NODE_BOUND & tn.tn_state) {
2873323Scindi 		mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_NODE_BOUND", "");
2883323Scindi 	}
2893323Scindi 	if (TOPO_NODE_LINKED & tn.tn_state) {
2903323Scindi 		mdb_printf("%-12s %-36s %-30s\n", "", "TOPO_NODE_LINKED", "");
2913323Scindi 	}
2923323Scindi 	mdb_printf("%-12s %-36d %-30s\n", "tn_fflags", tn.tn_fflags,
2934198Seschrock 	    "FMRI flags");
2943323Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tn_parent", tn.tn_parent,
2954198Seschrock 	    "Node parent");
2963323Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tn_phash", tn.tn_phash,
2974198Seschrock 	    "Parent hash bucket");
2983323Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tn_hdl", tn.tn_hdl,
2994198Seschrock 	    "Topo handle");
3003323Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tn_enum", tn.tn_enum,
3014198Seschrock 	    "Enumerator module");
3023323Scindi 	mdb_printf("%-12s %-36s %-30s\n", "tn_children", "",
3034198Seschrock 	    "Hash table of child nodes");
3044198Seschrock 	mdb_printf("  %-12s 0x%-34p\n", "l_prev", tn.tn_children.l_prev);
3054198Seschrock 	mdb_printf("  %-12s 0x%-34p\n", "l_next", tn.tn_children.l_next);
3063323Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tn_pgroups", &(tn.tn_pgroups),
3074198Seschrock 	    "Property group list");
3083323Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tn_methods", &(tn.tn_methods),
3094198Seschrock 	    "Registered method list");
3103323Scindi 	mdb_printf("%-12s 0x%-34p %-30s\n", "tn_priv", tn.tn_priv,
3114198Seschrock 	    "Private enumerator data");
3123323Scindi 	mdb_printf("%-12s %-36d %-30s\n", "tn_refs", tn.tn_refs,
3134198Seschrock 	    "Node reference count");
3143323Scindi 
3153323Scindi 	return (DCMD_OK);
3163323Scindi }
3173323Scindi 
3183323Scindi /*ARGSUSED*/
3193323Scindi static int
3203323Scindi find_tree_root(uintptr_t addr, const void *data, void *arg)
3213323Scindi {
3223323Scindi 	ttree_t *tree = (ttree_t *)data;
3233323Scindi 	char scheme[36];
3243323Scindi 
3253323Scindi 	if (mdb_readstr(scheme, sizeof (scheme), (uintptr_t)tree->tt_scheme)
3263323Scindi 	    < 0) {
3273323Scindi 		(void) mdb_snprintf(scheme, sizeof (scheme), "<%p>",
3283323Scindi 		    tree->tt_scheme);
3293323Scindi 	}
3303323Scindi 
3313323Scindi 	if (strncmp(tgt_scheme, scheme, 36) == 0) {
3323323Scindi 		*((tnode_t **)arg) = tree->tt_root;
3333323Scindi 		return (WALK_DONE);
3343323Scindi 	}
3353323Scindi 	return (WALK_NEXT);
3363323Scindi }
3373323Scindi 
3384087Scindi static void
3394087Scindi dump_propmethod(uintptr_t addr)
3404087Scindi {
3414087Scindi 	topo_propmethod_t pm;
3424087Scindi 
3434087Scindi 	if (mdb_vread(&pm, sizeof (pm), addr) != sizeof (pm)) {
3444087Scindi 		mdb_warn("failed to read topo_propmethod at %p", addr);
3454087Scindi 		return;
3464087Scindi 	}
3474087Scindi 
3484087Scindi 	mdb_printf("       method: %-32s version: %-16s args: %p\n",
3494087Scindi 	    pm.tpm_name, pm.tpm_version, pm.tpm_args);
3504087Scindi }
3513323Scindi 
3523323Scindi /*
3533323Scindi  * Dump the given property value. For the actual property values
3543323Scindi  * we dump a pointer to the nvlist which can be decoded using the ::nvlist
3553323Scindi  * dcmd from the libnvpair MDB module
3563323Scindi  */
3573323Scindi /*ARGSUSED*/
3583323Scindi static int
3593323Scindi dump_propval(uintptr_t addr, const void *data, void *arg)
3603323Scindi {
3613323Scindi 	topo_proplist_t *plistp = (topo_proplist_t *)data;
3623323Scindi 	topo_propval_t pval;
3633323Scindi 	char name[32], *type;
3643323Scindi 
3653323Scindi 	if (mdb_vread(&pval, sizeof (pval), (uintptr_t)plistp->tp_pval)
3663323Scindi 	    != sizeof (pval)) {
3673323Scindi 
3683323Scindi 		mdb_warn("failed to read topo_propval_t at %p",
3693323Scindi 		    plistp->tp_pval);
3703323Scindi 		return (WALK_ERR);
3713323Scindi 	}
3723323Scindi 	if (mdb_readstr(name, sizeof (name), (uintptr_t)pval.tp_name) < 0) {
3733323Scindi 		(void) mdb_snprintf(name, sizeof (name), "<%p>", pval.tp_name);
3743323Scindi 	}
3753323Scindi 	switch (pval.tp_type) {
3763323Scindi 		case TOPO_TYPE_BOOLEAN: type = "boolean"; break;
3773323Scindi 		case TOPO_TYPE_INT32: type = "int32"; break;
3783323Scindi 		case TOPO_TYPE_UINT32: type = "uint32"; break;
3793323Scindi 		case TOPO_TYPE_INT64: type = "int64"; break;
3803323Scindi 		case TOPO_TYPE_UINT64: type = "uint64"; break;
3813323Scindi 		case TOPO_TYPE_STRING: type = "string"; break;
3823323Scindi 		case TOPO_TYPE_FMRI: type = "fmri"; break;
3833323Scindi 		case TOPO_TYPE_INT32_ARRAY: type = "int32[]"; break;
3843323Scindi 		case TOPO_TYPE_UINT32_ARRAY: type = "uint32[]"; break;
3853323Scindi 		case TOPO_TYPE_INT64_ARRAY: type = "int64[]"; break;
3863323Scindi 		case TOPO_TYPE_UINT64_ARRAY: type = "uint64[]"; break;
3873323Scindi 		case TOPO_TYPE_STRING_ARRAY: type = "string[]"; break;
3883323Scindi 		case TOPO_TYPE_FMRI_ARRAY: type = "fmri[]"; break;
3893323Scindi 		default: type = "unknown type";
3903323Scindi 	}
3913323Scindi 	mdb_printf("    %-32s %-16s value: %p\n", name, type, pval.tp_val);
3924087Scindi 
3934087Scindi 	if (pval.tp_method != NULL)
3944087Scindi 		dump_propmethod((uintptr_t)pval.tp_method);
3954087Scindi 
3963323Scindi 	return (WALK_NEXT);
3973323Scindi }
3983323Scindi 
3993323Scindi 
4003323Scindi /*
4013323Scindi  * Dumps the contents of the property group.
4023323Scindi  */
4033323Scindi /*ARGSUSED*/
4043323Scindi static int
4053323Scindi dump_pgroup(uintptr_t addr, const void *data, void *arg)
4063323Scindi {
4073323Scindi 	topo_pgroup_t *pgp = (topo_pgroup_t *)data;
4083323Scindi 	topo_ipgroup_info_t ipg;
4093323Scindi 	char buf[32];
4103323Scindi 
4113323Scindi 	if (mdb_vread(&ipg, sizeof (ipg), (uintptr_t)pgp->tpg_info)
4123323Scindi 	    != sizeof (ipg)) {
4133323Scindi 
4143323Scindi 		mdb_warn("failed to read topo_ipgroup_info_t at %p",
4153323Scindi 		    pgp->tpg_info);
4163323Scindi 		return (WALK_ERR);
4173323Scindi 	}
4183323Scindi 	if (mdb_readstr(buf, sizeof (buf), (uintptr_t)ipg.tpi_name) < 0) {
4193323Scindi 		mdb_warn("failed to read string at %p", ipg.tpi_name);
4203323Scindi 		return (WALK_ERR);
4213323Scindi 	}
4223323Scindi 	/*
4233323Scindi 	 * If this property group is the one we're interested in or if the user
4243323Scindi 	 * specified the "all" property group, we'll dump it
4253323Scindi 	 */
4263323Scindi 	if ((strncmp(pgrp, buf, sizeof (buf)) == 0) ||
4273323Scindi 	    (strncmp(pgrp, "all", sizeof (buf)) == 0)) {
4283323Scindi 
4293323Scindi 		mdb_printf("  group: %-32s version: %d, stability: %s/%s\n",
4303323Scindi 		    buf, ipg.tpi_version, stab_lvls[ipg.tpi_namestab],
4313323Scindi 		    stab_lvls[ipg.tpi_datastab]);
4323323Scindi 
4333323Scindi 		(void) mdb_pwalk("topo_proplist", dump_propval, NULL, curr_pg);
4343323Scindi 	}
4353323Scindi 	return (WALK_NEXT);
4363323Scindi }
4373323Scindi 
4383323Scindi 
4393323Scindi /*
4403323Scindi  * Recursive function to dump the specified node and all of it's children
4413323Scindi  */
4423323Scindi /*ARGSUSED*/
4433323Scindi static int
4443323Scindi dump_tnode(uintptr_t addr, const void *data, void *arg)
4453323Scindi {
4463323Scindi 	tnode_t node;
4473323Scindi 	char pname[255], buf[80], old_pname[255];
4483323Scindi 
4493323Scindi 	if (!addr) {
4503323Scindi 		return (WALK_NEXT);
4513323Scindi 	}
4523323Scindi 
4533323Scindi 	if (mdb_vread(&node, sizeof (node), addr) != sizeof (node)) {
4543323Scindi 		mdb_warn("failed to read tnode_t at %p", addr);
4553323Scindi 		return (WALK_ERR);
4563323Scindi 	}
4573323Scindi 	if (mdb_readstr(buf, sizeof (buf), (uintptr_t)node.tn_name) < 0) {
4583323Scindi 		(void) mdb_snprintf(buf, sizeof (buf), "<%p>",
4593323Scindi 		    node.tn_name);
4603323Scindi 	}
4613323Scindi 
4623323Scindi 	if (is_root) {
4633323Scindi 		mdb_snprintf(pname, sizeof (pname), "%s", parent);
4643323Scindi 		is_root = 0;
4653323Scindi 	} else {
4663323Scindi 		mdb_snprintf(pname, sizeof (pname), "%s/%s=%u",
4673323Scindi 		    parent, buf, node.tn_instance);
4683323Scindi 
4693323Scindi 		if (verbose)
4703323Scindi 			mdb_printf("%s\n  tnode_t: %p\n", pname, addr);
4713323Scindi 		else
4723323Scindi 			mdb_printf("%s\n", pname);
4733323Scindi 	}
4743323Scindi 	mdb_snprintf(old_pname, sizeof (old_pname), "%s", parent);
4753323Scindi 	mdb_snprintf(parent, sizeof (parent), "%s", pname);
4763323Scindi 
4773323Scindi 	if (pgrp)
4783323Scindi 		(void) mdb_pwalk("topo_pgroup", dump_pgroup, NULL, addr);
4793323Scindi 
4803323Scindi 	(void) mdb_pwalk("topo_nodehash", dump_tnode, NULL, addr);
4813323Scindi 	mdb_snprintf(parent, sizeof (parent), "%s", old_pname);
4823323Scindi 
4833323Scindi 	return (WALK_NEXT);
4843323Scindi }
4853323Scindi 
4863323Scindi 
4873323Scindi /*
4883323Scindi  * Given a topo_hdl_t *, the topo dcmd dumps the topo tree.  The format of the
4893323Scindi  * output is modeled after fmtopo.  Like fmtopo, by default, we'll dump the
4903323Scindi  * "hc" scheme tree.  The user can optionally specify a different tree via the
4913323Scindi  * "-s <scheme>" option.
4923323Scindi  *
4933323Scindi  * Specifying the "-v" option provides more verbose output.  Currently it
4943323Scindi  * outputs the tnode_t * addr for each node, which is useful if you want to
4953323Scindi  * dump it with the topo_node dcmd.
4963323Scindi  *
4973323Scindi  * The functionality of the "-P" option is similar to fmtopo.
4983323Scindi  */
4993323Scindi /*ARGSUSED*/
5003323Scindi static int
5013323Scindi fmtopo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
5023323Scindi {
5033323Scindi 	char product[36], *opt_s = NULL, *opt_P = NULL;
5043323Scindi 	topo_hdl_t th;
5053323Scindi 	tnode_t *tree_root;
5063323Scindi 	uint_t opt_v = FALSE;
5073323Scindi 	char *def_scheme = "hc";
5083323Scindi 
5093323Scindi 	if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &opt_v,
5103323Scindi 	    's', MDB_OPT_STR, &opt_s, 'P', MDB_OPT_STR, &opt_P, NULL)
5113323Scindi 	    != argc) {
5123323Scindi 		return (DCMD_USAGE);
5133323Scindi 	}
5143323Scindi 
5153323Scindi 	if (opt_s) {
5163323Scindi 		tgt_scheme = opt_s;
5173323Scindi 	} else {
5183323Scindi 		tgt_scheme = def_scheme;
5193323Scindi 	}
5203323Scindi 
5213323Scindi 	pgrp = opt_P;
5223323Scindi 	verbose = opt_v;
5233323Scindi 	is_root = 1;
5243323Scindi 
5253323Scindi 	/*
5263323Scindi 	 * Read in the topo_handle and some of its string fields from
5273323Scindi 	 * the target's addr space
5283323Scindi 	 */
5293323Scindi 	if (mdb_vread(&th, sizeof (th), addr) != sizeof (th)) {
5303323Scindi 		mdb_warn("failed to read topo_hdl_t at %p", addr);
5313323Scindi 		return (DCMD_ERR);
5323323Scindi 	}
5333323Scindi 
5343323Scindi 	if (mdb_readstr(product, sizeof (product), (uintptr_t)th.th_product)
5353323Scindi 	    < 0) {
5363323Scindi 
5373323Scindi 		(void) mdb_snprintf(product, sizeof (product), "<%p>",
5383323Scindi 		    th.th_product);
5393323Scindi 	}
5403323Scindi 
5413323Scindi 	mdb_snprintf(parent, sizeof (parent),
5423323Scindi 	    "%s://:product-id=%s", tgt_scheme, product);
5433323Scindi 
5443323Scindi 	/*
5453323Scindi 	 * Walk the list of topo trees, looking for the one that is for the
5463323Scindi 	 * scheme we're interested in.
5473323Scindi 	 */
5483323Scindi 	tree_root = NULL;
5493323Scindi 	mdb_pwalk("topo_tree", find_tree_root, &tree_root, addr);
5503323Scindi 
5513323Scindi 	if (! tree_root) {
5523323Scindi 		mdb_warn("failed to find a topo tree for scheme %s\n",
5533323Scindi 		    tgt_scheme);
5543323Scindi 		return (DCMD_ERR);
5553323Scindi 	}
5563323Scindi 
5573323Scindi 	return (dump_tnode((uintptr_t)tree_root, NULL, NULL));
5583323Scindi }
5593323Scindi 
5603323Scindi 
5613323Scindi static int
5623323Scindi ttree_walk_init(mdb_walk_state_t *wsp)
5633323Scindi {
5643323Scindi 	topo_hdl_t th;
5653323Scindi 
5663323Scindi 	if (wsp->walk_addr == NULL) {
5673323Scindi 		mdb_warn("NULL topo_hdl_t passed in");
5683323Scindi 		return (WALK_ERR);
5693323Scindi 	}
5703323Scindi 
5713323Scindi 	if (mdb_vread(&th, sizeof (th), wsp->walk_addr) != sizeof (th)) {
5723323Scindi 		mdb_warn("failed to read topo_hdl_t at %p", wsp->walk_addr);
5733323Scindi 		return (WALK_ERR);
5743323Scindi 	}
5753323Scindi 
5763323Scindi 	wsp->walk_addr = (uintptr_t)th.th_trees.l_next;
5773323Scindi 	wsp->walk_data = mdb_alloc(sizeof (ttree_t), UM_SLEEP);
5783323Scindi 
5793323Scindi 	return (WALK_NEXT);
5803323Scindi }
5813323Scindi 
5823323Scindi 
5833323Scindi static int
5843323Scindi ttree_walk_step(mdb_walk_state_t *wsp)
5853323Scindi {
5863323Scindi 	int rv;
5873323Scindi 	ttree_t *tree;
5883323Scindi 
5893323Scindi 	if (wsp->walk_addr == NULL)
5903323Scindi 		return (WALK_DONE);
5913323Scindi 
5923323Scindi 	if (mdb_vread(wsp->walk_data, sizeof (ttree_t), wsp->walk_addr)
5933323Scindi 	    != sizeof (ttree_t)) {
5943323Scindi 
5953323Scindi 		mdb_warn("failed to read ttree_t at %p", wsp->walk_addr);
5963323Scindi 		return (WALK_ERR);
5973323Scindi 	}
5983323Scindi 
5993323Scindi 	rv = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
6003323Scindi 	    wsp->walk_cbdata);
6013323Scindi 
6023323Scindi 	tree = (ttree_t *)wsp->walk_data;
6033323Scindi 	wsp->walk_addr = (uintptr_t)tree->tt_list.l_next;
6043323Scindi 
6053323Scindi 	return (rv);
6063323Scindi }
6073323Scindi 
6083323Scindi 
6093323Scindi static void
6103323Scindi ttree_walk_fini(mdb_walk_state_t *wsp)
6113323Scindi {
6123323Scindi 	mdb_free(wsp->walk_data, sizeof (ttree_t));
6133323Scindi }
6143323Scindi 
6153323Scindi 
6163323Scindi static int
6173323Scindi tmod_walk_init(mdb_walk_state_t *wsp)
6183323Scindi {
6193323Scindi 	topo_hdl_t th;
6203323Scindi 
6213323Scindi 	if (wsp->walk_addr == NULL) {
6223323Scindi 		mdb_warn("NULL topo_hdl_t passed in");
6233323Scindi 		return (WALK_ERR);
6243323Scindi 	}
6253323Scindi 
6263323Scindi 	if (mdb_vread(&th, sizeof (th), wsp->walk_addr) != sizeof (th)) {
6273323Scindi 		mdb_warn("failed to read topo_hdl_t at %p", wsp->walk_addr);
6283323Scindi 		return (WALK_ERR);
6293323Scindi 	}
6303323Scindi 
6313323Scindi 	if (mdb_vread(&tmh, sizeof (topo_modhash_t), (uintptr_t)th.th_modhash)
6323323Scindi 	    == -1) {
6333323Scindi 
6343323Scindi 		mdb_warn("failed to read topo_modhash_t at %p", wsp->walk_addr);
6353323Scindi 		return (WALK_DONE);
6363323Scindi 	}
6373323Scindi 
6383323Scindi 	hash_idx = 0;
6393323Scindi 
6403323Scindi 	if (mdb_vread(&(wsp->walk_addr), sizeof (uintptr_t *),
6413323Scindi 	    (uintptr_t)(tmh.mh_hash)) != sizeof (tnode_t *)) {
6423323Scindi 
6433323Scindi 		mdb_warn("failed to read %u bytes at %p", sizeof (tnode_t *),
6443323Scindi 		    tmh.mh_hash);
6453323Scindi 		return (WALK_ERR);
6463323Scindi 	}
6473323Scindi 
6483323Scindi 	wsp->walk_data = mdb_alloc(sizeof (topo_mod_t), UM_SLEEP);
6493323Scindi 
6503323Scindi 	return (WALK_NEXT);
6513323Scindi }
6523323Scindi 
6533323Scindi 
6543323Scindi static int
6553323Scindi tmod_walk_step(mdb_walk_state_t *wsp)
6563323Scindi {
6573323Scindi 	int rv;
6583323Scindi 	topo_mod_t *tm;
6593323Scindi 
6603323Scindi 	if (wsp->walk_addr == NULL)
6613323Scindi 		return (WALK_DONE);
6623323Scindi 
6633323Scindi 	if (mdb_vread(wsp->walk_data, sizeof (topo_mod_t), wsp->walk_addr)
6643323Scindi 	    == -1) {
6653323Scindi 
6663323Scindi 		mdb_warn("failed to read topo_mod_t at %p", wsp->walk_addr);
6673323Scindi 		return (WALK_DONE);
6683323Scindi 	}
6693323Scindi 
6703323Scindi 	rv = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
6713323Scindi 	    wsp->walk_cbdata);
6723323Scindi 
6733323Scindi 	tm = (topo_mod_t *)wsp->walk_data;
6743323Scindi 
6753323Scindi 	if (tm->tm_next)
6763323Scindi 		wsp->walk_addr = (uintptr_t)tm->tm_next;
6773323Scindi 	else if (++hash_idx < tmh.mh_hashlen)
6783323Scindi 		if (mdb_vread(&(wsp->walk_addr), sizeof (uintptr_t *),
6793323Scindi 		    (uintptr_t)(tmh.mh_hash+hash_idx)) != sizeof (tnode_t *)) {
6803323Scindi 
6813323Scindi 			mdb_warn("failed to read %u bytes at %p",
6823323Scindi 			    sizeof (tnode_t *), tmh.mh_hash+hash_idx);
6833323Scindi 			return (DCMD_ERR);
6843323Scindi 		}
6853323Scindi 	else
6863323Scindi 		wsp->walk_addr = NULL;
6873323Scindi 
6883323Scindi 	return (rv);
6893323Scindi }
6903323Scindi 
6913323Scindi static void
6923323Scindi tmod_walk_fini(mdb_walk_state_t *wsp)
6933323Scindi {
6943323Scindi 	mdb_free(wsp->walk_data, sizeof (topo_mod_t));
6953323Scindi }
6963323Scindi 
6973323Scindi 
6983323Scindi static int
6993323Scindi tpg_walk_init(mdb_walk_state_t *wsp)
7003323Scindi {
7013323Scindi 	tnode_t node;
7023323Scindi 
7033323Scindi 	if (wsp->walk_addr == NULL) {
7043323Scindi 		mdb_warn("NULL tnode_t passed in");
7053323Scindi 		return (WALK_ERR);
7063323Scindi 	}
7073323Scindi 
7083323Scindi 	if (mdb_vread(&node, sizeof (node), wsp->walk_addr) != sizeof (node)) {
7093323Scindi 		mdb_warn("failed to read tnode_t at %p", wsp->walk_addr);
7103323Scindi 		return (WALK_ERR);
7113323Scindi 	}
7123323Scindi 
7133323Scindi 	wsp->walk_addr = (uintptr_t)node.tn_pgroups.l_next;
7143323Scindi 	wsp->walk_data = mdb_alloc(sizeof (topo_pgroup_t), UM_SLEEP);
7153323Scindi 
7163323Scindi 	return (WALK_NEXT);
7173323Scindi }
7183323Scindi 
7193323Scindi 
7203323Scindi static int
7213323Scindi tpg_walk_step(mdb_walk_state_t *wsp)
7223323Scindi {
7233323Scindi 	int rv;
7243323Scindi 	topo_pgroup_t *tpgp;
7253323Scindi 
7263323Scindi 	if (wsp->walk_addr == NULL)
7273323Scindi 		return (WALK_DONE);
7283323Scindi 
7293323Scindi 	if (mdb_vread(wsp->walk_data, sizeof (topo_pgroup_t), wsp->walk_addr)
7303323Scindi 	    == -1) {
7313323Scindi 
7323323Scindi 		mdb_warn("failed to read topo_pgroup_t at %p", wsp->walk_addr);
7333323Scindi 		return (WALK_DONE);
7343323Scindi 	}
7353323Scindi 
7363323Scindi 	curr_pg = wsp->walk_addr;
7373323Scindi 	rv = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
7383323Scindi 	    wsp->walk_cbdata);
7393323Scindi 
7403323Scindi 	tpgp = (topo_pgroup_t *)wsp->walk_data;
7413323Scindi 	wsp->walk_addr = (uintptr_t)tpgp->tpg_list.l_next;
7423323Scindi 
7433323Scindi 	return (rv);
7443323Scindi }
7453323Scindi 
7463323Scindi 
7473323Scindi static void
7483323Scindi tpg_walk_fini(mdb_walk_state_t *wsp)
7493323Scindi {
7503323Scindi 	mdb_free(wsp->walk_data, sizeof (topo_pgroup_t));
7513323Scindi }
7523323Scindi 
7533323Scindi 
7543323Scindi static int
7553323Scindi tpl_walk_init(mdb_walk_state_t *wsp)
7563323Scindi {
7573323Scindi 	topo_pgroup_t pg;
7583323Scindi 
7593323Scindi 	if (wsp->walk_addr == NULL) {
7603323Scindi 		mdb_warn("NULL topo_pgroup_t passed in");
7613323Scindi 		return (WALK_ERR);
7623323Scindi 	}
7633323Scindi 
7643323Scindi 	if (mdb_vread(&pg, sizeof (pg), wsp->walk_addr) != sizeof (pg)) {
7653323Scindi 		mdb_warn("failed to read topo_pgroup_t at %p", wsp->walk_addr);
7663323Scindi 		return (WALK_ERR);
7673323Scindi 	}
7683323Scindi 
7693323Scindi 	wsp->walk_addr = (uintptr_t)pg.tpg_pvals.l_next;
7703323Scindi 	wsp->walk_data = mdb_alloc(sizeof (topo_proplist_t), UM_SLEEP);
7713323Scindi 
7723323Scindi 	return (WALK_NEXT);
7733323Scindi }
7743323Scindi 
7753323Scindi 
7763323Scindi static int
7773323Scindi tpl_walk_step(mdb_walk_state_t *wsp)
7783323Scindi {
7793323Scindi 	int rv;
7803323Scindi 	topo_proplist_t *plp;
7813323Scindi 
7823323Scindi 	if (wsp->walk_addr == NULL)
7833323Scindi 		return (WALK_DONE);
7843323Scindi 
7853323Scindi 	if (mdb_vread(wsp->walk_data, sizeof (topo_proplist_t), wsp->walk_addr)
7863323Scindi 	    == -1) {
7873323Scindi 
7883323Scindi 		mdb_warn("failed to read topo_proplist_t at %p",
7893323Scindi 		    wsp->walk_addr);
7903323Scindi 		return (WALK_DONE);
7913323Scindi 	}
7923323Scindi 	plp = (topo_proplist_t *)wsp->walk_data;
7933323Scindi 
7943323Scindi 	rv = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
7953323Scindi 	    wsp->walk_cbdata);
7963323Scindi 
7973323Scindi 	wsp->walk_addr = (uintptr_t)plp->tp_list.l_next;
7983323Scindi 
7993323Scindi 	return (rv);
8003323Scindi }
8013323Scindi 
8023323Scindi 
8033323Scindi static void
8043323Scindi tpl_walk_fini(mdb_walk_state_t *wsp)
8053323Scindi {
8063323Scindi 	mdb_free(wsp->walk_data, sizeof (topo_proplist_t));
8073323Scindi }
8083323Scindi 
8093323Scindi 
8103323Scindi static int
8113323Scindi tnh_walk_init(mdb_walk_state_t *wsp)
8123323Scindi {
8133323Scindi 	tnode_t node;
8143323Scindi 	tnwalk_state_t *state;
8153323Scindi 
8163323Scindi 	if (wsp->walk_addr == NULL) {
8173323Scindi 		mdb_warn("NULL tnode_t passed in");
8183323Scindi 		return (WALK_ERR);
8193323Scindi 	}
8203323Scindi 
8213323Scindi 	if (mdb_vread(&node, sizeof (node), wsp->walk_addr) != sizeof (node)) {
8223323Scindi 		mdb_warn("failed to read tnode_t at %p", wsp->walk_addr);
8233323Scindi 		return (WALK_ERR);
8243323Scindi 	}
8253323Scindi 
8263323Scindi 	state = mdb_zalloc(sizeof (tnwalk_state_t), UM_SLEEP);
8273323Scindi 
8283323Scindi 	state->curr_hash = (topo_nodehash_t *)node.tn_children.l_next;
8293323Scindi 	state->hash_idx = 0;
8303323Scindi 	wsp->walk_data = state;
8313323Scindi 
8323323Scindi 	return (WALK_NEXT);
8333323Scindi }
8343323Scindi 
8353323Scindi 
8363323Scindi static int
8373323Scindi tnh_walk_step(mdb_walk_state_t *wsp)
8383323Scindi {
8393323Scindi 	tnwalk_state_t *state = wsp->walk_data;
8403323Scindi 	int rv, i = state->hash_idx++;
8413323Scindi 	tnode_t *npp;
8423323Scindi 
8433323Scindi 	if (state->curr_hash == NULL)
8443323Scindi 		return (WALK_DONE);
8453323Scindi 
8463323Scindi 	if (mdb_vread(&(state->hash), sizeof (topo_nodehash_t),
8473323Scindi 	    (uintptr_t)state->curr_hash) != sizeof (topo_nodehash_t)) {
8483323Scindi 
8493323Scindi 		mdb_warn("failed to read topo_nodehash_t at %p",
8503323Scindi 		    (uintptr_t)state->curr_hash);
8513323Scindi 		return (WALK_ERR);
8523323Scindi 	}
8533323Scindi 
8543323Scindi 	if (mdb_vread(&npp, sizeof (tnode_t *),
8553323Scindi 	    (uintptr_t)(state->hash.th_nodearr+i)) != sizeof (tnode_t *)) {
8563323Scindi 
8573323Scindi 		mdb_warn("failed to read %u bytes at %p", sizeof (tnode_t *),
8583323Scindi 		    state->hash.th_nodearr+i);
8593323Scindi 		return (WALK_ERR);
8603323Scindi 	}
8613323Scindi 	wsp->walk_addr = (uintptr_t)npp;
8623323Scindi 
8633323Scindi 	rv = wsp->walk_callback(wsp->walk_addr, state, wsp->walk_cbdata);
8643323Scindi 
8653323Scindi 	if (state->hash_idx >= state->hash.th_arrlen) {
8663323Scindi 		/*
8673323Scindi 		 * move on to the next child hash bucket
8683323Scindi 		 */
8693323Scindi 		state->curr_hash =
8703323Scindi 		    (topo_nodehash_t *)(state->hash.th_list.l_next);
8713323Scindi 		state->hash_idx = 0;
8723323Scindi 	}
8733323Scindi 
8743323Scindi 	return (rv);
8753323Scindi }
8763323Scindi 
8773323Scindi 
8783323Scindi static void
8793323Scindi tnh_walk_fini(mdb_walk_state_t *wsp)
8803323Scindi {
8813323Scindi 	mdb_free(wsp->walk_data, sizeof (tnwalk_state_t));
8823323Scindi }
8833323Scindi 
8843323Scindi 
8853323Scindi static const mdb_dcmd_t dcmds[] = {
8863323Scindi 	{ "topo_handle", "", "print contents of a topo handle", topo_handle,
8873323Scindi 		NULL },
8883323Scindi 	{ "topo_module", "", "print contents of a topo module handle",
8893323Scindi 		topo_module, NULL },
8903323Scindi 	{ "topo_node", "", "print contents of a topo node", topo_node, NULL },
8913323Scindi 	{ "fmtopo", "[-P <pgroup>][-s <scheme>][-v]",
8923323Scindi 	    "print topology of the given handle", fmtopo, NULL },
8933323Scindi 	{ NULL }
8943323Scindi };
8953323Scindi 
8963323Scindi static const mdb_walker_t walkers[] = {
8973323Scindi 	{ "topo_tree", "walk the tree list for a given topo handle",
8983323Scindi 		ttree_walk_init, ttree_walk_step, ttree_walk_fini, NULL },
8993323Scindi 	{ "topo_module", "walk the module hash for a given topo handle",
9003323Scindi 		tmod_walk_init, tmod_walk_step, tmod_walk_fini, NULL },
9013323Scindi 	{ "topo_pgroup", "walk the property groups for a given topo node",
9023323Scindi 		tpg_walk_init, tpg_walk_step, tpg_walk_fini, NULL },
9033323Scindi 	{ "topo_proplist", "walk the property list for a given property group",
9043323Scindi 		tpl_walk_init, tpl_walk_step, tpl_walk_fini, NULL },
9053323Scindi 	{ "topo_nodehash", "walk the child nodehash for a given topo node",
9063323Scindi 		tnh_walk_init, tnh_walk_step, tnh_walk_fini, NULL },
9073323Scindi 	{ NULL }
9083323Scindi };
9093323Scindi 
9103323Scindi static const mdb_modinfo_t modinfo = {
9113323Scindi 	MDB_API_VERSION, dcmds, walkers
9123323Scindi };
9133323Scindi 
9143323Scindi const mdb_modinfo_t *
9153323Scindi _mdb_init(void)
9163323Scindi {
9173323Scindi 	return (&modinfo);
9183323Scindi }
919