Home | History | Annotate | Download | only in mdb_ks
      1      0    stevel /*
      2      0    stevel  * CDDL HEADER START
      3      0    stevel  *
      4      0    stevel  * The contents of this file are subject to the terms of the
      5   2116     anish  * Common Development and Distribution License (the "License").
      6   2116     anish  * You may not use this file except in compliance with the License.
      7      0    stevel  *
      8      0    stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9      0    stevel  * or http://www.opensolaris.org/os/licensing.
     10      0    stevel  * See the License for the specific language governing permissions
     11      0    stevel  * and limitations under the License.
     12      0    stevel  *
     13      0    stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14      0    stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15      0    stevel  * If applicable, add the following below this CDDL HEADER, with the
     16      0    stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17      0    stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18      0    stevel  *
     19      0    stevel  * CDDL HEADER END
     20      0    stevel  */
     21      0    stevel /*
     22   9073     Cathy  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23      0    stevel  * Use is subject to license terms.
     24      0    stevel  */
     25      0    stevel 
     26      0    stevel /*
     27      0    stevel  * Mdb kernel support module.  This module is loaded automatically when the
     28      0    stevel  * kvm target is initialized.  Any global functions declared here are exported
     29      0    stevel  * for the resolution of symbols in subsequently loaded modules.
     30      0    stevel  *
     31      0    stevel  * WARNING: Do not assume that static variables in mdb_ks will be initialized
     32      0    stevel  * to zero.
     33      0    stevel  */
     34      0    stevel 
     35      0    stevel 
     36      0    stevel #include <mdb/mdb_target.h>
     37      0    stevel #include <mdb/mdb_param.h>
     38      0    stevel #include <mdb/mdb_modapi.h>
     39      0    stevel #include <mdb/mdb_ks.h>
     40      0    stevel 
     41      0    stevel #include <sys/types.h>
     42      0    stevel #include <sys/procfs.h>
     43      0    stevel #include <sys/proc.h>
     44      0    stevel #include <sys/dnlc.h>
     45      0    stevel #include <sys/autoconf.h>
     46      0    stevel #include <sys/machelf.h>
     47      0    stevel #include <sys/modctl.h>
     48      0    stevel #include <sys/hwconf.h>
     49      0    stevel #include <sys/kobj.h>
     50      0    stevel #include <sys/fs/autofs.h>
     51      0    stevel #include <sys/ddi_impldefs.h>
     52      0    stevel #include <sys/refstr_impl.h>
     53   1234   johnlev #include <sys/cpuvar.h>
     54   2546  carlsonj #include <sys/dlpi.h>
     55  11066    rafael #include <sys/clock_impl.h>
     56      0    stevel #include <errno.h>
     57      0    stevel 
     58      0    stevel #include <vm/seg_vn.h>
     59      0    stevel #include <vm/page.h>
     60      0    stevel 
     61      0    stevel #define	MDB_PATH_NELEM	256			/* Maximum path components */
     62      0    stevel 
     63      0    stevel typedef struct mdb_path {
     64      0    stevel 	size_t mdp_nelem;			/* Number of components */
     65      0    stevel 	uint_t mdp_complete;			/* Path completely resolved? */
     66      0    stevel 	uintptr_t mdp_vnode[MDB_PATH_NELEM];	/* Array of vnode_t addresses */
     67      0    stevel 	char *mdp_name[MDB_PATH_NELEM];		/* Array of name components */
     68      0    stevel } mdb_path_t;
     69      0    stevel 
     70      0    stevel static int mdb_autonode2path(uintptr_t, mdb_path_t *);
     71      0    stevel static int mdb_sprintpath(char *, size_t, mdb_path_t *);
     72      0    stevel 
     73      0    stevel /*
     74      0    stevel  * Kernel parameters from <sys/param.h> which we keep in-core:
     75      0    stevel  */
     76      0    stevel unsigned long _mdb_ks_pagesize;
     77      0    stevel unsigned int _mdb_ks_pageshift;
     78      0    stevel unsigned long _mdb_ks_pageoffset;
     79      0    stevel unsigned long long _mdb_ks_pagemask;
     80      0    stevel unsigned long _mdb_ks_mmu_pagesize;
     81      0    stevel unsigned int _mdb_ks_mmu_pageshift;
     82      0    stevel unsigned long _mdb_ks_mmu_pageoffset;
     83      0    stevel unsigned long _mdb_ks_mmu_pagemask;
     84      0    stevel uintptr_t _mdb_ks_kernelbase;
     85      0    stevel uintptr_t _mdb_ks_userlimit;
     86      0    stevel uintptr_t _mdb_ks_userlimit32;
     87      0    stevel uintptr_t _mdb_ks_argsbase;
     88      0    stevel unsigned long _mdb_ks_msg_bsize;
     89      0    stevel unsigned long _mdb_ks_defaultstksz;
     90      0    stevel int _mdb_ks_ncpu;
     91      0    stevel 
     92      0    stevel /*
     93      0    stevel  * In-core copy of DNLC information:
     94      0    stevel  */
     95      0    stevel #define	MDB_DNLC_HSIZE	1024
     96      0    stevel #define	MDB_DNLC_HASH(vp)	(((uintptr_t)(vp) >> 3) & (MDB_DNLC_HSIZE - 1))
     97      0    stevel #define	MDB_DNLC_NCACHE_SZ(ncp) (sizeof (ncache_t) + (ncp)->namlen)
     98      0    stevel #define	MDB_DNLC_MAX_RETRY 4
     99      0    stevel 
    100      0    stevel 
    101      0    stevel static ncache_t **dnlc_hash;	/* mdbs hash array of dnlc entries */
    102      0    stevel 
    103      0    stevel /*
    104      0    stevel  * This will be the location of the vnodeops pointer for "autofs_vnodeops"
    105      0    stevel  * The pointer still needs to be read with mdb_vread() to get the location
    106      0    stevel  * of the vnodeops structure for autofs.
    107      0    stevel  */
    108      0    stevel static struct vnodeops *autofs_vnops_ptr;
    109      0    stevel 
    110      0    stevel /*
    111      0    stevel  * STREAMS queue registrations:
    112      0    stevel  */
    113      0    stevel typedef struct mdb_qinfo {
    114      0    stevel 	const mdb_qops_t *qi_ops;	/* Address of ops vector */
    115      0    stevel 	uintptr_t qi_addr;		/* Address of qinit structure (key) */
    116      0    stevel 	struct mdb_qinfo *qi_next;	/* Next qinfo in list */
    117      0    stevel } mdb_qinfo_t;
    118      0    stevel 
    119      0    stevel static mdb_qinfo_t *qi_head;		/* Head of qinfo chain */
    120      0    stevel 
    121      0    stevel /*
    122      0    stevel  * Device naming callback structure:
    123      0    stevel  */
    124      0    stevel typedef struct nm_query {
    125      0    stevel 	const char *nm_name;		/* Device driver name [in/out] */
    126      0    stevel 	major_t nm_major;		/* Device major number [in/out] */
    127      0    stevel 	ushort_t nm_found;		/* Did we find a match? [out] */
    128      0    stevel } nm_query_t;
    129      0    stevel 
    130      0    stevel /*
    131      0    stevel  * Address-to-modctl callback structure:
    132      0    stevel  */
    133      0    stevel typedef struct a2m_query {
    134      0    stevel 	uintptr_t a2m_addr;		/* Virtual address [in] */
    135      0    stevel 	uintptr_t a2m_where;		/* Modctl address [out] */
    136      0    stevel } a2m_query_t;
    137      0    stevel 
    138      0    stevel /*
    139      0    stevel  * Segment-to-mdb_map callback structure:
    140      0    stevel  */
    141      0    stevel typedef struct {
    142      0    stevel 	struct seg_ops *asm_segvn_ops;	/* Address of segvn ops [in] */
    143      0    stevel 	void (*asm_callback)(const struct mdb_map *, void *); /* Callb [in] */
    144      0    stevel 	void *asm_cbdata;		/* Callback data [in] */
    145      0    stevel } asmap_arg_t;
    146      0    stevel 
    147      0    stevel static void
    148      0    stevel dnlc_free(void)
    149      0    stevel {
    150      0    stevel 	ncache_t *ncp, *next;
    151      0    stevel 	int i;
    152      0    stevel 
    153      0    stevel 	if (dnlc_hash == NULL) {
    154      0    stevel 		return;
    155      0    stevel 	}
    156      0    stevel 
    157      0    stevel 	/*
    158      0    stevel 	 * Free up current dnlc entries
    159      0    stevel 	 */
    160      0    stevel 	for (i = 0; i < MDB_DNLC_HSIZE; i++) {
    161      0    stevel 		for (ncp = dnlc_hash[i]; ncp; ncp = next) {
    162      0    stevel 			next = ncp->hash_next;
    163      0    stevel 			mdb_free(ncp, MDB_DNLC_NCACHE_SZ(ncp));
    164      0    stevel 		}
    165      0    stevel 	}
    166      0    stevel 	mdb_free(dnlc_hash, MDB_DNLC_HSIZE * sizeof (ncache_t *));
    167      0    stevel 	dnlc_hash = NULL;
    168      0    stevel }
    169      0    stevel 
    170      0    stevel char bad_dnlc[] = "inconsistent dnlc chain: %d, ncache va: %p"
    171      0    stevel 	" - continuing with the rest\n";
    172      0    stevel 
    173      0    stevel static int
    174      0    stevel dnlc_load(void)
    175      0    stevel {
    176      0    stevel 	int i; /* hash index */
    177      0    stevel 	int retry_cnt = 0;
    178      0    stevel 	int skip_bad_chains = 0;
    179      0    stevel 	int nc_hashsz; /* kernel hash array size */
    180      0    stevel 	uintptr_t nc_hash_addr; /* kernel va of ncache hash array */
    181      0    stevel 	uintptr_t head; /* kernel va of head of hash chain */
    182      0    stevel 
    183      0    stevel 	/*
    184      0    stevel 	 * If we've already cached the DNLC and we're looking at a dump,
    185      0    stevel 	 * our cache is good forever, so don't bother re-loading.
    186      0    stevel 	 */
    187      0    stevel 	if (dnlc_hash && mdb_prop_postmortem) {
    188      0    stevel 		return (0);
    189      0    stevel 	}
    190      0    stevel 
    191      0    stevel 	/*
    192      0    stevel 	 * For a core dump, retries wont help.
    193      0    stevel 	 * Just print and skip any bad chains.
    194      0    stevel 	 */
    195      0    stevel 	if (mdb_prop_postmortem) {
    196      0    stevel 		skip_bad_chains = 1;
    197      0    stevel 	}
    198      0    stevel retry:
    199      0    stevel 	if (retry_cnt++ >= MDB_DNLC_MAX_RETRY) {
    200      0    stevel 		/*
    201      0    stevel 		 * Give up retrying the rapidly changing dnlc.
    202      0    stevel 		 * Just print and skip any bad chains
    203      0    stevel 		 */
    204      0    stevel 		skip_bad_chains = 1;
    205      0    stevel 	}
    206      0    stevel 
    207      0    stevel 	dnlc_free(); /* Free up the mdb hashed dnlc - if any */
    208      0    stevel 
    209      0    stevel 	/*
    210      0    stevel 	 * Although nc_hashsz and the location of nc_hash doesn't currently
    211      0    stevel 	 * change, it may do in the future with a more dynamic dnlc.
    212      0    stevel 	 * So always read these values afresh.
    213      0    stevel 	 */
    214      0    stevel 	if (mdb_readvar(&nc_hashsz, "nc_hashsz") == -1) {
    215      0    stevel 		mdb_warn("failed to read nc_hashsz");
    216      0    stevel 		return (-1);
    217      0    stevel 	}
    218      0    stevel 	if (mdb_readvar(&nc_hash_addr, "nc_hash") == -1) {
    219      0    stevel 		mdb_warn("failed to read nc_hash");
    220      0    stevel 		return (-1);
    221      0    stevel 	}
    222      0    stevel 
    223      0    stevel 	/*
    224      0    stevel 	 * Allocate the mdb dnlc hash array
    225      0    stevel 	 */
    226      0    stevel 	dnlc_hash = mdb_zalloc(MDB_DNLC_HSIZE * sizeof (ncache_t *), UM_SLEEP);
    227      0    stevel 
    228      0    stevel 	/* for each kernel hash chain */
    229      0    stevel 	for (i = 0, head = nc_hash_addr; i < nc_hashsz;
    230      0    stevel 	    i++, head += sizeof (nc_hash_t)) {
    231      0    stevel 		nc_hash_t nch; /* kernel hash chain header */
    232      0    stevel 		ncache_t *ncp; /* name cache pointer */
    233      0    stevel 		int hash; /* mdb hash value */
    234      0    stevel 		uintptr_t nc_va; /* kernel va of next ncache */
    235      0    stevel 		uintptr_t ncprev_va; /* kernel va of previous ncache */
    236      0    stevel 		int khash; /* kernel dnlc hash value */
    237      0    stevel 		uchar_t namelen; /* name length */
    238      0    stevel 		ncache_t nc; /* name cache entry */
    239      0    stevel 		int nc_size; /* size of a name cache entry */
    240      0    stevel 
    241      0    stevel 		/*
    242      0    stevel 		 * We read each element of the nc_hash array individually
    243      0    stevel 		 * just before we process the entries in its chain. This is
    244      0    stevel 		 * because the chain can change so rapidly on a running system.
    245      0    stevel 		 */
    246      0    stevel 		if (mdb_vread(&nch, sizeof (nc_hash_t), head) == -1) {
    247      0    stevel 			mdb_warn("failed to read nc_hash chain header %d", i);
    248      0    stevel 			dnlc_free();
    249      0    stevel 			return (-1);
    250      0    stevel 		}
    251      0    stevel 
    252      0    stevel 		ncprev_va = head;
    253      0    stevel 		nc_va = (uintptr_t)(nch.hash_next);
    254      0    stevel 		/* for each entry in the chain */
    255      0    stevel 		while (nc_va != head) {
    256      0    stevel 			/*
    257      0    stevel 			 * The size of the ncache entries varies
    258      0    stevel 			 * because the name is appended to the structure.
    259      0    stevel 			 * So we read in the structure then re-read
    260      0    stevel 			 * for the structure plus name.
    261      0    stevel 			 */
    262      0    stevel 			if (mdb_vread(&nc, sizeof (ncache_t), nc_va) == -1) {
    263      0    stevel 				if (skip_bad_chains) {
    264      0    stevel 					mdb_warn(bad_dnlc, i, nc_va);
    265      0    stevel 					break;
    266      0    stevel 				}
    267      0    stevel 				goto retry;
    268      0    stevel 			}
    269      0    stevel 			nc_size = MDB_DNLC_NCACHE_SZ(&nc);
    270      0    stevel 			ncp = mdb_alloc(nc_size, UM_SLEEP);
    271      0    stevel 			if (mdb_vread(ncp, nc_size - 1, nc_va) == -1) {
    272      0    stevel 				mdb_free(ncp, nc_size);
    273      0    stevel 				if (skip_bad_chains) {
    274      0    stevel 					mdb_warn(bad_dnlc, i, nc_va);
    275      0    stevel 					break;
    276      0    stevel 				}
    277      0    stevel 				goto retry;
    278      0    stevel 			}
    279      0    stevel 
    280      0    stevel 			/*
    281      0    stevel 			 * Check for chain consistency
    282      0    stevel 			 */
    283      0    stevel 			if ((uintptr_t)ncp->hash_prev != ncprev_va) {
    284      0    stevel 				mdb_free(ncp, nc_size);
    285      0    stevel 				if (skip_bad_chains) {
    286      0    stevel 					mdb_warn(bad_dnlc, i, nc_va);
    287      0    stevel 					break;
    288      0    stevel 				}
    289      0    stevel 				goto retry;
    290      0    stevel 			}
    291      0    stevel 			/*
    292      0    stevel 			 * Terminate the new name with a null.
    293      0    stevel 			 * Note, we allowed space for this null when
    294      0    stevel 			 * allocating space for the entry.
    295      0    stevel 			 */
    296      0    stevel 			ncp->name[ncp->namlen] = '\0';
    297      0    stevel 
    298      0    stevel 			/*
    299      0    stevel 			 * Validate new entry by re-hashing using the
    300      0    stevel 			 * kernel dnlc hash function and comparing the hash
    301      0    stevel 			 */
    302      0    stevel 			DNLCHASH(ncp->name, ncp->dp, khash, namelen);
    303      0    stevel 			if ((namelen != ncp->namlen) ||
    304      0    stevel 			    (khash != ncp->hash)) {
    305      0    stevel 				mdb_free(ncp, nc_size);
    306      0    stevel 				if (skip_bad_chains) {
    307      0    stevel 					mdb_warn(bad_dnlc, i, nc_va);
    308      0    stevel 					break;
    309      0    stevel 				}
    310      0    stevel 				goto retry;
    311      0    stevel 			}
    312      0    stevel 
    313      0    stevel 			/*
    314      0    stevel 			 * Finally put the validated entry into the mdb
    315      0    stevel 			 * hash chains. Reuse the kernel next hash field
    316      0    stevel 			 * for the mdb hash chain pointer.
    317      0    stevel 			 */
    318      0    stevel 			hash = MDB_DNLC_HASH(ncp->vp);
    319      0    stevel 			ncprev_va = nc_va;
    320      0    stevel 			nc_va = (uintptr_t)(ncp->hash_next);
    321      0    stevel 			ncp->hash_next = dnlc_hash[hash];
    322      0    stevel 			dnlc_hash[hash] = ncp;
    323      0    stevel 		}
    324      0    stevel 	}
    325      0    stevel 	return (0);
    326      0    stevel }
    327      0    stevel 
    328      0    stevel /*ARGSUSED*/
    329      0    stevel int
    330      0    stevel dnlcdump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    331      0    stevel {
    332      0    stevel 	ncache_t *ent;
    333      0    stevel 	int i;
    334      0    stevel 
    335      0    stevel 	if ((flags & DCMD_ADDRSPEC) || argc != 0)
    336      0    stevel 		return (DCMD_USAGE);
    337      0    stevel 
    338      0    stevel 	if (dnlc_load() == -1)
    339      0    stevel 		return (DCMD_ERR);
    340      0    stevel 
    341      0    stevel 	mdb_printf("%<u>%-?s %-?s %-32s%</u>\n", "VP", "DVP", "NAME");
    342      0    stevel 
    343      0    stevel 	for (i = 0; i < MDB_DNLC_HSIZE; i++) {
    344      0    stevel 		for (ent = dnlc_hash[i]; ent != NULL; ent = ent->hash_next) {
    345      0    stevel 			mdb_printf("%0?p %0?p %s\n",
    346      0    stevel 			    ent->vp, ent->dp, ent->name);
    347      0    stevel 		}
    348      0    stevel 	}
    349      0    stevel 
    350      0    stevel 	return (DCMD_OK);
    351      0    stevel }
    352      0    stevel 
    353      0    stevel static int
    354      0    stevel mdb_sprintpath(char *buf, size_t len, mdb_path_t *path)
    355      0    stevel {
    356      0    stevel 	char *s = buf;
    357      0    stevel 	int i;
    358      0    stevel 
    359      0    stevel 	if (len < sizeof ("/..."))
    360      0    stevel 		return (-1);
    361      0    stevel 
    362      0    stevel 	if (!path->mdp_complete) {
    363      0    stevel 		(void) strcpy(s, "??");
    364      0    stevel 		s += 2;
    365      0    stevel 
    366      0    stevel 		if (path->mdp_nelem == 0)
    367      0    stevel 			return (-1);
    368      0    stevel 	}
    369      0    stevel 
    370      0    stevel 	if (path->mdp_nelem == 0) {
    371      0    stevel 		(void) strcpy(s, "/");
    372      0    stevel 		return (0);
    373      0    stevel 	}
    374      0    stevel 
    375      0    stevel 	for (i = path->mdp_nelem - 1; i >= 0; i--) {
    376      0    stevel 		/*
    377      0    stevel 		 * Number of bytes left is the distance from where we
    378      0    stevel 		 * are to the end, minus 2 for '/' and '\0'
    379      0    stevel 		 */
    380      0    stevel 		ssize_t left = (ssize_t)(&buf[len] - s) - 2;
    381      0    stevel 
    382      0    stevel 		if (left <= 0)
    383      0    stevel 			break;
    384      0    stevel 
    385      0    stevel 		*s++ = '/';
    386      0    stevel 		(void) strncpy(s, path->mdp_name[i], left);
    387      0    stevel 		s[left - 1] = '\0';
    388      0    stevel 		s += strlen(s);
    389      0    stevel 
    390      0    stevel 		if (left < strlen(path->mdp_name[i]))
    391      0    stevel 			break;
    392      0    stevel 	}
    393      0    stevel 
    394      0    stevel 	if (i >= 0)
    395      0    stevel 		(void) strcpy(&buf[len - 4], "...");
    396      0    stevel 
    397      0    stevel 	return (0);
    398      0    stevel }
    399      0    stevel 
    400      0    stevel static int
    401      0    stevel mdb_autonode2path(uintptr_t addr, mdb_path_t *path)
    402      0    stevel {
    403      0    stevel 	fninfo_t fni;
    404      0    stevel 	fnnode_t fn;
    405      0    stevel 
    406      0    stevel 	vnode_t vn;
    407      0    stevel 	vfs_t vfs;
    408      0    stevel 	struct vnodeops *autofs_vnops = NULL;
    409      0    stevel 
    410      0    stevel 	/*
    411      0    stevel 	 * "autofs_vnops_ptr" is the address of the pointer to the vnodeops
    412      0    stevel 	 * structure for autofs.  We want to read it each time we access
    413      0    stevel 	 * it since autofs could (in theory) be unloaded and reloaded.
    414      0    stevel 	 */
    415      0    stevel 	if (mdb_vread(&autofs_vnops, sizeof (autofs_vnops),
    416      0    stevel 	    (uintptr_t)autofs_vnops_ptr) == -1)
    417      0    stevel 		return (-1);
    418      0    stevel 
    419      0    stevel 	if (mdb_vread(&vn, sizeof (vn), addr) == -1)
    420      0    stevel 		return (-1);
    421      0    stevel 
    422      0    stevel 	if (autofs_vnops == NULL || vn.v_op != autofs_vnops)
    423      0    stevel 		return (-1);
    424      0    stevel 
    425      0    stevel 	addr = (uintptr_t)vn.v_data;
    426      0    stevel 
    427      0    stevel 	if (mdb_vread(&vfs, sizeof (vfs), (uintptr_t)vn.v_vfsp) == -1 ||
    428      0    stevel 	    mdb_vread(&fni, sizeof (fni), (uintptr_t)vfs.vfs_data) == -1 ||
    429      0    stevel 	    mdb_vread(&vn, sizeof (vn), (uintptr_t)fni.fi_rootvp) == -1)
    430      0    stevel 		return (-1);
    431      0    stevel 
    432      0    stevel 	for (;;) {
    433      0    stevel 		size_t elem = path->mdp_nelem++;
    434      0    stevel 		char elemstr[MAXNAMELEN];
    435      0    stevel 		char *c, *p;
    436      0    stevel 
    437      0    stevel 		if (elem == MDB_PATH_NELEM) {
    438      0    stevel 			path->mdp_nelem--;
    439      0    stevel 			return (-1);
    440      0    stevel 		}
    441      0    stevel 
    442      0    stevel 		if (mdb_vread(&fn, sizeof (fn), addr) != sizeof (fn)) {
    443      0    stevel 			path->mdp_nelem--;
    444      0    stevel 			return (-1);
    445      0    stevel 		}
    446      0    stevel 
    447      0    stevel 		if (mdb_readstr(elemstr, sizeof (elemstr),
    448      0    stevel 		    (uintptr_t)fn.fn_name) <= 0) {
    449      0    stevel 			(void) strcpy(elemstr, "?");
    450      0    stevel 		}
    451      0    stevel 
    452      0    stevel 		c = mdb_alloc(strlen(elemstr) + 1, UM_SLEEP | UM_GC);
    453      0    stevel 		(void) strcpy(c, elemstr);
    454      0    stevel 
    455      0    stevel 		path->mdp_vnode[elem] = (uintptr_t)fn.fn_vnode;
    456      0    stevel 
    457      0    stevel 		if (addr == (uintptr_t)fn.fn_parent) {
    458      0    stevel 			path->mdp_name[elem] = &c[1];
    459      0    stevel 			path->mdp_complete = TRUE;
    460      0    stevel 			break;
    461      0    stevel 		}
    462      0    stevel 
    463      0    stevel 		if ((p = strrchr(c, '/')) != NULL)
    464      0    stevel 			path->mdp_name[elem] = p + 1;
    465      0    stevel 		else
    466      0    stevel 			path->mdp_name[elem] = c;
    467      0    stevel 
    468      0    stevel 		addr = (uintptr_t)fn.fn_parent;
    469      0    stevel 	}
    470      0    stevel 
    471      0    stevel 	return (0);
    472      0    stevel }
    473      0    stevel 
    474      0    stevel int
    475      0    stevel mdb_vnode2path(uintptr_t addr, char *buf, size_t buflen)
    476      0    stevel {
    477      0    stevel 	uintptr_t rootdir;
    478      0    stevel 	ncache_t *ent;
    479      0    stevel 	vnode_t vp;
    480      0    stevel 	mdb_path_t path;
    481      0    stevel 
    482      0    stevel 	/*
    483      0    stevel 	 * Check to see if we have a cached value for this vnode
    484      0    stevel 	 */
    485      0    stevel 	if (mdb_vread(&vp, sizeof (vp), addr) != -1 &&
    486      0    stevel 	    vp.v_path != NULL &&
    487      0    stevel 	    mdb_readstr(buf, buflen, (uintptr_t)vp.v_path) != -1)
    488      0    stevel 		return (0);
    489      0    stevel 
    490      0    stevel 	if (dnlc_load() == -1)
    491      0    stevel 		return (-1);
    492      0    stevel 
    493      0    stevel 	if (mdb_readvar(&rootdir, "rootdir") == -1) {
    494      0    stevel 		mdb_warn("failed to read 'rootdir'");
    495      0    stevel 		return (-1);
    496      0    stevel 	}
    497      0    stevel 
    498      0    stevel 	bzero(&path, sizeof (mdb_path_t));
    499      0    stevel again:
    500      0    stevel 	if ((addr == NULL) && (path.mdp_nelem == 0)) {
    501      0    stevel 		/*
    502      0    stevel 		 * 0 elems && complete tells sprintpath to just print "/"
    503      0    stevel 		 */
    504      0    stevel 		path.mdp_complete = TRUE;
    505      0    stevel 		goto out;
    506      0    stevel 	}
    507      0    stevel 
    508      0    stevel 	if (addr == rootdir) {
    509      0    stevel 		path.mdp_complete = TRUE;
    510      0    stevel 		goto out;
    511      0    stevel 	}
    512      0    stevel 
    513      0    stevel 	for (ent = dnlc_hash[MDB_DNLC_HASH(addr)]; ent; ent = ent->hash_next) {
    514      0    stevel 		if ((uintptr_t)ent->vp == addr) {
    515      0    stevel 			if (strcmp(ent->name, "..") == 0 ||
    516      0    stevel 			    strcmp(ent->name, ".") == 0)
    517      0    stevel 				continue;
    518      0    stevel 
    519      0    stevel 			path.mdp_vnode[path.mdp_nelem] = (uintptr_t)ent->vp;
    520      0    stevel 			path.mdp_name[path.mdp_nelem] = ent->name;
    521      0    stevel 			path.mdp_nelem++;
    522      0    stevel 
    523      0    stevel 			if (path.mdp_nelem == MDB_PATH_NELEM) {
    524      0    stevel 				path.mdp_nelem--;
    525      0    stevel 				mdb_warn("path exceeded maximum expected "
    526      0    stevel 				    "elements\n");
    527      0    stevel 				return (-1);
    528      0    stevel 			}
    529      0    stevel 
    530      0    stevel 			addr = (uintptr_t)ent->dp;
    531      0    stevel 			goto again;
    532      0    stevel 		}
    533      0    stevel 	}
    534      0    stevel 
    535      0    stevel 	(void) mdb_autonode2path(addr, &path);
    536      0    stevel 
    537      0    stevel out:
    538      0    stevel 	return (mdb_sprintpath(buf, buflen, &path));
    539      0    stevel }
    540      0    stevel 
    541      0    stevel 
    542      0    stevel uintptr_t
    543      0    stevel mdb_pid2proc(pid_t pid, proc_t *proc)
    544      0    stevel {
    545      0    stevel 	int pid_hashsz, hash;
    546      0    stevel 	uintptr_t paddr, pidhash, procdir;
    547      0    stevel 	struct pid pidp;
    548      0    stevel 
    549      0    stevel 	if (mdb_readvar(&pidhash, "pidhash") == -1)
    550      0    stevel 		return (NULL);
    551      0    stevel 
    552      0    stevel 	if (mdb_readvar(&pid_hashsz, "pid_hashsz") == -1)
    553      0    stevel 		return (NULL);
    554      0    stevel 
    555      0    stevel 	if (mdb_readvar(&procdir, "procdir") == -1)
    556      0    stevel 		return (NULL);
    557      0    stevel 
    558      0    stevel 	hash = pid & (pid_hashsz - 1);
    559      0    stevel 
    560      0    stevel 	if (mdb_vread(&paddr, sizeof (paddr),
    561      0    stevel 	    pidhash + (hash * sizeof (paddr))) == -1)
    562      0    stevel 		return (NULL);
    563      0    stevel 
    564      0    stevel 	while (paddr != 0) {
    565      0    stevel 		if (mdb_vread(&pidp, sizeof (pidp), paddr) == -1)
    566      0    stevel 			return (NULL);
    567      0    stevel 
    568      0    stevel 		if (pidp.pid_id == pid) {
    569      0    stevel 			uintptr_t procp;
    570      0    stevel 
    571      0    stevel 			if (mdb_vread(&procp, sizeof (procp), procdir +
    572      0    stevel 			    (pidp.pid_prslot * sizeof (procp))) == -1)
    573      0    stevel 				return (NULL);
    574      0    stevel 
    575      0    stevel 			if (proc != NULL)
    576      0    stevel 				(void) mdb_vread(proc, sizeof (proc_t), procp);
    577      0    stevel 
    578      0    stevel 			return (procp);
    579      0    stevel 		}
    580      0    stevel 		paddr = (uintptr_t)pidp.pid_link;
    581      0    stevel 	}
    582      0    stevel 	return (NULL);
    583      0    stevel }
    584      0    stevel 
    585   1234   johnlev int
    586   1234   johnlev mdb_cpu2cpuid(uintptr_t cpup)
    587   1234   johnlev {
    588   1234   johnlev 	cpu_t cpu;
    589   1234   johnlev 
    590   1234   johnlev 	if (mdb_vread(&cpu, sizeof (cpu_t), cpup) != sizeof (cpu_t))
    591   1234   johnlev 		return (-1);
    592   1234   johnlev 
    593   1234   johnlev 	return (cpu.cpu_id);
    594   1234   johnlev }
    595   1234   johnlev 
    596   2116     anish int
    597   2116     anish mdb_cpuset_find(uintptr_t cpusetp)
    598   2116     anish {
    599   2116     anish 	ulong_t	*cpuset;
    600   2116     anish 	size_t nr_words = BT_BITOUL(NCPU);
    601   2116     anish 	size_t sz = nr_words * sizeof (ulong_t);
    602   2116     anish 	size_t	i;
    603   2116     anish 	int cpu = -1;
    604   2116     anish 
    605   2116     anish 	cpuset = mdb_alloc(sz, UM_SLEEP);
    606   2116     anish 
    607   6336   bholler 	if (mdb_vread((void *)cpuset, sz, cpusetp) != sz)
    608   2116     anish 		goto out;
    609   2116     anish 
    610   2116     anish 	for (i = 0; i < nr_words; i++) {
    611   2116     anish 		size_t j;
    612   2116     anish 		ulong_t m;
    613   2116     anish 
    614   2116     anish 		for (j = 0, m = 1; j < BT_NBIPUL; j++, m <<= 1) {
    615   2116     anish 			if (cpuset[i] & m) {
    616   2116     anish 				cpu = i * BT_NBIPUL + j;
    617   2116     anish 				goto out;
    618   2116     anish 			}
    619   2116     anish 		}
    620   2116     anish 	}
    621   2116     anish 
    622   2116     anish out:
    623   2116     anish 	mdb_free(cpuset, sz);
    624   2116     anish 	return (cpu);
    625   2116     anish }
    626   2116     anish 
    627      0    stevel uintptr_t
    628      0    stevel mdb_vnode2page(uintptr_t vp, uintptr_t offset)
    629      0    stevel {
    630      0    stevel 	long page_hashsz, ndx;
    631      0    stevel 	uintptr_t page_hash, pp;
    632      0    stevel 
    633      0    stevel 	if (mdb_readvar(&page_hashsz, "page_hashsz") == -1 ||
    634      0    stevel 	    mdb_readvar(&page_hash, "page_hash") == -1)
    635      0    stevel 		return (NULL);
    636      0    stevel 
    637      0    stevel 	ndx = PAGE_HASH_FUNC(vp, offset);
    638      0    stevel 	page_hash += ndx * sizeof (uintptr_t);
    639      0    stevel 
    640      0    stevel 	mdb_vread(&pp, sizeof (pp), page_hash);
    641      0    stevel 
    642      0    stevel 	while (pp != NULL) {
    643      0    stevel 		page_t page;
    644      0    stevel 
    645      0    stevel 		mdb_vread(&page, sizeof (page), pp);
    646      0    stevel 
    647      0    stevel 		if ((uintptr_t)page.p_vnode == vp &&
    648      0    stevel 		    (uintptr_t)page.p_offset == offset)
    649      0    stevel 			return (pp);
    650      0    stevel 
    651      0    stevel 		pp = (uintptr_t)page.p_hash;
    652      0    stevel 	}
    653      0    stevel 
    654      0    stevel 	return (NULL);
    655      0    stevel }
    656      0    stevel 
    657      0    stevel char
    658      0    stevel mdb_vtype2chr(vtype_t type, mode_t mode)
    659      0    stevel {
    660      0    stevel 	static const char vttab[] = {
    661      0    stevel 		' ',	/* VNON */
    662      0    stevel 		' ',	/* VREG */
    663      0    stevel 		'/',	/* VDIR */
    664      0    stevel 		' ',	/* VBLK */
    665      0    stevel 		' ',	/* VCHR */
    666      0    stevel 		'@',	/* VLNK */
    667      0    stevel 		'|',	/* VFIFO */
    668      0    stevel 		'>',	/* VDOOR */
    669      0    stevel 		' ',	/* VPROC */
    670      0    stevel 		'=',	/* VSOCK */
    671      0    stevel 		' ',	/* VBAD */
    672      0    stevel 	};
    673      0    stevel 
    674      0    stevel 	if (type < 0 || type >= sizeof (vttab) / sizeof (vttab[0]))
    675      0    stevel 		return ('?');
    676      0    stevel 
    677      0    stevel 	if (type == VREG && (mode & 0111) != 0)
    678      0    stevel 		return ('*');
    679      0    stevel 
    680      0    stevel 	return (vttab[type]);
    681      0    stevel }
    682      0    stevel 
    683      0    stevel static int
    684      0    stevel a2m_walk_modctl(uintptr_t addr, const struct modctl *m, a2m_query_t *a2m)
    685      0    stevel {
    686      0    stevel 	struct module mod;
    687      0    stevel 
    688      0    stevel 	if (m->mod_mp == NULL)
    689      0    stevel 		return (0);
    690      0    stevel 
    691      0    stevel 	if (mdb_vread(&mod, sizeof (mod), (uintptr_t)m->mod_mp) == -1) {
    692      0    stevel 		mdb_warn("couldn't read modctl %p's module", addr);
    693      0    stevel 		return (0);
    694      0    stevel 	}
    695      0    stevel 
    696      0    stevel 	if (a2m->a2m_addr >= (uintptr_t)mod.text &&
    697      0    stevel 	    a2m->a2m_addr < (uintptr_t)mod.text + mod.text_size)
    698      0    stevel 		goto found;
    699      0    stevel 
    700      0    stevel 	if (a2m->a2m_addr >= (uintptr_t)mod.data &&
    701      0    stevel 	    a2m->a2m_addr < (uintptr_t)mod.data + mod.data_size)
    702      0    stevel 		goto found;
    703      0    stevel 
    704      0    stevel 	return (0);
    705      0    stevel 
    706      0    stevel found:
    707      0    stevel 	a2m->a2m_where = addr;
    708      0    stevel 	return (-1);
    709      0    stevel }
    710      0    stevel 
    711      0    stevel uintptr_t
    712      0    stevel mdb_addr2modctl(uintptr_t addr)
    713      0    stevel {
    714      0    stevel 	a2m_query_t a2m;
    715      0    stevel 
    716      0    stevel 	a2m.a2m_addr = addr;
    717      0    stevel 	a2m.a2m_where = NULL;
    718      0    stevel 
    719      0    stevel 	(void) mdb_walk("modctl", (mdb_walk_cb_t)a2m_walk_modctl, &a2m);
    720      0    stevel 	return (a2m.a2m_where);
    721      0    stevel }
    722      0    stevel 
    723      0    stevel static mdb_qinfo_t *
    724      0    stevel qi_lookup(uintptr_t qinit_addr)
    725      0    stevel {
    726      0    stevel 	mdb_qinfo_t *qip;
    727      0    stevel 
    728      0    stevel 	for (qip = qi_head; qip != NULL; qip = qip->qi_next) {
    729      0    stevel 		if (qip->qi_addr == qinit_addr)
    730      0    stevel 			return (qip);
    731      0    stevel 	}
    732      0    stevel 
    733      0    stevel 	return (NULL);
    734      0    stevel }
    735      0    stevel 
    736      0    stevel void
    737      0    stevel mdb_qops_install(const mdb_qops_t *qops, uintptr_t qinit_addr)
    738      0    stevel {
    739      0    stevel 	mdb_qinfo_t *qip = qi_lookup(qinit_addr);
    740      0    stevel 
    741      0    stevel 	if (qip != NULL) {
    742      0    stevel 		qip->qi_ops = qops;
    743      0    stevel 		return;
    744      0    stevel 	}
    745      0    stevel 
    746      0    stevel 	qip = mdb_alloc(sizeof (mdb_qinfo_t), UM_SLEEP);
    747      0    stevel 
    748      0    stevel 	qip->qi_ops = qops;
    749      0    stevel 	qip->qi_addr = qinit_addr;
    750      0    stevel 	qip->qi_next = qi_head;
    751      0    stevel 
    752      0    stevel 	qi_head = qip;
    753      0    stevel }
    754      0    stevel 
    755      0    stevel void
    756      0    stevel mdb_qops_remove(const mdb_qops_t *qops, uintptr_t qinit_addr)
    757      0    stevel {
    758      0    stevel 	mdb_qinfo_t *qip, *p = NULL;
    759      0    stevel 
    760      0    stevel 	for (qip = qi_head; qip != NULL; p = qip, qip = qip->qi_next) {
    761      0    stevel 		if (qip->qi_addr == qinit_addr && qip->qi_ops == qops) {
    762      0    stevel 			if (qi_head == qip)
    763      0    stevel 				qi_head = qip->qi_next;
    764      0    stevel 			else
    765      0    stevel 				p->qi_next = qip->qi_next;
    766      0    stevel 			mdb_free(qip, sizeof (mdb_qinfo_t));
    767      0    stevel 			return;
    768      0    stevel 		}
    769      0    stevel 	}
    770      0    stevel }
    771      0    stevel 
    772      0    stevel char *
    773      0    stevel mdb_qname(const queue_t *q, char *buf, size_t nbytes)
    774      0    stevel {
    775      0    stevel 	struct module_info mi;
    776      0    stevel 	struct qinit qi;
    777      0    stevel 
    778      0    stevel 	if (mdb_vread(&qi, sizeof (qi), (uintptr_t)q->q_qinfo) == -1) {
    779      0    stevel 		mdb_warn("failed to read qinit at %p", q->q_qinfo);
    780      0    stevel 		goto err;
    781      0    stevel 	}
    782      0    stevel 
    783      0    stevel 	if (mdb_vread(&mi, sizeof (mi), (uintptr_t)qi.qi_minfo) == -1) {
    784      0    stevel 		mdb_warn("failed to read module_info at %p", qi.qi_minfo);
    785      0    stevel 		goto err;
    786      0    stevel 	}
    787      0    stevel 
    788      0    stevel 	if (mdb_readstr(buf, nbytes, (uintptr_t)mi.mi_idname) <= 0) {
    789      0    stevel 		mdb_warn("failed to read mi_idname at %p", mi.mi_idname);
    790      0    stevel 		goto err;
    791      0    stevel 	}
    792      0    stevel 
    793      0    stevel 	return (buf);
    794      0    stevel 
    795      0    stevel err:
    796      0    stevel 	(void) mdb_snprintf(buf, nbytes, "???");
    797      0    stevel 	return (buf);
    798      0    stevel }
    799      0    stevel 
    800      0    stevel void
    801      0    stevel mdb_qinfo(const queue_t *q, char *buf, size_t nbytes)
    802      0    stevel {
    803      0    stevel 	mdb_qinfo_t *qip = qi_lookup((uintptr_t)q->q_qinfo);
    804      0    stevel 	buf[0] = '\0';
    805      0    stevel 
    806      0    stevel 	if (qip != NULL)
    807      0    stevel 		qip->qi_ops->q_info(q, buf, nbytes);
    808      0    stevel }
    809      0    stevel 
    810      0    stevel uintptr_t
    811      0    stevel mdb_qrnext(const queue_t *q)
    812      0    stevel {
    813      0    stevel 	mdb_qinfo_t *qip = qi_lookup((uintptr_t)q->q_qinfo);
    814      0    stevel 
    815      0    stevel 	if (qip != NULL)
    816      0    stevel 		return (qip->qi_ops->q_rnext(q));
    817      0    stevel 
    818      0    stevel 	return (NULL);
    819      0    stevel }
    820      0    stevel 
    821      0    stevel uintptr_t
    822      0    stevel mdb_qwnext(const queue_t *q)
    823      0    stevel {
    824      0    stevel 	mdb_qinfo_t *qip = qi_lookup((uintptr_t)q->q_qinfo);
    825      0    stevel 
    826      0    stevel 	if (qip != NULL)
    827      0    stevel 		return (qip->qi_ops->q_wnext(q));
    828      0    stevel 
    829      0    stevel 	return (NULL);
    830      0    stevel }
    831      0    stevel 
    832      0    stevel uintptr_t
    833      0    stevel mdb_qrnext_default(const queue_t *q)
    834      0    stevel {
    835      0    stevel 	return ((uintptr_t)q->q_next);
    836      0    stevel }
    837      0    stevel 
    838      0    stevel uintptr_t
    839      0    stevel mdb_qwnext_default(const queue_t *q)
    840      0    stevel {
    841      0    stevel 	return ((uintptr_t)q->q_next);
    842      0    stevel }
    843      0    stevel 
    844      0    stevel /*
    845      0    stevel  * The following three routines borrowed from modsubr.c
    846      0    stevel  */
    847      0    stevel static int
    848      0    stevel nm_hash(const char *name)
    849      0    stevel {
    850      0    stevel 	char c;
    851      0    stevel 	int hash = 0;
    852      0    stevel 
    853      0    stevel 	for (c = *name++; c; c = *name++)
    854      0    stevel 		hash ^= c;
    855      0    stevel 
    856      0    stevel 	return (hash & MOD_BIND_HASHMASK);
    857      0    stevel }
    858      0    stevel 
    859      0    stevel static uintptr_t
    860      0    stevel find_mbind(const char *name, uintptr_t *hashtab)
    861      0    stevel {
    862      0    stevel 	int hashndx;
    863      0    stevel 	uintptr_t mb;
    864      0    stevel 	struct bind mb_local;
    865   4145       cth 	char node_name[MAXPATHLEN + 1];
    866      0    stevel 
    867      0    stevel 	hashndx = nm_hash(name);
    868      0    stevel 	mb = hashtab[hashndx];
    869      0    stevel 	while (mb) {
    870      0    stevel 		if (mdb_vread(&mb_local, sizeof (mb_local), mb) == -1) {
    871      0    stevel 			mdb_warn("failed to read struct bind at %p", mb);
    872      0    stevel 			return (NULL);
    873      0    stevel 		}
    874      0    stevel 		if (mdb_readstr(node_name, sizeof (node_name),
    875      0    stevel 		    (uintptr_t)mb_local.b_name) == -1) {
    876      0    stevel 			mdb_warn("failed to read node name string at %p",
    877   6336   bholler 			    mb_local.b_name);
    878      0    stevel 			return (NULL);
    879      0    stevel 		}
    880      0    stevel 
    881      0    stevel 		if (strcmp(name, node_name) == 0)
    882      0    stevel 			break;
    883      0    stevel 
    884      0    stevel 		mb = (uintptr_t)mb_local.b_next;
    885      0    stevel 	}
    886      0    stevel 	return (mb);
    887      0    stevel }
    888      0    stevel 
    889      0    stevel int
    890      0    stevel mdb_name_to_major(const char *name, major_t *major)
    891      0    stevel {
    892      0    stevel 	uintptr_t	mbind;
    893      0    stevel 	uintptr_t	mb_hashtab[MOD_BIND_HASHSIZE];
    894      0    stevel 	struct bind 	mbind_local;
    895      0    stevel 
    896      0    stevel 
    897      0    stevel 	if (mdb_readsym(mb_hashtab, sizeof (mb_hashtab), "mb_hashtab") == -1) {
    898      0    stevel 		mdb_warn("failed to read symbol 'mb_hashtab'");
    899      0    stevel 		return (-1);
    900      0    stevel 	}
    901      0    stevel 
    902      0    stevel 	if ((mbind = find_mbind(name, mb_hashtab)) != NULL) {
    903      0    stevel 		if (mdb_vread(&mbind_local, sizeof (mbind_local), mbind) ==
    904      0    stevel 		    -1) {
    905      0    stevel 			mdb_warn("failed to read mbind struct at %p", mbind);
    906      0    stevel 			return (-1);
    907      0    stevel 		}
    908      0    stevel 
    909      0    stevel 		*major = (major_t)mbind_local.b_num;
    910      0    stevel 		return (0);
    911      0    stevel 	}
    912      0    stevel 	return (-1);
    913      0    stevel }
    914      0    stevel 
    915      0    stevel const char *
    916      0    stevel mdb_major_to_name(major_t major)
    917      0    stevel {
    918      0    stevel 	static char name[MODMAXNAMELEN + 1];
    919      0    stevel 
    920      0    stevel 	uintptr_t devnamesp;
    921      0    stevel 	struct devnames dn;
    922      0    stevel 	uint_t devcnt;
    923      0    stevel 
    924      0    stevel 	if (mdb_readvar(&devcnt, "devcnt") == -1 || major >= devcnt ||
    925      0    stevel 	    mdb_readvar(&devnamesp, "devnamesp") == -1)
    926      0    stevel 		return (NULL);
    927      0    stevel 
    928      0    stevel 	if (mdb_vread(&dn, sizeof (struct devnames), devnamesp +
    929      0    stevel 	    major * sizeof (struct devnames)) != sizeof (struct devnames))
    930      0    stevel 		return (NULL);
    931      0    stevel 
    932      0    stevel 	if (mdb_readstr(name, MODMAXNAMELEN + 1, (uintptr_t)dn.dn_name) == -1)
    933      0    stevel 		return (NULL);
    934      0    stevel 
    935      0    stevel 	return ((const char *)name);
    936      0    stevel }
    937      0    stevel 
    938      0    stevel /*
    939      0    stevel  * Return the name of the driver attached to the dip in drivername.
    940      0    stevel  */
    941      0    stevel int
    942      0    stevel mdb_devinfo2driver(uintptr_t dip_addr, char *drivername, size_t namebufsize)
    943      0    stevel {
    944      0    stevel 	struct dev_info	devinfo;
    945   4145       cth 	char bind_name[MAXPATHLEN + 1];
    946      0    stevel 	major_t	major;
    947      0    stevel 	const char *namestr;
    948      0    stevel 
    949      0    stevel 
    950      0    stevel 	if (mdb_vread(&devinfo, sizeof (devinfo), dip_addr) == -1) {
    951      0    stevel 		mdb_warn("failed to read devinfo at %p", dip_addr);
    952      0    stevel 		return (-1);
    953      0    stevel 	}
    954      0    stevel 
    955      0    stevel 	if (mdb_readstr(bind_name, sizeof (bind_name),
    956      0    stevel 	    (uintptr_t)devinfo.devi_binding_name) == -1) {
    957      0    stevel 		mdb_warn("failed to read binding name at %p",
    958      0    stevel 		    devinfo.devi_binding_name);
    959      0    stevel 		return (-1);
    960      0    stevel 	}
    961      0    stevel 
    962      0    stevel 	/*
    963      0    stevel 	 * Many->one relation: various names to one major number
    964      0    stevel 	 */
    965      0    stevel 	if (mdb_name_to_major(bind_name, &major) == -1) {
    966      0    stevel 		mdb_warn("failed to translate bind name to major number\n");
    967      0    stevel 		return (-1);
    968      0    stevel 	}
    969      0    stevel 
    970      0    stevel 	/*
    971      0    stevel 	 * One->one relation: one major number corresponds to one driver
    972      0    stevel 	 */
    973      0    stevel 	if ((namestr = mdb_major_to_name(major)) == NULL) {
    974      0    stevel 		(void) strncpy(drivername, "???", namebufsize);
    975      0    stevel 		return (-1);
    976      0    stevel 	}
    977      0    stevel 
    978      0    stevel 	(void) strncpy(drivername, namestr, namebufsize);
    979      0    stevel 	return (0);
    980      0    stevel }
    981      0    stevel 
    982      0    stevel /*
    983      0    stevel  * Find the name of the driver attached to this dip (if any), given:
    984      0    stevel  * - the address of a dip (in core)
    985      0    stevel  * - the NAME of the global pointer to the driver's i_ddi_soft_state struct
    986      0    stevel  * - pointer to a pointer to receive the address
    987      0    stevel  */
    988      0    stevel int
    989      0    stevel mdb_devinfo2statep(uintptr_t dip_addr, char *soft_statep_name,
    990      0    stevel     uintptr_t *statep)
    991      0    stevel {
    992      0    stevel 	struct dev_info	dev_info;
    993      0    stevel 
    994      0    stevel 
    995      0    stevel 	if (mdb_vread(&dev_info, sizeof (dev_info), dip_addr) == -1) {
    996      0    stevel 		mdb_warn("failed to read devinfo at %p", dip_addr);
    997      0    stevel 		return (-1);
    998      0    stevel 	}
    999      0    stevel 
   1000      0    stevel 	return (mdb_get_soft_state_byname(soft_statep_name,
   1001      0    stevel 	    dev_info.devi_instance, statep, NULL, 0));
   1002      0    stevel }
   1003      0    stevel 
   1004      0    stevel /*
   1005      0    stevel  * Returns a pointer to the top of the soft state struct for the instance
   1006      0    stevel  * specified (in state_addr), given the address of the global soft state
   1007      0    stevel  * pointer and size of the struct.  Also fills in the buffer pointed to by
   1008      0    stevel  * state_buf_p (if non-NULL) with the contents of the state struct.
   1009      0    stevel  */
   1010      0    stevel int
   1011      0    stevel mdb_get_soft_state_byaddr(uintptr_t ssaddr, uint_t instance,
   1012      0    stevel     uintptr_t *state_addr, void *state_buf_p, size_t sizeof_state)
   1013      0    stevel {
   1014      0    stevel 	struct i_ddi_soft_state ss;
   1015      0    stevel 	void *statep;
   1016      0    stevel 
   1017      0    stevel 
   1018      0    stevel 	if (mdb_vread(&ss, sizeof (ss), ssaddr) == -1)
   1019      0    stevel 		return (-1);
   1020      0    stevel 
   1021      0    stevel 	if (instance >= ss.n_items)
   1022      0    stevel 		return (-1);
   1023      0    stevel 
   1024      0    stevel 	if (mdb_vread(&statep, sizeof (statep), (uintptr_t)ss.array +
   1025      0    stevel 	    (sizeof (statep) * instance)) == -1)
   1026      0    stevel 		return (-1);
   1027      0    stevel 
   1028      0    stevel 	if (state_addr != NULL)
   1029      0    stevel 		*state_addr = (uintptr_t)statep;
   1030      0    stevel 
   1031      0    stevel 	if (statep == NULL) {
   1032      0    stevel 		errno = ENOENT;
   1033      0    stevel 		return (-1);
   1034      0    stevel 	}
   1035      0    stevel 
   1036      0    stevel 	if (state_buf_p != NULL) {
   1037      0    stevel 
   1038      0    stevel 		/* Read the state struct into the buffer in local space. */
   1039      0    stevel 		if (mdb_vread(state_buf_p, sizeof_state,
   1040      0    stevel 		    (uintptr_t)statep) == -1)
   1041      0    stevel 			return (-1);
   1042      0    stevel 	}
   1043      0    stevel 
   1044      0    stevel 	return (0);
   1045      0    stevel }
   1046      0    stevel 
   1047      0    stevel 
   1048      0    stevel /*
   1049      0    stevel  * Returns a pointer to the top of the soft state struct for the instance
   1050      0    stevel  * specified (in state_addr), given the name of the global soft state pointer
   1051      0    stevel  * and size of the struct.  Also fills in the buffer pointed to by
   1052      0    stevel  * state_buf_p (if non-NULL) with the contents of the state struct.
   1053      0    stevel  */
   1054      0    stevel int
   1055      0    stevel mdb_get_soft_state_byname(char *softstatep_name, uint_t instance,
   1056      0    stevel     uintptr_t *state_addr, void *state_buf_p, size_t sizeof_state)
   1057      0    stevel {
   1058      0    stevel 	uintptr_t ssaddr;
   1059      0    stevel 
   1060      0    stevel 	if (mdb_readvar((void *)&ssaddr, softstatep_name) == -1)
   1061      0    stevel 		return (-1);
   1062      0    stevel 
   1063      0    stevel 	return (mdb_get_soft_state_byaddr(ssaddr, instance, state_addr,
   1064      0    stevel 	    state_buf_p, sizeof_state));
   1065      0    stevel }
   1066      0    stevel 
   1067      0    stevel static const mdb_dcmd_t dcmds[] = {
   1068      0    stevel 	{ "dnlc", NULL, "print DNLC contents", dnlcdump },
   1069      0    stevel 	{ NULL }
   1070      0    stevel };
   1071      0    stevel 
   1072      0    stevel static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds };
   1073      0    stevel 
   1074      0    stevel /*ARGSUSED*/
   1075      0    stevel static void
   1076      0    stevel update_vars(void *arg)
   1077      0    stevel {
   1078      0    stevel 	GElf_Sym sym;
   1079      0    stevel 
   1080      0    stevel 	if (mdb_lookup_by_name("auto_vnodeops", &sym) == 0)
   1081      0    stevel 		autofs_vnops_ptr = (struct vnodeops *)(uintptr_t)sym.st_value;
   1082      0    stevel 	else
   1083      0    stevel 		autofs_vnops_ptr = NULL;
   1084      0    stevel 
   1085      0    stevel 	(void) mdb_readvar(&_mdb_ks_pagesize, "_pagesize");
   1086      0    stevel 	(void) mdb_readvar(&_mdb_ks_pageshift, "_pageshift");
   1087      0    stevel 	(void) mdb_readvar(&_mdb_ks_pageoffset, "_pageoffset");
   1088      0    stevel 	(void) mdb_readvar(&_mdb_ks_pagemask, "_pagemask");
   1089      0    stevel 	(void) mdb_readvar(&_mdb_ks_mmu_pagesize, "_mmu_pagesize");
   1090      0    stevel 	(void) mdb_readvar(&_mdb_ks_mmu_pageshift, "_mmu_pageshift");
   1091      0    stevel 	(void) mdb_readvar(&_mdb_ks_mmu_pageoffset, "_mmu_pageoffset");
   1092      0    stevel 	(void) mdb_readvar(&_mdb_ks_mmu_pagemask, "_mmu_pagemask");
   1093      0    stevel 	(void) mdb_readvar(&_mdb_ks_kernelbase, "_kernelbase");
   1094      0    stevel 
   1095      0    stevel 	(void) mdb_readvar(&_mdb_ks_userlimit, "_userlimit");
   1096      0    stevel 	(void) mdb_readvar(&_mdb_ks_userlimit32, "_userlimit32");
   1097      0    stevel 	(void) mdb_readvar(&_mdb_ks_argsbase, "_argsbase");
   1098      0    stevel 	(void) mdb_readvar(&_mdb_ks_msg_bsize, "_msg_bsize");
   1099      0    stevel 	(void) mdb_readvar(&_mdb_ks_defaultstksz, "_defaultstksz");
   1100      0    stevel 	(void) mdb_readvar(&_mdb_ks_ncpu, "_ncpu");
   1101      0    stevel }
   1102      0    stevel 
   1103      0    stevel const mdb_modinfo_t *
   1104      0    stevel _mdb_init(void)
   1105      0    stevel {
   1106      0    stevel 	/*
   1107      0    stevel 	 * When used with mdb, mdb_ks is a separate dmod.  With kmdb, however,
   1108      0    stevel 	 * mdb_ks is compiled into the debugger module.  kmdb cannot
   1109      0    stevel 	 * automatically modunload itself when it exits.  If it restarts after
   1110      0    stevel 	 * debugger fault, static variables may not be initialized to zero.
   1111      0    stevel 	 * They must be manually reinitialized here.
   1112      0    stevel 	 */
   1113      0    stevel 	dnlc_hash = NULL;
   1114      0    stevel 	qi_head = NULL;
   1115      0    stevel 
   1116      0    stevel 	mdb_callback_add(MDB_CALLBACK_STCHG, update_vars, NULL);
   1117      0    stevel 
   1118      0    stevel 	update_vars(NULL);
   1119      0    stevel 
   1120      0    stevel 	return (&modinfo);
   1121      0    stevel }
   1122      0    stevel 
   1123      0    stevel void
   1124      0    stevel _mdb_fini(void)
   1125      0    stevel {
   1126      0    stevel 	dnlc_free();
   1127      0    stevel 	while (qi_head != NULL) {
   1128      0    stevel 		mdb_qinfo_t *qip = qi_head;
   1129      0    stevel 		qi_head = qip->qi_next;
   1130      0    stevel 		mdb_free(qip, sizeof (mdb_qinfo_t));
   1131      0    stevel 	}
   1132      0    stevel }
   1133      0    stevel 
   1134      0    stevel /*
   1135      0    stevel  * Interface between MDB kproc target and mdb_ks.  The kproc target relies
   1136      0    stevel  * on looking up and invoking these functions in mdb_ks so that dependencies
   1137      0    stevel  * on the current kernel implementation are isolated in mdb_ks.
   1138      0    stevel  */
   1139      0    stevel 
   1140      0    stevel /*
   1141      0    stevel  * Given the address of a proc_t, return the p.p_as pointer; return NULL
   1142      0    stevel  * if we were unable to read a proc structure from the given address.
   1143      0    stevel  */
   1144      0    stevel uintptr_t
   1145      0    stevel mdb_kproc_as(uintptr_t proc_addr)
   1146      0    stevel {
   1147      0    stevel 	proc_t p;
   1148      0    stevel 
   1149      0    stevel 	if (mdb_vread(&p, sizeof (p), proc_addr) == sizeof (p))
   1150      0    stevel 		return ((uintptr_t)p.p_as);
   1151      0    stevel 
   1152      0    stevel 	return (NULL);
   1153      0    stevel }
   1154      0    stevel 
   1155      0    stevel /*
   1156      0    stevel  * Given the address of a proc_t, return the p.p_model value; return
   1157      0    stevel  * PR_MODEL_UNKNOWN if we were unable to read a proc structure or if
   1158      0    stevel  * the model value does not match one of the two known values.
   1159      0    stevel  */
   1160      0    stevel uint_t
   1161      0    stevel mdb_kproc_model(uintptr_t proc_addr)
   1162      0    stevel {
   1163      0    stevel 	proc_t p;
   1164      0    stevel 
   1165      0    stevel 	if (mdb_vread(&p, sizeof (p), proc_addr) == sizeof (p)) {
   1166      0    stevel 		switch (p.p_model) {
   1167      0    stevel 		case DATAMODEL_ILP32:
   1168      0    stevel 			return (PR_MODEL_ILP32);
   1169      0    stevel 		case DATAMODEL_LP64:
   1170      0    stevel 			return (PR_MODEL_LP64);
   1171      0    stevel 		}
   1172      0    stevel 	}
   1173      0    stevel 
   1174      0    stevel 	return (PR_MODEL_UNKNOWN);
   1175      0    stevel }
   1176      0    stevel 
   1177      0    stevel /*
   1178      0    stevel  * Callback function for walking process's segment list.  For each segment,
   1179      0    stevel  * we fill in an mdb_map_t describing its properties, and then invoke
   1180      0    stevel  * the callback function provided by the kproc target.
   1181      0    stevel  */
   1182      0    stevel static int
   1183      0    stevel asmap_step(uintptr_t addr, const struct seg *seg, asmap_arg_t *asmp)
   1184      0    stevel {
   1185      0    stevel 	struct segvn_data svd;
   1186      0    stevel 	mdb_map_t map;
   1187      0    stevel 
   1188      0    stevel 	if (seg->s_ops == asmp->asm_segvn_ops && mdb_vread(&svd,
   1189      0    stevel 	    sizeof (svd), (uintptr_t)seg->s_data) == sizeof (svd)) {
   1190      0    stevel 
   1191      0    stevel 		if (svd.vp != NULL) {
   1192      0    stevel 			if (mdb_vnode2path((uintptr_t)svd.vp, map.map_name,
   1193   6336   bholler 			    MDB_TGT_MAPSZ) != 0) {
   1194      0    stevel 				(void) mdb_snprintf(map.map_name,
   1195      0    stevel 				    MDB_TGT_MAPSZ, "[ vnode %p ]", svd.vp);
   1196      0    stevel 			}
   1197      0    stevel 		} else
   1198      0    stevel 			(void) strcpy(map.map_name, "[ anon ]");
   1199      0    stevel 
   1200      0    stevel 	} else {
   1201      0    stevel 		(void) mdb_snprintf(map.map_name, MDB_TGT_MAPSZ,
   1202      0    stevel 		    "[ seg %p ]", addr);
   1203      0    stevel 	}
   1204      0    stevel 
   1205      0    stevel 	map.map_base = (uintptr_t)seg->s_base;
   1206      0    stevel 	map.map_size = seg->s_size;
   1207      0    stevel 	map.map_flags = 0;
   1208      0    stevel 
   1209      0    stevel 	asmp->asm_callback((const struct mdb_map *)&map, asmp->asm_cbdata);
   1210      0    stevel 	return (WALK_NEXT);
   1211      0    stevel }
   1212      0    stevel 
   1213      0    stevel /*
   1214      0    stevel  * Given a process address space, walk its segment list using the seg walker,
   1215      0    stevel  * convert the segment data to an mdb_map_t, and pass this information
   1216      0    stevel  * back to the kproc target via the given callback function.
   1217      0    stevel  */
   1218      0    stevel int
   1219      0    stevel mdb_kproc_asiter(uintptr_t as,
   1220      0    stevel     void (*func)(const struct mdb_map *, void *), void *p)
   1221      0    stevel {
   1222      0    stevel 	asmap_arg_t arg;
   1223      0    stevel 	GElf_Sym sym;
   1224      0    stevel 
   1225      0    stevel 	arg.asm_segvn_ops = NULL;
   1226      0    stevel 	arg.asm_callback = func;
   1227      0    stevel 	arg.asm_cbdata = p;
   1228      0    stevel 
   1229      0    stevel 	if (mdb_lookup_by_name("segvn_ops", &sym) == 0)
   1230      0    stevel 		arg.asm_segvn_ops = (struct seg_ops *)(uintptr_t)sym.st_value;
   1231      0    stevel 
   1232      0    stevel 	return (mdb_pwalk("seg", (mdb_walk_cb_t)asmap_step, &arg, as));
   1233      0    stevel }
   1234      0    stevel 
   1235      0    stevel /*
   1236      0    stevel  * Copy the auxv array from the given process's u-area into the provided
   1237      0    stevel  * buffer.  If the buffer is NULL, only return the size of the auxv array
   1238      0    stevel  * so the caller knows how much space will be required.
   1239      0    stevel  */
   1240      0    stevel int
   1241      0    stevel mdb_kproc_auxv(uintptr_t proc, auxv_t *auxv)
   1242      0    stevel {
   1243      0    stevel 	if (auxv != NULL) {
   1244      0    stevel 		proc_t p;
   1245      0    stevel 
   1246      0    stevel 		if (mdb_vread(&p, sizeof (p), proc) != sizeof (p))
   1247      0    stevel 			return (-1);
   1248      0    stevel 
   1249      0    stevel 		bcopy(p.p_user.u_auxv, auxv,
   1250      0    stevel 		    sizeof (auxv_t) * __KERN_NAUXV_IMPL);
   1251      0    stevel 	}
   1252      0    stevel 
   1253      0    stevel 	return (__KERN_NAUXV_IMPL);
   1254      0    stevel }
   1255      0    stevel 
   1256      0    stevel /*
   1257      0    stevel  * Given a process address, return the PID.
   1258      0    stevel  */
   1259      0    stevel pid_t
   1260      0    stevel mdb_kproc_pid(uintptr_t proc_addr)
   1261      0    stevel {
   1262      0    stevel 	struct pid pid;
   1263      0    stevel 	proc_t p;
   1264      0    stevel 
   1265      0    stevel 	if (mdb_vread(&p, sizeof (p), proc_addr) == sizeof (p) &&
   1266      0    stevel 	    mdb_vread(&pid, sizeof (pid), (uintptr_t)p.p_pidp) == sizeof (pid))
   1267      0    stevel 		return (pid.pid_id);
   1268      0    stevel 
   1269      0    stevel 	return (-1);
   1270      0    stevel }
   1271      0    stevel 
   1272      0    stevel /*
   1273      0    stevel  * Interface between the MDB kvm target and mdb_ks.  The kvm target relies
   1274      0    stevel  * on looking up and invoking these functions in mdb_ks so that dependencies
   1275      0    stevel  * on the current kernel implementation are isolated in mdb_ks.
   1276      0    stevel  */
   1277      0    stevel 
   1278      0    stevel /*
   1279      0    stevel  * Determine whether or not the thread that panicked the given kernel was a
   1280      0    stevel  * kernel thread (panic_thread->t_procp == &p0).
   1281      0    stevel  */
   1282      0    stevel void
   1283      0    stevel mdb_dump_print_content(dumphdr_t *dh, pid_t content)
   1284      0    stevel {
   1285      0    stevel 	GElf_Sym sym;
   1286      0    stevel 	uintptr_t pt;
   1287      0    stevel 	uintptr_t procp;
   1288      0    stevel 	int expcont = 0;
   1289      0    stevel 	int actcont;
   1290      0    stevel 
   1291      0    stevel 	(void) mdb_readvar(&expcont, "dump_conflags");
   1292      0    stevel 	actcont = dh->dump_flags & DF_CONTENT;
   1293      0    stevel 
   1294      0    stevel 	if (actcont == DF_ALL) {
   1295      0    stevel 		mdb_printf("dump content: all kernel and user pages\n");
   1296      0    stevel 		return;
   1297      0    stevel 	} else if (actcont == DF_CURPROC) {
   1298      0    stevel 		mdb_printf("dump content: kernel pages and pages from "
   1299      0    stevel 		    "PID %d", content);
   1300      0    stevel 		return;
   1301      0    stevel 	}
   1302      0    stevel 
   1303      0    stevel 	mdb_printf("dump content: kernel pages only\n");
   1304      0    stevel 	if (!(expcont & DF_CURPROC))
   1305      0    stevel 		return;
   1306      0    stevel 
   1307      0    stevel 	if (mdb_readvar(&pt, "panic_thread") != sizeof (pt) || pt == NULL)
   1308      0    stevel 		goto kthreadpanic_err;
   1309      0    stevel 
   1310      0    stevel 	if (mdb_vread(&procp, sizeof (procp), pt + OFFSETOF(kthread_t,
   1311      0    stevel 	    t_procp)) == -1 || procp == NULL)
   1312      0    stevel 		goto kthreadpanic_err;
   1313      0    stevel 
   1314      0    stevel 	if (mdb_lookup_by_name("p0", &sym) != 0)
   1315      0    stevel 		goto kthreadpanic_err;
   1316      0    stevel 
   1317      0    stevel 	if (procp == (uintptr_t)sym.st_value) {
   1318      0    stevel 		mdb_printf("  (curproc requested, but a kernel thread "
   1319      0    stevel 		    "panicked)\n");
   1320      0    stevel 	} else {
   1321      0    stevel 		mdb_printf("  (curproc requested, but the process that "
   1322      0    stevel 		    "panicked could not be dumped)\n");
   1323      0    stevel 	}
   1324      0    stevel 
   1325      0    stevel 	return;
   1326      0    stevel 
   1327      0    stevel kthreadpanic_err:
   1328      0    stevel 	mdb_printf("  (curproc requested, but the process that panicked could "
   1329      0    stevel 	    "not be found)\n");
   1330      0    stevel }
   1331      0    stevel 
   1332      0    stevel /*
   1333      0    stevel  * Determine the process that was saved in a `curproc' dump.  This process will
   1334      0    stevel  * be recorded as the first element in dump_pids[].
   1335      0    stevel  */
   1336      0    stevel int
   1337      0    stevel mdb_dump_find_curproc(void)
   1338      0    stevel {
   1339      0    stevel 	uintptr_t pidp;
   1340      0    stevel 	pid_t pid = -1;
   1341      0    stevel 
   1342      0    stevel 	if (mdb_readvar(&pidp, "dump_pids") == sizeof (pidp) &&
   1343      0    stevel 	    mdb_vread(&pid, sizeof (pid), pidp) == sizeof (pid) &&
   1344      0    stevel 	    pid > 0)
   1345      0    stevel 		return (pid);
   1346      0    stevel 	else
   1347      0    stevel 		return (-1);
   1348      0    stevel }
   1349      0    stevel 
   1350      0    stevel 
   1351      0    stevel /*
   1352      0    stevel  * Following three funcs extracted from sunddi.c
   1353      0    stevel  */
   1354      0    stevel 
   1355      0    stevel /*
   1356      0    stevel  * Return core address of root node of devinfo tree
   1357      0    stevel  */
   1358      0    stevel static uintptr_t
   1359      0    stevel mdb_ddi_root_node(void)
   1360      0    stevel {
   1361      0    stevel 	uintptr_t	top_devinfo_addr;
   1362      0    stevel 
   1363      0    stevel 	/* return (top_devinfo);   */
   1364      0    stevel 	if (mdb_readvar(&top_devinfo_addr, "top_devinfo") == -1) {
   1365      0    stevel 		mdb_warn("failed to read top_devinfo");
   1366      0    stevel 		return (NULL);
   1367      0    stevel 	}
   1368      0    stevel 	return (top_devinfo_addr);
   1369      0    stevel }
   1370      0    stevel 
   1371      0    stevel /*
   1372      0    stevel  * Return the name of the devinfo node pointed at by 'dip_addr' in the buffer
   1373      0    stevel  * pointed at by 'name.'
   1374      0    stevel  *
   1375      0    stevel  * - dip_addr is a pointer to a dev_info struct in core.
   1376      0    stevel  */
   1377      0    stevel static char *
   1378      0    stevel mdb_ddi_deviname(uintptr_t dip_addr, char *name, size_t name_size)
   1379      0    stevel {
   1380      0    stevel 	uintptr_t addrname;
   1381      0    stevel 	ssize_t	length;
   1382      0    stevel 	char *local_namep = name;
   1383      0    stevel 	size_t local_name_size = name_size;
   1384      0    stevel 	struct dev_info	local_dip;
   1385      0    stevel 
   1386      0    stevel 
   1387      0    stevel 	if (dip_addr == mdb_ddi_root_node()) {
   1388      0    stevel 		if (name_size < 1) {
   1389      0    stevel 			mdb_warn("failed to get node name: buf too small\n");
   1390      0    stevel 			return (NULL);
   1391      0    stevel 		}
   1392      0    stevel 
   1393      0    stevel 		*name = '\0';
   1394      0    stevel 		return (name);
   1395      0    stevel 	}
   1396      0    stevel 
   1397      0    stevel 	if (name_size < 2) {
   1398      0    stevel 		mdb_warn("failed to get node name: buf too small\n");
   1399      0    stevel 		return (NULL);
   1400      0    stevel 	}
   1401      0    stevel 
   1402      0    stevel 	local_namep = name;
   1403      0    stevel 	*local_namep++ = '/';
   1404      0    stevel 	*local_namep = '\0';
   1405      0    stevel 	local_name_size--;
   1406      0    stevel 
   1407      0    stevel 	if (mdb_vread(&local_dip, sizeof (struct dev_info), dip_addr) == -1) {
   1408      0    stevel 		mdb_warn("failed to read devinfo struct");
   1409      0    stevel 	}
   1410      0    stevel 
   1411      0    stevel 	length = mdb_readstr(local_namep, local_name_size,
   1412      0    stevel 	    (uintptr_t)local_dip.devi_node_name);
   1413      0    stevel 	if (length == -1) {
   1414      0    stevel 		mdb_warn("failed to read node name");
   1415      0    stevel 		return (NULL);
   1416      0    stevel 	}
   1417      0    stevel 	local_namep += length;
   1418      0    stevel 	local_name_size -= length;
   1419      0    stevel 	addrname = (uintptr_t)local_dip.devi_addr;
   1420      0    stevel 
   1421      0    stevel 	if (addrname != NULL) {
   1422      0    stevel 
   1423      0    stevel 		if (local_name_size < 2) {
   1424      0    stevel 			mdb_warn("not enough room for node address string");
   1425      0    stevel 			return (name);
   1426      0    stevel 		}
   1427      0    stevel 		*local_namep++ = '@';
   1428      0    stevel 		*local_namep = '\0';
   1429      0    stevel 		local_name_size--;
   1430      0    stevel 
   1431      0    stevel 		length = mdb_readstr(local_namep, local_name_size, addrname);
   1432      0    stevel 		if (length == -1) {
   1433      0    stevel 			mdb_warn("failed to read name");
   1434      0    stevel 			return (NULL);
   1435      0    stevel 		}
   1436      0    stevel 	}
   1437      0    stevel 
   1438      0    stevel 	return (name);
   1439      0    stevel }
   1440      0    stevel 
   1441      0    stevel /*
   1442      0    stevel  * Generate the full path under the /devices dir to the device entry.
   1443      0    stevel  *
   1444      0    stevel  * dip is a pointer to a devinfo struct in core (not in local memory).
   1445      0    stevel  */
   1446      0    stevel char *
   1447      0    stevel mdb_ddi_pathname(uintptr_t dip_addr, char *path, size_t pathlen)
   1448      0    stevel {
   1449      0    stevel 	struct dev_info local_dip;
   1450      0    stevel 	uintptr_t	parent_dip;
   1451      0    stevel 	char		*bp;
   1452      0    stevel 	size_t		buf_left;
   1453      0    stevel 
   1454      0    stevel 
   1455      0    stevel 	if (dip_addr == mdb_ddi_root_node()) {
   1456      0    stevel 		*path = '\0';
   1457      0    stevel 		return (path);
   1458      0    stevel 	}
   1459      0    stevel 
   1460      0    stevel 
   1461      0    stevel 	if (mdb_vread(&local_dip, sizeof (struct dev_info), dip_addr) == -1) {
   1462      0    stevel 		mdb_warn("failed to read devinfo struct");
   1463      0    stevel 	}
   1464      0    stevel 
   1465      0    stevel 	parent_dip = (uintptr_t)local_dip.devi_parent;
   1466      0    stevel 	(void) mdb_ddi_pathname(parent_dip, path, pathlen);
   1467      0    stevel 
   1468      0    stevel 	bp = path + strlen(path);
   1469      0    stevel 	buf_left = pathlen - strlen(path);
   1470      0    stevel 	(void) mdb_ddi_deviname(dip_addr, bp, buf_left);
   1471      0    stevel 	return (path);
   1472      0    stevel }
   1473      0    stevel 
   1474      0    stevel 
   1475      0    stevel /*
   1476      0    stevel  * Read in the string value of a refstr, which is appended to the end of
   1477      0    stevel  * the structure.
   1478      0    stevel  */
   1479      0    stevel ssize_t
   1480      0    stevel mdb_read_refstr(uintptr_t refstr_addr, char *str, size_t nbytes)
   1481      0    stevel {
   1482      0    stevel 	struct refstr *r = (struct refstr *)refstr_addr;
   1483      0    stevel 
   1484      0    stevel 	return (mdb_readstr(str, nbytes, (uintptr_t)r->rs_string));
   1485      0    stevel }
   1486   2546  carlsonj 
   1487   2546  carlsonj /*
   1488   2546  carlsonj  * Chase an mblk list by b_next and return the length.
   1489   2546  carlsonj  */
   1490   2546  carlsonj int
   1491   2546  carlsonj mdb_mblk_count(const mblk_t *mb)
   1492   2546  carlsonj {
   1493   2546  carlsonj 	int count;
   1494   2546  carlsonj 	mblk_t mblk;
   1495   2546  carlsonj 
   1496   2546  carlsonj 	if (mb == NULL)
   1497   2546  carlsonj 		return (0);
   1498   2546  carlsonj 
   1499   2546  carlsonj 	count = 1;
   1500   2546  carlsonj 	while (mb->b_next != NULL) {
   1501   2546  carlsonj 		count++;
   1502   2546  carlsonj 		if (mdb_vread(&mblk, sizeof (mblk), (uintptr_t)mb->b_next) ==
   1503   2546  carlsonj 		    -1)
   1504   2546  carlsonj 			break;
   1505   2546  carlsonj 		mb = &mblk;
   1506   2546  carlsonj 	}
   1507   2546  carlsonj 	return (count);
   1508   2546  carlsonj }
   1509   2546  carlsonj 
   1510   2546  carlsonj /*
   1511   2546  carlsonj  * Write the given MAC address as a printable string in the usual colon-
   1512   2546  carlsonj  * separated format.  Assumes that buflen is at least 2.
   1513   2546  carlsonj  */
   1514   2546  carlsonj void
   1515   2546  carlsonj mdb_mac_addr(const uint8_t *addr, size_t alen, char *buf, size_t buflen)
   1516   2546  carlsonj {
   1517   2546  carlsonj 	int slen;
   1518   2546  carlsonj 
   1519   2546  carlsonj 	if (alen == 0 || buflen < 4) {
   1520   2546  carlsonj 		(void) strcpy(buf, "?");
   1521   2546  carlsonj 		return;
   1522   2546  carlsonj 	}
   1523   2546  carlsonj 	for (;;) {
   1524   2546  carlsonj 		/*
   1525   2546  carlsonj 		 * If there are more MAC address bytes available, but we won't
   1526   2546  carlsonj 		 * have any room to print them, then add "..." to the string
   1527   2546  carlsonj 		 * instead.  See below for the 'magic number' explanation.
   1528   2546  carlsonj 		 */
   1529   2546  carlsonj 		if ((alen == 2 && buflen < 6) || (alen > 2 && buflen < 7)) {
   1530   2546  carlsonj 			(void) strcpy(buf, "...");
   1531   2546  carlsonj 			break;
   1532   2546  carlsonj 		}
   1533   2546  carlsonj 		slen = mdb_snprintf(buf, buflen, "%02x", *addr++);
   1534   2546  carlsonj 		buf += slen;
   1535   2546  carlsonj 		if (--alen == 0)
   1536   2546  carlsonj 			break;
   1537   2546  carlsonj 		*buf++ = ':';
   1538   2546  carlsonj 		buflen -= slen + 1;
   1539   2546  carlsonj 		/*
   1540   2546  carlsonj 		 * At this point, based on the first 'if' statement above,
   1541   2546  carlsonj 		 * either alen == 1 and buflen >= 3, or alen > 1 and
   1542   2546  carlsonj 		 * buflen >= 4.  The first case leaves room for the final "xx"
   1543   2546  carlsonj 		 * number and trailing NUL byte.  The second leaves room for at
   1544   2546  carlsonj 		 * least "...".  Thus the apparently 'magic' numbers chosen for
   1545   2546  carlsonj 		 * that statement.
   1546   2546  carlsonj 		 */
   1547   2546  carlsonj 	}
   1548   2546  carlsonj }
   1549   2546  carlsonj 
   1550   2546  carlsonj /*
   1551   2546  carlsonj  * Produce a string that represents a DLPI primitive, or NULL if no such string
   1552   2546  carlsonj  * is possible.
   1553   2546  carlsonj  */
   1554   2546  carlsonj const char *
   1555   2546  carlsonj mdb_dlpi_prim(int prim)
   1556   2546  carlsonj {
   1557   2546  carlsonj 	switch (prim) {
   1558   2546  carlsonj 	case DL_INFO_REQ:	return ("DL_INFO_REQ");
   1559   2546  carlsonj 	case DL_INFO_ACK:	return ("DL_INFO_ACK");
   1560   2546  carlsonj 	case DL_ATTACH_REQ:	return ("DL_ATTACH_REQ");
   1561   2546  carlsonj 	case DL_DETACH_REQ:	return ("DL_DETACH_REQ");
   1562   2546  carlsonj 	case DL_BIND_REQ:	return ("DL_BIND_REQ");
   1563   2546  carlsonj 	case DL_BIND_ACK:	return ("DL_BIND_ACK");
   1564   2546  carlsonj 	case DL_UNBIND_REQ:	return ("DL_UNBIND_REQ");
   1565   2546  carlsonj 	case DL_OK_ACK:		return ("DL_OK_ACK");
   1566   2546  carlsonj 	case DL_ERROR_ACK:	return ("DL_ERROR_ACK");
   1567   2546  carlsonj 	case DL_ENABMULTI_REQ:	return ("DL_ENABMULTI_REQ");
   1568   2546  carlsonj 	case DL_DISABMULTI_REQ:	return ("DL_DISABMULTI_REQ");
   1569   2546  carlsonj 	case DL_PROMISCON_REQ:	return ("DL_PROMISCON_REQ");
   1570   2546  carlsonj 	case DL_PROMISCOFF_REQ:	return ("DL_PROMISCOFF_REQ");
   1571   2546  carlsonj 	case DL_UNITDATA_REQ:	return ("DL_UNITDATA_REQ");
   1572   2546  carlsonj 	case DL_UNITDATA_IND:	return ("DL_UNITDATA_IND");
   1573   2546  carlsonj 	case DL_UDERROR_IND:	return ("DL_UDERROR_IND");
   1574   2546  carlsonj 	case DL_PHYS_ADDR_REQ:	return ("DL_PHYS_ADDR_REQ");
   1575   2546  carlsonj 	case DL_PHYS_ADDR_ACK:	return ("DL_PHYS_ADDR_ACK");
   1576   2546  carlsonj 	case DL_SET_PHYS_ADDR_REQ:	return ("DL_SET_PHYS_ADDR_REQ");
   1577   2546  carlsonj 	case DL_NOTIFY_REQ:	return ("DL_NOTIFY_REQ");
   1578   2546  carlsonj 	case DL_NOTIFY_ACK:	return ("DL_NOTIFY_ACK");
   1579   2546  carlsonj 	case DL_NOTIFY_IND:	return ("DL_NOTIFY_IND");
   1580   9073     Cathy 	case DL_NOTIFY_CONF:	return ("DL_NOTIFY_CONF");
   1581   2546  carlsonj 	case DL_CAPABILITY_REQ:	return ("DL_CAPABILITY_REQ");
   1582   2546  carlsonj 	case DL_CAPABILITY_ACK:	return ("DL_CAPABILITY_ACK");
   1583   2546  carlsonj 	case DL_CONTROL_REQ:	return ("DL_CONTROL_REQ");
   1584   2546  carlsonj 	case DL_CONTROL_ACK:	return ("DL_CONTROL_ACK");
   1585   2546  carlsonj 	case DL_PASSIVE_REQ:	return ("DL_PASSIVE_REQ");
   1586   2546  carlsonj 	default:		return (NULL);
   1587   2546  carlsonj 	}
   1588   2546  carlsonj }
   1589  11066    rafael 
   1590  11066    rafael /*
   1591  11066    rafael  * mdb_gethrtime() returns the hires system time. This will be the timestamp at
   1592  11066    rafael  * which we dropped into, if called from, kmdb(1); the core dump's hires time
   1593  11066    rafael  * if inspecting one; or the running system's hires time if we're inspecting
   1594  11066    rafael  * a live kernel.
   1595  11066    rafael  */
   1596  11066    rafael hrtime_t
   1597  11066    rafael mdb_gethrtime(void)
   1598  11066    rafael {
   1599  11066    rafael 	uintptr_t ptr;
   1600  11066    rafael 	lbolt_info_t lbi;
   1601  11066    rafael 	hrtime_t ts;
   1602  11066    rafael 
   1603  11066    rafael #ifdef _KMDB
   1604  11066    rafael 	if (mdb_readvar(&ptr, "lb_info") == -1)
   1605  11066    rafael 		return (0);
   1606  11066    rafael 
   1607  11066    rafael 	if (mdb_vread(&lbi, sizeof (lbolt_info_t), ptr) !=
   1608  11066    rafael 	    sizeof (lbolt_info_t))
   1609  11066    rafael 		return (0);
   1610  11066    rafael 
   1611  11066    rafael 	ts = lbi.lbi_debug_ts;
   1612  11066    rafael #else
   1613  11066    rafael 	if (mdb_prop_postmortem) {
   1614  11066    rafael 		if (mdb_readvar(&ptr, "lb_info") == -1)
   1615  11066    rafael 			return (0);
   1616  11066    rafael 
   1617  11066    rafael 		if (mdb_vread(&lbi, sizeof (lbolt_info_t), ptr) !=
   1618  11066    rafael 		    sizeof (lbolt_info_t))
   1619  11066    rafael 			return (0);
   1620  11066    rafael 
   1621  11066    rafael 		ts = lbi.lbi_debug_ts;
   1622  11066    rafael 	} else {
   1623  11066    rafael 		ts = gethrtime();
   1624  11066    rafael 	}
   1625  11066    rafael #endif
   1626  11066    rafael 	return (ts);
   1627  11066    rafael }
   1628  11066    rafael 
   1629  11066    rafael /*
   1630  11066    rafael  * mdb_get_lbolt() returns the number of clock ticks since system boot.
   1631  11066    rafael  * Depending on the context in which it's called, the value will be derived
   1632  11066    rafael  * from different sources per mdb_gethrtime(). If inspecting a panicked
   1633  11066    rafael  * system, the routine returns the 'panic_lbolt64' variable from the core file.
   1634  11066    rafael  */
   1635  11066    rafael int64_t
   1636  11066    rafael mdb_get_lbolt(void)
   1637  11066    rafael {
   1638  11066    rafael 	lbolt_info_t lbi;
   1639  11066    rafael 	uintptr_t ptr;
   1640  11066    rafael 	int64_t pl;
   1641  11066    rafael 	hrtime_t ts;
   1642  11066    rafael 	int nsec;
   1643  11066    rafael 
   1644  11066    rafael 	if (mdb_readvar(&pl, "panic_lbolt64") != -1 && pl > 0)
   1645  11066    rafael 		return (pl);
   1646  11066    rafael 
   1647  11066    rafael 	/*
   1648  11066    rafael 	 * Load the time spent in kmdb, if any.
   1649  11066    rafael 	 */
   1650  11066    rafael 	if (mdb_readvar(&ptr, "lb_info") == -1)
   1651  11066    rafael 		return (0);
   1652  11066    rafael 
   1653  11066    rafael 	if (mdb_vread(&lbi, sizeof (lbolt_info_t), ptr) !=
   1654  11066    rafael 	    sizeof (lbolt_info_t))
   1655  11066    rafael 		return (0);
   1656  11066    rafael 
   1657  11066    rafael 	if ((ts = mdb_gethrtime()) <= 0)
   1658  11066    rafael 		return (0);
   1659  11066    rafael 
   1660  11066    rafael 	if (mdb_readvar(&nsec, "nsec_per_tick") == -1 || nsec == 0) {
   1661  11066    rafael 		mdb_warn("failed to read 'nsec_per_tick'");
   1662  11066    rafael 		return (-1);
   1663  11066    rafael 	}
   1664  11066    rafael 
   1665  11066    rafael 	return ((ts/nsec) - lbi.lbi_debug_time);
   1666  11066    rafael }
   1667