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