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