xref: /onnv-gate/usr/src/cmd/mdb/common/modules/mdb_ks/mdb_ks.c (revision 13076:e0735b974926)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52116Sanish  * Common Development and Distribution License (the "License").
62116Sanish  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
2212230SFrank.Rival@oracle.com  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate /*
260Sstevel@tonic-gate  * Mdb kernel support module.  This module is loaded automatically when the
270Sstevel@tonic-gate  * kvm target is initialized.  Any global functions declared here are exported
280Sstevel@tonic-gate  * for the resolution of symbols in subsequently loaded modules.
290Sstevel@tonic-gate  *
300Sstevel@tonic-gate  * WARNING: Do not assume that static variables in mdb_ks will be initialized
310Sstevel@tonic-gate  * to zero.
320Sstevel@tonic-gate  */
330Sstevel@tonic-gate 
340Sstevel@tonic-gate #include <mdb/mdb_target.h>
350Sstevel@tonic-gate #include <mdb/mdb_param.h>
360Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
370Sstevel@tonic-gate #include <mdb/mdb_ks.h>
380Sstevel@tonic-gate 
390Sstevel@tonic-gate #include <sys/types.h>
400Sstevel@tonic-gate #include <sys/procfs.h>
410Sstevel@tonic-gate #include <sys/proc.h>
420Sstevel@tonic-gate #include <sys/dnlc.h>
430Sstevel@tonic-gate #include <sys/autoconf.h>
440Sstevel@tonic-gate #include <sys/machelf.h>
450Sstevel@tonic-gate #include <sys/modctl.h>
460Sstevel@tonic-gate #include <sys/hwconf.h>
470Sstevel@tonic-gate #include <sys/kobj.h>
480Sstevel@tonic-gate #include <sys/fs/autofs.h>
490Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
500Sstevel@tonic-gate #include <sys/refstr_impl.h>
511234Sjohnlev #include <sys/cpuvar.h>
522546Scarlsonj #include <sys/dlpi.h>
5311066Srafael.vanoni@sun.com #include <sys/clock_impl.h>
5412230SFrank.Rival@oracle.com #include <sys/swap.h>
550Sstevel@tonic-gate #include <errno.h>
560Sstevel@tonic-gate 
570Sstevel@tonic-gate #include <vm/seg_vn.h>
580Sstevel@tonic-gate #include <vm/page.h>
590Sstevel@tonic-gate 
600Sstevel@tonic-gate #define	MDB_PATH_NELEM	256			/* Maximum path components */
610Sstevel@tonic-gate 
620Sstevel@tonic-gate typedef struct mdb_path {
630Sstevel@tonic-gate 	size_t mdp_nelem;			/* Number of components */
640Sstevel@tonic-gate 	uint_t mdp_complete;			/* Path completely resolved? */
650Sstevel@tonic-gate 	uintptr_t mdp_vnode[MDB_PATH_NELEM];	/* Array of vnode_t addresses */
660Sstevel@tonic-gate 	char *mdp_name[MDB_PATH_NELEM];		/* Array of name components */
670Sstevel@tonic-gate } mdb_path_t;
680Sstevel@tonic-gate 
690Sstevel@tonic-gate static int mdb_autonode2path(uintptr_t, mdb_path_t *);
700Sstevel@tonic-gate static int mdb_sprintpath(char *, size_t, mdb_path_t *);
710Sstevel@tonic-gate 
720Sstevel@tonic-gate /*
730Sstevel@tonic-gate  * Kernel parameters from <sys/param.h> which we keep in-core:
740Sstevel@tonic-gate  */
750Sstevel@tonic-gate unsigned long _mdb_ks_pagesize;
760Sstevel@tonic-gate unsigned int _mdb_ks_pageshift;
770Sstevel@tonic-gate unsigned long _mdb_ks_pageoffset;
780Sstevel@tonic-gate unsigned long long _mdb_ks_pagemask;
790Sstevel@tonic-gate unsigned long _mdb_ks_mmu_pagesize;
800Sstevel@tonic-gate unsigned int _mdb_ks_mmu_pageshift;
810Sstevel@tonic-gate unsigned long _mdb_ks_mmu_pageoffset;
820Sstevel@tonic-gate unsigned long _mdb_ks_mmu_pagemask;
830Sstevel@tonic-gate uintptr_t _mdb_ks_kernelbase;
840Sstevel@tonic-gate uintptr_t _mdb_ks_userlimit;
850Sstevel@tonic-gate uintptr_t _mdb_ks_userlimit32;
860Sstevel@tonic-gate uintptr_t _mdb_ks_argsbase;
870Sstevel@tonic-gate unsigned long _mdb_ks_msg_bsize;
880Sstevel@tonic-gate unsigned long _mdb_ks_defaultstksz;
890Sstevel@tonic-gate int _mdb_ks_ncpu;
90*13076SJonathan.Adams@Sun.COM int _mdb_ks_ncpu_log2;
91*13076SJonathan.Adams@Sun.COM int _mdb_ks_ncpu_p2;
920Sstevel@tonic-gate 
930Sstevel@tonic-gate /*
940Sstevel@tonic-gate  * In-core copy of DNLC information:
950Sstevel@tonic-gate  */
960Sstevel@tonic-gate #define	MDB_DNLC_HSIZE	1024
970Sstevel@tonic-gate #define	MDB_DNLC_HASH(vp)	(((uintptr_t)(vp) >> 3) & (MDB_DNLC_HSIZE - 1))
980Sstevel@tonic-gate #define	MDB_DNLC_NCACHE_SZ(ncp) (sizeof (ncache_t) + (ncp)->namlen)
990Sstevel@tonic-gate #define	MDB_DNLC_MAX_RETRY 4
1000Sstevel@tonic-gate 
101*13076SJonathan.Adams@Sun.COM static ncache_t **dnlc_hash;	/* mdbs hash array of dnlc entries */
1020Sstevel@tonic-gate 
103*13076SJonathan.Adams@Sun.COM /*
104*13076SJonathan.Adams@Sun.COM  * copy of page_hash-related data
105*13076SJonathan.Adams@Sun.COM  */
106*13076SJonathan.Adams@Sun.COM static int page_hash_loaded;
107*13076SJonathan.Adams@Sun.COM static long mdb_page_hashsz;
108*13076SJonathan.Adams@Sun.COM static uint_t mdb_page_hashsz_shift;	/* Needed for PAGE_HASH_FUNC */
109*13076SJonathan.Adams@Sun.COM static uintptr_t mdb_page_hash;		/* base address of page hash */
110*13076SJonathan.Adams@Sun.COM #define	page_hashsz		mdb_page_hashsz
111*13076SJonathan.Adams@Sun.COM #define	page_hashsz_shift	mdb_page_hashsz_shift
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate /*
1140Sstevel@tonic-gate  * This will be the location of the vnodeops pointer for "autofs_vnodeops"
1150Sstevel@tonic-gate  * The pointer still needs to be read with mdb_vread() to get the location
1160Sstevel@tonic-gate  * of the vnodeops structure for autofs.
1170Sstevel@tonic-gate  */
1180Sstevel@tonic-gate static struct vnodeops *autofs_vnops_ptr;
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate /*
1210Sstevel@tonic-gate  * STREAMS queue registrations:
1220Sstevel@tonic-gate  */
1230Sstevel@tonic-gate typedef struct mdb_qinfo {
1240Sstevel@tonic-gate 	const mdb_qops_t *qi_ops;	/* Address of ops vector */
1250Sstevel@tonic-gate 	uintptr_t qi_addr;		/* Address of qinit structure (key) */
1260Sstevel@tonic-gate 	struct mdb_qinfo *qi_next;	/* Next qinfo in list */
1270Sstevel@tonic-gate } mdb_qinfo_t;
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate static mdb_qinfo_t *qi_head;		/* Head of qinfo chain */
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate /*
1320Sstevel@tonic-gate  * Device naming callback structure:
1330Sstevel@tonic-gate  */
1340Sstevel@tonic-gate typedef struct nm_query {
1350Sstevel@tonic-gate 	const char *nm_name;		/* Device driver name [in/out] */
1360Sstevel@tonic-gate 	major_t nm_major;		/* Device major number [in/out] */
1370Sstevel@tonic-gate 	ushort_t nm_found;		/* Did we find a match? [out] */
1380Sstevel@tonic-gate } nm_query_t;
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate /*
1410Sstevel@tonic-gate  * Address-to-modctl callback structure:
1420Sstevel@tonic-gate  */
1430Sstevel@tonic-gate typedef struct a2m_query {
1440Sstevel@tonic-gate 	uintptr_t a2m_addr;		/* Virtual address [in] */
1450Sstevel@tonic-gate 	uintptr_t a2m_where;		/* Modctl address [out] */
1460Sstevel@tonic-gate } a2m_query_t;
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate /*
1490Sstevel@tonic-gate  * Segment-to-mdb_map callback structure:
1500Sstevel@tonic-gate  */
1510Sstevel@tonic-gate typedef struct {
1520Sstevel@tonic-gate 	struct seg_ops *asm_segvn_ops;	/* Address of segvn ops [in] */
1530Sstevel@tonic-gate 	void (*asm_callback)(const struct mdb_map *, void *); /* Callb [in] */
1540Sstevel@tonic-gate 	void *asm_cbdata;		/* Callback data [in] */
1550Sstevel@tonic-gate } asmap_arg_t;
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate static void
dnlc_free(void)1580Sstevel@tonic-gate dnlc_free(void)
1590Sstevel@tonic-gate {
1600Sstevel@tonic-gate 	ncache_t *ncp, *next;
1610Sstevel@tonic-gate 	int i;
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	if (dnlc_hash == NULL) {
1640Sstevel@tonic-gate 		return;
1650Sstevel@tonic-gate 	}
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 	/*
1680Sstevel@tonic-gate 	 * Free up current dnlc entries
1690Sstevel@tonic-gate 	 */
1700Sstevel@tonic-gate 	for (i = 0; i < MDB_DNLC_HSIZE; i++) {
1710Sstevel@tonic-gate 		for (ncp = dnlc_hash[i]; ncp; ncp = next) {
1720Sstevel@tonic-gate 			next = ncp->hash_next;
1730Sstevel@tonic-gate 			mdb_free(ncp, MDB_DNLC_NCACHE_SZ(ncp));
1740Sstevel@tonic-gate 		}
1750Sstevel@tonic-gate 	}
1760Sstevel@tonic-gate 	mdb_free(dnlc_hash, MDB_DNLC_HSIZE * sizeof (ncache_t *));
1770Sstevel@tonic-gate 	dnlc_hash = NULL;
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate char bad_dnlc[] = "inconsistent dnlc chain: %d, ncache va: %p"
1810Sstevel@tonic-gate 	" - continuing with the rest\n";
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate static int
dnlc_load(void)1840Sstevel@tonic-gate dnlc_load(void)
1850Sstevel@tonic-gate {
1860Sstevel@tonic-gate 	int i; /* hash index */
1870Sstevel@tonic-gate 	int retry_cnt = 0;
1880Sstevel@tonic-gate 	int skip_bad_chains = 0;
1890Sstevel@tonic-gate 	int nc_hashsz; /* kernel hash array size */
1900Sstevel@tonic-gate 	uintptr_t nc_hash_addr; /* kernel va of ncache hash array */
1910Sstevel@tonic-gate 	uintptr_t head; /* kernel va of head of hash chain */
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	/*
1940Sstevel@tonic-gate 	 * If we've already cached the DNLC and we're looking at a dump,
1950Sstevel@tonic-gate 	 * our cache is good forever, so don't bother re-loading.
1960Sstevel@tonic-gate 	 */
1970Sstevel@tonic-gate 	if (dnlc_hash && mdb_prop_postmortem) {
1980Sstevel@tonic-gate 		return (0);
1990Sstevel@tonic-gate 	}
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	/*
2020Sstevel@tonic-gate 	 * For a core dump, retries wont help.
2030Sstevel@tonic-gate 	 * Just print and skip any bad chains.
2040Sstevel@tonic-gate 	 */
2050Sstevel@tonic-gate 	if (mdb_prop_postmortem) {
2060Sstevel@tonic-gate 		skip_bad_chains = 1;
2070Sstevel@tonic-gate 	}
2080Sstevel@tonic-gate retry:
2090Sstevel@tonic-gate 	if (retry_cnt++ >= MDB_DNLC_MAX_RETRY) {
2100Sstevel@tonic-gate 		/*
2110Sstevel@tonic-gate 		 * Give up retrying the rapidly changing dnlc.
2120Sstevel@tonic-gate 		 * Just print and skip any bad chains
2130Sstevel@tonic-gate 		 */
2140Sstevel@tonic-gate 		skip_bad_chains = 1;
2150Sstevel@tonic-gate 	}
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	dnlc_free(); /* Free up the mdb hashed dnlc - if any */
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	/*
2200Sstevel@tonic-gate 	 * Although nc_hashsz and the location of nc_hash doesn't currently
2210Sstevel@tonic-gate 	 * change, it may do in the future with a more dynamic dnlc.
2220Sstevel@tonic-gate 	 * So always read these values afresh.
2230Sstevel@tonic-gate 	 */
2240Sstevel@tonic-gate 	if (mdb_readvar(&nc_hashsz, "nc_hashsz") == -1) {
2250Sstevel@tonic-gate 		mdb_warn("failed to read nc_hashsz");
2260Sstevel@tonic-gate 		return (-1);
2270Sstevel@tonic-gate 	}
2280Sstevel@tonic-gate 	if (mdb_readvar(&nc_hash_addr, "nc_hash") == -1) {
2290Sstevel@tonic-gate 		mdb_warn("failed to read nc_hash");
2300Sstevel@tonic-gate 		return (-1);
2310Sstevel@tonic-gate 	}
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	/*
2340Sstevel@tonic-gate 	 * Allocate the mdb dnlc hash array
2350Sstevel@tonic-gate 	 */
2360Sstevel@tonic-gate 	dnlc_hash = mdb_zalloc(MDB_DNLC_HSIZE * sizeof (ncache_t *), UM_SLEEP);
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	/* for each kernel hash chain */
2390Sstevel@tonic-gate 	for (i = 0, head = nc_hash_addr; i < nc_hashsz;
2400Sstevel@tonic-gate 	    i++, head += sizeof (nc_hash_t)) {
2410Sstevel@tonic-gate 		nc_hash_t nch; /* kernel hash chain header */
2420Sstevel@tonic-gate 		ncache_t *ncp; /* name cache pointer */
2430Sstevel@tonic-gate 		int hash; /* mdb hash value */
2440Sstevel@tonic-gate 		uintptr_t nc_va; /* kernel va of next ncache */
2450Sstevel@tonic-gate 		uintptr_t ncprev_va; /* kernel va of previous ncache */
2460Sstevel@tonic-gate 		int khash; /* kernel dnlc hash value */
2470Sstevel@tonic-gate 		uchar_t namelen; /* name length */
2480Sstevel@tonic-gate 		ncache_t nc; /* name cache entry */
2490Sstevel@tonic-gate 		int nc_size; /* size of a name cache entry */
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 		/*
2520Sstevel@tonic-gate 		 * We read each element of the nc_hash array individually
2530Sstevel@tonic-gate 		 * just before we process the entries in its chain. This is
2540Sstevel@tonic-gate 		 * because the chain can change so rapidly on a running system.
2550Sstevel@tonic-gate 		 */
2560Sstevel@tonic-gate 		if (mdb_vread(&nch, sizeof (nc_hash_t), head) == -1) {
2570Sstevel@tonic-gate 			mdb_warn("failed to read nc_hash chain header %d", i);
2580Sstevel@tonic-gate 			dnlc_free();
2590Sstevel@tonic-gate 			return (-1);
2600Sstevel@tonic-gate 		}
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 		ncprev_va = head;
2630Sstevel@tonic-gate 		nc_va = (uintptr_t)(nch.hash_next);
2640Sstevel@tonic-gate 		/* for each entry in the chain */
2650Sstevel@tonic-gate 		while (nc_va != head) {
2660Sstevel@tonic-gate 			/*
2670Sstevel@tonic-gate 			 * The size of the ncache entries varies
2680Sstevel@tonic-gate 			 * because the name is appended to the structure.
2690Sstevel@tonic-gate 			 * So we read in the structure then re-read
2700Sstevel@tonic-gate 			 * for the structure plus name.
2710Sstevel@tonic-gate 			 */
2720Sstevel@tonic-gate 			if (mdb_vread(&nc, sizeof (ncache_t), nc_va) == -1) {
2730Sstevel@tonic-gate 				if (skip_bad_chains) {
2740Sstevel@tonic-gate 					mdb_warn(bad_dnlc, i, nc_va);
2750Sstevel@tonic-gate 					break;
2760Sstevel@tonic-gate 				}
2770Sstevel@tonic-gate 				goto retry;
2780Sstevel@tonic-gate 			}
2790Sstevel@tonic-gate 			nc_size = MDB_DNLC_NCACHE_SZ(&nc);
2800Sstevel@tonic-gate 			ncp = mdb_alloc(nc_size, UM_SLEEP);
2810Sstevel@tonic-gate 			if (mdb_vread(ncp, nc_size - 1, nc_va) == -1) {
2820Sstevel@tonic-gate 				mdb_free(ncp, nc_size);
2830Sstevel@tonic-gate 				if (skip_bad_chains) {
2840Sstevel@tonic-gate 					mdb_warn(bad_dnlc, i, nc_va);
2850Sstevel@tonic-gate 					break;
2860Sstevel@tonic-gate 				}
2870Sstevel@tonic-gate 				goto retry;
2880Sstevel@tonic-gate 			}
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate 			/*
2910Sstevel@tonic-gate 			 * Check for chain consistency
2920Sstevel@tonic-gate 			 */
2930Sstevel@tonic-gate 			if ((uintptr_t)ncp->hash_prev != ncprev_va) {
2940Sstevel@tonic-gate 				mdb_free(ncp, nc_size);
2950Sstevel@tonic-gate 				if (skip_bad_chains) {
2960Sstevel@tonic-gate 					mdb_warn(bad_dnlc, i, nc_va);
2970Sstevel@tonic-gate 					break;
2980Sstevel@tonic-gate 				}
2990Sstevel@tonic-gate 				goto retry;
3000Sstevel@tonic-gate 			}
3010Sstevel@tonic-gate 			/*
3020Sstevel@tonic-gate 			 * Terminate the new name with a null.
3030Sstevel@tonic-gate 			 * Note, we allowed space for this null when
3040Sstevel@tonic-gate 			 * allocating space for the entry.
3050Sstevel@tonic-gate 			 */
3060Sstevel@tonic-gate 			ncp->name[ncp->namlen] = '\0';
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 			/*
3090Sstevel@tonic-gate 			 * Validate new entry by re-hashing using the
3100Sstevel@tonic-gate 			 * kernel dnlc hash function and comparing the hash
3110Sstevel@tonic-gate 			 */
3120Sstevel@tonic-gate 			DNLCHASH(ncp->name, ncp->dp, khash, namelen);
3130Sstevel@tonic-gate 			if ((namelen != ncp->namlen) ||
3140Sstevel@tonic-gate 			    (khash != ncp->hash)) {
3150Sstevel@tonic-gate 				mdb_free(ncp, nc_size);
3160Sstevel@tonic-gate 				if (skip_bad_chains) {
3170Sstevel@tonic-gate 					mdb_warn(bad_dnlc, i, nc_va);
3180Sstevel@tonic-gate 					break;
3190Sstevel@tonic-gate 				}
3200Sstevel@tonic-gate 				goto retry;
3210Sstevel@tonic-gate 			}
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 			/*
3240Sstevel@tonic-gate 			 * Finally put the validated entry into the mdb
3250Sstevel@tonic-gate 			 * hash chains. Reuse the kernel next hash field
3260Sstevel@tonic-gate 			 * for the mdb hash chain pointer.
3270Sstevel@tonic-gate 			 */
3280Sstevel@tonic-gate 			hash = MDB_DNLC_HASH(ncp->vp);
3290Sstevel@tonic-gate 			ncprev_va = nc_va;
3300Sstevel@tonic-gate 			nc_va = (uintptr_t)(ncp->hash_next);
3310Sstevel@tonic-gate 			ncp->hash_next = dnlc_hash[hash];
3320Sstevel@tonic-gate 			dnlc_hash[hash] = ncp;
3330Sstevel@tonic-gate 		}
3340Sstevel@tonic-gate 	}
3350Sstevel@tonic-gate 	return (0);
3360Sstevel@tonic-gate }
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate /*ARGSUSED*/
3390Sstevel@tonic-gate int
dnlcdump(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)3400Sstevel@tonic-gate dnlcdump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3410Sstevel@tonic-gate {
3420Sstevel@tonic-gate 	ncache_t *ent;
3430Sstevel@tonic-gate 	int i;
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) || argc != 0)
3460Sstevel@tonic-gate 		return (DCMD_USAGE);
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	if (dnlc_load() == -1)
3490Sstevel@tonic-gate 		return (DCMD_ERR);
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 	mdb_printf("%<u>%-?s %-?s %-32s%</u>\n", "VP", "DVP", "NAME");
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	for (i = 0; i < MDB_DNLC_HSIZE; i++) {
3540Sstevel@tonic-gate 		for (ent = dnlc_hash[i]; ent != NULL; ent = ent->hash_next) {
3550Sstevel@tonic-gate 			mdb_printf("%0?p %0?p %s\n",
3560Sstevel@tonic-gate 			    ent->vp, ent->dp, ent->name);
3570Sstevel@tonic-gate 		}
3580Sstevel@tonic-gate 	}
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	return (DCMD_OK);
3610Sstevel@tonic-gate }
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate static int
mdb_sprintpath(char * buf,size_t len,mdb_path_t * path)3640Sstevel@tonic-gate mdb_sprintpath(char *buf, size_t len, mdb_path_t *path)
3650Sstevel@tonic-gate {
3660Sstevel@tonic-gate 	char *s = buf;
3670Sstevel@tonic-gate 	int i;
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 	if (len < sizeof ("/..."))
3700Sstevel@tonic-gate 		return (-1);
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 	if (!path->mdp_complete) {
3730Sstevel@tonic-gate 		(void) strcpy(s, "??");
3740Sstevel@tonic-gate 		s += 2;
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 		if (path->mdp_nelem == 0)
3770Sstevel@tonic-gate 			return (-1);
3780Sstevel@tonic-gate 	}
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	if (path->mdp_nelem == 0) {
3810Sstevel@tonic-gate 		(void) strcpy(s, "/");
3820Sstevel@tonic-gate 		return (0);
3830Sstevel@tonic-gate 	}
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 	for (i = path->mdp_nelem - 1; i >= 0; i--) {
3860Sstevel@tonic-gate 		/*
3870Sstevel@tonic-gate 		 * Number of bytes left is the distance from where we
3880Sstevel@tonic-gate 		 * are to the end, minus 2 for '/' and '\0'
3890Sstevel@tonic-gate 		 */
3900Sstevel@tonic-gate 		ssize_t left = (ssize_t)(&buf[len] - s) - 2;
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 		if (left <= 0)
3930Sstevel@tonic-gate 			break;
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 		*s++ = '/';
3960Sstevel@tonic-gate 		(void) strncpy(s, path->mdp_name[i], left);
3970Sstevel@tonic-gate 		s[left - 1] = '\0';
3980Sstevel@tonic-gate 		s += strlen(s);
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 		if (left < strlen(path->mdp_name[i]))
4010Sstevel@tonic-gate 			break;
4020Sstevel@tonic-gate 	}
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 	if (i >= 0)
4050Sstevel@tonic-gate 		(void) strcpy(&buf[len - 4], "...");
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	return (0);
4080Sstevel@tonic-gate }
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate static int
mdb_autonode2path(uintptr_t addr,mdb_path_t * path)4110Sstevel@tonic-gate mdb_autonode2path(uintptr_t addr, mdb_path_t *path)
4120Sstevel@tonic-gate {
4130Sstevel@tonic-gate 	fninfo_t fni;
4140Sstevel@tonic-gate 	fnnode_t fn;
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	vnode_t vn;
4170Sstevel@tonic-gate 	vfs_t vfs;
4180Sstevel@tonic-gate 	struct vnodeops *autofs_vnops = NULL;
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	/*
4210Sstevel@tonic-gate 	 * "autofs_vnops_ptr" is the address of the pointer to the vnodeops
4220Sstevel@tonic-gate 	 * structure for autofs.  We want to read it each time we access
4230Sstevel@tonic-gate 	 * it since autofs could (in theory) be unloaded and reloaded.
4240Sstevel@tonic-gate 	 */
4250Sstevel@tonic-gate 	if (mdb_vread(&autofs_vnops, sizeof (autofs_vnops),
4260Sstevel@tonic-gate 	    (uintptr_t)autofs_vnops_ptr) == -1)
4270Sstevel@tonic-gate 		return (-1);
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	if (mdb_vread(&vn, sizeof (vn), addr) == -1)
4300Sstevel@tonic-gate 		return (-1);
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	if (autofs_vnops == NULL || vn.v_op != autofs_vnops)
4330Sstevel@tonic-gate 		return (-1);
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	addr = (uintptr_t)vn.v_data;
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	if (mdb_vread(&vfs, sizeof (vfs), (uintptr_t)vn.v_vfsp) == -1 ||
4380Sstevel@tonic-gate 	    mdb_vread(&fni, sizeof (fni), (uintptr_t)vfs.vfs_data) == -1 ||
4390Sstevel@tonic-gate 	    mdb_vread(&vn, sizeof (vn), (uintptr_t)fni.fi_rootvp) == -1)
4400Sstevel@tonic-gate 		return (-1);
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	for (;;) {
4430Sstevel@tonic-gate 		size_t elem = path->mdp_nelem++;
4440Sstevel@tonic-gate 		char elemstr[MAXNAMELEN];
4450Sstevel@tonic-gate 		char *c, *p;
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 		if (elem == MDB_PATH_NELEM) {
4480Sstevel@tonic-gate 			path->mdp_nelem--;
4490Sstevel@tonic-gate 			return (-1);
4500Sstevel@tonic-gate 		}
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 		if (mdb_vread(&fn, sizeof (fn), addr) != sizeof (fn)) {
4530Sstevel@tonic-gate 			path->mdp_nelem--;
4540Sstevel@tonic-gate 			return (-1);
4550Sstevel@tonic-gate 		}
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 		if (mdb_readstr(elemstr, sizeof (elemstr),
4580Sstevel@tonic-gate 		    (uintptr_t)fn.fn_name) <= 0) {
4590Sstevel@tonic-gate 			(void) strcpy(elemstr, "?");
4600Sstevel@tonic-gate 		}
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 		c = mdb_alloc(strlen(elemstr) + 1, UM_SLEEP | UM_GC);
4630Sstevel@tonic-gate 		(void) strcpy(c, elemstr);
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 		path->mdp_vnode[elem] = (uintptr_t)fn.fn_vnode;
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 		if (addr == (uintptr_t)fn.fn_parent) {
4680Sstevel@tonic-gate 			path->mdp_name[elem] = &c[1];
4690Sstevel@tonic-gate 			path->mdp_complete = TRUE;
4700Sstevel@tonic-gate 			break;
4710Sstevel@tonic-gate 		}
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 		if ((p = strrchr(c, '/')) != NULL)
4740Sstevel@tonic-gate 			path->mdp_name[elem] = p + 1;
4750Sstevel@tonic-gate 		else
4760Sstevel@tonic-gate 			path->mdp_name[elem] = c;
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 		addr = (uintptr_t)fn.fn_parent;
4790Sstevel@tonic-gate 	}
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	return (0);
4820Sstevel@tonic-gate }
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate int
mdb_vnode2path(uintptr_t addr,char * buf,size_t buflen)4850Sstevel@tonic-gate mdb_vnode2path(uintptr_t addr, char *buf, size_t buflen)
4860Sstevel@tonic-gate {
4870Sstevel@tonic-gate 	uintptr_t rootdir;
4880Sstevel@tonic-gate 	ncache_t *ent;
4890Sstevel@tonic-gate 	vnode_t vp;
4900Sstevel@tonic-gate 	mdb_path_t path;
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 	/*
4930Sstevel@tonic-gate 	 * Check to see if we have a cached value for this vnode
4940Sstevel@tonic-gate 	 */
4950Sstevel@tonic-gate 	if (mdb_vread(&vp, sizeof (vp), addr) != -1 &&
4960Sstevel@tonic-gate 	    vp.v_path != NULL &&
4970Sstevel@tonic-gate 	    mdb_readstr(buf, buflen, (uintptr_t)vp.v_path) != -1)
4980Sstevel@tonic-gate 		return (0);
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 	if (dnlc_load() == -1)
5010Sstevel@tonic-gate 		return (-1);
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 	if (mdb_readvar(&rootdir, "rootdir") == -1) {
5040Sstevel@tonic-gate 		mdb_warn("failed to read 'rootdir'");
5050Sstevel@tonic-gate 		return (-1);
5060Sstevel@tonic-gate 	}
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	bzero(&path, sizeof (mdb_path_t));
5090Sstevel@tonic-gate again:
5100Sstevel@tonic-gate 	if ((addr == NULL) && (path.mdp_nelem == 0)) {
5110Sstevel@tonic-gate 		/*
5120Sstevel@tonic-gate 		 * 0 elems && complete tells sprintpath to just print "/"
5130Sstevel@tonic-gate 		 */
5140Sstevel@tonic-gate 		path.mdp_complete = TRUE;
5150Sstevel@tonic-gate 		goto out;
5160Sstevel@tonic-gate 	}
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 	if (addr == rootdir) {
5190Sstevel@tonic-gate 		path.mdp_complete = TRUE;
5200Sstevel@tonic-gate 		goto out;
5210Sstevel@tonic-gate 	}
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 	for (ent = dnlc_hash[MDB_DNLC_HASH(addr)]; ent; ent = ent->hash_next) {
5240Sstevel@tonic-gate 		if ((uintptr_t)ent->vp == addr) {
5250Sstevel@tonic-gate 			if (strcmp(ent->name, "..") == 0 ||
5260Sstevel@tonic-gate 			    strcmp(ent->name, ".") == 0)
5270Sstevel@tonic-gate 				continue;
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 			path.mdp_vnode[path.mdp_nelem] = (uintptr_t)ent->vp;
5300Sstevel@tonic-gate 			path.mdp_name[path.mdp_nelem] = ent->name;
5310Sstevel@tonic-gate 			path.mdp_nelem++;
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 			if (path.mdp_nelem == MDB_PATH_NELEM) {
5340Sstevel@tonic-gate 				path.mdp_nelem--;
5350Sstevel@tonic-gate 				mdb_warn("path exceeded maximum expected "
5360Sstevel@tonic-gate 				    "elements\n");
5370Sstevel@tonic-gate 				return (-1);
5380Sstevel@tonic-gate 			}
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 			addr = (uintptr_t)ent->dp;
5410Sstevel@tonic-gate 			goto again;
5420Sstevel@tonic-gate 		}
5430Sstevel@tonic-gate 	}
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	(void) mdb_autonode2path(addr, &path);
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate out:
5480Sstevel@tonic-gate 	return (mdb_sprintpath(buf, buflen, &path));
5490Sstevel@tonic-gate }
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate uintptr_t
mdb_pid2proc(pid_t pid,proc_t * proc)5530Sstevel@tonic-gate mdb_pid2proc(pid_t pid, proc_t *proc)
5540Sstevel@tonic-gate {
5550Sstevel@tonic-gate 	int pid_hashsz, hash;
5560Sstevel@tonic-gate 	uintptr_t paddr, pidhash, procdir;
5570Sstevel@tonic-gate 	struct pid pidp;
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	if (mdb_readvar(&pidhash, "pidhash") == -1)
5600Sstevel@tonic-gate 		return (NULL);
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 	if (mdb_readvar(&pid_hashsz, "pid_hashsz") == -1)
5630Sstevel@tonic-gate 		return (NULL);
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 	if (mdb_readvar(&procdir, "procdir") == -1)
5660Sstevel@tonic-gate 		return (NULL);
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 	hash = pid & (pid_hashsz - 1);
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate 	if (mdb_vread(&paddr, sizeof (paddr),
5710Sstevel@tonic-gate 	    pidhash + (hash * sizeof (paddr))) == -1)
5720Sstevel@tonic-gate 		return (NULL);
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	while (paddr != 0) {
5750Sstevel@tonic-gate 		if (mdb_vread(&pidp, sizeof (pidp), paddr) == -1)
5760Sstevel@tonic-gate 			return (NULL);
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 		if (pidp.pid_id == pid) {
5790Sstevel@tonic-gate 			uintptr_t procp;
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 			if (mdb_vread(&procp, sizeof (procp), procdir +
5820Sstevel@tonic-gate 			    (pidp.pid_prslot * sizeof (procp))) == -1)
5830Sstevel@tonic-gate 				return (NULL);
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 			if (proc != NULL)
5860Sstevel@tonic-gate 				(void) mdb_vread(proc, sizeof (proc_t), procp);
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 			return (procp);
5890Sstevel@tonic-gate 		}
5900Sstevel@tonic-gate 		paddr = (uintptr_t)pidp.pid_link;
5910Sstevel@tonic-gate 	}
5920Sstevel@tonic-gate 	return (NULL);
5930Sstevel@tonic-gate }
5940Sstevel@tonic-gate 
5951234Sjohnlev int
mdb_cpu2cpuid(uintptr_t cpup)5961234Sjohnlev mdb_cpu2cpuid(uintptr_t cpup)
5971234Sjohnlev {
5981234Sjohnlev 	cpu_t cpu;
5991234Sjohnlev 
6001234Sjohnlev 	if (mdb_vread(&cpu, sizeof (cpu_t), cpup) != sizeof (cpu_t))
6011234Sjohnlev 		return (-1);
6021234Sjohnlev 
6031234Sjohnlev 	return (cpu.cpu_id);
6041234Sjohnlev }
6051234Sjohnlev 
6062116Sanish int
mdb_cpuset_find(uintptr_t cpusetp)6072116Sanish mdb_cpuset_find(uintptr_t cpusetp)
6082116Sanish {
6092116Sanish 	ulong_t	*cpuset;
6102116Sanish 	size_t nr_words = BT_BITOUL(NCPU);
6112116Sanish 	size_t sz = nr_words * sizeof (ulong_t);
6122116Sanish 	size_t	i;
6132116Sanish 	int cpu = -1;
6142116Sanish 
6152116Sanish 	cpuset = mdb_alloc(sz, UM_SLEEP);
6162116Sanish 
6176336Sbholler 	if (mdb_vread((void *)cpuset, sz, cpusetp) != sz)
6182116Sanish 		goto out;
6192116Sanish 
6202116Sanish 	for (i = 0; i < nr_words; i++) {
6212116Sanish 		size_t j;
6222116Sanish 		ulong_t m;
6232116Sanish 
6242116Sanish 		for (j = 0, m = 1; j < BT_NBIPUL; j++, m <<= 1) {
6252116Sanish 			if (cpuset[i] & m) {
6262116Sanish 				cpu = i * BT_NBIPUL + j;
6272116Sanish 				goto out;
6282116Sanish 			}
6292116Sanish 		}
6302116Sanish 	}
6312116Sanish 
6322116Sanish out:
6332116Sanish 	mdb_free(cpuset, sz);
6342116Sanish 	return (cpu);
6352116Sanish }
6362116Sanish 
637*13076SJonathan.Adams@Sun.COM static int
page_hash_load(void)638*13076SJonathan.Adams@Sun.COM page_hash_load(void)
639*13076SJonathan.Adams@Sun.COM {
640*13076SJonathan.Adams@Sun.COM 	if (page_hash_loaded) {
641*13076SJonathan.Adams@Sun.COM 		return (1);
642*13076SJonathan.Adams@Sun.COM 	}
643*13076SJonathan.Adams@Sun.COM 
644*13076SJonathan.Adams@Sun.COM 	if (mdb_readvar(&mdb_page_hashsz, "page_hashsz") == -1) {
645*13076SJonathan.Adams@Sun.COM 		mdb_warn("unable to read page_hashsz");
646*13076SJonathan.Adams@Sun.COM 		return (0);
647*13076SJonathan.Adams@Sun.COM 	}
648*13076SJonathan.Adams@Sun.COM 	if (mdb_readvar(&mdb_page_hashsz_shift, "page_hashsz_shift") == -1) {
649*13076SJonathan.Adams@Sun.COM 		mdb_warn("unable to read page_hashsz_shift");
650*13076SJonathan.Adams@Sun.COM 		return (0);
651*13076SJonathan.Adams@Sun.COM 	}
652*13076SJonathan.Adams@Sun.COM 	if (mdb_readvar(&mdb_page_hash, "page_hash") == -1) {
653*13076SJonathan.Adams@Sun.COM 		mdb_warn("unable to read page_hash");
654*13076SJonathan.Adams@Sun.COM 		return (0);
655*13076SJonathan.Adams@Sun.COM 	}
656*13076SJonathan.Adams@Sun.COM 
657*13076SJonathan.Adams@Sun.COM 	page_hash_loaded = 1;	/* zeroed on state change */
658*13076SJonathan.Adams@Sun.COM 	return (1);
659*13076SJonathan.Adams@Sun.COM }
660*13076SJonathan.Adams@Sun.COM 
6610Sstevel@tonic-gate uintptr_t
mdb_page_lookup(uintptr_t vp,u_offset_t offset)66211459SJonathan.Adams@Sun.COM mdb_page_lookup(uintptr_t vp, u_offset_t offset)
6630Sstevel@tonic-gate {
664*13076SJonathan.Adams@Sun.COM 	size_t ndx;
665*13076SJonathan.Adams@Sun.COM 	uintptr_t page_hash_entry, pp;
6660Sstevel@tonic-gate 
667*13076SJonathan.Adams@Sun.COM 	if (!page_hash_loaded && !page_hash_load()) {
6680Sstevel@tonic-gate 		return (NULL);
669*13076SJonathan.Adams@Sun.COM 	}
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	ndx = PAGE_HASH_FUNC(vp, offset);
672*13076SJonathan.Adams@Sun.COM 	page_hash_entry = mdb_page_hash + ndx * sizeof (uintptr_t);
6730Sstevel@tonic-gate 
674*13076SJonathan.Adams@Sun.COM 	if (mdb_vread(&pp, sizeof (pp), page_hash_entry) < 0) {
675*13076SJonathan.Adams@Sun.COM 		mdb_warn("unable to read page_hash[%ld] (%p)", ndx,
676*13076SJonathan.Adams@Sun.COM 		    page_hash_entry);
677*13076SJonathan.Adams@Sun.COM 		return (NULL);
678*13076SJonathan.Adams@Sun.COM 	}
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate 	while (pp != NULL) {
6810Sstevel@tonic-gate 		page_t page;
682*13076SJonathan.Adams@Sun.COM 		long nndx;
6830Sstevel@tonic-gate 
684*13076SJonathan.Adams@Sun.COM 		if (mdb_vread(&page, sizeof (page), pp) < 0) {
685*13076SJonathan.Adams@Sun.COM 			mdb_warn("unable to read page_t at %p", pp);
686*13076SJonathan.Adams@Sun.COM 			return (NULL);
687*13076SJonathan.Adams@Sun.COM 		}
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 		if ((uintptr_t)page.p_vnode == vp &&
69011459SJonathan.Adams@Sun.COM 		    (uint64_t)page.p_offset == offset)
6910Sstevel@tonic-gate 			return (pp);
6920Sstevel@tonic-gate 
693*13076SJonathan.Adams@Sun.COM 		/*
694*13076SJonathan.Adams@Sun.COM 		 * Double check that the pages actually hash to the
695*13076SJonathan.Adams@Sun.COM 		 * bucket we're searching.  If not, our version of
696*13076SJonathan.Adams@Sun.COM 		 * PAGE_HASH_FUNC() doesn't match the kernel's, and we're
697*13076SJonathan.Adams@Sun.COM 		 * not going to be able to find the page.  The most
698*13076SJonathan.Adams@Sun.COM 		 * likely reason for this that mdb_ks doesn't match the
699*13076SJonathan.Adams@Sun.COM 		 * kernel we're running against.
700*13076SJonathan.Adams@Sun.COM 		 */
701*13076SJonathan.Adams@Sun.COM 		nndx = PAGE_HASH_FUNC(page.p_vnode, page.p_offset);
702*13076SJonathan.Adams@Sun.COM 		if (page.p_vnode != NULL && nndx != ndx) {
703*13076SJonathan.Adams@Sun.COM 			mdb_warn("mdb_page_lookup: mdb_ks PAGE_HASH_FUNC() "
704*13076SJonathan.Adams@Sun.COM 			    "mismatch: in bucket %ld, but page %p hashes to "
705*13076SJonathan.Adams@Sun.COM 			    "bucket %ld\n", ndx, pp, nndx);
706*13076SJonathan.Adams@Sun.COM 			return (NULL);
707*13076SJonathan.Adams@Sun.COM 		}
708*13076SJonathan.Adams@Sun.COM 
7090Sstevel@tonic-gate 		pp = (uintptr_t)page.p_hash;
7100Sstevel@tonic-gate 	}
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 	return (NULL);
7130Sstevel@tonic-gate }
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate char
mdb_vtype2chr(vtype_t type,mode_t mode)7160Sstevel@tonic-gate mdb_vtype2chr(vtype_t type, mode_t mode)
7170Sstevel@tonic-gate {
7180Sstevel@tonic-gate 	static const char vttab[] = {
7190Sstevel@tonic-gate 		' ',	/* VNON */
7200Sstevel@tonic-gate 		' ',	/* VREG */
7210Sstevel@tonic-gate 		'/',	/* VDIR */
7220Sstevel@tonic-gate 		' ',	/* VBLK */
7230Sstevel@tonic-gate 		' ',	/* VCHR */
7240Sstevel@tonic-gate 		'@',	/* VLNK */
7250Sstevel@tonic-gate 		'|',	/* VFIFO */
7260Sstevel@tonic-gate 		'>',	/* VDOOR */
7270Sstevel@tonic-gate 		' ',	/* VPROC */
7280Sstevel@tonic-gate 		'=',	/* VSOCK */
7290Sstevel@tonic-gate 		' ',	/* VBAD */
7300Sstevel@tonic-gate 	};
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	if (type < 0 || type >= sizeof (vttab) / sizeof (vttab[0]))
7330Sstevel@tonic-gate 		return ('?');
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 	if (type == VREG && (mode & 0111) != 0)
7360Sstevel@tonic-gate 		return ('*');
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate 	return (vttab[type]);
7390Sstevel@tonic-gate }
7400Sstevel@tonic-gate 
74111459SJonathan.Adams@Sun.COM struct pfn2page {
74211459SJonathan.Adams@Sun.COM 	pfn_t pfn;
74311459SJonathan.Adams@Sun.COM 	page_t *pp;
74411459SJonathan.Adams@Sun.COM };
74511459SJonathan.Adams@Sun.COM 
74611459SJonathan.Adams@Sun.COM /*ARGSUSED*/
74711459SJonathan.Adams@Sun.COM static int
pfn2page_cb(uintptr_t addr,const struct memseg * msp,void * data)74811459SJonathan.Adams@Sun.COM pfn2page_cb(uintptr_t addr, const struct memseg *msp, void *data)
74911459SJonathan.Adams@Sun.COM {
75011459SJonathan.Adams@Sun.COM 	struct pfn2page *p = data;
75111459SJonathan.Adams@Sun.COM 
75211459SJonathan.Adams@Sun.COM 	if (p->pfn >= msp->pages_base && p->pfn < msp->pages_end) {
75311459SJonathan.Adams@Sun.COM 		p->pp = msp->pages + (p->pfn - msp->pages_base);
75411459SJonathan.Adams@Sun.COM 		return (WALK_DONE);
75511459SJonathan.Adams@Sun.COM 	}
75611459SJonathan.Adams@Sun.COM 
75711459SJonathan.Adams@Sun.COM 	return (WALK_NEXT);
75811459SJonathan.Adams@Sun.COM }
75911459SJonathan.Adams@Sun.COM 
76011459SJonathan.Adams@Sun.COM uintptr_t
mdb_pfn2page(pfn_t pfn)76111459SJonathan.Adams@Sun.COM mdb_pfn2page(pfn_t pfn)
76211459SJonathan.Adams@Sun.COM {
76311459SJonathan.Adams@Sun.COM 	struct pfn2page	arg;
76411459SJonathan.Adams@Sun.COM 	struct page	page;
76511459SJonathan.Adams@Sun.COM 
76611459SJonathan.Adams@Sun.COM 	arg.pfn = pfn;
76711459SJonathan.Adams@Sun.COM 	arg.pp = NULL;
76811459SJonathan.Adams@Sun.COM 
76911459SJonathan.Adams@Sun.COM 	if (mdb_walk("memseg", (mdb_walk_cb_t)pfn2page_cb, &arg) == -1) {
77011459SJonathan.Adams@Sun.COM 		mdb_warn("pfn2page: can't walk memsegs");
77111459SJonathan.Adams@Sun.COM 		return (0);
77211459SJonathan.Adams@Sun.COM 	}
77311459SJonathan.Adams@Sun.COM 	if (arg.pp == NULL) {
77411459SJonathan.Adams@Sun.COM 		mdb_warn("pfn2page: unable to find page_t for pfn %lx\n",
77511459SJonathan.Adams@Sun.COM 		    pfn);
77611459SJonathan.Adams@Sun.COM 		return (0);
77711459SJonathan.Adams@Sun.COM 	}
77811459SJonathan.Adams@Sun.COM 
77911459SJonathan.Adams@Sun.COM 	if (mdb_vread(&page, sizeof (page_t), (uintptr_t)arg.pp) == -1) {
78011459SJonathan.Adams@Sun.COM 		mdb_warn("pfn2page: can't read page 0x%lx at %p", pfn, arg.pp);
78111459SJonathan.Adams@Sun.COM 		return (0);
78211459SJonathan.Adams@Sun.COM 	}
78311459SJonathan.Adams@Sun.COM 	if (page.p_pagenum != pfn) {
78411459SJonathan.Adams@Sun.COM 		mdb_warn("pfn2page: page_t 0x%p should have PFN 0x%lx, "
78511459SJonathan.Adams@Sun.COM 		    "but actually has 0x%lx\n", arg.pp, pfn, page.p_pagenum);
78611459SJonathan.Adams@Sun.COM 		return (0);
78711459SJonathan.Adams@Sun.COM 	}
78811459SJonathan.Adams@Sun.COM 
78911459SJonathan.Adams@Sun.COM 	return ((uintptr_t)arg.pp);
79011459SJonathan.Adams@Sun.COM }
79111459SJonathan.Adams@Sun.COM 
79211459SJonathan.Adams@Sun.COM pfn_t
mdb_page2pfn(uintptr_t addr)79311459SJonathan.Adams@Sun.COM mdb_page2pfn(uintptr_t addr)
79411459SJonathan.Adams@Sun.COM {
79511459SJonathan.Adams@Sun.COM 	struct page	page;
79611459SJonathan.Adams@Sun.COM 
79711459SJonathan.Adams@Sun.COM 	if (mdb_vread(&page, sizeof (page_t), addr) == -1) {
79811459SJonathan.Adams@Sun.COM 		mdb_warn("pp2pfn: can't read page at %p", addr);
79911459SJonathan.Adams@Sun.COM 		return ((pfn_t)(-1));
80011459SJonathan.Adams@Sun.COM 	}
80111459SJonathan.Adams@Sun.COM 
80211459SJonathan.Adams@Sun.COM 	return (page.p_pagenum);
80311459SJonathan.Adams@Sun.COM }
80411459SJonathan.Adams@Sun.COM 
8050Sstevel@tonic-gate static int
a2m_walk_modctl(uintptr_t addr,const struct modctl * m,a2m_query_t * a2m)8060Sstevel@tonic-gate a2m_walk_modctl(uintptr_t addr, const struct modctl *m, a2m_query_t *a2m)
8070Sstevel@tonic-gate {
8080Sstevel@tonic-gate 	struct module mod;
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 	if (m->mod_mp == NULL)
8110Sstevel@tonic-gate 		return (0);
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 	if (mdb_vread(&mod, sizeof (mod), (uintptr_t)m->mod_mp) == -1) {
8140Sstevel@tonic-gate 		mdb_warn("couldn't read modctl %p's module", addr);
8150Sstevel@tonic-gate 		return (0);
8160Sstevel@tonic-gate 	}
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 	if (a2m->a2m_addr >= (uintptr_t)mod.text &&
8190Sstevel@tonic-gate 	    a2m->a2m_addr < (uintptr_t)mod.text + mod.text_size)
8200Sstevel@tonic-gate 		goto found;
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate 	if (a2m->a2m_addr >= (uintptr_t)mod.data &&
8230Sstevel@tonic-gate 	    a2m->a2m_addr < (uintptr_t)mod.data + mod.data_size)
8240Sstevel@tonic-gate 		goto found;
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 	return (0);
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate found:
8290Sstevel@tonic-gate 	a2m->a2m_where = addr;
8300Sstevel@tonic-gate 	return (-1);
8310Sstevel@tonic-gate }
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate uintptr_t
mdb_addr2modctl(uintptr_t addr)8340Sstevel@tonic-gate mdb_addr2modctl(uintptr_t addr)
8350Sstevel@tonic-gate {
8360Sstevel@tonic-gate 	a2m_query_t a2m;
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 	a2m.a2m_addr = addr;
8390Sstevel@tonic-gate 	a2m.a2m_where = NULL;
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate 	(void) mdb_walk("modctl", (mdb_walk_cb_t)a2m_walk_modctl, &a2m);
8420Sstevel@tonic-gate 	return (a2m.a2m_where);
8430Sstevel@tonic-gate }
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate static mdb_qinfo_t *
qi_lookup(uintptr_t qinit_addr)8460Sstevel@tonic-gate qi_lookup(uintptr_t qinit_addr)
8470Sstevel@tonic-gate {
8480Sstevel@tonic-gate 	mdb_qinfo_t *qip;
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 	for (qip = qi_head; qip != NULL; qip = qip->qi_next) {
8510Sstevel@tonic-gate 		if (qip->qi_addr == qinit_addr)
8520Sstevel@tonic-gate 			return (qip);
8530Sstevel@tonic-gate 	}
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate 	return (NULL);
8560Sstevel@tonic-gate }
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate void
mdb_qops_install(const mdb_qops_t * qops,uintptr_t qinit_addr)8590Sstevel@tonic-gate mdb_qops_install(const mdb_qops_t *qops, uintptr_t qinit_addr)
8600Sstevel@tonic-gate {
8610Sstevel@tonic-gate 	mdb_qinfo_t *qip = qi_lookup(qinit_addr);
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 	if (qip != NULL) {
8640Sstevel@tonic-gate 		qip->qi_ops = qops;
8650Sstevel@tonic-gate 		return;
8660Sstevel@tonic-gate 	}
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 	qip = mdb_alloc(sizeof (mdb_qinfo_t), UM_SLEEP);
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate 	qip->qi_ops = qops;
8710Sstevel@tonic-gate 	qip->qi_addr = qinit_addr;
8720Sstevel@tonic-gate 	qip->qi_next = qi_head;
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	qi_head = qip;
8750Sstevel@tonic-gate }
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate void
mdb_qops_remove(const mdb_qops_t * qops,uintptr_t qinit_addr)8780Sstevel@tonic-gate mdb_qops_remove(const mdb_qops_t *qops, uintptr_t qinit_addr)
8790Sstevel@tonic-gate {
8800Sstevel@tonic-gate 	mdb_qinfo_t *qip, *p = NULL;
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	for (qip = qi_head; qip != NULL; p = qip, qip = qip->qi_next) {
8830Sstevel@tonic-gate 		if (qip->qi_addr == qinit_addr && qip->qi_ops == qops) {
8840Sstevel@tonic-gate 			if (qi_head == qip)
8850Sstevel@tonic-gate 				qi_head = qip->qi_next;
8860Sstevel@tonic-gate 			else
8870Sstevel@tonic-gate 				p->qi_next = qip->qi_next;
8880Sstevel@tonic-gate 			mdb_free(qip, sizeof (mdb_qinfo_t));
8890Sstevel@tonic-gate 			return;
8900Sstevel@tonic-gate 		}
8910Sstevel@tonic-gate 	}
8920Sstevel@tonic-gate }
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate char *
mdb_qname(const queue_t * q,char * buf,size_t nbytes)8950Sstevel@tonic-gate mdb_qname(const queue_t *q, char *buf, size_t nbytes)
8960Sstevel@tonic-gate {
8970Sstevel@tonic-gate 	struct module_info mi;
8980Sstevel@tonic-gate 	struct qinit qi;
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	if (mdb_vread(&qi, sizeof (qi), (uintptr_t)q->q_qinfo) == -1) {
9010Sstevel@tonic-gate 		mdb_warn("failed to read qinit at %p", q->q_qinfo);
9020Sstevel@tonic-gate 		goto err;
9030Sstevel@tonic-gate 	}
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 	if (mdb_vread(&mi, sizeof (mi), (uintptr_t)qi.qi_minfo) == -1) {
9060Sstevel@tonic-gate 		mdb_warn("failed to read module_info at %p", qi.qi_minfo);
9070Sstevel@tonic-gate 		goto err;
9080Sstevel@tonic-gate 	}
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate 	if (mdb_readstr(buf, nbytes, (uintptr_t)mi.mi_idname) <= 0) {
9110Sstevel@tonic-gate 		mdb_warn("failed to read mi_idname at %p", mi.mi_idname);
9120Sstevel@tonic-gate 		goto err;
9130Sstevel@tonic-gate 	}
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate 	return (buf);
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate err:
9180Sstevel@tonic-gate 	(void) mdb_snprintf(buf, nbytes, "???");
9190Sstevel@tonic-gate 	return (buf);
9200Sstevel@tonic-gate }
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate void
mdb_qinfo(const queue_t * q,char * buf,size_t nbytes)9230Sstevel@tonic-gate mdb_qinfo(const queue_t *q, char *buf, size_t nbytes)
9240Sstevel@tonic-gate {
9250Sstevel@tonic-gate 	mdb_qinfo_t *qip = qi_lookup((uintptr_t)q->q_qinfo);
9260Sstevel@tonic-gate 	buf[0] = '\0';
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 	if (qip != NULL)
9290Sstevel@tonic-gate 		qip->qi_ops->q_info(q, buf, nbytes);
9300Sstevel@tonic-gate }
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate uintptr_t
mdb_qrnext(const queue_t * q)9330Sstevel@tonic-gate mdb_qrnext(const queue_t *q)
9340Sstevel@tonic-gate {
9350Sstevel@tonic-gate 	mdb_qinfo_t *qip = qi_lookup((uintptr_t)q->q_qinfo);
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate 	if (qip != NULL)
9380Sstevel@tonic-gate 		return (qip->qi_ops->q_rnext(q));
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 	return (NULL);
9410Sstevel@tonic-gate }
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate uintptr_t
mdb_qwnext(const queue_t * q)9440Sstevel@tonic-gate mdb_qwnext(const queue_t *q)
9450Sstevel@tonic-gate {
9460Sstevel@tonic-gate 	mdb_qinfo_t *qip = qi_lookup((uintptr_t)q->q_qinfo);
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 	if (qip != NULL)
9490Sstevel@tonic-gate 		return (qip->qi_ops->q_wnext(q));
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate 	return (NULL);
9520Sstevel@tonic-gate }
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate uintptr_t
mdb_qrnext_default(const queue_t * q)9550Sstevel@tonic-gate mdb_qrnext_default(const queue_t *q)
9560Sstevel@tonic-gate {
9570Sstevel@tonic-gate 	return ((uintptr_t)q->q_next);
9580Sstevel@tonic-gate }
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate uintptr_t
mdb_qwnext_default(const queue_t * q)9610Sstevel@tonic-gate mdb_qwnext_default(const queue_t *q)
9620Sstevel@tonic-gate {
9630Sstevel@tonic-gate 	return ((uintptr_t)q->q_next);
9640Sstevel@tonic-gate }
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate /*
9670Sstevel@tonic-gate  * The following three routines borrowed from modsubr.c
9680Sstevel@tonic-gate  */
9690Sstevel@tonic-gate static int
nm_hash(const char * name)9700Sstevel@tonic-gate nm_hash(const char *name)
9710Sstevel@tonic-gate {
9720Sstevel@tonic-gate 	char c;
9730Sstevel@tonic-gate 	int hash = 0;
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 	for (c = *name++; c; c = *name++)
9760Sstevel@tonic-gate 		hash ^= c;
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	return (hash & MOD_BIND_HASHMASK);
9790Sstevel@tonic-gate }
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate static uintptr_t
find_mbind(const char * name,uintptr_t * hashtab)9820Sstevel@tonic-gate find_mbind(const char *name, uintptr_t *hashtab)
9830Sstevel@tonic-gate {
9840Sstevel@tonic-gate 	int hashndx;
9850Sstevel@tonic-gate 	uintptr_t mb;
9860Sstevel@tonic-gate 	struct bind mb_local;
9874145Scth 	char node_name[MAXPATHLEN + 1];
9880Sstevel@tonic-gate 
9890Sstevel@tonic-gate 	hashndx = nm_hash(name);
9900Sstevel@tonic-gate 	mb = hashtab[hashndx];
9910Sstevel@tonic-gate 	while (mb) {
9920Sstevel@tonic-gate 		if (mdb_vread(&mb_local, sizeof (mb_local), mb) == -1) {
9930Sstevel@tonic-gate 			mdb_warn("failed to read struct bind at %p", mb);
9940Sstevel@tonic-gate 			return (NULL);
9950Sstevel@tonic-gate 		}
9960Sstevel@tonic-gate 		if (mdb_readstr(node_name, sizeof (node_name),
9970Sstevel@tonic-gate 		    (uintptr_t)mb_local.b_name) == -1) {
9980Sstevel@tonic-gate 			mdb_warn("failed to read node name string at %p",
9996336Sbholler 			    mb_local.b_name);
10000Sstevel@tonic-gate 			return (NULL);
10010Sstevel@tonic-gate 		}
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate 		if (strcmp(name, node_name) == 0)
10040Sstevel@tonic-gate 			break;
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate 		mb = (uintptr_t)mb_local.b_next;
10070Sstevel@tonic-gate 	}
10080Sstevel@tonic-gate 	return (mb);
10090Sstevel@tonic-gate }
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate int
mdb_name_to_major(const char * name,major_t * major)10120Sstevel@tonic-gate mdb_name_to_major(const char *name, major_t *major)
10130Sstevel@tonic-gate {
10140Sstevel@tonic-gate 	uintptr_t	mbind;
10150Sstevel@tonic-gate 	uintptr_t	mb_hashtab[MOD_BIND_HASHSIZE];
10160Sstevel@tonic-gate 	struct bind 	mbind_local;
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate 	if (mdb_readsym(mb_hashtab, sizeof (mb_hashtab), "mb_hashtab") == -1) {
10200Sstevel@tonic-gate 		mdb_warn("failed to read symbol 'mb_hashtab'");
10210Sstevel@tonic-gate 		return (-1);
10220Sstevel@tonic-gate 	}
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	if ((mbind = find_mbind(name, mb_hashtab)) != NULL) {
10250Sstevel@tonic-gate 		if (mdb_vread(&mbind_local, sizeof (mbind_local), mbind) ==
10260Sstevel@tonic-gate 		    -1) {
10270Sstevel@tonic-gate 			mdb_warn("failed to read mbind struct at %p", mbind);
10280Sstevel@tonic-gate 			return (-1);
10290Sstevel@tonic-gate 		}
10300Sstevel@tonic-gate 
10310Sstevel@tonic-gate 		*major = (major_t)mbind_local.b_num;
10320Sstevel@tonic-gate 		return (0);
10330Sstevel@tonic-gate 	}
10340Sstevel@tonic-gate 	return (-1);
10350Sstevel@tonic-gate }
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate const char *
mdb_major_to_name(major_t major)10380Sstevel@tonic-gate mdb_major_to_name(major_t major)
10390Sstevel@tonic-gate {
10400Sstevel@tonic-gate 	static char name[MODMAXNAMELEN + 1];
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate 	uintptr_t devnamesp;
10430Sstevel@tonic-gate 	struct devnames dn;
10440Sstevel@tonic-gate 	uint_t devcnt;
10450Sstevel@tonic-gate 
10460Sstevel@tonic-gate 	if (mdb_readvar(&devcnt, "devcnt") == -1 || major >= devcnt ||
10470Sstevel@tonic-gate 	    mdb_readvar(&devnamesp, "devnamesp") == -1)
10480Sstevel@tonic-gate 		return (NULL);
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 	if (mdb_vread(&dn, sizeof (struct devnames), devnamesp +
10510Sstevel@tonic-gate 	    major * sizeof (struct devnames)) != sizeof (struct devnames))
10520Sstevel@tonic-gate 		return (NULL);
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate 	if (mdb_readstr(name, MODMAXNAMELEN + 1, (uintptr_t)dn.dn_name) == -1)
10550Sstevel@tonic-gate 		return (NULL);
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 	return ((const char *)name);
10580Sstevel@tonic-gate }
10590Sstevel@tonic-gate 
10600Sstevel@tonic-gate /*
10610Sstevel@tonic-gate  * Return the name of the driver attached to the dip in drivername.
10620Sstevel@tonic-gate  */
10630Sstevel@tonic-gate int
mdb_devinfo2driver(uintptr_t dip_addr,char * drivername,size_t namebufsize)10640Sstevel@tonic-gate mdb_devinfo2driver(uintptr_t dip_addr, char *drivername, size_t namebufsize)
10650Sstevel@tonic-gate {
10660Sstevel@tonic-gate 	struct dev_info	devinfo;
10674145Scth 	char bind_name[MAXPATHLEN + 1];
10680Sstevel@tonic-gate 	major_t	major;
10690Sstevel@tonic-gate 	const char *namestr;
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 	if (mdb_vread(&devinfo, sizeof (devinfo), dip_addr) == -1) {
10730Sstevel@tonic-gate 		mdb_warn("failed to read devinfo at %p", dip_addr);
10740Sstevel@tonic-gate 		return (-1);
10750Sstevel@tonic-gate 	}
10760Sstevel@tonic-gate 
10770Sstevel@tonic-gate 	if (mdb_readstr(bind_name, sizeof (bind_name),
10780Sstevel@tonic-gate 	    (uintptr_t)devinfo.devi_binding_name) == -1) {
10790Sstevel@tonic-gate 		mdb_warn("failed to read binding name at %p",
10800Sstevel@tonic-gate 		    devinfo.devi_binding_name);
10810Sstevel@tonic-gate 		return (-1);
10820Sstevel@tonic-gate 	}
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate 	/*
10850Sstevel@tonic-gate 	 * Many->one relation: various names to one major number
10860Sstevel@tonic-gate 	 */
10870Sstevel@tonic-gate 	if (mdb_name_to_major(bind_name, &major) == -1) {
10880Sstevel@tonic-gate 		mdb_warn("failed to translate bind name to major number\n");
10890Sstevel@tonic-gate 		return (-1);
10900Sstevel@tonic-gate 	}
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 	/*
10930Sstevel@tonic-gate 	 * One->one relation: one major number corresponds to one driver
10940Sstevel@tonic-gate 	 */
10950Sstevel@tonic-gate 	if ((namestr = mdb_major_to_name(major)) == NULL) {
10960Sstevel@tonic-gate 		(void) strncpy(drivername, "???", namebufsize);
10970Sstevel@tonic-gate 		return (-1);
10980Sstevel@tonic-gate 	}
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 	(void) strncpy(drivername, namestr, namebufsize);
11010Sstevel@tonic-gate 	return (0);
11020Sstevel@tonic-gate }
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate /*
11050Sstevel@tonic-gate  * Find the name of the driver attached to this dip (if any), given:
11060Sstevel@tonic-gate  * - the address of a dip (in core)
11070Sstevel@tonic-gate  * - the NAME of the global pointer to the driver's i_ddi_soft_state struct
11080Sstevel@tonic-gate  * - pointer to a pointer to receive the address
11090Sstevel@tonic-gate  */
11100Sstevel@tonic-gate int
mdb_devinfo2statep(uintptr_t dip_addr,char * soft_statep_name,uintptr_t * statep)11110Sstevel@tonic-gate mdb_devinfo2statep(uintptr_t dip_addr, char *soft_statep_name,
11120Sstevel@tonic-gate     uintptr_t *statep)
11130Sstevel@tonic-gate {
11140Sstevel@tonic-gate 	struct dev_info	dev_info;
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 
11170Sstevel@tonic-gate 	if (mdb_vread(&dev_info, sizeof (dev_info), dip_addr) == -1) {
11180Sstevel@tonic-gate 		mdb_warn("failed to read devinfo at %p", dip_addr);
11190Sstevel@tonic-gate 		return (-1);
11200Sstevel@tonic-gate 	}
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate 	return (mdb_get_soft_state_byname(soft_statep_name,
11230Sstevel@tonic-gate 	    dev_info.devi_instance, statep, NULL, 0));
11240Sstevel@tonic-gate }
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate /*
11270Sstevel@tonic-gate  * Returns a pointer to the top of the soft state struct for the instance
11280Sstevel@tonic-gate  * specified (in state_addr), given the address of the global soft state
11290Sstevel@tonic-gate  * pointer and size of the struct.  Also fills in the buffer pointed to by
11300Sstevel@tonic-gate  * state_buf_p (if non-NULL) with the contents of the state struct.
11310Sstevel@tonic-gate  */
11320Sstevel@tonic-gate int
mdb_get_soft_state_byaddr(uintptr_t ssaddr,uint_t instance,uintptr_t * state_addr,void * state_buf_p,size_t sizeof_state)11330Sstevel@tonic-gate mdb_get_soft_state_byaddr(uintptr_t ssaddr, uint_t instance,
11340Sstevel@tonic-gate     uintptr_t *state_addr, void *state_buf_p, size_t sizeof_state)
11350Sstevel@tonic-gate {
11360Sstevel@tonic-gate 	struct i_ddi_soft_state ss;
11370Sstevel@tonic-gate 	void *statep;
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate 	if (mdb_vread(&ss, sizeof (ss), ssaddr) == -1)
11410Sstevel@tonic-gate 		return (-1);
11420Sstevel@tonic-gate 
11430Sstevel@tonic-gate 	if (instance >= ss.n_items)
11440Sstevel@tonic-gate 		return (-1);
11450Sstevel@tonic-gate 
11460Sstevel@tonic-gate 	if (mdb_vread(&statep, sizeof (statep), (uintptr_t)ss.array +
11470Sstevel@tonic-gate 	    (sizeof (statep) * instance)) == -1)
11480Sstevel@tonic-gate 		return (-1);
11490Sstevel@tonic-gate 
11500Sstevel@tonic-gate 	if (state_addr != NULL)
11510Sstevel@tonic-gate 		*state_addr = (uintptr_t)statep;
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate 	if (statep == NULL) {
11540Sstevel@tonic-gate 		errno = ENOENT;
11550Sstevel@tonic-gate 		return (-1);
11560Sstevel@tonic-gate 	}
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate 	if (state_buf_p != NULL) {
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate 		/* Read the state struct into the buffer in local space. */
11610Sstevel@tonic-gate 		if (mdb_vread(state_buf_p, sizeof_state,
11620Sstevel@tonic-gate 		    (uintptr_t)statep) == -1)
11630Sstevel@tonic-gate 			return (-1);
11640Sstevel@tonic-gate 	}
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate 	return (0);
11670Sstevel@tonic-gate }
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate /*
11710Sstevel@tonic-gate  * Returns a pointer to the top of the soft state struct for the instance
11720Sstevel@tonic-gate  * specified (in state_addr), given the name of the global soft state pointer
11730Sstevel@tonic-gate  * and size of the struct.  Also fills in the buffer pointed to by
11740Sstevel@tonic-gate  * state_buf_p (if non-NULL) with the contents of the state struct.
11750Sstevel@tonic-gate  */
11760Sstevel@tonic-gate int
mdb_get_soft_state_byname(char * softstatep_name,uint_t instance,uintptr_t * state_addr,void * state_buf_p,size_t sizeof_state)11770Sstevel@tonic-gate mdb_get_soft_state_byname(char *softstatep_name, uint_t instance,
11780Sstevel@tonic-gate     uintptr_t *state_addr, void *state_buf_p, size_t sizeof_state)
11790Sstevel@tonic-gate {
11800Sstevel@tonic-gate 	uintptr_t ssaddr;
11810Sstevel@tonic-gate 
11820Sstevel@tonic-gate 	if (mdb_readvar((void *)&ssaddr, softstatep_name) == -1)
11830Sstevel@tonic-gate 		return (-1);
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate 	return (mdb_get_soft_state_byaddr(ssaddr, instance, state_addr,
11860Sstevel@tonic-gate 	    state_buf_p, sizeof_state));
11870Sstevel@tonic-gate }
11880Sstevel@tonic-gate 
11890Sstevel@tonic-gate static const mdb_dcmd_t dcmds[] = {
11900Sstevel@tonic-gate 	{ "dnlc", NULL, "print DNLC contents", dnlcdump },
11910Sstevel@tonic-gate 	{ NULL }
11920Sstevel@tonic-gate };
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds };
11950Sstevel@tonic-gate 
11960Sstevel@tonic-gate /*ARGSUSED*/
11970Sstevel@tonic-gate static void
update_vars(void * arg)11980Sstevel@tonic-gate update_vars(void *arg)
11990Sstevel@tonic-gate {
12000Sstevel@tonic-gate 	GElf_Sym sym;
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate 	if (mdb_lookup_by_name("auto_vnodeops", &sym) == 0)
12030Sstevel@tonic-gate 		autofs_vnops_ptr = (struct vnodeops *)(uintptr_t)sym.st_value;
12040Sstevel@tonic-gate 	else
12050Sstevel@tonic-gate 		autofs_vnops_ptr = NULL;
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate 	(void) mdb_readvar(&_mdb_ks_pagesize, "_pagesize");
12080Sstevel@tonic-gate 	(void) mdb_readvar(&_mdb_ks_pageshift, "_pageshift");
12090Sstevel@tonic-gate 	(void) mdb_readvar(&_mdb_ks_pageoffset, "_pageoffset");
12100Sstevel@tonic-gate 	(void) mdb_readvar(&_mdb_ks_pagemask, "_pagemask");
12110Sstevel@tonic-gate 	(void) mdb_readvar(&_mdb_ks_mmu_pagesize, "_mmu_pagesize");
12120Sstevel@tonic-gate 	(void) mdb_readvar(&_mdb_ks_mmu_pageshift, "_mmu_pageshift");
12130Sstevel@tonic-gate 	(void) mdb_readvar(&_mdb_ks_mmu_pageoffset, "_mmu_pageoffset");
12140Sstevel@tonic-gate 	(void) mdb_readvar(&_mdb_ks_mmu_pagemask, "_mmu_pagemask");
12150Sstevel@tonic-gate 	(void) mdb_readvar(&_mdb_ks_kernelbase, "_kernelbase");
12160Sstevel@tonic-gate 
12170Sstevel@tonic-gate 	(void) mdb_readvar(&_mdb_ks_userlimit, "_userlimit");
12180Sstevel@tonic-gate 	(void) mdb_readvar(&_mdb_ks_userlimit32, "_userlimit32");
12190Sstevel@tonic-gate 	(void) mdb_readvar(&_mdb_ks_argsbase, "_argsbase");
12200Sstevel@tonic-gate 	(void) mdb_readvar(&_mdb_ks_msg_bsize, "_msg_bsize");
12210Sstevel@tonic-gate 	(void) mdb_readvar(&_mdb_ks_defaultstksz, "_defaultstksz");
12220Sstevel@tonic-gate 	(void) mdb_readvar(&_mdb_ks_ncpu, "_ncpu");
1223*13076SJonathan.Adams@Sun.COM 	(void) mdb_readvar(&_mdb_ks_ncpu_log2, "_ncpu_log2");
1224*13076SJonathan.Adams@Sun.COM 	(void) mdb_readvar(&_mdb_ks_ncpu_p2, "_ncpu_p2");
1225*13076SJonathan.Adams@Sun.COM 
1226*13076SJonathan.Adams@Sun.COM 	page_hash_loaded = 0;	/* invalidate cached page_hash state */
12270Sstevel@tonic-gate }
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate const mdb_modinfo_t *
_mdb_init(void)12300Sstevel@tonic-gate _mdb_init(void)
12310Sstevel@tonic-gate {
12320Sstevel@tonic-gate 	/*
12330Sstevel@tonic-gate 	 * When used with mdb, mdb_ks is a separate dmod.  With kmdb, however,
12340Sstevel@tonic-gate 	 * mdb_ks is compiled into the debugger module.  kmdb cannot
12350Sstevel@tonic-gate 	 * automatically modunload itself when it exits.  If it restarts after
12360Sstevel@tonic-gate 	 * debugger fault, static variables may not be initialized to zero.
12370Sstevel@tonic-gate 	 * They must be manually reinitialized here.
12380Sstevel@tonic-gate 	 */
12390Sstevel@tonic-gate 	dnlc_hash = NULL;
12400Sstevel@tonic-gate 	qi_head = NULL;
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate 	mdb_callback_add(MDB_CALLBACK_STCHG, update_vars, NULL);
12430Sstevel@tonic-gate 
12440Sstevel@tonic-gate 	update_vars(NULL);
12450Sstevel@tonic-gate 
12460Sstevel@tonic-gate 	return (&modinfo);
12470Sstevel@tonic-gate }
12480Sstevel@tonic-gate 
12490Sstevel@tonic-gate void
_mdb_fini(void)12500Sstevel@tonic-gate _mdb_fini(void)
12510Sstevel@tonic-gate {
12520Sstevel@tonic-gate 	dnlc_free();
12530Sstevel@tonic-gate 	while (qi_head != NULL) {
12540Sstevel@tonic-gate 		mdb_qinfo_t *qip = qi_head;
12550Sstevel@tonic-gate 		qi_head = qip->qi_next;
12560Sstevel@tonic-gate 		mdb_free(qip, sizeof (mdb_qinfo_t));
12570Sstevel@tonic-gate 	}
12580Sstevel@tonic-gate }
12590Sstevel@tonic-gate 
12600Sstevel@tonic-gate /*
12610Sstevel@tonic-gate  * Interface between MDB kproc target and mdb_ks.  The kproc target relies
12620Sstevel@tonic-gate  * on looking up and invoking these functions in mdb_ks so that dependencies
12630Sstevel@tonic-gate  * on the current kernel implementation are isolated in mdb_ks.
12640Sstevel@tonic-gate  */
12650Sstevel@tonic-gate 
12660Sstevel@tonic-gate /*
12670Sstevel@tonic-gate  * Given the address of a proc_t, return the p.p_as pointer; return NULL
12680Sstevel@tonic-gate  * if we were unable to read a proc structure from the given address.
12690Sstevel@tonic-gate  */
12700Sstevel@tonic-gate uintptr_t
mdb_kproc_as(uintptr_t proc_addr)12710Sstevel@tonic-gate mdb_kproc_as(uintptr_t proc_addr)
12720Sstevel@tonic-gate {
12730Sstevel@tonic-gate 	proc_t p;
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate 	if (mdb_vread(&p, sizeof (p), proc_addr) == sizeof (p))
12760Sstevel@tonic-gate 		return ((uintptr_t)p.p_as);
12770Sstevel@tonic-gate 
12780Sstevel@tonic-gate 	return (NULL);
12790Sstevel@tonic-gate }
12800Sstevel@tonic-gate 
12810Sstevel@tonic-gate /*
12820Sstevel@tonic-gate  * Given the address of a proc_t, return the p.p_model value; return
12830Sstevel@tonic-gate  * PR_MODEL_UNKNOWN if we were unable to read a proc structure or if
12840Sstevel@tonic-gate  * the model value does not match one of the two known values.
12850Sstevel@tonic-gate  */
12860Sstevel@tonic-gate uint_t
mdb_kproc_model(uintptr_t proc_addr)12870Sstevel@tonic-gate mdb_kproc_model(uintptr_t proc_addr)
12880Sstevel@tonic-gate {
12890Sstevel@tonic-gate 	proc_t p;
12900Sstevel@tonic-gate 
12910Sstevel@tonic-gate 	if (mdb_vread(&p, sizeof (p), proc_addr) == sizeof (p)) {
12920Sstevel@tonic-gate 		switch (p.p_model) {
12930Sstevel@tonic-gate 		case DATAMODEL_ILP32:
12940Sstevel@tonic-gate 			return (PR_MODEL_ILP32);
12950Sstevel@tonic-gate 		case DATAMODEL_LP64:
12960Sstevel@tonic-gate 			return (PR_MODEL_LP64);
12970Sstevel@tonic-gate 		}
12980Sstevel@tonic-gate 	}
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate 	return (PR_MODEL_UNKNOWN);
13010Sstevel@tonic-gate }
13020Sstevel@tonic-gate 
13030Sstevel@tonic-gate /*
13040Sstevel@tonic-gate  * Callback function for walking process's segment list.  For each segment,
13050Sstevel@tonic-gate  * we fill in an mdb_map_t describing its properties, and then invoke
13060Sstevel@tonic-gate  * the callback function provided by the kproc target.
13070Sstevel@tonic-gate  */
13080Sstevel@tonic-gate static int
asmap_step(uintptr_t addr,const struct seg * seg,asmap_arg_t * asmp)13090Sstevel@tonic-gate asmap_step(uintptr_t addr, const struct seg *seg, asmap_arg_t *asmp)
13100Sstevel@tonic-gate {
13110Sstevel@tonic-gate 	struct segvn_data svd;
13120Sstevel@tonic-gate 	mdb_map_t map;
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate 	if (seg->s_ops == asmp->asm_segvn_ops && mdb_vread(&svd,
13150Sstevel@tonic-gate 	    sizeof (svd), (uintptr_t)seg->s_data) == sizeof (svd)) {
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate 		if (svd.vp != NULL) {
13180Sstevel@tonic-gate 			if (mdb_vnode2path((uintptr_t)svd.vp, map.map_name,
13196336Sbholler 			    MDB_TGT_MAPSZ) != 0) {
13200Sstevel@tonic-gate 				(void) mdb_snprintf(map.map_name,
13210Sstevel@tonic-gate 				    MDB_TGT_MAPSZ, "[ vnode %p ]", svd.vp);
13220Sstevel@tonic-gate 			}
13230Sstevel@tonic-gate 		} else
13240Sstevel@tonic-gate 			(void) strcpy(map.map_name, "[ anon ]");
13250Sstevel@tonic-gate 
13260Sstevel@tonic-gate 	} else {
13270Sstevel@tonic-gate 		(void) mdb_snprintf(map.map_name, MDB_TGT_MAPSZ,
13280Sstevel@tonic-gate 		    "[ seg %p ]", addr);
13290Sstevel@tonic-gate 	}
13300Sstevel@tonic-gate 
13310Sstevel@tonic-gate 	map.map_base = (uintptr_t)seg->s_base;
13320Sstevel@tonic-gate 	map.map_size = seg->s_size;
13330Sstevel@tonic-gate 	map.map_flags = 0;
13340Sstevel@tonic-gate 
13350Sstevel@tonic-gate 	asmp->asm_callback((const struct mdb_map *)&map, asmp->asm_cbdata);
13360Sstevel@tonic-gate 	return (WALK_NEXT);
13370Sstevel@tonic-gate }
13380Sstevel@tonic-gate 
13390Sstevel@tonic-gate /*
13400Sstevel@tonic-gate  * Given a process address space, walk its segment list using the seg walker,
13410Sstevel@tonic-gate  * convert the segment data to an mdb_map_t, and pass this information
13420Sstevel@tonic-gate  * back to the kproc target via the given callback function.
13430Sstevel@tonic-gate  */
13440Sstevel@tonic-gate int
mdb_kproc_asiter(uintptr_t as,void (* func)(const struct mdb_map *,void *),void * p)13450Sstevel@tonic-gate mdb_kproc_asiter(uintptr_t as,
13460Sstevel@tonic-gate     void (*func)(const struct mdb_map *, void *), void *p)
13470Sstevel@tonic-gate {
13480Sstevel@tonic-gate 	asmap_arg_t arg;
13490Sstevel@tonic-gate 	GElf_Sym sym;
13500Sstevel@tonic-gate 
13510Sstevel@tonic-gate 	arg.asm_segvn_ops = NULL;
13520Sstevel@tonic-gate 	arg.asm_callback = func;
13530Sstevel@tonic-gate 	arg.asm_cbdata = p;
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate 	if (mdb_lookup_by_name("segvn_ops", &sym) == 0)
13560Sstevel@tonic-gate 		arg.asm_segvn_ops = (struct seg_ops *)(uintptr_t)sym.st_value;
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 	return (mdb_pwalk("seg", (mdb_walk_cb_t)asmap_step, &arg, as));
13590Sstevel@tonic-gate }
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate /*
13620Sstevel@tonic-gate  * Copy the auxv array from the given process's u-area into the provided
13630Sstevel@tonic-gate  * buffer.  If the buffer is NULL, only return the size of the auxv array
13640Sstevel@tonic-gate  * so the caller knows how much space will be required.
13650Sstevel@tonic-gate  */
13660Sstevel@tonic-gate int
mdb_kproc_auxv(uintptr_t proc,auxv_t * auxv)13670Sstevel@tonic-gate mdb_kproc_auxv(uintptr_t proc, auxv_t *auxv)
13680Sstevel@tonic-gate {
13690Sstevel@tonic-gate 	if (auxv != NULL) {
13700Sstevel@tonic-gate 		proc_t p;
13710Sstevel@tonic-gate 
13720Sstevel@tonic-gate 		if (mdb_vread(&p, sizeof (p), proc) != sizeof (p))
13730Sstevel@tonic-gate 			return (-1);
13740Sstevel@tonic-gate 
13750Sstevel@tonic-gate 		bcopy(p.p_user.u_auxv, auxv,
13760Sstevel@tonic-gate 		    sizeof (auxv_t) * __KERN_NAUXV_IMPL);
13770Sstevel@tonic-gate 	}
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 	return (__KERN_NAUXV_IMPL);
13800Sstevel@tonic-gate }
13810Sstevel@tonic-gate 
13820Sstevel@tonic-gate /*
13830Sstevel@tonic-gate  * Given a process address, return the PID.
13840Sstevel@tonic-gate  */
13850Sstevel@tonic-gate pid_t
mdb_kproc_pid(uintptr_t proc_addr)13860Sstevel@tonic-gate mdb_kproc_pid(uintptr_t proc_addr)
13870Sstevel@tonic-gate {
13880Sstevel@tonic-gate 	struct pid pid;
13890Sstevel@tonic-gate 	proc_t p;
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate 	if (mdb_vread(&p, sizeof (p), proc_addr) == sizeof (p) &&
13920Sstevel@tonic-gate 	    mdb_vread(&pid, sizeof (pid), (uintptr_t)p.p_pidp) == sizeof (pid))
13930Sstevel@tonic-gate 		return (pid.pid_id);
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate 	return (-1);
13960Sstevel@tonic-gate }
13970Sstevel@tonic-gate 
13980Sstevel@tonic-gate /*
13990Sstevel@tonic-gate  * Interface between the MDB kvm target and mdb_ks.  The kvm target relies
14000Sstevel@tonic-gate  * on looking up and invoking these functions in mdb_ks so that dependencies
14010Sstevel@tonic-gate  * on the current kernel implementation are isolated in mdb_ks.
14020Sstevel@tonic-gate  */
14030Sstevel@tonic-gate 
14040Sstevel@tonic-gate /*
14050Sstevel@tonic-gate  * Determine whether or not the thread that panicked the given kernel was a
14060Sstevel@tonic-gate  * kernel thread (panic_thread->t_procp == &p0).
14070Sstevel@tonic-gate  */
14080Sstevel@tonic-gate void
mdb_dump_print_content(dumphdr_t * dh,pid_t content)14090Sstevel@tonic-gate mdb_dump_print_content(dumphdr_t *dh, pid_t content)
14100Sstevel@tonic-gate {
14110Sstevel@tonic-gate 	GElf_Sym sym;
14120Sstevel@tonic-gate 	uintptr_t pt;
14130Sstevel@tonic-gate 	uintptr_t procp;
14140Sstevel@tonic-gate 	int expcont = 0;
14150Sstevel@tonic-gate 	int actcont;
14160Sstevel@tonic-gate 
14170Sstevel@tonic-gate 	(void) mdb_readvar(&expcont, "dump_conflags");
14180Sstevel@tonic-gate 	actcont = dh->dump_flags & DF_CONTENT;
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate 	if (actcont == DF_ALL) {
14210Sstevel@tonic-gate 		mdb_printf("dump content: all kernel and user pages\n");
14220Sstevel@tonic-gate 		return;
14230Sstevel@tonic-gate 	} else if (actcont == DF_CURPROC) {
14240Sstevel@tonic-gate 		mdb_printf("dump content: kernel pages and pages from "
14250Sstevel@tonic-gate 		    "PID %d", content);
14260Sstevel@tonic-gate 		return;
14270Sstevel@tonic-gate 	}
14280Sstevel@tonic-gate 
14290Sstevel@tonic-gate 	mdb_printf("dump content: kernel pages only\n");
14300Sstevel@tonic-gate 	if (!(expcont & DF_CURPROC))
14310Sstevel@tonic-gate 		return;
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate 	if (mdb_readvar(&pt, "panic_thread") != sizeof (pt) || pt == NULL)
14340Sstevel@tonic-gate 		goto kthreadpanic_err;
14350Sstevel@tonic-gate 
14360Sstevel@tonic-gate 	if (mdb_vread(&procp, sizeof (procp), pt + OFFSETOF(kthread_t,
14370Sstevel@tonic-gate 	    t_procp)) == -1 || procp == NULL)
14380Sstevel@tonic-gate 		goto kthreadpanic_err;
14390Sstevel@tonic-gate 
14400Sstevel@tonic-gate 	if (mdb_lookup_by_name("p0", &sym) != 0)
14410Sstevel@tonic-gate 		goto kthreadpanic_err;
14420Sstevel@tonic-gate 
14430Sstevel@tonic-gate 	if (procp == (uintptr_t)sym.st_value) {
14440Sstevel@tonic-gate 		mdb_printf("  (curproc requested, but a kernel thread "
14450Sstevel@tonic-gate 		    "panicked)\n");
14460Sstevel@tonic-gate 	} else {
14470Sstevel@tonic-gate 		mdb_printf("  (curproc requested, but the process that "
14480Sstevel@tonic-gate 		    "panicked could not be dumped)\n");
14490Sstevel@tonic-gate 	}
14500Sstevel@tonic-gate 
14510Sstevel@tonic-gate 	return;
14520Sstevel@tonic-gate 
14530Sstevel@tonic-gate kthreadpanic_err:
14540Sstevel@tonic-gate 	mdb_printf("  (curproc requested, but the process that panicked could "
14550Sstevel@tonic-gate 	    "not be found)\n");
14560Sstevel@tonic-gate }
14570Sstevel@tonic-gate 
14580Sstevel@tonic-gate /*
14590Sstevel@tonic-gate  * Determine the process that was saved in a `curproc' dump.  This process will
14600Sstevel@tonic-gate  * be recorded as the first element in dump_pids[].
14610Sstevel@tonic-gate  */
14620Sstevel@tonic-gate int
mdb_dump_find_curproc(void)14630Sstevel@tonic-gate mdb_dump_find_curproc(void)
14640Sstevel@tonic-gate {
14650Sstevel@tonic-gate 	uintptr_t pidp;
14660Sstevel@tonic-gate 	pid_t pid = -1;
14670Sstevel@tonic-gate 
14680Sstevel@tonic-gate 	if (mdb_readvar(&pidp, "dump_pids") == sizeof (pidp) &&
14690Sstevel@tonic-gate 	    mdb_vread(&pid, sizeof (pid), pidp) == sizeof (pid) &&
14700Sstevel@tonic-gate 	    pid > 0)
14710Sstevel@tonic-gate 		return (pid);
14720Sstevel@tonic-gate 	else
14730Sstevel@tonic-gate 		return (-1);
14740Sstevel@tonic-gate }
14750Sstevel@tonic-gate 
14760Sstevel@tonic-gate 
14770Sstevel@tonic-gate /*
14780Sstevel@tonic-gate  * Following three funcs extracted from sunddi.c
14790Sstevel@tonic-gate  */
14800Sstevel@tonic-gate 
14810Sstevel@tonic-gate /*
14820Sstevel@tonic-gate  * Return core address of root node of devinfo tree
14830Sstevel@tonic-gate  */
14840Sstevel@tonic-gate static uintptr_t
mdb_ddi_root_node(void)14850Sstevel@tonic-gate mdb_ddi_root_node(void)
14860Sstevel@tonic-gate {
14870Sstevel@tonic-gate 	uintptr_t	top_devinfo_addr;
14880Sstevel@tonic-gate 
14890Sstevel@tonic-gate 	/* return (top_devinfo);   */
14900Sstevel@tonic-gate 	if (mdb_readvar(&top_devinfo_addr, "top_devinfo") == -1) {
14910Sstevel@tonic-gate 		mdb_warn("failed to read top_devinfo");
14920Sstevel@tonic-gate 		return (NULL);
14930Sstevel@tonic-gate 	}
14940Sstevel@tonic-gate 	return (top_devinfo_addr);
14950Sstevel@tonic-gate }
14960Sstevel@tonic-gate 
14970Sstevel@tonic-gate /*
14980Sstevel@tonic-gate  * Return the name of the devinfo node pointed at by 'dip_addr' in the buffer
14990Sstevel@tonic-gate  * pointed at by 'name.'
15000Sstevel@tonic-gate  *
15010Sstevel@tonic-gate  * - dip_addr is a pointer to a dev_info struct in core.
15020Sstevel@tonic-gate  */
15030Sstevel@tonic-gate static char *
mdb_ddi_deviname(uintptr_t dip_addr,char * name,size_t name_size)15040Sstevel@tonic-gate mdb_ddi_deviname(uintptr_t dip_addr, char *name, size_t name_size)
15050Sstevel@tonic-gate {
15060Sstevel@tonic-gate 	uintptr_t addrname;
15070Sstevel@tonic-gate 	ssize_t	length;
15080Sstevel@tonic-gate 	char *local_namep = name;
15090Sstevel@tonic-gate 	size_t local_name_size = name_size;
15100Sstevel@tonic-gate 	struct dev_info	local_dip;
15110Sstevel@tonic-gate 
15120Sstevel@tonic-gate 
15130Sstevel@tonic-gate 	if (dip_addr == mdb_ddi_root_node()) {
15140Sstevel@tonic-gate 		if (name_size < 1) {
15150Sstevel@tonic-gate 			mdb_warn("failed to get node name: buf too small\n");
15160Sstevel@tonic-gate 			return (NULL);
15170Sstevel@tonic-gate 		}
15180Sstevel@tonic-gate 
15190Sstevel@tonic-gate 		*name = '\0';
15200Sstevel@tonic-gate 		return (name);
15210Sstevel@tonic-gate 	}
15220Sstevel@tonic-gate 
15230Sstevel@tonic-gate 	if (name_size < 2) {
15240Sstevel@tonic-gate 		mdb_warn("failed to get node name: buf too small\n");
15250Sstevel@tonic-gate 		return (NULL);
15260Sstevel@tonic-gate 	}
15270Sstevel@tonic-gate 
15280Sstevel@tonic-gate 	local_namep = name;
15290Sstevel@tonic-gate 	*local_namep++ = '/';
15300Sstevel@tonic-gate 	*local_namep = '\0';
15310Sstevel@tonic-gate 	local_name_size--;
15320Sstevel@tonic-gate 
15330Sstevel@tonic-gate 	if (mdb_vread(&local_dip, sizeof (struct dev_info), dip_addr) == -1) {
15340Sstevel@tonic-gate 		mdb_warn("failed to read devinfo struct");
15350Sstevel@tonic-gate 	}
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate 	length = mdb_readstr(local_namep, local_name_size,
15380Sstevel@tonic-gate 	    (uintptr_t)local_dip.devi_node_name);
15390Sstevel@tonic-gate 	if (length == -1) {
15400Sstevel@tonic-gate 		mdb_warn("failed to read node name");
15410Sstevel@tonic-gate 		return (NULL);
15420Sstevel@tonic-gate 	}
15430Sstevel@tonic-gate 	local_namep += length;
15440Sstevel@tonic-gate 	local_name_size -= length;
15450Sstevel@tonic-gate 	addrname = (uintptr_t)local_dip.devi_addr;
15460Sstevel@tonic-gate 
15470Sstevel@tonic-gate 	if (addrname != NULL) {
15480Sstevel@tonic-gate 
15490Sstevel@tonic-gate 		if (local_name_size < 2) {
15500Sstevel@tonic-gate 			mdb_warn("not enough room for node address string");
15510Sstevel@tonic-gate 			return (name);
15520Sstevel@tonic-gate 		}
15530Sstevel@tonic-gate 		*local_namep++ = '@';
15540Sstevel@tonic-gate 		*local_namep = '\0';
15550Sstevel@tonic-gate 		local_name_size--;
15560Sstevel@tonic-gate 
15570Sstevel@tonic-gate 		length = mdb_readstr(local_namep, local_name_size, addrname);
15580Sstevel@tonic-gate 		if (length == -1) {
15590Sstevel@tonic-gate 			mdb_warn("failed to read name");
15600Sstevel@tonic-gate 			return (NULL);
15610Sstevel@tonic-gate 		}
15620Sstevel@tonic-gate 	}
15630Sstevel@tonic-gate 
15640Sstevel@tonic-gate 	return (name);
15650Sstevel@tonic-gate }
15660Sstevel@tonic-gate 
15670Sstevel@tonic-gate /*
15680Sstevel@tonic-gate  * Generate the full path under the /devices dir to the device entry.
15690Sstevel@tonic-gate  *
15700Sstevel@tonic-gate  * dip is a pointer to a devinfo struct in core (not in local memory).
15710Sstevel@tonic-gate  */
15720Sstevel@tonic-gate char *
mdb_ddi_pathname(uintptr_t dip_addr,char * path,size_t pathlen)15730Sstevel@tonic-gate mdb_ddi_pathname(uintptr_t dip_addr, char *path, size_t pathlen)
15740Sstevel@tonic-gate {
15750Sstevel@tonic-gate 	struct dev_info local_dip;
15760Sstevel@tonic-gate 	uintptr_t	parent_dip;
15770Sstevel@tonic-gate 	char		*bp;
15780Sstevel@tonic-gate 	size_t		buf_left;
15790Sstevel@tonic-gate 
15800Sstevel@tonic-gate 
15810Sstevel@tonic-gate 	if (dip_addr == mdb_ddi_root_node()) {
15820Sstevel@tonic-gate 		*path = '\0';
15830Sstevel@tonic-gate 		return (path);
15840Sstevel@tonic-gate 	}
15850Sstevel@tonic-gate 
15860Sstevel@tonic-gate 
15870Sstevel@tonic-gate 	if (mdb_vread(&local_dip, sizeof (struct dev_info), dip_addr) == -1) {
15880Sstevel@tonic-gate 		mdb_warn("failed to read devinfo struct");
15890Sstevel@tonic-gate 	}
15900Sstevel@tonic-gate 
15910Sstevel@tonic-gate 	parent_dip = (uintptr_t)local_dip.devi_parent;
15920Sstevel@tonic-gate 	(void) mdb_ddi_pathname(parent_dip, path, pathlen);
15930Sstevel@tonic-gate 
15940Sstevel@tonic-gate 	bp = path + strlen(path);
15950Sstevel@tonic-gate 	buf_left = pathlen - strlen(path);
15960Sstevel@tonic-gate 	(void) mdb_ddi_deviname(dip_addr, bp, buf_left);
15970Sstevel@tonic-gate 	return (path);
15980Sstevel@tonic-gate }
15990Sstevel@tonic-gate 
16000Sstevel@tonic-gate 
16010Sstevel@tonic-gate /*
16020Sstevel@tonic-gate  * Read in the string value of a refstr, which is appended to the end of
16030Sstevel@tonic-gate  * the structure.
16040Sstevel@tonic-gate  */
16050Sstevel@tonic-gate ssize_t
mdb_read_refstr(uintptr_t refstr_addr,char * str,size_t nbytes)16060Sstevel@tonic-gate mdb_read_refstr(uintptr_t refstr_addr, char *str, size_t nbytes)
16070Sstevel@tonic-gate {
16080Sstevel@tonic-gate 	struct refstr *r = (struct refstr *)refstr_addr;
16090Sstevel@tonic-gate 
16100Sstevel@tonic-gate 	return (mdb_readstr(str, nbytes, (uintptr_t)r->rs_string));
16110Sstevel@tonic-gate }
16122546Scarlsonj 
16132546Scarlsonj /*
16142546Scarlsonj  * Chase an mblk list by b_next and return the length.
16152546Scarlsonj  */
16162546Scarlsonj int
mdb_mblk_count(const mblk_t * mb)16172546Scarlsonj mdb_mblk_count(const mblk_t *mb)
16182546Scarlsonj {
16192546Scarlsonj 	int count;
16202546Scarlsonj 	mblk_t mblk;
16212546Scarlsonj 
16222546Scarlsonj 	if (mb == NULL)
16232546Scarlsonj 		return (0);
16242546Scarlsonj 
16252546Scarlsonj 	count = 1;
16262546Scarlsonj 	while (mb->b_next != NULL) {
16272546Scarlsonj 		count++;
16282546Scarlsonj 		if (mdb_vread(&mblk, sizeof (mblk), (uintptr_t)mb->b_next) ==
16292546Scarlsonj 		    -1)
16302546Scarlsonj 			break;
16312546Scarlsonj 		mb = &mblk;
16322546Scarlsonj 	}
16332546Scarlsonj 	return (count);
16342546Scarlsonj }
16352546Scarlsonj 
16362546Scarlsonj /*
16372546Scarlsonj  * Write the given MAC address as a printable string in the usual colon-
16382546Scarlsonj  * separated format.  Assumes that buflen is at least 2.
16392546Scarlsonj  */
16402546Scarlsonj void
mdb_mac_addr(const uint8_t * addr,size_t alen,char * buf,size_t buflen)16412546Scarlsonj mdb_mac_addr(const uint8_t *addr, size_t alen, char *buf, size_t buflen)
16422546Scarlsonj {
16432546Scarlsonj 	int slen;
16442546Scarlsonj 
16452546Scarlsonj 	if (alen == 0 || buflen < 4) {
16462546Scarlsonj 		(void) strcpy(buf, "?");
16472546Scarlsonj 		return;
16482546Scarlsonj 	}
16492546Scarlsonj 	for (;;) {
16502546Scarlsonj 		/*
16512546Scarlsonj 		 * If there are more MAC address bytes available, but we won't
16522546Scarlsonj 		 * have any room to print them, then add "..." to the string
16532546Scarlsonj 		 * instead.  See below for the 'magic number' explanation.
16542546Scarlsonj 		 */
16552546Scarlsonj 		if ((alen == 2 && buflen < 6) || (alen > 2 && buflen < 7)) {
16562546Scarlsonj 			(void) strcpy(buf, "...");
16572546Scarlsonj 			break;
16582546Scarlsonj 		}
16592546Scarlsonj 		slen = mdb_snprintf(buf, buflen, "%02x", *addr++);
16602546Scarlsonj 		buf += slen;
16612546Scarlsonj 		if (--alen == 0)
16622546Scarlsonj 			break;
16632546Scarlsonj 		*buf++ = ':';
16642546Scarlsonj 		buflen -= slen + 1;
16652546Scarlsonj 		/*
16662546Scarlsonj 		 * At this point, based on the first 'if' statement above,
16672546Scarlsonj 		 * either alen == 1 and buflen >= 3, or alen > 1 and
16682546Scarlsonj 		 * buflen >= 4.  The first case leaves room for the final "xx"
16692546Scarlsonj 		 * number and trailing NUL byte.  The second leaves room for at
16702546Scarlsonj 		 * least "...".  Thus the apparently 'magic' numbers chosen for
16712546Scarlsonj 		 * that statement.
16722546Scarlsonj 		 */
16732546Scarlsonj 	}
16742546Scarlsonj }
16752546Scarlsonj 
16762546Scarlsonj /*
16772546Scarlsonj  * Produce a string that represents a DLPI primitive, or NULL if no such string
16782546Scarlsonj  * is possible.
16792546Scarlsonj  */
16802546Scarlsonj const char *
mdb_dlpi_prim(int prim)16812546Scarlsonj mdb_dlpi_prim(int prim)
16822546Scarlsonj {
16832546Scarlsonj 	switch (prim) {
16842546Scarlsonj 	case DL_INFO_REQ:	return ("DL_INFO_REQ");
16852546Scarlsonj 	case DL_INFO_ACK:	return ("DL_INFO_ACK");
16862546Scarlsonj 	case DL_ATTACH_REQ:	return ("DL_ATTACH_REQ");
16872546Scarlsonj 	case DL_DETACH_REQ:	return ("DL_DETACH_REQ");
16882546Scarlsonj 	case DL_BIND_REQ:	return ("DL_BIND_REQ");
16892546Scarlsonj 	case DL_BIND_ACK:	return ("DL_BIND_ACK");
16902546Scarlsonj 	case DL_UNBIND_REQ:	return ("DL_UNBIND_REQ");
16912546Scarlsonj 	case DL_OK_ACK:		return ("DL_OK_ACK");
16922546Scarlsonj 	case DL_ERROR_ACK:	return ("DL_ERROR_ACK");
16932546Scarlsonj 	case DL_ENABMULTI_REQ:	return ("DL_ENABMULTI_REQ");
16942546Scarlsonj 	case DL_DISABMULTI_REQ:	return ("DL_DISABMULTI_REQ");
16952546Scarlsonj 	case DL_PROMISCON_REQ:	return ("DL_PROMISCON_REQ");
16962546Scarlsonj 	case DL_PROMISCOFF_REQ:	return ("DL_PROMISCOFF_REQ");
16972546Scarlsonj 	case DL_UNITDATA_REQ:	return ("DL_UNITDATA_REQ");
16982546Scarlsonj 	case DL_UNITDATA_IND:	return ("DL_UNITDATA_IND");
16992546Scarlsonj 	case DL_UDERROR_IND:	return ("DL_UDERROR_IND");
17002546Scarlsonj 	case DL_PHYS_ADDR_REQ:	return ("DL_PHYS_ADDR_REQ");
17012546Scarlsonj 	case DL_PHYS_ADDR_ACK:	return ("DL_PHYS_ADDR_ACK");
17022546Scarlsonj 	case DL_SET_PHYS_ADDR_REQ:	return ("DL_SET_PHYS_ADDR_REQ");
17032546Scarlsonj 	case DL_NOTIFY_REQ:	return ("DL_NOTIFY_REQ");
17042546Scarlsonj 	case DL_NOTIFY_ACK:	return ("DL_NOTIFY_ACK");
17052546Scarlsonj 	case DL_NOTIFY_IND:	return ("DL_NOTIFY_IND");
17069073SCathy.Zhou@Sun.COM 	case DL_NOTIFY_CONF:	return ("DL_NOTIFY_CONF");
17072546Scarlsonj 	case DL_CAPABILITY_REQ:	return ("DL_CAPABILITY_REQ");
17082546Scarlsonj 	case DL_CAPABILITY_ACK:	return ("DL_CAPABILITY_ACK");
17092546Scarlsonj 	case DL_CONTROL_REQ:	return ("DL_CONTROL_REQ");
17102546Scarlsonj 	case DL_CONTROL_ACK:	return ("DL_CONTROL_ACK");
17112546Scarlsonj 	case DL_PASSIVE_REQ:	return ("DL_PASSIVE_REQ");
17122546Scarlsonj 	default:		return (NULL);
17132546Scarlsonj 	}
17142546Scarlsonj }
171511066Srafael.vanoni@sun.com 
171611066Srafael.vanoni@sun.com /*
171711066Srafael.vanoni@sun.com  * mdb_gethrtime() returns the hires system time. This will be the timestamp at
171811066Srafael.vanoni@sun.com  * which we dropped into, if called from, kmdb(1); the core dump's hires time
171911066Srafael.vanoni@sun.com  * if inspecting one; or the running system's hires time if we're inspecting
172011066Srafael.vanoni@sun.com  * a live kernel.
172111066Srafael.vanoni@sun.com  */
172211066Srafael.vanoni@sun.com hrtime_t
mdb_gethrtime(void)172311066Srafael.vanoni@sun.com mdb_gethrtime(void)
172411066Srafael.vanoni@sun.com {
172511066Srafael.vanoni@sun.com 	uintptr_t ptr;
172611226Srafael.vanoni@sun.com 	GElf_Sym sym;
172711066Srafael.vanoni@sun.com 	lbolt_info_t lbi;
172811066Srafael.vanoni@sun.com 	hrtime_t ts;
172911066Srafael.vanoni@sun.com 
173011226Srafael.vanoni@sun.com 	/*
173111226Srafael.vanoni@sun.com 	 * We first check whether the lbolt info structure has been allocated
173211226Srafael.vanoni@sun.com 	 * and initialized. If not, lbolt_hybrid will be pointing at
173311226Srafael.vanoni@sun.com 	 * lbolt_bootstrap.
173411226Srafael.vanoni@sun.com 	 */
173511226Srafael.vanoni@sun.com 	if (mdb_lookup_by_name("lbolt_bootstrap", &sym) == -1)
173611226Srafael.vanoni@sun.com 		return (0);
173711226Srafael.vanoni@sun.com 
173811226Srafael.vanoni@sun.com 	if (mdb_readvar(&ptr, "lbolt_hybrid") == -1)
173911226Srafael.vanoni@sun.com 		return (0);
174011226Srafael.vanoni@sun.com 
174111226Srafael.vanoni@sun.com 	if (ptr == (uintptr_t)sym.st_value)
174211226Srafael.vanoni@sun.com 		return (0);
174311226Srafael.vanoni@sun.com 
174411066Srafael.vanoni@sun.com #ifdef _KMDB
174511066Srafael.vanoni@sun.com 	if (mdb_readvar(&ptr, "lb_info") == -1)
174611066Srafael.vanoni@sun.com 		return (0);
174711066Srafael.vanoni@sun.com 
174811066Srafael.vanoni@sun.com 	if (mdb_vread(&lbi, sizeof (lbolt_info_t), ptr) !=
174911066Srafael.vanoni@sun.com 	    sizeof (lbolt_info_t))
175011066Srafael.vanoni@sun.com 		return (0);
175111066Srafael.vanoni@sun.com 
175211066Srafael.vanoni@sun.com 	ts = lbi.lbi_debug_ts;
175311066Srafael.vanoni@sun.com #else
175411066Srafael.vanoni@sun.com 	if (mdb_prop_postmortem) {
175511066Srafael.vanoni@sun.com 		if (mdb_readvar(&ptr, "lb_info") == -1)
175611066Srafael.vanoni@sun.com 			return (0);
175711066Srafael.vanoni@sun.com 
175811066Srafael.vanoni@sun.com 		if (mdb_vread(&lbi, sizeof (lbolt_info_t), ptr) !=
175911066Srafael.vanoni@sun.com 		    sizeof (lbolt_info_t))
176011066Srafael.vanoni@sun.com 			return (0);
176111066Srafael.vanoni@sun.com 
176211066Srafael.vanoni@sun.com 		ts = lbi.lbi_debug_ts;
176311066Srafael.vanoni@sun.com 	} else {
176411066Srafael.vanoni@sun.com 		ts = gethrtime();
176511066Srafael.vanoni@sun.com 	}
176611066Srafael.vanoni@sun.com #endif
176711066Srafael.vanoni@sun.com 	return (ts);
176811066Srafael.vanoni@sun.com }
176911066Srafael.vanoni@sun.com 
177011066Srafael.vanoni@sun.com /*
177111066Srafael.vanoni@sun.com  * mdb_get_lbolt() returns the number of clock ticks since system boot.
177211066Srafael.vanoni@sun.com  * Depending on the context in which it's called, the value will be derived
177311066Srafael.vanoni@sun.com  * from different sources per mdb_gethrtime(). If inspecting a panicked
177411066Srafael.vanoni@sun.com  * system, the routine returns the 'panic_lbolt64' variable from the core file.
177511066Srafael.vanoni@sun.com  */
177611066Srafael.vanoni@sun.com int64_t
mdb_get_lbolt(void)177711066Srafael.vanoni@sun.com mdb_get_lbolt(void)
177811066Srafael.vanoni@sun.com {
177911066Srafael.vanoni@sun.com 	lbolt_info_t lbi;
178011066Srafael.vanoni@sun.com 	uintptr_t ptr;
178111066Srafael.vanoni@sun.com 	int64_t pl;
178211066Srafael.vanoni@sun.com 	hrtime_t ts;
178311066Srafael.vanoni@sun.com 	int nsec;
178411066Srafael.vanoni@sun.com 
178511066Srafael.vanoni@sun.com 	if (mdb_readvar(&pl, "panic_lbolt64") != -1 && pl > 0)
178611066Srafael.vanoni@sun.com 		return (pl);
178711066Srafael.vanoni@sun.com 
178811066Srafael.vanoni@sun.com 	/*
178911226Srafael.vanoni@sun.com 	 * mdb_gethrtime() will return zero if the lbolt info structure hasn't
179011226Srafael.vanoni@sun.com 	 * been allocated and initialized yet, or if it fails to read it.
179111226Srafael.vanoni@sun.com 	 */
179211226Srafael.vanoni@sun.com 	if ((ts = mdb_gethrtime()) <= 0)
179311226Srafael.vanoni@sun.com 		return (0);
179411226Srafael.vanoni@sun.com 
179511226Srafael.vanoni@sun.com 	/*
179611066Srafael.vanoni@sun.com 	 * Load the time spent in kmdb, if any.
179711066Srafael.vanoni@sun.com 	 */
179811066Srafael.vanoni@sun.com 	if (mdb_readvar(&ptr, "lb_info") == -1)
179911066Srafael.vanoni@sun.com 		return (0);
180011066Srafael.vanoni@sun.com 
180111066Srafael.vanoni@sun.com 	if (mdb_vread(&lbi, sizeof (lbolt_info_t), ptr) !=
180211066Srafael.vanoni@sun.com 	    sizeof (lbolt_info_t))
180311066Srafael.vanoni@sun.com 		return (0);
180411066Srafael.vanoni@sun.com 
180511066Srafael.vanoni@sun.com 	if (mdb_readvar(&nsec, "nsec_per_tick") == -1 || nsec == 0) {
180611066Srafael.vanoni@sun.com 		mdb_warn("failed to read 'nsec_per_tick'");
180711066Srafael.vanoni@sun.com 		return (-1);
180811066Srafael.vanoni@sun.com 	}
180911066Srafael.vanoni@sun.com 
181011066Srafael.vanoni@sun.com 	return ((ts/nsec) - lbi.lbi_debug_time);
181111066Srafael.vanoni@sun.com }
1812