xref: /illumos-gate/usr/src/cmd/mdb/common/modules/genunix/genunix.c (revision 4fceebdf03eeac0d7c58a4f70cc19b00a8c40a73)
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 2007 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 #include <mdb/mdb_param.h>
29 #include <mdb/mdb_modapi.h>
30 #include <mdb/mdb_ks.h>
31 #include <mdb/mdb_ctf.h>
32 
33 #include <sys/types.h>
34 #include <sys/thread.h>
35 #include <sys/session.h>
36 #include <sys/user.h>
37 #include <sys/proc.h>
38 #include <sys/var.h>
39 #include <sys/t_lock.h>
40 #include <sys/callo.h>
41 #include <sys/priocntl.h>
42 #include <sys/class.h>
43 #include <sys/regset.h>
44 #include <sys/stack.h>
45 #include <sys/cpuvar.h>
46 #include <sys/vnode.h>
47 #include <sys/vfs.h>
48 #include <sys/flock_impl.h>
49 #include <sys/kmem_impl.h>
50 #include <sys/vmem_impl.h>
51 #include <sys/kstat.h>
52 #include <vm/seg_vn.h>
53 #include <vm/anon.h>
54 #include <vm/as.h>
55 #include <vm/seg_map.h>
56 #include <sys/dditypes.h>
57 #include <sys/ddi_impldefs.h>
58 #include <sys/sysmacros.h>
59 #include <sys/sysconf.h>
60 #include <sys/task.h>
61 #include <sys/project.h>
62 #include <sys/taskq.h>
63 #include <sys/taskq_impl.h>
64 #include <sys/errorq_impl.h>
65 #include <sys/cred_impl.h>
66 #include <sys/zone.h>
67 #include <sys/panic.h>
68 #include <regex.h>
69 #include <sys/port_impl.h>
70 
71 #include "avl.h"
72 #include "contract.h"
73 #include "cpupart_mdb.h"
74 #include "devinfo.h"
75 #include "leaky.h"
76 #include "lgrp.h"
77 #include "pg.h"
78 #include "group.h"
79 #include "list.h"
80 #include "log.h"
81 #include "kgrep.h"
82 #include "kmem.h"
83 #include "bio.h"
84 #include "streams.h"
85 #include "cyclic.h"
86 #include "findstack.h"
87 #include "ndievents.h"
88 #include "mmd.h"
89 #include "net.h"
90 #include "nvpair.h"
91 #include "ctxop.h"
92 #include "tsd.h"
93 #include "thread.h"
94 #include "memory.h"
95 #include "sobj.h"
96 #include "sysevent.h"
97 #include "rctl.h"
98 #include "tsol.h"
99 #include "typegraph.h"
100 #include "ldi.h"
101 #include "vfs.h"
102 #include "zone.h"
103 #include "modhash.h"
104 #include "mdi.h"
105 #include "fm.h"
106 
107 /*
108  * Surely this is defined somewhere...
109  */
110 #define	NINTR		16
111 
112 #ifndef STACK_BIAS
113 #define	STACK_BIAS	0
114 #endif
115 
116 static char
117 pstat2ch(uchar_t state)
118 {
119 	switch (state) {
120 		case SSLEEP: return ('S');
121 		case SRUN: return ('R');
122 		case SZOMB: return ('Z');
123 		case SIDL: return ('I');
124 		case SONPROC: return ('O');
125 		case SSTOP: return ('T');
126 		default: return ('?');
127 	}
128 }
129 
130 #define	PS_PRTTHREADS	0x1
131 #define	PS_PRTLWPS	0x2
132 #define	PS_PSARGS	0x4
133 #define	PS_TASKS	0x8
134 #define	PS_PROJECTS	0x10
135 #define	PS_ZONES	0x20
136 
137 static int
138 ps_threadprint(uintptr_t addr, const void *data, void *private)
139 {
140 	const kthread_t *t = (const kthread_t *)data;
141 	uint_t prt_flags = *((uint_t *)private);
142 
143 	static const mdb_bitmask_t t_state_bits[] = {
144 		{ "TS_FREE",	UINT_MAX,	TS_FREE		},
145 		{ "TS_SLEEP",	TS_SLEEP,	TS_SLEEP	},
146 		{ "TS_RUN",	TS_RUN,		TS_RUN		},
147 		{ "TS_ONPROC",	TS_ONPROC,	TS_ONPROC	},
148 		{ "TS_ZOMB",	TS_ZOMB,	TS_ZOMB		},
149 		{ "TS_STOPPED",	TS_STOPPED,	TS_STOPPED	},
150 		{ NULL,		0,		0		}
151 	};
152 
153 	if (prt_flags & PS_PRTTHREADS)
154 		mdb_printf("\tT  %?a <%b>\n", addr, t->t_state, t_state_bits);
155 
156 	if (prt_flags & PS_PRTLWPS)
157 		mdb_printf("\tL  %?a ID: %u\n", t->t_lwp, t->t_tid);
158 
159 	return (WALK_NEXT);
160 }
161 
162 int
163 ps(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
164 {
165 	uint_t prt_flags = 0;
166 	proc_t pr;
167 	struct pid pid, pgid, sid;
168 	sess_t session;
169 	cred_t cred;
170 	task_t tk;
171 	kproject_t pj;
172 	zone_t zn;
173 
174 	if (!(flags & DCMD_ADDRSPEC)) {
175 		if (mdb_walk_dcmd("proc", "ps", argc, argv) == -1) {
176 			mdb_warn("can't walk 'proc'");
177 			return (DCMD_ERR);
178 		}
179 		return (DCMD_OK);
180 	}
181 
182 	if (mdb_getopts(argc, argv,
183 	    'f', MDB_OPT_SETBITS, PS_PSARGS, &prt_flags,
184 	    'l', MDB_OPT_SETBITS, PS_PRTLWPS, &prt_flags,
185 	    'T', MDB_OPT_SETBITS, PS_TASKS, &prt_flags,
186 	    'P', MDB_OPT_SETBITS, PS_PROJECTS, &prt_flags,
187 	    'z', MDB_OPT_SETBITS, PS_ZONES, &prt_flags,
188 	    't', MDB_OPT_SETBITS, PS_PRTTHREADS, &prt_flags, NULL) != argc)
189 		return (DCMD_USAGE);
190 
191 	if (DCMD_HDRSPEC(flags)) {
192 		mdb_printf("%<u>%1s %6s %6s %6s %6s ",
193 		    "S", "PID", "PPID", "PGID", "SID");
194 		if (prt_flags & PS_TASKS)
195 			mdb_printf("%5s ", "TASK");
196 		if (prt_flags & PS_PROJECTS)
197 			mdb_printf("%5s ", "PROJ");
198 		if (prt_flags & PS_ZONES)
199 			mdb_printf("%5s ", "ZONE");
200 		mdb_printf("%6s %10s %?s %s%</u>\n",
201 		    "UID", "FLAGS", "ADDR", "NAME");
202 	}
203 
204 	mdb_vread(&pr, sizeof (pr), addr);
205 	mdb_vread(&pid, sizeof (pid), (uintptr_t)pr.p_pidp);
206 	mdb_vread(&pgid, sizeof (pgid), (uintptr_t)pr.p_pgidp);
207 	mdb_vread(&cred, sizeof (cred), (uintptr_t)pr.p_cred);
208 	mdb_vread(&session, sizeof (session), (uintptr_t)pr.p_sessp);
209 	mdb_vread(&sid, sizeof (sid), (uintptr_t)session.s_sidp);
210 	if (prt_flags & (PS_TASKS | PS_PROJECTS))
211 		mdb_vread(&tk, sizeof (tk), (uintptr_t)pr.p_task);
212 	if (prt_flags & PS_PROJECTS)
213 		mdb_vread(&pj, sizeof (pj), (uintptr_t)tk.tk_proj);
214 	if (prt_flags & PS_ZONES)
215 		mdb_vread(&zn, sizeof (zone_t), (uintptr_t)pr.p_zone);
216 
217 	mdb_printf("%c %6d %6d %6d %6d ",
218 	    pstat2ch(pr.p_stat), pid.pid_id, pr.p_ppid, pgid.pid_id,
219 	    sid.pid_id);
220 	if (prt_flags & PS_TASKS)
221 		mdb_printf("%5d ", tk.tk_tkid);
222 	if (prt_flags & PS_PROJECTS)
223 		mdb_printf("%5d ", pj.kpj_id);
224 	if (prt_flags & PS_ZONES)
225 		mdb_printf("%5d ", zn.zone_id);
226 	mdb_printf("%6d 0x%08x %0?p %s\n",
227 	    cred.cr_uid, pr.p_flag, addr,
228 	    (prt_flags & PS_PSARGS) ? pr.p_user.u_psargs : pr.p_user.u_comm);
229 
230 	if (prt_flags & ~PS_PSARGS)
231 		(void) mdb_pwalk("thread", ps_threadprint, &prt_flags, addr);
232 
233 	return (DCMD_OK);
234 }
235 
236 #define	PG_NEWEST	0x0001
237 #define	PG_OLDEST	0x0002
238 #define	PG_PIPE_OUT	0x0004
239 #define	PG_EXACT_MATCH	0x0008
240 
241 typedef struct pgrep_data {
242 	uint_t pg_flags;
243 	uint_t pg_psflags;
244 	uintptr_t pg_xaddr;
245 	hrtime_t pg_xstart;
246 	const char *pg_pat;
247 #ifndef _KMDB
248 	regex_t pg_reg;
249 #endif
250 } pgrep_data_t;
251 
252 /*ARGSUSED*/
253 static int
254 pgrep_cb(uintptr_t addr, const void *pdata, void *data)
255 {
256 	const proc_t *prp = pdata;
257 	pgrep_data_t *pgp = data;
258 #ifndef _KMDB
259 	regmatch_t pmatch;
260 #endif
261 
262 	/*
263 	 * kmdb doesn't have access to the reg* functions, so we fall back
264 	 * to strstr/strcmp.
265 	 */
266 #ifdef _KMDB
267 	if ((pgp->pg_flags & PG_EXACT_MATCH) ?
268 	    (strcmp(prp->p_user.u_comm, pgp->pg_pat) != 0) :
269 	    (strstr(prp->p_user.u_comm, pgp->pg_pat) == NULL))
270 		return (WALK_NEXT);
271 #else
272 	if (regexec(&pgp->pg_reg, prp->p_user.u_comm, 1, &pmatch, 0) != 0)
273 		return (WALK_NEXT);
274 
275 	if ((pgp->pg_flags & PG_EXACT_MATCH) &&
276 	    (pmatch.rm_so != 0 || prp->p_user.u_comm[pmatch.rm_eo] != '\0'))
277 		return (WALK_NEXT);
278 #endif
279 
280 	if (pgp->pg_flags & (PG_NEWEST | PG_OLDEST)) {
281 		hrtime_t start;
282 
283 		start = (hrtime_t)prp->p_user.u_start.tv_sec * NANOSEC +
284 		    prp->p_user.u_start.tv_nsec;
285 
286 		if (pgp->pg_flags & PG_NEWEST) {
287 			if (pgp->pg_xaddr == NULL || start > pgp->pg_xstart) {
288 				pgp->pg_xaddr = addr;
289 				pgp->pg_xstart = start;
290 			}
291 		} else {
292 			if (pgp->pg_xaddr == NULL || start < pgp->pg_xstart) {
293 				pgp->pg_xaddr = addr;
294 				pgp->pg_xstart = start;
295 			}
296 		}
297 
298 	} else if (pgp->pg_flags & PG_PIPE_OUT) {
299 		mdb_printf("%p\n", addr);
300 
301 	} else {
302 		if (mdb_call_dcmd("ps", addr, pgp->pg_psflags, 0, NULL) != 0) {
303 			mdb_warn("can't invoke 'ps'");
304 			return (WALK_DONE);
305 		}
306 		pgp->pg_psflags &= ~DCMD_LOOPFIRST;
307 	}
308 
309 	return (WALK_NEXT);
310 }
311 
312 /*ARGSUSED*/
313 int
314 pgrep(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
315 {
316 	pgrep_data_t pg;
317 	int i;
318 #ifndef _KMDB
319 	int err;
320 #endif
321 
322 	if (flags & DCMD_ADDRSPEC)
323 		return (DCMD_USAGE);
324 
325 	pg.pg_flags = 0;
326 	pg.pg_xaddr = 0;
327 
328 	i = mdb_getopts(argc, argv,
329 	    'n', MDB_OPT_SETBITS, PG_NEWEST, &pg.pg_flags,
330 	    'o', MDB_OPT_SETBITS, PG_OLDEST, &pg.pg_flags,
331 	    'x', MDB_OPT_SETBITS, PG_EXACT_MATCH, &pg.pg_flags,
332 	    NULL);
333 
334 	argc -= i;
335 	argv += i;
336 
337 	if (argc != 1)
338 		return (DCMD_USAGE);
339 
340 	/*
341 	 * -n and -o are mutually exclusive.
342 	 */
343 	if ((pg.pg_flags & PG_NEWEST) && (pg.pg_flags & PG_OLDEST))
344 		return (DCMD_USAGE);
345 
346 	if (argv->a_type != MDB_TYPE_STRING)
347 		return (DCMD_USAGE);
348 
349 	if (flags & DCMD_PIPE_OUT)
350 		pg.pg_flags |= PG_PIPE_OUT;
351 
352 	pg.pg_pat = argv->a_un.a_str;
353 	if (DCMD_HDRSPEC(flags))
354 		pg.pg_psflags = DCMD_ADDRSPEC | DCMD_LOOP | DCMD_LOOPFIRST;
355 	else
356 		pg.pg_psflags = DCMD_ADDRSPEC | DCMD_LOOP;
357 
358 #ifndef _KMDB
359 	if ((err = regcomp(&pg.pg_reg, pg.pg_pat, REG_EXTENDED)) != 0) {
360 		size_t nbytes;
361 		char *buf;
362 
363 		nbytes = regerror(err, &pg.pg_reg, NULL, 0);
364 		buf = mdb_alloc(nbytes + 1, UM_SLEEP | UM_GC);
365 		(void) regerror(err, &pg.pg_reg, buf, nbytes);
366 		mdb_warn("%s\n", buf);
367 
368 		return (DCMD_ERR);
369 	}
370 #endif
371 
372 	if (mdb_walk("proc", pgrep_cb, &pg) != 0) {
373 		mdb_warn("can't walk 'proc'");
374 		return (DCMD_ERR);
375 	}
376 
377 	if (pg.pg_xaddr != 0 && (pg.pg_flags & (PG_NEWEST | PG_OLDEST))) {
378 		if (pg.pg_flags & PG_PIPE_OUT) {
379 			mdb_printf("%p\n", pg.pg_xaddr);
380 		} else {
381 			if (mdb_call_dcmd("ps", pg.pg_xaddr, pg.pg_psflags,
382 			    0, NULL) != 0) {
383 				mdb_warn("can't invoke 'ps'");
384 				return (DCMD_ERR);
385 			}
386 		}
387 	}
388 
389 	return (DCMD_OK);
390 }
391 
392 int
393 task(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
394 {
395 	task_t tk;
396 	kproject_t pj;
397 
398 	if (!(flags & DCMD_ADDRSPEC)) {
399 		if (mdb_walk_dcmd("task_cache", "task", argc, argv) == -1) {
400 			mdb_warn("can't walk task_cache");
401 			return (DCMD_ERR);
402 		}
403 		return (DCMD_OK);
404 	}
405 	if (DCMD_HDRSPEC(flags)) {
406 		mdb_printf("%<u>%?s %6s %6s %6s %6s %10s%</u>\n",
407 		    "ADDR", "TASKID", "PROJID", "ZONEID", "REFCNT", "FLAGS");
408 	}
409 	if (mdb_vread(&tk, sizeof (task_t), addr) == -1) {
410 		mdb_warn("can't read task_t structure at %p", addr);
411 		return (DCMD_ERR);
412 	}
413 	if (mdb_vread(&pj, sizeof (kproject_t), (uintptr_t)tk.tk_proj) == -1) {
414 		mdb_warn("can't read project_t structure at %p", addr);
415 		return (DCMD_ERR);
416 	}
417 	mdb_printf("%0?p %6d %6d %6d %6u 0x%08x\n",
418 	    addr, tk.tk_tkid, pj.kpj_id, pj.kpj_zoneid, tk.tk_hold_count,
419 	    tk.tk_flags);
420 	return (DCMD_OK);
421 }
422 
423 int
424 project(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
425 {
426 	kproject_t pj;
427 
428 	if (!(flags & DCMD_ADDRSPEC)) {
429 		if (mdb_walk_dcmd("projects", "project", argc, argv) == -1) {
430 			mdb_warn("can't walk projects");
431 			return (DCMD_ERR);
432 		}
433 		return (DCMD_OK);
434 	}
435 	if (DCMD_HDRSPEC(flags)) {
436 		mdb_printf("%<u>%?s %6s %6s %6s%</u>\n",
437 		    "ADDR", "PROJID", "ZONEID", "REFCNT");
438 	}
439 	if (mdb_vread(&pj, sizeof (kproject_t), addr) == -1) {
440 		mdb_warn("can't read kproject_t structure at %p", addr);
441 		return (DCMD_ERR);
442 	}
443 	mdb_printf("%0?p %6d %6d %6u\n", addr, pj.kpj_id, pj.kpj_zoneid,
444 	    pj.kpj_count);
445 	return (DCMD_OK);
446 }
447 
448 /*ARGSUSED*/
449 int
450 callout(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
451 {
452 	callout_table_t	*co_ktable[CALLOUT_TABLES];
453 	int co_kfanout;
454 	callout_table_t co_table;
455 	callout_t co_callout;
456 	callout_t *co_ptr;
457 	int co_id;
458 	clock_t lbolt;
459 	int i, j, k;
460 	const char *lbolt_sym;
461 
462 	if ((flags & DCMD_ADDRSPEC) || argc != 0)
463 		return (DCMD_USAGE);
464 
465 	if (mdb_prop_postmortem)
466 		lbolt_sym = "panic_lbolt";
467 	else
468 		lbolt_sym = "lbolt";
469 
470 	if (mdb_readvar(&lbolt, lbolt_sym) == -1) {
471 		mdb_warn("failed to read '%s'", lbolt_sym);
472 		return (DCMD_ERR);
473 	}
474 
475 	if (mdb_readvar(&co_kfanout, "callout_fanout") == -1) {
476 		mdb_warn("failed to read callout_fanout");
477 		return (DCMD_ERR);
478 	}
479 
480 	if (mdb_readvar(&co_ktable, "callout_table") == -1) {
481 		mdb_warn("failed to read callout_table");
482 		return (DCMD_ERR);
483 	}
484 
485 	mdb_printf("%<u>%-24s %-?s %-?s %-?s%</u>\n",
486 	    "FUNCTION", "ARGUMENT", "ID", "TIME");
487 
488 	for (i = 0; i < CALLOUT_NTYPES; i++) {
489 		for (j = 0; j < co_kfanout; j++) {
490 
491 			co_id = CALLOUT_TABLE(i, j);
492 
493 			if (mdb_vread(&co_table, sizeof (co_table),
494 			    (uintptr_t)co_ktable[co_id]) == -1) {
495 				mdb_warn("failed to read table at %p",
496 				    (uintptr_t)co_ktable[co_id]);
497 				continue;
498 			}
499 
500 			for (k = 0; k < CALLOUT_BUCKETS; k++) {
501 				co_ptr = co_table.ct_idhash[k];
502 
503 				while (co_ptr != NULL) {
504 					mdb_vread(&co_callout,
505 					    sizeof (co_callout),
506 					    (uintptr_t)co_ptr);
507 
508 					mdb_printf("%-24a %0?p %0?lx %?lx "
509 					    "(T%+ld)\n", co_callout.c_func,
510 					    co_callout.c_arg, co_callout.c_xid,
511 					    co_callout.c_runtime,
512 					    co_callout.c_runtime - lbolt);
513 
514 					co_ptr = co_callout.c_idnext;
515 				}
516 			}
517 		}
518 	}
519 
520 	return (DCMD_OK);
521 }
522 
523 /*ARGSUSED*/
524 int
525 class(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
526 {
527 	long num_classes, i;
528 	sclass_t *class_tbl;
529 	GElf_Sym g_sclass;
530 	char class_name[PC_CLNMSZ];
531 	size_t tbl_size;
532 
533 	if (mdb_lookup_by_name("sclass", &g_sclass) == -1) {
534 		mdb_warn("failed to find symbol sclass\n");
535 		return (DCMD_ERR);
536 	}
537 
538 	tbl_size = (size_t)g_sclass.st_size;
539 	num_classes = tbl_size / (sizeof (sclass_t));
540 	class_tbl = mdb_alloc(tbl_size, UM_SLEEP | UM_GC);
541 
542 	if (mdb_readsym(class_tbl, tbl_size, "sclass") == -1) {
543 		mdb_warn("failed to read sclass");
544 		return (DCMD_ERR);
545 	}
546 
547 	mdb_printf("%<u>%4s %-10s %-24s %-24s%</u>\n", "SLOT", "NAME",
548 	    "INIT FCN", "CLASS FCN");
549 
550 	for (i = 0; i < num_classes; i++) {
551 		if (mdb_vread(class_name, sizeof (class_name),
552 		    (uintptr_t)class_tbl[i].cl_name) == -1)
553 			(void) strcpy(class_name, "???");
554 
555 		mdb_printf("%4ld %-10s %-24a %-24a\n", i, class_name,
556 		    class_tbl[i].cl_init, class_tbl[i].cl_funcs);
557 	}
558 
559 	return (DCMD_OK);
560 }
561 
562 #define	FSNAMELEN	32	/* Max len of FS name we read from vnodeops */
563 
564 int
565 vnode2path(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
566 {
567 	uintptr_t rootdir;
568 	vnode_t vn;
569 	char buf[MAXPATHLEN];
570 
571 	uint_t opt_F = FALSE;
572 
573 	if (mdb_getopts(argc, argv,
574 	    'F', MDB_OPT_SETBITS, TRUE, &opt_F, NULL) != argc)
575 		return (DCMD_USAGE);
576 
577 	if (!(flags & DCMD_ADDRSPEC)) {
578 		mdb_warn("expected explicit vnode_t address before ::\n");
579 		return (DCMD_USAGE);
580 	}
581 
582 	if (mdb_readvar(&rootdir, "rootdir") == -1) {
583 		mdb_warn("failed to read rootdir");
584 		return (DCMD_ERR);
585 	}
586 
587 	if (mdb_vnode2path(addr, buf, sizeof (buf)) == -1)
588 		return (DCMD_ERR);
589 
590 	if (*buf == '\0') {
591 		mdb_printf("??\n");
592 		return (DCMD_OK);
593 	}
594 
595 	mdb_printf("%s", buf);
596 	if (opt_F && buf[strlen(buf)-1] != '/' &&
597 	    mdb_vread(&vn, sizeof (vn), addr) == sizeof (vn))
598 		mdb_printf("%c", mdb_vtype2chr(vn.v_type, 0));
599 	mdb_printf("\n");
600 
601 	return (DCMD_OK);
602 }
603 
604 int
605 ld_walk_init(mdb_walk_state_t *wsp)
606 {
607 	wsp->walk_data = (void *)wsp->walk_addr;
608 	return (WALK_NEXT);
609 }
610 
611 int
612 ld_walk_step(mdb_walk_state_t *wsp)
613 {
614 	int status;
615 	lock_descriptor_t ld;
616 
617 	if (mdb_vread(&ld, sizeof (lock_descriptor_t), wsp->walk_addr) == -1) {
618 		mdb_warn("couldn't read lock_descriptor_t at %p\n",
619 		    wsp->walk_addr);
620 		return (WALK_ERR);
621 	}
622 
623 	status = wsp->walk_callback(wsp->walk_addr, &ld, wsp->walk_cbdata);
624 	if (status == WALK_ERR)
625 		return (WALK_ERR);
626 
627 	wsp->walk_addr = (uintptr_t)ld.l_next;
628 	if (wsp->walk_addr == (uintptr_t)wsp->walk_data)
629 		return (WALK_DONE);
630 
631 	return (status);
632 }
633 
634 int
635 lg_walk_init(mdb_walk_state_t *wsp)
636 {
637 	GElf_Sym sym;
638 
639 	if (mdb_lookup_by_name("lock_graph", &sym) == -1) {
640 		mdb_warn("failed to find symbol 'lock_graph'\n");
641 		return (WALK_ERR);
642 	}
643 
644 	wsp->walk_addr = (uintptr_t)sym.st_value;
645 	wsp->walk_data = (void *)(uintptr_t)(sym.st_value + sym.st_size);
646 
647 	return (WALK_NEXT);
648 }
649 
650 typedef struct lg_walk_data {
651 	uintptr_t startaddr;
652 	mdb_walk_cb_t callback;
653 	void *data;
654 } lg_walk_data_t;
655 
656 /*
657  * We can't use ::walk lock_descriptor directly, because the head of each graph
658  * is really a dummy lock.  Rather than trying to dynamically determine if this
659  * is a dummy node or not, we just filter out the initial element of the
660  * list.
661  */
662 static int
663 lg_walk_cb(uintptr_t addr, const void *data, void *priv)
664 {
665 	lg_walk_data_t *lw = priv;
666 
667 	if (addr != lw->startaddr)
668 		return (lw->callback(addr, data, lw->data));
669 
670 	return (WALK_NEXT);
671 }
672 
673 int
674 lg_walk_step(mdb_walk_state_t *wsp)
675 {
676 	graph_t *graph;
677 	lg_walk_data_t lw;
678 
679 	if (wsp->walk_addr >= (uintptr_t)wsp->walk_data)
680 		return (WALK_DONE);
681 
682 	if (mdb_vread(&graph, sizeof (graph), wsp->walk_addr) == -1) {
683 		mdb_warn("failed to read graph_t at %p", wsp->walk_addr);
684 		return (WALK_ERR);
685 	}
686 
687 	wsp->walk_addr += sizeof (graph);
688 
689 	if (graph == NULL)
690 		return (WALK_NEXT);
691 
692 	lw.callback = wsp->walk_callback;
693 	lw.data = wsp->walk_cbdata;
694 
695 	lw.startaddr = (uintptr_t)&(graph->active_locks);
696 	if (mdb_pwalk("lock_descriptor", lg_walk_cb, &lw, lw.startaddr)) {
697 		mdb_warn("couldn't walk lock_descriptor at %p\n", lw.startaddr);
698 		return (WALK_ERR);
699 	}
700 
701 	lw.startaddr = (uintptr_t)&(graph->sleeping_locks);
702 	if (mdb_pwalk("lock_descriptor", lg_walk_cb, &lw, lw.startaddr)) {
703 		mdb_warn("couldn't walk lock_descriptor at %p\n", lw.startaddr);
704 		return (WALK_ERR);
705 	}
706 
707 	return (WALK_NEXT);
708 }
709 
710 /*
711  * The space available for the path corresponding to the locked vnode depends
712  * on whether we are printing 32- or 64-bit addresses.
713  */
714 #ifdef _LP64
715 #define	LM_VNPATHLEN	20
716 #else
717 #define	LM_VNPATHLEN	30
718 #endif
719 
720 /*ARGSUSED*/
721 static int
722 lminfo_cb(uintptr_t addr, const void *data, void *priv)
723 {
724 	const lock_descriptor_t *ld = data;
725 	char buf[LM_VNPATHLEN];
726 	proc_t p;
727 
728 	mdb_printf("%-?p %2s %04x %6d %-16s %-?p ",
729 	    addr, ld->l_type == F_RDLCK ? "RD" :
730 	    ld->l_type == F_WRLCK ? "WR" : "??",
731 	    ld->l_state, ld->l_flock.l_pid,
732 	    ld->l_flock.l_pid == 0 ? "<kernel>" :
733 	    mdb_pid2proc(ld->l_flock.l_pid, &p) == NULL ?
734 	    "<defunct>" : p.p_user.u_comm,
735 	    ld->l_vnode);
736 
737 	mdb_vnode2path((uintptr_t)ld->l_vnode, buf,
738 	    sizeof (buf));
739 	mdb_printf("%s\n", buf);
740 
741 	return (WALK_NEXT);
742 }
743 
744 /*ARGSUSED*/
745 int
746 lminfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
747 {
748 	if (DCMD_HDRSPEC(flags))
749 		mdb_printf("%<u>%-?s %2s %4s %6s %-16s %-?s %s%</u>\n",
750 		    "ADDR", "TP", "FLAG", "PID", "COMM", "VNODE", "PATH");
751 
752 	return (mdb_pwalk("lock_graph", lminfo_cb, NULL, NULL));
753 }
754 
755 /*ARGSUSED*/
756 int
757 seg(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
758 {
759 	struct seg s;
760 
761 	if (argc != 0)
762 		return (DCMD_USAGE);
763 
764 	if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) {
765 		mdb_printf("%<u>%?s %?s %?s %?s %s%</u>\n",
766 		    "SEG", "BASE", "SIZE", "DATA", "OPS");
767 	}
768 
769 	if (mdb_vread(&s, sizeof (s), addr) == -1) {
770 		mdb_warn("failed to read seg at %p", addr);
771 		return (DCMD_ERR);
772 	}
773 
774 	mdb_printf("%?p %?p %?lx %?p %a\n",
775 	    addr, s.s_base, s.s_size, s.s_data, s.s_ops);
776 
777 	return (DCMD_OK);
778 }
779 
780 /*ARGSUSED*/
781 static int
782 pmap_walk_anon(uintptr_t addr, const struct anon *anon, int *nres)
783 {
784 	uintptr_t pp =
785 	    mdb_vnode2page((uintptr_t)anon->an_vp, (uintptr_t)anon->an_off);
786 
787 	if (pp != NULL)
788 		(*nres)++;
789 
790 	return (WALK_NEXT);
791 }
792 
793 static int
794 pmap_walk_seg(uintptr_t addr, const struct seg *seg, uintptr_t segvn)
795 {
796 
797 	mdb_printf("%0?p %0?p %7dk", addr, seg->s_base, seg->s_size / 1024);
798 
799 	if (segvn == (uintptr_t)seg->s_ops) {
800 		struct segvn_data svn;
801 		int nres = 0;
802 
803 		(void) mdb_vread(&svn, sizeof (svn), (uintptr_t)seg->s_data);
804 
805 		if (svn.amp == NULL) {
806 			mdb_printf(" %8s", "");
807 			goto drive_on;
808 		}
809 
810 		/*
811 		 * We've got an amp for this segment; walk through
812 		 * the amp, and determine mappings.
813 		 */
814 		if (mdb_pwalk("anon", (mdb_walk_cb_t)pmap_walk_anon,
815 		    &nres, (uintptr_t)svn.amp) == -1)
816 			mdb_warn("failed to walk anon (amp=%p)", svn.amp);
817 
818 		mdb_printf(" %7dk", (nres * PAGESIZE) / 1024);
819 drive_on:
820 
821 		if (svn.vp != NULL) {
822 			char buf[29];
823 
824 			mdb_vnode2path((uintptr_t)svn.vp, buf, sizeof (buf));
825 			mdb_printf(" %s", buf);
826 		} else
827 			mdb_printf(" [ anon ]");
828 	}
829 
830 	mdb_printf("\n");
831 	return (WALK_NEXT);
832 }
833 
834 static int
835 pmap_walk_seg_quick(uintptr_t addr, const struct seg *seg, uintptr_t segvn)
836 {
837 	mdb_printf("%0?p %0?p %7dk", addr, seg->s_base, seg->s_size / 1024);
838 
839 	if (segvn == (uintptr_t)seg->s_ops) {
840 		struct segvn_data svn;
841 
842 		(void) mdb_vread(&svn, sizeof (svn), (uintptr_t)seg->s_data);
843 
844 		if (svn.vp != NULL) {
845 			mdb_printf(" %0?p", svn.vp);
846 		} else {
847 			mdb_printf(" [ anon ]");
848 		}
849 	}
850 
851 	mdb_printf("\n");
852 	return (WALK_NEXT);
853 }
854 
855 /*ARGSUSED*/
856 int
857 pmap(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
858 {
859 	uintptr_t segvn;
860 	proc_t proc;
861 	uint_t quick = FALSE;
862 	mdb_walk_cb_t cb = (mdb_walk_cb_t)pmap_walk_seg;
863 
864 	GElf_Sym sym;
865 
866 	if (!(flags & DCMD_ADDRSPEC))
867 		return (DCMD_USAGE);
868 
869 	if (mdb_getopts(argc, argv,
870 	    'q', MDB_OPT_SETBITS, TRUE, &quick, NULL) != argc)
871 		return (DCMD_USAGE);
872 
873 	if (mdb_vread(&proc, sizeof (proc), addr) == -1) {
874 		mdb_warn("failed to read proc at %p", addr);
875 		return (DCMD_ERR);
876 	}
877 
878 	if (mdb_lookup_by_name("segvn_ops", &sym) == 0)
879 		segvn = (uintptr_t)sym.st_value;
880 	else
881 		segvn = NULL;
882 
883 	mdb_printf("%?s %?s %8s ", "SEG", "BASE", "SIZE");
884 
885 	if (quick) {
886 		mdb_printf("VNODE\n");
887 		cb = (mdb_walk_cb_t)pmap_walk_seg_quick;
888 	} else {
889 		mdb_printf("%8s %s\n", "RES", "PATH");
890 	}
891 
892 	if (mdb_pwalk("seg", cb, (void *)segvn, (uintptr_t)proc.p_as) == -1) {
893 		mdb_warn("failed to walk segments of as %p", proc.p_as);
894 		return (DCMD_ERR);
895 	}
896 
897 	return (DCMD_OK);
898 }
899 
900 typedef struct anon_walk_data {
901 	uintptr_t *aw_levone;
902 	uintptr_t *aw_levtwo;
903 	int aw_nlevone;
904 	int aw_levone_ndx;
905 	int aw_levtwo_ndx;
906 	struct anon_map aw_amp;
907 	struct anon_hdr aw_ahp;
908 } anon_walk_data_t;
909 
910 int
911 anon_walk_init(mdb_walk_state_t *wsp)
912 {
913 	anon_walk_data_t *aw;
914 
915 	if (wsp->walk_addr == NULL) {
916 		mdb_warn("anon walk doesn't support global walks\n");
917 		return (WALK_ERR);
918 	}
919 
920 	aw = mdb_alloc(sizeof (anon_walk_data_t), UM_SLEEP);
921 
922 	if (mdb_vread(&aw->aw_amp, sizeof (aw->aw_amp), wsp->walk_addr) == -1) {
923 		mdb_warn("failed to read anon map at %p", wsp->walk_addr);
924 		mdb_free(aw, sizeof (anon_walk_data_t));
925 		return (WALK_ERR);
926 	}
927 
928 	if (mdb_vread(&aw->aw_ahp, sizeof (aw->aw_ahp),
929 	    (uintptr_t)(aw->aw_amp.ahp)) == -1) {
930 		mdb_warn("failed to read anon hdr ptr at %p", aw->aw_amp.ahp);
931 		mdb_free(aw, sizeof (anon_walk_data_t));
932 		return (WALK_ERR);
933 	}
934 
935 	if (aw->aw_ahp.size <= ANON_CHUNK_SIZE ||
936 	    (aw->aw_ahp.flags & ANON_ALLOC_FORCE)) {
937 		aw->aw_nlevone = aw->aw_ahp.size;
938 		aw->aw_levtwo = NULL;
939 	} else {
940 		aw->aw_nlevone =
941 		    (aw->aw_ahp.size + ANON_CHUNK_OFF) >> ANON_CHUNK_SHIFT;
942 		aw->aw_levtwo =
943 		    mdb_zalloc(ANON_CHUNK_SIZE * sizeof (uintptr_t), UM_SLEEP);
944 	}
945 
946 	aw->aw_levone =
947 	    mdb_alloc(aw->aw_nlevone * sizeof (uintptr_t), UM_SLEEP);
948 
949 	aw->aw_levone_ndx = 0;
950 	aw->aw_levtwo_ndx = 0;
951 
952 	mdb_vread(aw->aw_levone, aw->aw_nlevone * sizeof (uintptr_t),
953 	    (uintptr_t)aw->aw_ahp.array_chunk);
954 
955 	if (aw->aw_levtwo != NULL) {
956 		while (aw->aw_levone[aw->aw_levone_ndx] == NULL) {
957 			aw->aw_levone_ndx++;
958 			if (aw->aw_levone_ndx == aw->aw_nlevone) {
959 				mdb_warn("corrupt anon; couldn't"
960 				    "find ptr to lev two map");
961 				goto out;
962 			}
963 		}
964 
965 		mdb_vread(aw->aw_levtwo, ANON_CHUNK_SIZE * sizeof (uintptr_t),
966 		    aw->aw_levone[aw->aw_levone_ndx]);
967 	}
968 
969 out:
970 	wsp->walk_data = aw;
971 	return (0);
972 }
973 
974 int
975 anon_walk_step(mdb_walk_state_t *wsp)
976 {
977 	int status;
978 	anon_walk_data_t *aw = (anon_walk_data_t *)wsp->walk_data;
979 	struct anon anon;
980 	uintptr_t anonptr;
981 
982 again:
983 	/*
984 	 * Once we've walked through level one, we're done.
985 	 */
986 	if (aw->aw_levone_ndx == aw->aw_nlevone)
987 		return (WALK_DONE);
988 
989 	if (aw->aw_levtwo == NULL) {
990 		anonptr = aw->aw_levone[aw->aw_levone_ndx];
991 		aw->aw_levone_ndx++;
992 	} else {
993 		anonptr = aw->aw_levtwo[aw->aw_levtwo_ndx];
994 		aw->aw_levtwo_ndx++;
995 
996 		if (aw->aw_levtwo_ndx == ANON_CHUNK_SIZE) {
997 			aw->aw_levtwo_ndx = 0;
998 
999 			do {
1000 				aw->aw_levone_ndx++;
1001 
1002 				if (aw->aw_levone_ndx == aw->aw_nlevone)
1003 					return (WALK_DONE);
1004 			} while (aw->aw_levone[aw->aw_levone_ndx] == NULL);
1005 
1006 			mdb_vread(aw->aw_levtwo, ANON_CHUNK_SIZE *
1007 			    sizeof (uintptr_t),
1008 			    aw->aw_levone[aw->aw_levone_ndx]);
1009 		}
1010 	}
1011 
1012 	if (anonptr != NULL) {
1013 		mdb_vread(&anon, sizeof (anon), anonptr);
1014 		status = wsp->walk_callback(anonptr, &anon, wsp->walk_cbdata);
1015 	} else
1016 		goto again;
1017 
1018 	return (status);
1019 }
1020 
1021 void
1022 anon_walk_fini(mdb_walk_state_t *wsp)
1023 {
1024 	anon_walk_data_t *aw = (anon_walk_data_t *)wsp->walk_data;
1025 
1026 	if (aw->aw_levtwo != NULL)
1027 		mdb_free(aw->aw_levtwo, ANON_CHUNK_SIZE * sizeof (uintptr_t));
1028 
1029 	mdb_free(aw->aw_levone, aw->aw_nlevone * sizeof (uintptr_t));
1030 	mdb_free(aw, sizeof (anon_walk_data_t));
1031 }
1032 
1033 /*ARGSUSED*/
1034 int
1035 whereopen_fwalk(uintptr_t addr, struct file *f, uintptr_t *target)
1036 {
1037 	if ((uintptr_t)f->f_vnode == *target) {
1038 		mdb_printf("file %p\n", addr);
1039 		*target = NULL;
1040 	}
1041 
1042 	return (WALK_NEXT);
1043 }
1044 
1045 /*ARGSUSED*/
1046 int
1047 whereopen_pwalk(uintptr_t addr, void *ignored, uintptr_t *target)
1048 {
1049 	uintptr_t t = *target;
1050 
1051 	if (mdb_pwalk("file", (mdb_walk_cb_t)whereopen_fwalk, &t, addr) == -1) {
1052 		mdb_warn("couldn't file walk proc %p", addr);
1053 		return (WALK_ERR);
1054 	}
1055 
1056 	if (t == NULL)
1057 		mdb_printf("%p\n", addr);
1058 
1059 	return (WALK_NEXT);
1060 }
1061 
1062 /*ARGSUSED*/
1063 int
1064 whereopen(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1065 {
1066 	uintptr_t target = addr;
1067 
1068 	if (!(flags & DCMD_ADDRSPEC) || addr == NULL)
1069 		return (DCMD_USAGE);
1070 
1071 	if (mdb_walk("proc", (mdb_walk_cb_t)whereopen_pwalk, &target) == -1) {
1072 		mdb_warn("can't proc walk");
1073 		return (DCMD_ERR);
1074 	}
1075 
1076 	return (DCMD_OK);
1077 }
1078 
1079 typedef struct datafmt {
1080 	char	*hdr1;
1081 	char	*hdr2;
1082 	char	*dashes;
1083 	char	*fmt;
1084 } datafmt_t;
1085 
1086 static datafmt_t kmemfmt[] = {
1087 	{ "cache                    ", "name                     ",
1088 	"-------------------------", "%-25s "				},
1089 	{ "   buf",	"  size",	"------",	"%6u "		},
1090 	{ "   buf",	"in use",	"------",	"%6u "		},
1091 	{ "   buf",	" total",	"------",	"%6u "		},
1092 	{ "   memory",	"   in use",	"---------",	"%9u "		},
1093 	{ "    alloc",	"  succeed",	"---------",	"%9u "		},
1094 	{ "alloc",	" fail",	"-----",	"%5u "		},
1095 	{ NULL,		NULL,		NULL,		NULL		}
1096 };
1097 
1098 static datafmt_t vmemfmt[] = {
1099 	{ "vmem                     ", "name                     ",
1100 	"-------------------------", "%-*s "				},
1101 	{ "   memory",	"   in use",	"---------",	"%9llu "	},
1102 	{ "    memory",	"     total",	"----------",	"%10llu "	},
1103 	{ "   memory",	"   import",	"---------",	"%9llu "	},
1104 	{ "    alloc",	"  succeed",	"---------",	"%9llu "	},
1105 	{ "alloc",	" fail",	"-----",	"%5llu "	},
1106 	{ NULL,		NULL,		NULL,		NULL		}
1107 };
1108 
1109 /*ARGSUSED*/
1110 static int
1111 kmastat_cpu_avail(uintptr_t addr, const kmem_cpu_cache_t *ccp, int *avail)
1112 {
1113 	if (ccp->cc_rounds > 0)
1114 		*avail += ccp->cc_rounds;
1115 	if (ccp->cc_prounds > 0)
1116 		*avail += ccp->cc_prounds;
1117 
1118 	return (WALK_NEXT);
1119 }
1120 
1121 /*ARGSUSED*/
1122 static int
1123 kmastat_cpu_alloc(uintptr_t addr, const kmem_cpu_cache_t *ccp, int *alloc)
1124 {
1125 	*alloc += ccp->cc_alloc;
1126 
1127 	return (WALK_NEXT);
1128 }
1129 
1130 /*ARGSUSED*/
1131 static int
1132 kmastat_slab_avail(uintptr_t addr, const kmem_slab_t *sp, int *avail)
1133 {
1134 	*avail += sp->slab_chunks - sp->slab_refcnt;
1135 
1136 	return (WALK_NEXT);
1137 }
1138 
1139 typedef struct kmastat_vmem {
1140 	uintptr_t kv_addr;
1141 	struct kmastat_vmem *kv_next;
1142 	int kv_meminuse;
1143 	int kv_alloc;
1144 	int kv_fail;
1145 } kmastat_vmem_t;
1146 
1147 typedef struct kmastat_args {
1148 	kmastat_vmem_t **ka_kvpp;
1149 	uint_t ka_shift;
1150 } kmastat_args_t;
1151 
1152 static int
1153 kmastat_cache(uintptr_t addr, const kmem_cache_t *cp, kmastat_args_t *kap)
1154 {
1155 	kmastat_vmem_t **kvp = kap->ka_kvpp;
1156 	kmastat_vmem_t *kv;
1157 	datafmt_t *dfp = kmemfmt;
1158 	int magsize;
1159 
1160 	int avail, alloc, total;
1161 	size_t meminuse = (cp->cache_slab_create - cp->cache_slab_destroy) *
1162 	    cp->cache_slabsize;
1163 
1164 	mdb_walk_cb_t cpu_avail = (mdb_walk_cb_t)kmastat_cpu_avail;
1165 	mdb_walk_cb_t cpu_alloc = (mdb_walk_cb_t)kmastat_cpu_alloc;
1166 	mdb_walk_cb_t slab_avail = (mdb_walk_cb_t)kmastat_slab_avail;
1167 
1168 	magsize = kmem_get_magsize(cp);
1169 
1170 	alloc = cp->cache_slab_alloc + cp->cache_full.ml_alloc;
1171 	avail = cp->cache_full.ml_total * magsize;
1172 	total = cp->cache_buftotal;
1173 
1174 	(void) mdb_pwalk("kmem_cpu_cache", cpu_alloc, &alloc, addr);
1175 	(void) mdb_pwalk("kmem_cpu_cache", cpu_avail, &avail, addr);
1176 	(void) mdb_pwalk("kmem_slab_partial", slab_avail, &avail, addr);
1177 
1178 	for (kv = *kvp; kv != NULL; kv = kv->kv_next) {
1179 		if (kv->kv_addr == (uintptr_t)cp->cache_arena)
1180 			goto out;
1181 	}
1182 
1183 	kv = mdb_zalloc(sizeof (kmastat_vmem_t), UM_SLEEP | UM_GC);
1184 	kv->kv_next = *kvp;
1185 	kv->kv_addr = (uintptr_t)cp->cache_arena;
1186 	*kvp = kv;
1187 out:
1188 	kv->kv_meminuse += meminuse;
1189 	kv->kv_alloc += alloc;
1190 	kv->kv_fail += cp->cache_alloc_fail;
1191 
1192 	mdb_printf((dfp++)->fmt, cp->cache_name);
1193 	mdb_printf((dfp++)->fmt, cp->cache_bufsize);
1194 	mdb_printf((dfp++)->fmt, total - avail);
1195 	mdb_printf((dfp++)->fmt, total);
1196 	mdb_printf((dfp++)->fmt, meminuse >> kap->ka_shift);
1197 	mdb_printf((dfp++)->fmt, alloc);
1198 	mdb_printf((dfp++)->fmt, cp->cache_alloc_fail);
1199 	mdb_printf("\n");
1200 
1201 	return (WALK_NEXT);
1202 }
1203 
1204 static int
1205 kmastat_vmem_totals(uintptr_t addr, const vmem_t *v, kmastat_args_t *kap)
1206 {
1207 	kmastat_vmem_t *kv = *kap->ka_kvpp;
1208 	size_t len;
1209 
1210 	while (kv != NULL && kv->kv_addr != addr)
1211 		kv = kv->kv_next;
1212 
1213 	if (kv == NULL || kv->kv_alloc == 0)
1214 		return (WALK_NEXT);
1215 
1216 	len = MIN(17, strlen(v->vm_name));
1217 
1218 	mdb_printf("Total [%s]%*s %6s %6s %6s %9u %9u %5u\n", v->vm_name,
1219 	    17 - len, "", "", "", "",
1220 	    kv->kv_meminuse >> kap->ka_shift, kv->kv_alloc, kv->kv_fail);
1221 
1222 	return (WALK_NEXT);
1223 }
1224 
1225 /*ARGSUSED*/
1226 static int
1227 kmastat_vmem(uintptr_t addr, const vmem_t *v, const uint_t *shiftp)
1228 {
1229 	datafmt_t *dfp = vmemfmt;
1230 	const vmem_kstat_t *vkp = &v->vm_kstat;
1231 	uintptr_t paddr;
1232 	vmem_t parent;
1233 	int ident = 0;
1234 
1235 	for (paddr = (uintptr_t)v->vm_source; paddr != NULL; ident += 4) {
1236 		if (mdb_vread(&parent, sizeof (parent), paddr) == -1) {
1237 			mdb_warn("couldn't trace %p's ancestry", addr);
1238 			ident = 0;
1239 			break;
1240 		}
1241 		paddr = (uintptr_t)parent.vm_source;
1242 	}
1243 
1244 	mdb_printf("%*s", ident, "");
1245 	mdb_printf((dfp++)->fmt, 25 - ident, v->vm_name);
1246 	mdb_printf((dfp++)->fmt, vkp->vk_mem_inuse.value.ui64);
1247 	mdb_printf((dfp++)->fmt, vkp->vk_mem_total.value.ui64);
1248 	mdb_printf((dfp++)->fmt, vkp->vk_mem_import.value.ui64 >> *shiftp);
1249 	mdb_printf((dfp++)->fmt, vkp->vk_alloc.value.ui64);
1250 	mdb_printf((dfp++)->fmt, vkp->vk_fail.value.ui64);
1251 
1252 	mdb_printf("\n");
1253 
1254 	return (WALK_NEXT);
1255 }
1256 
1257 /*ARGSUSED*/
1258 int
1259 kmastat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1260 {
1261 	kmastat_vmem_t *kv = NULL;
1262 	datafmt_t *dfp;
1263 	kmastat_args_t ka;
1264 
1265 	ka.ka_shift = 0;
1266 	if (mdb_getopts(argc, argv,
1267 	    'k', MDB_OPT_SETBITS, 10, &ka.ka_shift,
1268 	    'm', MDB_OPT_SETBITS, 20, &ka.ka_shift,
1269 	    'g', MDB_OPT_SETBITS, 30, &ka.ka_shift, NULL) != argc)
1270 		return (DCMD_USAGE);
1271 
1272 	for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++)
1273 		mdb_printf("%s ", dfp->hdr1);
1274 	mdb_printf("\n");
1275 
1276 	for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++)
1277 		mdb_printf("%s ", dfp->hdr2);
1278 	mdb_printf("\n");
1279 
1280 	for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++)
1281 		mdb_printf("%s ", dfp->dashes);
1282 	mdb_printf("\n");
1283 
1284 	ka.ka_kvpp = &kv;
1285 	if (mdb_walk("kmem_cache", (mdb_walk_cb_t)kmastat_cache, &ka) == -1) {
1286 		mdb_warn("can't walk 'kmem_cache'");
1287 		return (DCMD_ERR);
1288 	}
1289 
1290 	for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++)
1291 		mdb_printf("%s ", dfp->dashes);
1292 	mdb_printf("\n");
1293 
1294 	if (mdb_walk("vmem", (mdb_walk_cb_t)kmastat_vmem_totals, &ka) == -1) {
1295 		mdb_warn("can't walk 'vmem'");
1296 		return (DCMD_ERR);
1297 	}
1298 
1299 	for (dfp = kmemfmt; dfp->hdr1 != NULL; dfp++)
1300 		mdb_printf("%s ", dfp->dashes);
1301 	mdb_printf("\n");
1302 
1303 	mdb_printf("\n");
1304 
1305 	for (dfp = vmemfmt; dfp->hdr1 != NULL; dfp++)
1306 		mdb_printf("%s ", dfp->hdr1);
1307 	mdb_printf("\n");
1308 
1309 	for (dfp = vmemfmt; dfp->hdr1 != NULL; dfp++)
1310 		mdb_printf("%s ", dfp->hdr2);
1311 	mdb_printf("\n");
1312 
1313 	for (dfp = vmemfmt; dfp->hdr1 != NULL; dfp++)
1314 		mdb_printf("%s ", dfp->dashes);
1315 	mdb_printf("\n");
1316 
1317 	if (mdb_walk("vmem", (mdb_walk_cb_t)kmastat_vmem, &ka.ka_shift) == -1) {
1318 		mdb_warn("can't walk 'vmem'");
1319 		return (DCMD_ERR);
1320 	}
1321 
1322 	for (dfp = vmemfmt; dfp->hdr1 != NULL; dfp++)
1323 		mdb_printf("%s ", dfp->dashes);
1324 	mdb_printf("\n");
1325 	return (DCMD_OK);
1326 }
1327 
1328 /*
1329  * Our ::kgrep callback scans the entire kernel VA space (kas).  kas is made
1330  * up of a set of 'struct seg's.  We could just scan each seg en masse, but
1331  * unfortunately, a few of the segs are both large and sparse, so we could
1332  * spend quite a bit of time scanning VAs which have no backing pages.
1333  *
1334  * So for the few very sparse segs, we skip the segment itself, and scan
1335  * the allocated vmem_segs in the vmem arena which manages that part of kas.
1336  * Currently, we do this for:
1337  *
1338  *	SEG		VMEM ARENA
1339  *	kvseg		heap_arena
1340  *	kvseg32		heap32_arena
1341  *	kvseg_core	heap_core_arena
1342  *
1343  * In addition, we skip the segkpm segment in its entirety, since it is very
1344  * sparse, and contains no new kernel data.
1345  */
1346 typedef struct kgrep_walk_data {
1347 	kgrep_cb_func *kg_cb;
1348 	void *kg_cbdata;
1349 	uintptr_t kg_kvseg;
1350 	uintptr_t kg_kvseg32;
1351 	uintptr_t kg_kvseg_core;
1352 	uintptr_t kg_segkpm;
1353 	uintptr_t kg_heap_lp_base;
1354 	uintptr_t kg_heap_lp_end;
1355 } kgrep_walk_data_t;
1356 
1357 static int
1358 kgrep_walk_seg(uintptr_t addr, const struct seg *seg, kgrep_walk_data_t *kg)
1359 {
1360 	uintptr_t base = (uintptr_t)seg->s_base;
1361 
1362 	if (addr == kg->kg_kvseg || addr == kg->kg_kvseg32 ||
1363 	    addr == kg->kg_kvseg_core)
1364 		return (WALK_NEXT);
1365 
1366 	if ((uintptr_t)seg->s_ops == kg->kg_segkpm)
1367 		return (WALK_NEXT);
1368 
1369 	return (kg->kg_cb(base, base + seg->s_size, kg->kg_cbdata));
1370 }
1371 
1372 /*ARGSUSED*/
1373 static int
1374 kgrep_walk_vseg(uintptr_t addr, const vmem_seg_t *seg, kgrep_walk_data_t *kg)
1375 {
1376 	/*
1377 	 * skip large page heap address range - it is scanned by walking
1378 	 * allocated vmem_segs in the heap_lp_arena
1379 	 */
1380 	if (seg->vs_start == kg->kg_heap_lp_base &&
1381 	    seg->vs_end == kg->kg_heap_lp_end)
1382 		return (WALK_NEXT);
1383 
1384 	return (kg->kg_cb(seg->vs_start, seg->vs_end, kg->kg_cbdata));
1385 }
1386 
1387 /*ARGSUSED*/
1388 static int
1389 kgrep_xwalk_vseg(uintptr_t addr, const vmem_seg_t *seg, kgrep_walk_data_t *kg)
1390 {
1391 	return (kg->kg_cb(seg->vs_start, seg->vs_end, kg->kg_cbdata));
1392 }
1393 
1394 static int
1395 kgrep_walk_vmem(uintptr_t addr, const vmem_t *vmem, kgrep_walk_data_t *kg)
1396 {
1397 	mdb_walk_cb_t walk_vseg = (mdb_walk_cb_t)kgrep_walk_vseg;
1398 
1399 	if (strcmp(vmem->vm_name, "heap") != 0 &&
1400 	    strcmp(vmem->vm_name, "heap32") != 0 &&
1401 	    strcmp(vmem->vm_name, "heap_core") != 0 &&
1402 	    strcmp(vmem->vm_name, "heap_lp") != 0)
1403 		return (WALK_NEXT);
1404 
1405 	if (strcmp(vmem->vm_name, "heap_lp") == 0)
1406 		walk_vseg = (mdb_walk_cb_t)kgrep_xwalk_vseg;
1407 
1408 	if (mdb_pwalk("vmem_alloc", walk_vseg, kg, addr) == -1) {
1409 		mdb_warn("couldn't walk vmem_alloc for vmem %p", addr);
1410 		return (WALK_ERR);
1411 	}
1412 
1413 	return (WALK_NEXT);
1414 }
1415 
1416 int
1417 kgrep_subr(kgrep_cb_func *cb, void *cbdata)
1418 {
1419 	GElf_Sym kas, kvseg, kvseg32, kvseg_core, segkpm;
1420 	kgrep_walk_data_t kg;
1421 
1422 	if (mdb_get_state() == MDB_STATE_RUNNING) {
1423 		mdb_warn("kgrep can only be run on a system "
1424 		    "dump or under kmdb; see dumpadm(1M)\n");
1425 		return (DCMD_ERR);
1426 	}
1427 
1428 	if (mdb_lookup_by_name("kas", &kas) == -1) {
1429 		mdb_warn("failed to locate 'kas' symbol\n");
1430 		return (DCMD_ERR);
1431 	}
1432 
1433 	if (mdb_lookup_by_name("kvseg", &kvseg) == -1) {
1434 		mdb_warn("failed to locate 'kvseg' symbol\n");
1435 		return (DCMD_ERR);
1436 	}
1437 
1438 	if (mdb_lookup_by_name("kvseg32", &kvseg32) == -1) {
1439 		mdb_warn("failed to locate 'kvseg32' symbol\n");
1440 		return (DCMD_ERR);
1441 	}
1442 
1443 	if (mdb_lookup_by_name("kvseg_core", &kvseg_core) == -1) {
1444 		mdb_warn("failed to locate 'kvseg_core' symbol\n");
1445 		return (DCMD_ERR);
1446 	}
1447 
1448 	if (mdb_lookup_by_name("segkpm_ops", &segkpm) == -1) {
1449 		mdb_warn("failed to locate 'segkpm_ops' symbol\n");
1450 		return (DCMD_ERR);
1451 	}
1452 
1453 	if (mdb_readvar(&kg.kg_heap_lp_base, "heap_lp_base") == -1) {
1454 		mdb_warn("failed to read 'heap_lp_base'\n");
1455 		return (DCMD_ERR);
1456 	}
1457 
1458 	if (mdb_readvar(&kg.kg_heap_lp_end, "heap_lp_end") == -1) {
1459 		mdb_warn("failed to read 'heap_lp_end'\n");
1460 		return (DCMD_ERR);
1461 	}
1462 
1463 	kg.kg_cb = cb;
1464 	kg.kg_cbdata = cbdata;
1465 	kg.kg_kvseg = (uintptr_t)kvseg.st_value;
1466 	kg.kg_kvseg32 = (uintptr_t)kvseg32.st_value;
1467 	kg.kg_kvseg_core = (uintptr_t)kvseg_core.st_value;
1468 	kg.kg_segkpm = (uintptr_t)segkpm.st_value;
1469 
1470 	if (mdb_pwalk("seg", (mdb_walk_cb_t)kgrep_walk_seg,
1471 	    &kg, kas.st_value) == -1) {
1472 		mdb_warn("failed to walk kas segments");
1473 		return (DCMD_ERR);
1474 	}
1475 
1476 	if (mdb_walk("vmem", (mdb_walk_cb_t)kgrep_walk_vmem, &kg) == -1) {
1477 		mdb_warn("failed to walk heap/heap32 vmem arenas");
1478 		return (DCMD_ERR);
1479 	}
1480 
1481 	return (DCMD_OK);
1482 }
1483 
1484 size_t
1485 kgrep_subr_pagesize(void)
1486 {
1487 	return (PAGESIZE);
1488 }
1489 
1490 typedef struct file_walk_data {
1491 	struct uf_entry *fw_flist;
1492 	int fw_flistsz;
1493 	int fw_ndx;
1494 	int fw_nofiles;
1495 } file_walk_data_t;
1496 
1497 int
1498 file_walk_init(mdb_walk_state_t *wsp)
1499 {
1500 	file_walk_data_t *fw;
1501 	proc_t p;
1502 
1503 	if (wsp->walk_addr == NULL) {
1504 		mdb_warn("file walk doesn't support global walks\n");
1505 		return (WALK_ERR);
1506 	}
1507 
1508 	fw = mdb_alloc(sizeof (file_walk_data_t), UM_SLEEP);
1509 
1510 	if (mdb_vread(&p, sizeof (p), wsp->walk_addr) == -1) {
1511 		mdb_free(fw, sizeof (file_walk_data_t));
1512 		mdb_warn("failed to read proc structure at %p", wsp->walk_addr);
1513 		return (WALK_ERR);
1514 	}
1515 
1516 	if (p.p_user.u_finfo.fi_nfiles == 0) {
1517 		mdb_free(fw, sizeof (file_walk_data_t));
1518 		return (WALK_DONE);
1519 	}
1520 
1521 	fw->fw_nofiles = p.p_user.u_finfo.fi_nfiles;
1522 	fw->fw_flistsz = sizeof (struct uf_entry) * fw->fw_nofiles;
1523 	fw->fw_flist = mdb_alloc(fw->fw_flistsz, UM_SLEEP);
1524 
1525 	if (mdb_vread(fw->fw_flist, fw->fw_flistsz,
1526 	    (uintptr_t)p.p_user.u_finfo.fi_list) == -1) {
1527 		mdb_warn("failed to read file array at %p",
1528 		    p.p_user.u_finfo.fi_list);
1529 		mdb_free(fw->fw_flist, fw->fw_flistsz);
1530 		mdb_free(fw, sizeof (file_walk_data_t));
1531 		return (WALK_ERR);
1532 	}
1533 
1534 	fw->fw_ndx = 0;
1535 	wsp->walk_data = fw;
1536 
1537 	return (WALK_NEXT);
1538 }
1539 
1540 int
1541 file_walk_step(mdb_walk_state_t *wsp)
1542 {
1543 	file_walk_data_t *fw = (file_walk_data_t *)wsp->walk_data;
1544 	struct file file;
1545 	uintptr_t fp;
1546 
1547 again:
1548 	if (fw->fw_ndx == fw->fw_nofiles)
1549 		return (WALK_DONE);
1550 
1551 	if ((fp = (uintptr_t)fw->fw_flist[fw->fw_ndx++].uf_file) == NULL)
1552 		goto again;
1553 
1554 	(void) mdb_vread(&file, sizeof (file), (uintptr_t)fp);
1555 	return (wsp->walk_callback(fp, &file, wsp->walk_cbdata));
1556 }
1557 
1558 int
1559 allfile_walk_step(mdb_walk_state_t *wsp)
1560 {
1561 	file_walk_data_t *fw = (file_walk_data_t *)wsp->walk_data;
1562 	struct file file;
1563 	uintptr_t fp;
1564 
1565 	if (fw->fw_ndx == fw->fw_nofiles)
1566 		return (WALK_DONE);
1567 
1568 	if ((fp = (uintptr_t)fw->fw_flist[fw->fw_ndx++].uf_file) != NULL)
1569 		(void) mdb_vread(&file, sizeof (file), (uintptr_t)fp);
1570 	else
1571 		bzero(&file, sizeof (file));
1572 
1573 	return (wsp->walk_callback(fp, &file, wsp->walk_cbdata));
1574 }
1575 
1576 void
1577 file_walk_fini(mdb_walk_state_t *wsp)
1578 {
1579 	file_walk_data_t *fw = (file_walk_data_t *)wsp->walk_data;
1580 
1581 	mdb_free(fw->fw_flist, fw->fw_flistsz);
1582 	mdb_free(fw, sizeof (file_walk_data_t));
1583 }
1584 
1585 int
1586 port_walk_init(mdb_walk_state_t *wsp)
1587 {
1588 	if (wsp->walk_addr == NULL) {
1589 		mdb_warn("port walk doesn't support global walks\n");
1590 		return (WALK_ERR);
1591 	}
1592 
1593 	if (mdb_layered_walk("file", wsp) == -1) {
1594 		mdb_warn("couldn't walk 'file'");
1595 		return (WALK_ERR);
1596 	}
1597 	return (WALK_NEXT);
1598 }
1599 
1600 int
1601 port_walk_step(mdb_walk_state_t *wsp)
1602 {
1603 	struct vnode	vn;
1604 	uintptr_t	vp;
1605 	uintptr_t	pp;
1606 	struct port	port;
1607 
1608 	vp = (uintptr_t)((struct file *)wsp->walk_layer)->f_vnode;
1609 	if (mdb_vread(&vn, sizeof (vn), vp) == -1) {
1610 		mdb_warn("failed to read vnode_t at %p", vp);
1611 		return (WALK_ERR);
1612 	}
1613 	if (vn.v_type != VPORT)
1614 		return (WALK_NEXT);
1615 
1616 	pp = (uintptr_t)vn.v_data;
1617 	if (mdb_vread(&port, sizeof (port), pp) == -1) {
1618 		mdb_warn("failed to read port_t at %p", pp);
1619 		return (WALK_ERR);
1620 	}
1621 	return (wsp->walk_callback(pp, &port, wsp->walk_cbdata));
1622 }
1623 
1624 typedef struct portev_walk_data {
1625 	list_node_t	*pev_node;
1626 	list_node_t	*pev_last;
1627 	size_t		pev_offset;
1628 } portev_walk_data_t;
1629 
1630 int
1631 portev_walk_init(mdb_walk_state_t *wsp)
1632 {
1633 	portev_walk_data_t *pevd;
1634 	struct port	port;
1635 	struct vnode	vn;
1636 	struct list	*list;
1637 	uintptr_t	vp;
1638 
1639 	if (wsp->walk_addr == NULL) {
1640 		mdb_warn("portev walk doesn't support global walks\n");
1641 		return (WALK_ERR);
1642 	}
1643 
1644 	pevd = mdb_alloc(sizeof (portev_walk_data_t), UM_SLEEP);
1645 
1646 	if (mdb_vread(&port, sizeof (port), wsp->walk_addr) == -1) {
1647 		mdb_free(pevd, sizeof (portev_walk_data_t));
1648 		mdb_warn("failed to read port structure at %p", wsp->walk_addr);
1649 		return (WALK_ERR);
1650 	}
1651 
1652 	vp = (uintptr_t)port.port_vnode;
1653 	if (mdb_vread(&vn, sizeof (vn), vp) == -1) {
1654 		mdb_free(pevd, sizeof (portev_walk_data_t));
1655 		mdb_warn("failed to read vnode_t at %p", vp);
1656 		return (WALK_ERR);
1657 	}
1658 
1659 	if (vn.v_type != VPORT) {
1660 		mdb_free(pevd, sizeof (portev_walk_data_t));
1661 		mdb_warn("input address (%p) does not point to an event port",
1662 		    wsp->walk_addr);
1663 		return (WALK_ERR);
1664 	}
1665 
1666 	if (port.port_queue.portq_nent == 0) {
1667 		mdb_free(pevd, sizeof (portev_walk_data_t));
1668 		return (WALK_DONE);
1669 	}
1670 	list = &port.port_queue.portq_list;
1671 	pevd->pev_offset = list->list_offset;
1672 	pevd->pev_last = list->list_head.list_prev;
1673 	pevd->pev_node = list->list_head.list_next;
1674 	wsp->walk_data = pevd;
1675 	return (WALK_NEXT);
1676 }
1677 
1678 int
1679 portev_walk_step(mdb_walk_state_t *wsp)
1680 {
1681 	portev_walk_data_t	*pevd;
1682 	struct port_kevent	ev;
1683 	uintptr_t		evp;
1684 
1685 	pevd = (portev_walk_data_t *)wsp->walk_data;
1686 
1687 	if (pevd->pev_last == NULL)
1688 		return (WALK_DONE);
1689 	if (pevd->pev_node == pevd->pev_last)
1690 		pevd->pev_last = NULL;		/* last round */
1691 
1692 	evp = ((uintptr_t)(((char *)pevd->pev_node) - pevd->pev_offset));
1693 	if (mdb_vread(&ev, sizeof (ev), evp) == -1) {
1694 		mdb_warn("failed to read port_kevent at %p", evp);
1695 		return (WALK_DONE);
1696 	}
1697 	pevd->pev_node = ev.portkev_node.list_next;
1698 	return (wsp->walk_callback(evp, &ev, wsp->walk_cbdata));
1699 }
1700 
1701 void
1702 portev_walk_fini(mdb_walk_state_t *wsp)
1703 {
1704 	portev_walk_data_t *pevd = (portev_walk_data_t *)wsp->walk_data;
1705 
1706 	if (pevd != NULL)
1707 		mdb_free(pevd, sizeof (portev_walk_data_t));
1708 }
1709 
1710 typedef struct proc_walk_data {
1711 	uintptr_t *pw_stack;
1712 	int pw_depth;
1713 	int pw_max;
1714 } proc_walk_data_t;
1715 
1716 int
1717 proc_walk_init(mdb_walk_state_t *wsp)
1718 {
1719 	GElf_Sym sym;
1720 	proc_walk_data_t *pw;
1721 
1722 	if (wsp->walk_addr == NULL) {
1723 		if (mdb_lookup_by_name("p0", &sym) == -1) {
1724 			mdb_warn("failed to read 'practive'");
1725 			return (WALK_ERR);
1726 		}
1727 		wsp->walk_addr = (uintptr_t)sym.st_value;
1728 	}
1729 
1730 	pw = mdb_zalloc(sizeof (proc_walk_data_t), UM_SLEEP);
1731 
1732 	if (mdb_readvar(&pw->pw_max, "nproc") == -1) {
1733 		mdb_warn("failed to read 'nproc'");
1734 		mdb_free(pw, sizeof (pw));
1735 		return (WALK_ERR);
1736 	}
1737 
1738 	pw->pw_stack = mdb_alloc(pw->pw_max * sizeof (uintptr_t), UM_SLEEP);
1739 	wsp->walk_data = pw;
1740 
1741 	return (WALK_NEXT);
1742 }
1743 
1744 int
1745 proc_walk_step(mdb_walk_state_t *wsp)
1746 {
1747 	proc_walk_data_t *pw = wsp->walk_data;
1748 	uintptr_t addr = wsp->walk_addr;
1749 	uintptr_t cld, sib;
1750 
1751 	int status;
1752 	proc_t pr;
1753 
1754 	if (mdb_vread(&pr, sizeof (proc_t), addr) == -1) {
1755 		mdb_warn("failed to read proc at %p", addr);
1756 		return (WALK_DONE);
1757 	}
1758 
1759 	cld = (uintptr_t)pr.p_child;
1760 	sib = (uintptr_t)pr.p_sibling;
1761 
1762 	if (pw->pw_depth > 0 && addr == pw->pw_stack[pw->pw_depth - 1]) {
1763 		pw->pw_depth--;
1764 		goto sib;
1765 	}
1766 
1767 	status = wsp->walk_callback(addr, &pr, wsp->walk_cbdata);
1768 
1769 	if (status != WALK_NEXT)
1770 		return (status);
1771 
1772 	if ((wsp->walk_addr = cld) != NULL) {
1773 		if (mdb_vread(&pr, sizeof (proc_t), cld) == -1) {
1774 			mdb_warn("proc %p has invalid p_child %p; skipping\n",
1775 			    addr, cld);
1776 			goto sib;
1777 		}
1778 
1779 		pw->pw_stack[pw->pw_depth++] = addr;
1780 
1781 		if (pw->pw_depth == pw->pw_max) {
1782 			mdb_warn("depth %d exceeds max depth; try again\n",
1783 			    pw->pw_depth);
1784 			return (WALK_DONE);
1785 		}
1786 		return (WALK_NEXT);
1787 	}
1788 
1789 sib:
1790 	/*
1791 	 * We know that p0 has no siblings, and if another starting proc
1792 	 * was given, we don't want to walk its siblings anyway.
1793 	 */
1794 	if (pw->pw_depth == 0)
1795 		return (WALK_DONE);
1796 
1797 	if (sib != NULL && mdb_vread(&pr, sizeof (proc_t), sib) == -1) {
1798 		mdb_warn("proc %p has invalid p_sibling %p; skipping\n",
1799 		    addr, sib);
1800 		sib = NULL;
1801 	}
1802 
1803 	if ((wsp->walk_addr = sib) == NULL) {
1804 		if (pw->pw_depth > 0) {
1805 			wsp->walk_addr = pw->pw_stack[pw->pw_depth - 1];
1806 			return (WALK_NEXT);
1807 		}
1808 		return (WALK_DONE);
1809 	}
1810 
1811 	return (WALK_NEXT);
1812 }
1813 
1814 void
1815 proc_walk_fini(mdb_walk_state_t *wsp)
1816 {
1817 	proc_walk_data_t *pw = wsp->walk_data;
1818 
1819 	mdb_free(pw->pw_stack, pw->pw_max * sizeof (uintptr_t));
1820 	mdb_free(pw, sizeof (proc_walk_data_t));
1821 }
1822 
1823 int
1824 task_walk_init(mdb_walk_state_t *wsp)
1825 {
1826 	task_t task;
1827 
1828 	if (mdb_vread(&task, sizeof (task_t), wsp->walk_addr) == -1) {
1829 		mdb_warn("failed to read task at %p", wsp->walk_addr);
1830 		return (WALK_ERR);
1831 	}
1832 	wsp->walk_addr = (uintptr_t)task.tk_memb_list;
1833 	wsp->walk_data = task.tk_memb_list;
1834 	return (WALK_NEXT);
1835 }
1836 
1837 int
1838 task_walk_step(mdb_walk_state_t *wsp)
1839 {
1840 	proc_t proc;
1841 	int status;
1842 
1843 	if (mdb_vread(&proc, sizeof (proc_t), wsp->walk_addr) == -1) {
1844 		mdb_warn("failed to read proc at %p", wsp->walk_addr);
1845 		return (WALK_DONE);
1846 	}
1847 
1848 	status = wsp->walk_callback(wsp->walk_addr, NULL, wsp->walk_cbdata);
1849 
1850 	if (proc.p_tasknext == wsp->walk_data)
1851 		return (WALK_DONE);
1852 
1853 	wsp->walk_addr = (uintptr_t)proc.p_tasknext;
1854 	return (status);
1855 }
1856 
1857 int
1858 project_walk_init(mdb_walk_state_t *wsp)
1859 {
1860 	if (wsp->walk_addr == NULL) {
1861 		if (mdb_readvar(&wsp->walk_addr, "proj0p") == -1) {
1862 			mdb_warn("failed to read 'proj0p'");
1863 			return (WALK_ERR);
1864 		}
1865 	}
1866 	wsp->walk_data = (void *)wsp->walk_addr;
1867 	return (WALK_NEXT);
1868 }
1869 
1870 int
1871 project_walk_step(mdb_walk_state_t *wsp)
1872 {
1873 	uintptr_t addr = wsp->walk_addr;
1874 	kproject_t pj;
1875 	int status;
1876 
1877 	if (mdb_vread(&pj, sizeof (kproject_t), addr) == -1) {
1878 		mdb_warn("failed to read project at %p", addr);
1879 		return (WALK_DONE);
1880 	}
1881 	status = wsp->walk_callback(addr, &pj, wsp->walk_cbdata);
1882 	if (status != WALK_NEXT)
1883 		return (status);
1884 	wsp->walk_addr = (uintptr_t)pj.kpj_next;
1885 	if ((void *)wsp->walk_addr == wsp->walk_data)
1886 		return (WALK_DONE);
1887 	return (WALK_NEXT);
1888 }
1889 
1890 static int
1891 generic_walk_step(mdb_walk_state_t *wsp)
1892 {
1893 	return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer,
1894 	    wsp->walk_cbdata));
1895 }
1896 
1897 int
1898 seg_walk_init(mdb_walk_state_t *wsp)
1899 {
1900 	if (wsp->walk_addr == NULL) {
1901 		mdb_warn("seg walk must begin at struct as *\n");
1902 		return (WALK_ERR);
1903 	}
1904 
1905 	/*
1906 	 * this is really just a wrapper to AVL tree walk
1907 	 */
1908 	wsp->walk_addr = (uintptr_t)&((struct as *)wsp->walk_addr)->a_segtree;
1909 	return (avl_walk_init(wsp));
1910 }
1911 
1912 static int
1913 cpu_walk_cmp(const void *l, const void *r)
1914 {
1915 	uintptr_t lhs = *((uintptr_t *)l);
1916 	uintptr_t rhs = *((uintptr_t *)r);
1917 	cpu_t lcpu, rcpu;
1918 
1919 	(void) mdb_vread(&lcpu, sizeof (lcpu), lhs);
1920 	(void) mdb_vread(&rcpu, sizeof (rcpu), rhs);
1921 
1922 	if (lcpu.cpu_id < rcpu.cpu_id)
1923 		return (-1);
1924 
1925 	if (lcpu.cpu_id > rcpu.cpu_id)
1926 		return (1);
1927 
1928 	return (0);
1929 }
1930 
1931 typedef struct cpu_walk {
1932 	uintptr_t *cw_array;
1933 	int cw_ndx;
1934 } cpu_walk_t;
1935 
1936 int
1937 cpu_walk_init(mdb_walk_state_t *wsp)
1938 {
1939 	cpu_walk_t *cw;
1940 	int max_ncpus, i = 0;
1941 	uintptr_t current, first;
1942 	cpu_t cpu, panic_cpu;
1943 	uintptr_t panicstr, addr;
1944 	GElf_Sym sym;
1945 
1946 	cw = mdb_zalloc(sizeof (cpu_walk_t), UM_SLEEP | UM_GC);
1947 
1948 	if (mdb_readvar(&max_ncpus, "max_ncpus") == -1) {
1949 		mdb_warn("failed to read 'max_ncpus'");
1950 		return (WALK_ERR);
1951 	}
1952 
1953 	if (mdb_readvar(&panicstr, "panicstr") == -1) {
1954 		mdb_warn("failed to read 'panicstr'");
1955 		return (WALK_ERR);
1956 	}
1957 
1958 	if (panicstr != NULL) {
1959 		if (mdb_lookup_by_name("panic_cpu", &sym) == -1) {
1960 			mdb_warn("failed to find 'panic_cpu'");
1961 			return (WALK_ERR);
1962 		}
1963 
1964 		addr = (uintptr_t)sym.st_value;
1965 
1966 		if (mdb_vread(&panic_cpu, sizeof (cpu_t), addr) == -1) {
1967 			mdb_warn("failed to read 'panic_cpu'");
1968 			return (WALK_ERR);
1969 		}
1970 	}
1971 
1972 	/*
1973 	 * Unfortunately, there is no platform-independent way to walk
1974 	 * CPUs in ID order.  We therefore loop through in cpu_next order,
1975 	 * building an array of CPU pointers which will subsequently be
1976 	 * sorted.
1977 	 */
1978 	cw->cw_array =
1979 	    mdb_zalloc((max_ncpus + 1) * sizeof (uintptr_t), UM_SLEEP | UM_GC);
1980 
1981 	if (mdb_readvar(&first, "cpu_list") == -1) {
1982 		mdb_warn("failed to read 'cpu_list'");
1983 		return (WALK_ERR);
1984 	}
1985 
1986 	current = first;
1987 	do {
1988 		if (mdb_vread(&cpu, sizeof (cpu), current) == -1) {
1989 			mdb_warn("failed to read cpu at %p", current);
1990 			return (WALK_ERR);
1991 		}
1992 
1993 		if (panicstr != NULL && panic_cpu.cpu_id == cpu.cpu_id) {
1994 			cw->cw_array[i++] = addr;
1995 		} else {
1996 			cw->cw_array[i++] = current;
1997 		}
1998 	} while ((current = (uintptr_t)cpu.cpu_next) != first);
1999 
2000 	qsort(cw->cw_array, i, sizeof (uintptr_t), cpu_walk_cmp);
2001 	wsp->walk_data = cw;
2002 
2003 	return (WALK_NEXT);
2004 }
2005 
2006 int
2007 cpu_walk_step(mdb_walk_state_t *wsp)
2008 {
2009 	cpu_walk_t *cw = wsp->walk_data;
2010 	cpu_t cpu;
2011 	uintptr_t addr = cw->cw_array[cw->cw_ndx++];
2012 
2013 	if (addr == NULL)
2014 		return (WALK_DONE);
2015 
2016 	if (mdb_vread(&cpu, sizeof (cpu), addr) == -1) {
2017 		mdb_warn("failed to read cpu at %p", addr);
2018 		return (WALK_DONE);
2019 	}
2020 
2021 	return (wsp->walk_callback(addr, &cpu, wsp->walk_cbdata));
2022 }
2023 
2024 typedef struct cpuinfo_data {
2025 	intptr_t cid_cpu;
2026 	uintptr_t cid_lbolt;
2027 	uintptr_t **cid_ithr;
2028 	char	cid_print_head;
2029 	char	cid_print_thr;
2030 	char	cid_print_ithr;
2031 	char	cid_print_flags;
2032 } cpuinfo_data_t;
2033 
2034 int
2035 cpuinfo_walk_ithread(uintptr_t addr, const kthread_t *thr, cpuinfo_data_t *cid)
2036 {
2037 	cpu_t c;
2038 	int id;
2039 	uint8_t pil;
2040 
2041 	if (!(thr->t_flag & T_INTR_THREAD) || thr->t_state == TS_FREE)
2042 		return (WALK_NEXT);
2043 
2044 	if (thr->t_bound_cpu == NULL) {
2045 		mdb_warn("thr %p is intr thread w/out a CPU\n", addr);
2046 		return (WALK_NEXT);
2047 	}
2048 
2049 	(void) mdb_vread(&c, sizeof (c), (uintptr_t)thr->t_bound_cpu);
2050 
2051 	if ((id = c.cpu_id) >= NCPU) {
2052 		mdb_warn("CPU %p has id (%d) greater than NCPU (%d)\n",
2053 		    thr->t_bound_cpu, id, NCPU);
2054 		return (WALK_NEXT);
2055 	}
2056 
2057 	if ((pil = thr->t_pil) >= NINTR) {
2058 		mdb_warn("thread %p has pil (%d) greater than %d\n",
2059 		    addr, pil, NINTR);
2060 		return (WALK_NEXT);
2061 	}
2062 
2063 	if (cid->cid_ithr[id][pil] != NULL) {
2064 		mdb_warn("CPU %d has multiple threads at pil %d (at least "
2065 		    "%p and %p)\n", id, pil, addr, cid->cid_ithr[id][pil]);
2066 		return (WALK_NEXT);
2067 	}
2068 
2069 	cid->cid_ithr[id][pil] = addr;
2070 
2071 	return (WALK_NEXT);
2072 }
2073 
2074 #define	CPUINFO_IDWIDTH		3
2075 #define	CPUINFO_FLAGWIDTH	9
2076 
2077 #ifdef _LP64
2078 #if defined(__amd64)
2079 #define	CPUINFO_TWIDTH		16
2080 #define	CPUINFO_CPUWIDTH	16
2081 #else
2082 #define	CPUINFO_CPUWIDTH	11
2083 #define	CPUINFO_TWIDTH		11
2084 #endif
2085 #else
2086 #define	CPUINFO_CPUWIDTH	8
2087 #define	CPUINFO_TWIDTH		8
2088 #endif
2089 
2090 #define	CPUINFO_THRDELT		(CPUINFO_IDWIDTH + CPUINFO_CPUWIDTH + 9)
2091 #define	CPUINFO_FLAGDELT	(CPUINFO_IDWIDTH + CPUINFO_CPUWIDTH + 4)
2092 #define	CPUINFO_ITHRDELT	4
2093 
2094 #define	CPUINFO_INDENT	mdb_printf("%*s", CPUINFO_THRDELT, \
2095     flagline < nflaglines ? flagbuf[flagline++] : "")
2096 
2097 int
2098 cpuinfo_walk_cpu(uintptr_t addr, const cpu_t *cpu, cpuinfo_data_t *cid)
2099 {
2100 	kthread_t t;
2101 	disp_t disp;
2102 	proc_t p;
2103 	uintptr_t pinned;
2104 	char **flagbuf;
2105 	int nflaglines = 0, flagline = 0, bspl, rval = WALK_NEXT;
2106 
2107 	const char *flags[] = {
2108 	    "RUNNING", "READY", "QUIESCED", "EXISTS",
2109 	    "ENABLE", "OFFLINE", "POWEROFF", "FROZEN",
2110 	    "SPARE", "FAULTED", NULL
2111 	};
2112 
2113 	if (cid->cid_cpu != -1) {
2114 		if (addr != cid->cid_cpu && cpu->cpu_id != cid->cid_cpu)
2115 			return (WALK_NEXT);
2116 
2117 		/*
2118 		 * Set cid_cpu to -1 to indicate that we found a matching CPU.
2119 		 */
2120 		cid->cid_cpu = -1;
2121 		rval = WALK_DONE;
2122 	}
2123 
2124 	if (cid->cid_print_head) {
2125 		mdb_printf("%3s %-*s %3s %4s %4s %3s %4s %5s %-6s %-*s %s\n",
2126 		    "ID", CPUINFO_CPUWIDTH, "ADDR", "FLG", "NRUN", "BSPL",
2127 		    "PRI", "RNRN", "KRNRN", "SWITCH", CPUINFO_TWIDTH, "THREAD",
2128 		    "PROC");
2129 		cid->cid_print_head = FALSE;
2130 	}
2131 
2132 	bspl = cpu->cpu_base_spl;
2133 
2134 	if (mdb_vread(&disp, sizeof (disp_t), (uintptr_t)cpu->cpu_disp) == -1) {
2135 		mdb_warn("failed to read disp_t at %p", cpu->cpu_disp);
2136 		return (WALK_ERR);
2137 	}
2138 
2139 	mdb_printf("%3d %0*p %3x %4d %4d ",
2140 	    cpu->cpu_id, CPUINFO_CPUWIDTH, addr, cpu->cpu_flags,
2141 	    disp.disp_nrunnable, bspl);
2142 
2143 	if (mdb_vread(&t, sizeof (t), (uintptr_t)cpu->cpu_thread) != -1) {
2144 		mdb_printf("%3d ", t.t_pri);
2145 	} else {
2146 		mdb_printf("%3s ", "-");
2147 	}
2148 
2149 	mdb_printf("%4s %5s ", cpu->cpu_runrun ? "yes" : "no",
2150 	    cpu->cpu_kprunrun ? "yes" : "no");
2151 
2152 	if (cpu->cpu_last_swtch) {
2153 		clock_t lbolt;
2154 
2155 		if (mdb_vread(&lbolt, sizeof (lbolt), cid->cid_lbolt) == -1) {
2156 			mdb_warn("failed to read lbolt at %p", cid->cid_lbolt);
2157 			return (WALK_ERR);
2158 		}
2159 		mdb_printf("t-%-4d ", lbolt - cpu->cpu_last_swtch);
2160 	} else {
2161 		mdb_printf("%-6s ", "-");
2162 	}
2163 
2164 	mdb_printf("%0*p", CPUINFO_TWIDTH, cpu->cpu_thread);
2165 
2166 	if (cpu->cpu_thread == cpu->cpu_idle_thread)
2167 		mdb_printf(" (idle)\n");
2168 	else if (cpu->cpu_thread == NULL)
2169 		mdb_printf(" -\n");
2170 	else {
2171 		if (mdb_vread(&p, sizeof (p), (uintptr_t)t.t_procp) != -1) {
2172 			mdb_printf(" %s\n", p.p_user.u_comm);
2173 		} else {
2174 			mdb_printf(" ?\n");
2175 		}
2176 	}
2177 
2178 	flagbuf = mdb_zalloc(sizeof (flags), UM_SLEEP | UM_GC);
2179 
2180 	if (cid->cid_print_flags) {
2181 		int first = 1, i, j, k;
2182 		char *s;
2183 
2184 		cid->cid_print_head = TRUE;
2185 
2186 		for (i = 1, j = 0; flags[j] != NULL; i <<= 1, j++) {
2187 			if (!(cpu->cpu_flags & i))
2188 				continue;
2189 
2190 			if (first) {
2191 				s = mdb_alloc(CPUINFO_THRDELT + 1,
2192 				    UM_GC | UM_SLEEP);
2193 
2194 				(void) mdb_snprintf(s, CPUINFO_THRDELT + 1,
2195 				    "%*s|%*s", CPUINFO_FLAGDELT, "",
2196 				    CPUINFO_THRDELT - 1 - CPUINFO_FLAGDELT, "");
2197 				flagbuf[nflaglines++] = s;
2198 			}
2199 
2200 			s = mdb_alloc(CPUINFO_THRDELT + 1, UM_GC | UM_SLEEP);
2201 			(void) mdb_snprintf(s, CPUINFO_THRDELT + 1, "%*s%*s %s",
2202 			    CPUINFO_IDWIDTH + CPUINFO_CPUWIDTH -
2203 			    CPUINFO_FLAGWIDTH, "", CPUINFO_FLAGWIDTH, flags[j],
2204 			    first ? "<--+" : "");
2205 
2206 			for (k = strlen(s); k < CPUINFO_THRDELT; k++)
2207 				s[k] = ' ';
2208 			s[k] = '\0';
2209 
2210 			flagbuf[nflaglines++] = s;
2211 			first = 0;
2212 		}
2213 	}
2214 
2215 	if (cid->cid_print_ithr) {
2216 		int i, found_one = FALSE;
2217 		int print_thr = disp.disp_nrunnable && cid->cid_print_thr;
2218 
2219 		for (i = NINTR - 1; i >= 0; i--) {
2220 			uintptr_t iaddr = cid->cid_ithr[cpu->cpu_id][i];
2221 
2222 			if (iaddr == NULL)
2223 				continue;
2224 
2225 			if (!found_one) {
2226 				found_one = TRUE;
2227 
2228 				CPUINFO_INDENT;
2229 				mdb_printf("%c%*s|\n", print_thr ? '|' : ' ',
2230 				    CPUINFO_ITHRDELT, "");
2231 
2232 				CPUINFO_INDENT;
2233 				mdb_printf("%c%*s+--> %3s %s\n",
2234 				    print_thr ? '|' : ' ', CPUINFO_ITHRDELT,
2235 				    "", "PIL", "THREAD");
2236 			}
2237 
2238 			if (mdb_vread(&t, sizeof (t), iaddr) == -1) {
2239 				mdb_warn("failed to read kthread_t at %p",
2240 				    iaddr);
2241 				return (WALK_ERR);
2242 			}
2243 
2244 			CPUINFO_INDENT;
2245 			mdb_printf("%c%*s     %3d %0*p\n",
2246 			    print_thr ? '|' : ' ', CPUINFO_ITHRDELT, "",
2247 			    t.t_pil, CPUINFO_TWIDTH, iaddr);
2248 
2249 			pinned = (uintptr_t)t.t_intr;
2250 		}
2251 
2252 		if (found_one && pinned != NULL) {
2253 			cid->cid_print_head = TRUE;
2254 			(void) strcpy(p.p_user.u_comm, "?");
2255 
2256 			if (mdb_vread(&t, sizeof (t),
2257 			    (uintptr_t)pinned) == -1) {
2258 				mdb_warn("failed to read kthread_t at %p",
2259 				    pinned);
2260 				return (WALK_ERR);
2261 			}
2262 			if (mdb_vread(&p, sizeof (p),
2263 			    (uintptr_t)t.t_procp) == -1) {
2264 				mdb_warn("failed to read proc_t at %p",
2265 				    t.t_procp);
2266 				return (WALK_ERR);
2267 			}
2268 
2269 			CPUINFO_INDENT;
2270 			mdb_printf("%c%*s     %3s %0*p %s\n",
2271 			    print_thr ? '|' : ' ', CPUINFO_ITHRDELT, "", "-",
2272 			    CPUINFO_TWIDTH, pinned,
2273 			    pinned == (uintptr_t)cpu->cpu_idle_thread ?
2274 			    "(idle)" : p.p_user.u_comm);
2275 		}
2276 	}
2277 
2278 	if (disp.disp_nrunnable && cid->cid_print_thr) {
2279 		dispq_t *dq;
2280 
2281 		int i, npri = disp.disp_npri;
2282 
2283 		dq = mdb_alloc(sizeof (dispq_t) * npri, UM_SLEEP | UM_GC);
2284 
2285 		if (mdb_vread(dq, sizeof (dispq_t) * npri,
2286 		    (uintptr_t)disp.disp_q) == -1) {
2287 			mdb_warn("failed to read dispq_t at %p", disp.disp_q);
2288 			return (WALK_ERR);
2289 		}
2290 
2291 		CPUINFO_INDENT;
2292 		mdb_printf("|\n");
2293 
2294 		CPUINFO_INDENT;
2295 		mdb_printf("+-->  %3s %-*s %s\n", "PRI",
2296 		    CPUINFO_TWIDTH, "THREAD", "PROC");
2297 
2298 		for (i = npri - 1; i >= 0; i--) {
2299 			uintptr_t taddr = (uintptr_t)dq[i].dq_first;
2300 
2301 			while (taddr != NULL) {
2302 				if (mdb_vread(&t, sizeof (t), taddr) == -1) {
2303 					mdb_warn("failed to read kthread_t "
2304 					    "at %p", taddr);
2305 					return (WALK_ERR);
2306 				}
2307 				if (mdb_vread(&p, sizeof (p),
2308 				    (uintptr_t)t.t_procp) == -1) {
2309 					mdb_warn("failed to read proc_t at %p",
2310 					    t.t_procp);
2311 					return (WALK_ERR);
2312 				}
2313 
2314 				CPUINFO_INDENT;
2315 				mdb_printf("      %3d %0*p %s\n", t.t_pri,
2316 				    CPUINFO_TWIDTH, taddr, p.p_user.u_comm);
2317 
2318 				taddr = (uintptr_t)t.t_link;
2319 			}
2320 		}
2321 		cid->cid_print_head = TRUE;
2322 	}
2323 
2324 	while (flagline < nflaglines)
2325 		mdb_printf("%s\n", flagbuf[flagline++]);
2326 
2327 	if (cid->cid_print_head)
2328 		mdb_printf("\n");
2329 
2330 	return (rval);
2331 }
2332 
2333 int
2334 cpuinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2335 {
2336 	uint_t verbose = FALSE;
2337 	cpuinfo_data_t cid;
2338 	GElf_Sym sym;
2339 	clock_t lbolt;
2340 
2341 	cid.cid_print_ithr = FALSE;
2342 	cid.cid_print_thr = FALSE;
2343 	cid.cid_print_flags = FALSE;
2344 	cid.cid_print_head = DCMD_HDRSPEC(flags) ? TRUE : FALSE;
2345 	cid.cid_cpu = -1;
2346 
2347 	if (flags & DCMD_ADDRSPEC)
2348 		cid.cid_cpu = addr;
2349 
2350 	if (mdb_getopts(argc, argv,
2351 	    'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) != argc)
2352 		return (DCMD_USAGE);
2353 
2354 	if (verbose) {
2355 		cid.cid_print_ithr = TRUE;
2356 		cid.cid_print_thr = TRUE;
2357 		cid.cid_print_flags = TRUE;
2358 		cid.cid_print_head = TRUE;
2359 	}
2360 
2361 	if (cid.cid_print_ithr) {
2362 		int i;
2363 
2364 		cid.cid_ithr = mdb_alloc(sizeof (uintptr_t **)
2365 		    * NCPU, UM_SLEEP | UM_GC);
2366 
2367 		for (i = 0; i < NCPU; i++)
2368 			cid.cid_ithr[i] = mdb_zalloc(sizeof (uintptr_t *) *
2369 			    NINTR, UM_SLEEP | UM_GC);
2370 
2371 		if (mdb_walk("thread", (mdb_walk_cb_t)cpuinfo_walk_ithread,
2372 		    &cid) == -1) {
2373 			mdb_warn("couldn't walk thread");
2374 			return (DCMD_ERR);
2375 		}
2376 	}
2377 
2378 	if (mdb_lookup_by_name("panic_lbolt", &sym) == -1) {
2379 		mdb_warn("failed to find panic_lbolt");
2380 		return (DCMD_ERR);
2381 	}
2382 
2383 	cid.cid_lbolt = (uintptr_t)sym.st_value;
2384 
2385 	if (mdb_vread(&lbolt, sizeof (lbolt), cid.cid_lbolt) == -1) {
2386 		mdb_warn("failed to read panic_lbolt");
2387 		return (DCMD_ERR);
2388 	}
2389 
2390 	if (lbolt == 0) {
2391 		if (mdb_lookup_by_name("lbolt", &sym) == -1) {
2392 			mdb_warn("failed to find lbolt");
2393 			return (DCMD_ERR);
2394 		}
2395 		cid.cid_lbolt = (uintptr_t)sym.st_value;
2396 	}
2397 
2398 	if (mdb_walk("cpu", (mdb_walk_cb_t)cpuinfo_walk_cpu, &cid) == -1) {
2399 		mdb_warn("can't walk cpus");
2400 		return (DCMD_ERR);
2401 	}
2402 
2403 	if (cid.cid_cpu != -1) {
2404 		/*
2405 		 * We didn't find this CPU when we walked through the CPUs
2406 		 * (i.e. the address specified doesn't show up in the "cpu"
2407 		 * walk).  However, the specified address may still correspond
2408 		 * to a valid cpu_t (for example, if the specified address is
2409 		 * the actual panicking cpu_t and not the cached panic_cpu).
2410 		 * Point is:  even if we didn't find it, we still want to try
2411 		 * to print the specified address as a cpu_t.
2412 		 */
2413 		cpu_t cpu;
2414 
2415 		if (mdb_vread(&cpu, sizeof (cpu), cid.cid_cpu) == -1) {
2416 			mdb_warn("%p is neither a valid CPU ID nor a "
2417 			    "valid cpu_t address\n", cid.cid_cpu);
2418 			return (DCMD_ERR);
2419 		}
2420 
2421 		(void) cpuinfo_walk_cpu(cid.cid_cpu, &cpu, &cid);
2422 	}
2423 
2424 	return (DCMD_OK);
2425 }
2426 
2427 /*ARGSUSED*/
2428 int
2429 flipone(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2430 {
2431 	int i;
2432 
2433 	if (!(flags & DCMD_ADDRSPEC))
2434 		return (DCMD_USAGE);
2435 
2436 	for (i = 0; i < sizeof (addr) * NBBY; i++)
2437 		mdb_printf("%p\n", addr ^ (1UL << i));
2438 
2439 	return (DCMD_OK);
2440 }
2441 
2442 /*
2443  * Grumble, grumble.
2444  */
2445 #define	SMAP_HASHFUNC(vp, off)	\
2446 	((((uintptr_t)(vp) >> 6) + ((uintptr_t)(vp) >> 3) + \
2447 	((off) >> MAXBSHIFT)) & smd_hashmsk)
2448 
2449 int
2450 vnode2smap(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2451 {
2452 	long smd_hashmsk;
2453 	int hash;
2454 	uintptr_t offset = 0;
2455 	struct smap smp;
2456 	uintptr_t saddr, kaddr;
2457 	uintptr_t smd_hash, smd_smap;
2458 	struct seg seg;
2459 
2460 	if (!(flags & DCMD_ADDRSPEC))
2461 		return (DCMD_USAGE);
2462 
2463 	if (mdb_readvar(&smd_hashmsk, "smd_hashmsk") == -1) {
2464 		mdb_warn("failed to read smd_hashmsk");
2465 		return (DCMD_ERR);
2466 	}
2467 
2468 	if (mdb_readvar(&smd_hash, "smd_hash") == -1) {
2469 		mdb_warn("failed to read smd_hash");
2470 		return (DCMD_ERR);
2471 	}
2472 
2473 	if (mdb_readvar(&smd_smap, "smd_smap") == -1) {
2474 		mdb_warn("failed to read smd_hash");
2475 		return (DCMD_ERR);
2476 	}
2477 
2478 	if (mdb_readvar(&kaddr, "segkmap") == -1) {
2479 		mdb_warn("failed to read segkmap");
2480 		return (DCMD_ERR);
2481 	}
2482 
2483 	if (mdb_vread(&seg, sizeof (seg), kaddr) == -1) {
2484 		mdb_warn("failed to read segkmap at %p", kaddr);
2485 		return (DCMD_ERR);
2486 	}
2487 
2488 	if (argc != 0) {
2489 		const mdb_arg_t *arg = &argv[0];
2490 
2491 		if (arg->a_type == MDB_TYPE_IMMEDIATE)
2492 			offset = arg->a_un.a_val;
2493 		else
2494 			offset = (uintptr_t)mdb_strtoull(arg->a_un.a_str);
2495 	}
2496 
2497 	hash = SMAP_HASHFUNC(addr, offset);
2498 
2499 	if (mdb_vread(&saddr, sizeof (saddr),
2500 	    smd_hash + hash * sizeof (uintptr_t)) == -1) {
2501 		mdb_warn("couldn't read smap at %p",
2502 		    smd_hash + hash * sizeof (uintptr_t));
2503 		return (DCMD_ERR);
2504 	}
2505 
2506 	do {
2507 		if (mdb_vread(&smp, sizeof (smp), saddr) == -1) {
2508 			mdb_warn("couldn't read smap at %p", saddr);
2509 			return (DCMD_ERR);
2510 		}
2511 
2512 		if ((uintptr_t)smp.sm_vp == addr && smp.sm_off == offset) {
2513 			mdb_printf("vnode %p, offs %p is smap %p, vaddr %p\n",
2514 			    addr, offset, saddr, ((saddr - smd_smap) /
2515 			    sizeof (smp)) * MAXBSIZE + seg.s_base);
2516 			return (DCMD_OK);
2517 		}
2518 
2519 		saddr = (uintptr_t)smp.sm_hash;
2520 	} while (saddr != NULL);
2521 
2522 	mdb_printf("no smap for vnode %p, offs %p\n", addr, offset);
2523 	return (DCMD_OK);
2524 }
2525 
2526 /*ARGSUSED*/
2527 int
2528 addr2smap(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2529 {
2530 	uintptr_t kaddr;
2531 	struct seg seg;
2532 	struct segmap_data sd;
2533 
2534 	if (!(flags & DCMD_ADDRSPEC))
2535 		return (DCMD_USAGE);
2536 
2537 	if (mdb_readvar(&kaddr, "segkmap") == -1) {
2538 		mdb_warn("failed to read segkmap");
2539 		return (DCMD_ERR);
2540 	}
2541 
2542 	if (mdb_vread(&seg, sizeof (seg), kaddr) == -1) {
2543 		mdb_warn("failed to read segkmap at %p", kaddr);
2544 		return (DCMD_ERR);
2545 	}
2546 
2547 	if (mdb_vread(&sd, sizeof (sd), (uintptr_t)seg.s_data) == -1) {
2548 		mdb_warn("failed to read segmap_data at %p", seg.s_data);
2549 		return (DCMD_ERR);
2550 	}
2551 
2552 	mdb_printf("%p is smap %p\n", addr,
2553 	    ((addr - (uintptr_t)seg.s_base) >> MAXBSHIFT) *
2554 	    sizeof (struct smap) + (uintptr_t)sd.smd_sm);
2555 
2556 	return (DCMD_OK);
2557 }
2558 
2559 int
2560 as2proc_walk(uintptr_t addr, const proc_t *p, struct as **asp)
2561 {
2562 	if (p->p_as == *asp)
2563 		mdb_printf("%p\n", addr);
2564 	return (WALK_NEXT);
2565 }
2566 
2567 /*ARGSUSED*/
2568 int
2569 as2proc(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2570 {
2571 	if (!(flags & DCMD_ADDRSPEC) || argc != 0)
2572 		return (DCMD_USAGE);
2573 
2574 	if (mdb_walk("proc", (mdb_walk_cb_t)as2proc_walk, &addr) == -1) {
2575 		mdb_warn("failed to walk proc");
2576 		return (DCMD_ERR);
2577 	}
2578 
2579 	return (DCMD_OK);
2580 }
2581 
2582 /*ARGSUSED*/
2583 int
2584 ptree_walk(uintptr_t addr, const proc_t *p, void *ignored)
2585 {
2586 	proc_t parent;
2587 	int ident = 0;
2588 	uintptr_t paddr;
2589 
2590 	for (paddr = (uintptr_t)p->p_parent; paddr != NULL; ident += 5) {
2591 		mdb_vread(&parent, sizeof (parent), paddr);
2592 		paddr = (uintptr_t)parent.p_parent;
2593 	}
2594 
2595 	mdb_inc_indent(ident);
2596 	mdb_printf("%0?p  %s\n", addr, p->p_user.u_comm);
2597 	mdb_dec_indent(ident);
2598 
2599 	return (WALK_NEXT);
2600 }
2601 
2602 void
2603 ptree_ancestors(uintptr_t addr, uintptr_t start)
2604 {
2605 	proc_t p;
2606 
2607 	if (mdb_vread(&p, sizeof (p), addr) == -1) {
2608 		mdb_warn("couldn't read ancestor at %p", addr);
2609 		return;
2610 	}
2611 
2612 	if (p.p_parent != NULL)
2613 		ptree_ancestors((uintptr_t)p.p_parent, start);
2614 
2615 	if (addr != start)
2616 		(void) ptree_walk(addr, &p, NULL);
2617 }
2618 
2619 /*ARGSUSED*/
2620 int
2621 ptree(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2622 {
2623 	if (!(flags & DCMD_ADDRSPEC))
2624 		addr = NULL;
2625 	else
2626 		ptree_ancestors(addr, addr);
2627 
2628 	if (mdb_pwalk("proc", (mdb_walk_cb_t)ptree_walk, NULL, addr) == -1) {
2629 		mdb_warn("couldn't walk 'proc'");
2630 		return (DCMD_ERR);
2631 	}
2632 
2633 	return (DCMD_OK);
2634 }
2635 
2636 /*ARGSUSED*/
2637 static int
2638 fd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2639 {
2640 	int fdnum;
2641 	const mdb_arg_t *argp = &argv[0];
2642 	proc_t p;
2643 	uf_entry_t uf;
2644 
2645 	if ((flags & DCMD_ADDRSPEC) == 0) {
2646 		mdb_warn("fd doesn't give global information\n");
2647 		return (DCMD_ERR);
2648 	}
2649 	if (argc != 1)
2650 		return (DCMD_USAGE);
2651 
2652 	if (argp->a_type == MDB_TYPE_IMMEDIATE)
2653 		fdnum = argp->a_un.a_val;
2654 	else
2655 		fdnum = mdb_strtoull(argp->a_un.a_str);
2656 
2657 	if (mdb_vread(&p, sizeof (struct proc), addr) == -1) {
2658 		mdb_warn("couldn't read proc_t at %p", addr);
2659 		return (DCMD_ERR);
2660 	}
2661 	if (fdnum > p.p_user.u_finfo.fi_nfiles) {
2662 		mdb_warn("process %p only has %d files open.\n",
2663 		    addr, p.p_user.u_finfo.fi_nfiles);
2664 		return (DCMD_ERR);
2665 	}
2666 	if (mdb_vread(&uf, sizeof (uf_entry_t),
2667 	    (uintptr_t)&p.p_user.u_finfo.fi_list[fdnum]) == -1) {
2668 		mdb_warn("couldn't read uf_entry_t at %p",
2669 		    &p.p_user.u_finfo.fi_list[fdnum]);
2670 		return (DCMD_ERR);
2671 	}
2672 
2673 	mdb_printf("%p\n", uf.uf_file);
2674 	return (DCMD_OK);
2675 }
2676 
2677 /*ARGSUSED*/
2678 static int
2679 pid2proc(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2680 {
2681 	pid_t pid = (pid_t)addr;
2682 
2683 	if (argc != 0)
2684 		return (DCMD_USAGE);
2685 
2686 	if ((addr = mdb_pid2proc(pid, NULL)) == NULL) {
2687 		mdb_warn("PID 0t%d not found\n", pid);
2688 		return (DCMD_ERR);
2689 	}
2690 
2691 	mdb_printf("%p\n", addr);
2692 	return (DCMD_OK);
2693 }
2694 
2695 static char *sysfile_cmd[] = {
2696 	"exclude:",
2697 	"include:",
2698 	"forceload:",
2699 	"rootdev:",
2700 	"rootfs:",
2701 	"swapdev:",
2702 	"swapfs:",
2703 	"moddir:",
2704 	"set",
2705 	"unknown",
2706 };
2707 
2708 static char *sysfile_ops[] = { "", "=", "&", "|" };
2709 
2710 /*ARGSUSED*/
2711 static int
2712 sysfile_vmem_seg(uintptr_t addr, const vmem_seg_t *vsp, void **target)
2713 {
2714 	if (vsp->vs_type == VMEM_ALLOC && (void *)vsp->vs_start == *target) {
2715 		*target = NULL;
2716 		return (WALK_DONE);
2717 	}
2718 	return (WALK_NEXT);
2719 }
2720 
2721 /*ARGSUSED*/
2722 static int
2723 sysfile(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2724 {
2725 	struct sysparam *sysp, sys;
2726 	char var[256];
2727 	char modname[256];
2728 	char val[256];
2729 	char strval[256];
2730 	vmem_t *mod_sysfile_arena;
2731 	void *straddr;
2732 
2733 	if (mdb_readvar(&sysp, "sysparam_hd") == -1) {
2734 		mdb_warn("failed to read sysparam_hd");
2735 		return (DCMD_ERR);
2736 	}
2737 
2738 	if (mdb_readvar(&mod_sysfile_arena, "mod_sysfile_arena") == -1) {
2739 		mdb_warn("failed to read mod_sysfile_arena");
2740 		return (DCMD_ERR);
2741 	}
2742 
2743 	while (sysp != NULL) {
2744 		var[0] = '\0';
2745 		val[0] = '\0';
2746 		modname[0] = '\0';
2747 		if (mdb_vread(&sys, sizeof (sys), (uintptr_t)sysp) == -1) {
2748 			mdb_warn("couldn't read sysparam %p", sysp);
2749 			return (DCMD_ERR);
2750 		}
2751 		if (sys.sys_modnam != NULL &&
2752 		    mdb_readstr(modname, 256,
2753 		    (uintptr_t)sys.sys_modnam) == -1) {
2754 			mdb_warn("couldn't read modname in %p", sysp);
2755 			return (DCMD_ERR);
2756 		}
2757 		if (sys.sys_ptr != NULL &&
2758 		    mdb_readstr(var, 256, (uintptr_t)sys.sys_ptr) == -1) {
2759 			mdb_warn("couldn't read ptr in %p", sysp);
2760 			return (DCMD_ERR);
2761 		}
2762 		if (sys.sys_op != SETOP_NONE) {
2763 			/*
2764 			 * Is this an int or a string?  We determine this
2765 			 * by checking whether straddr is contained in
2766 			 * mod_sysfile_arena.  If so, the walker will set
2767 			 * straddr to NULL.
2768 			 */
2769 			straddr = (void *)(uintptr_t)sys.sys_info;
2770 			if (sys.sys_op == SETOP_ASSIGN &&
2771 			    sys.sys_info != 0 &&
2772 			    mdb_pwalk("vmem_seg",
2773 			    (mdb_walk_cb_t)sysfile_vmem_seg, &straddr,
2774 			    (uintptr_t)mod_sysfile_arena) == 0 &&
2775 			    straddr == NULL &&
2776 			    mdb_readstr(strval, 256,
2777 			    (uintptr_t)sys.sys_info) != -1) {
2778 				(void) mdb_snprintf(val, sizeof (val), "\"%s\"",
2779 				    strval);
2780 			} else {
2781 				(void) mdb_snprintf(val, sizeof (val),
2782 				    "0x%llx [0t%llu]", sys.sys_info,
2783 				    sys.sys_info);
2784 			}
2785 		}
2786 		mdb_printf("%s %s%s%s%s%s\n", sysfile_cmd[sys.sys_type],
2787 		    modname, modname[0] == '\0' ? "" : ":",
2788 		    var, sysfile_ops[sys.sys_op], val);
2789 
2790 		sysp = sys.sys_next;
2791 	}
2792 
2793 	return (DCMD_OK);
2794 }
2795 
2796 /*
2797  * Dump a taskq_ent_t given its address.
2798  */
2799 /*ARGSUSED*/
2800 int
2801 taskq_ent(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2802 {
2803 	taskq_ent_t	taskq_ent;
2804 	GElf_Sym	sym;
2805 	char		buf[MDB_SYM_NAMLEN+1];
2806 
2807 
2808 	if (!(flags & DCMD_ADDRSPEC)) {
2809 		mdb_warn("expected explicit taskq_ent_t address before ::\n");
2810 		return (DCMD_USAGE);
2811 	}
2812 
2813 	if (mdb_vread(&taskq_ent, sizeof (taskq_ent_t), addr) == -1) {
2814 		mdb_warn("failed to read taskq_ent_t at %p", addr);
2815 		return (DCMD_ERR);
2816 	}
2817 
2818 	if (DCMD_HDRSPEC(flags)) {
2819 		mdb_printf("%<u>%-?s    %-?s    %-s%</u>\n",
2820 		"ENTRY", "ARG", "FUNCTION");
2821 	}
2822 
2823 	if (mdb_lookup_by_addr((uintptr_t)taskq_ent.tqent_func, MDB_SYM_EXACT,
2824 	    buf, sizeof (buf), &sym) == -1) {
2825 		(void) strcpy(buf, "????");
2826 	}
2827 
2828 	mdb_printf("%-?p    %-?p    %s\n", addr, taskq_ent.tqent_arg, buf);
2829 
2830 	return (DCMD_OK);
2831 }
2832 
2833 /*
2834  * Given the address of the (taskq_t) task queue head, walk the queue listing
2835  * the address of every taskq_ent_t.
2836  */
2837 int
2838 taskq_walk_init(mdb_walk_state_t *wsp)
2839 {
2840 	taskq_t	tq_head;
2841 
2842 
2843 	if (wsp->walk_addr == NULL) {
2844 		mdb_warn("start address required\n");
2845 		return (WALK_ERR);
2846 	}
2847 
2848 
2849 	/*
2850 	 * Save the address of the list head entry.  This terminates the list.
2851 	 */
2852 	wsp->walk_data = (void *)
2853 	    ((size_t)wsp->walk_addr + offsetof(taskq_t, tq_task));
2854 
2855 
2856 	/*
2857 	 * Read in taskq head, set walk_addr to point to first taskq_ent_t.
2858 	 */
2859 	if (mdb_vread((void *)&tq_head, sizeof (taskq_t), wsp->walk_addr) ==
2860 	    -1) {
2861 		mdb_warn("failed to read taskq list head at %p",
2862 		    wsp->walk_addr);
2863 	}
2864 	wsp->walk_addr = (uintptr_t)tq_head.tq_task.tqent_next;
2865 
2866 
2867 	/*
2868 	 * Check for null list (next=head)
2869 	 */
2870 	if (wsp->walk_addr == (uintptr_t)wsp->walk_data) {
2871 		return (WALK_DONE);
2872 	}
2873 
2874 	return (WALK_NEXT);
2875 }
2876 
2877 
2878 int
2879 taskq_walk_step(mdb_walk_state_t *wsp)
2880 {
2881 	taskq_ent_t	tq_ent;
2882 	int		status;
2883 
2884 
2885 	if (mdb_vread((void *)&tq_ent, sizeof (taskq_ent_t), wsp->walk_addr) ==
2886 	    -1) {
2887 		mdb_warn("failed to read taskq_ent_t at %p", wsp->walk_addr);
2888 		return (DCMD_ERR);
2889 	}
2890 
2891 	status = wsp->walk_callback(wsp->walk_addr, (void *)&tq_ent,
2892 	    wsp->walk_cbdata);
2893 
2894 	wsp->walk_addr = (uintptr_t)tq_ent.tqent_next;
2895 
2896 
2897 	/* Check if we're at the last element (next=head) */
2898 	if (wsp->walk_addr == (uintptr_t)wsp->walk_data) {
2899 		return (WALK_DONE);
2900 	}
2901 
2902 	return (status);
2903 }
2904 
2905 int
2906 didmatch(uintptr_t addr, const kthread_t *thr, kt_did_t *didp)
2907 {
2908 
2909 	if (*didp == thr->t_did) {
2910 		mdb_printf("%p\n", addr);
2911 		return (WALK_DONE);
2912 	} else
2913 		return (WALK_NEXT);
2914 }
2915 
2916 /*ARGSUSED*/
2917 int
2918 did2thread(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2919 {
2920 	const mdb_arg_t *argp = &argv[0];
2921 	kt_did_t	did;
2922 
2923 	if (argc != 1)
2924 		return (DCMD_USAGE);
2925 
2926 	did = (kt_did_t)mdb_strtoull(argp->a_un.a_str);
2927 
2928 	if (mdb_walk("thread", (mdb_walk_cb_t)didmatch, (void *)&did) == -1) {
2929 		mdb_warn("failed to walk thread");
2930 		return (DCMD_ERR);
2931 
2932 	}
2933 	return (DCMD_OK);
2934 
2935 }
2936 
2937 static int
2938 errorq_walk_init(mdb_walk_state_t *wsp)
2939 {
2940 	if (wsp->walk_addr == NULL &&
2941 	    mdb_readvar(&wsp->walk_addr, "errorq_list") == -1) {
2942 		mdb_warn("failed to read errorq_list");
2943 		return (WALK_ERR);
2944 	}
2945 
2946 	return (WALK_NEXT);
2947 }
2948 
2949 static int
2950 errorq_walk_step(mdb_walk_state_t *wsp)
2951 {
2952 	uintptr_t addr = wsp->walk_addr;
2953 	errorq_t eq;
2954 
2955 	if (addr == NULL)
2956 		return (WALK_DONE);
2957 
2958 	if (mdb_vread(&eq, sizeof (eq), addr) == -1) {
2959 		mdb_warn("failed to read errorq at %p", addr);
2960 		return (WALK_ERR);
2961 	}
2962 
2963 	wsp->walk_addr = (uintptr_t)eq.eq_next;
2964 	return (wsp->walk_callback(addr, &eq, wsp->walk_cbdata));
2965 }
2966 
2967 typedef struct eqd_walk_data {
2968 	uintptr_t *eqd_stack;
2969 	void *eqd_buf;
2970 	ulong_t eqd_qpos;
2971 	ulong_t eqd_qlen;
2972 	size_t eqd_size;
2973 } eqd_walk_data_t;
2974 
2975 /*
2976  * In order to walk the list of pending error queue elements, we push the
2977  * addresses of the corresponding data buffers in to the eqd_stack array.
2978  * The error lists are in reverse chronological order when iterating using
2979  * eqe_prev, so we then pop things off the top in eqd_walk_step so that the
2980  * walker client gets addresses in order from oldest error to newest error.
2981  */
2982 static void
2983 eqd_push_list(eqd_walk_data_t *eqdp, uintptr_t addr)
2984 {
2985 	errorq_elem_t eqe;
2986 
2987 	while (addr != NULL) {
2988 		if (mdb_vread(&eqe, sizeof (eqe), addr) != sizeof (eqe)) {
2989 			mdb_warn("failed to read errorq element at %p", addr);
2990 			break;
2991 		}
2992 
2993 		if (eqdp->eqd_qpos == eqdp->eqd_qlen) {
2994 			mdb_warn("errorq is overfull -- more than %lu "
2995 			    "elems found\n", eqdp->eqd_qlen);
2996 			break;
2997 		}
2998 
2999 		eqdp->eqd_stack[eqdp->eqd_qpos++] = (uintptr_t)eqe.eqe_data;
3000 		addr = (uintptr_t)eqe.eqe_prev;
3001 	}
3002 }
3003 
3004 static int
3005 eqd_walk_init(mdb_walk_state_t *wsp)
3006 {
3007 	eqd_walk_data_t *eqdp;
3008 	errorq_elem_t eqe, *addr;
3009 	errorq_t eq;
3010 	ulong_t i;
3011 
3012 	if (mdb_vread(&eq, sizeof (eq), wsp->walk_addr) == -1) {
3013 		mdb_warn("failed to read errorq at %p", wsp->walk_addr);
3014 		return (WALK_ERR);
3015 	}
3016 
3017 	if (eq.eq_ptail != NULL &&
3018 	    mdb_vread(&eqe, sizeof (eqe), (uintptr_t)eq.eq_ptail) == -1) {
3019 		mdb_warn("failed to read errorq element at %p", eq.eq_ptail);
3020 		return (WALK_ERR);
3021 	}
3022 
3023 	eqdp = mdb_alloc(sizeof (eqd_walk_data_t), UM_SLEEP);
3024 	wsp->walk_data = eqdp;
3025 
3026 	eqdp->eqd_stack = mdb_zalloc(sizeof (uintptr_t) * eq.eq_qlen, UM_SLEEP);
3027 	eqdp->eqd_buf = mdb_alloc(eq.eq_size, UM_SLEEP);
3028 	eqdp->eqd_qlen = eq.eq_qlen;
3029 	eqdp->eqd_qpos = 0;
3030 	eqdp->eqd_size = eq.eq_size;
3031 
3032 	/*
3033 	 * The newest elements in the queue are on the pending list, so we
3034 	 * push those on to our stack first.
3035 	 */
3036 	eqd_push_list(eqdp, (uintptr_t)eq.eq_pend);
3037 
3038 	/*
3039 	 * If eq_ptail is set, it may point to a subset of the errors on the
3040 	 * pending list in the event a casptr() failed; if ptail's data is
3041 	 * already in our stack, NULL out eq_ptail and ignore it.
3042 	 */
3043 	if (eq.eq_ptail != NULL) {
3044 		for (i = 0; i < eqdp->eqd_qpos; i++) {
3045 			if (eqdp->eqd_stack[i] == (uintptr_t)eqe.eqe_data) {
3046 				eq.eq_ptail = NULL;
3047 				break;
3048 			}
3049 		}
3050 	}
3051 
3052 	/*
3053 	 * If eq_phead is set, it has the processing list in order from oldest
3054 	 * to newest.  Use this to recompute eq_ptail as best we can and then
3055 	 * we nicely fall into eqd_push_list() of eq_ptail below.
3056 	 */
3057 	for (addr = eq.eq_phead; addr != NULL && mdb_vread(&eqe, sizeof (eqe),
3058 	    (uintptr_t)addr) == sizeof (eqe); addr = eqe.eqe_next)
3059 		eq.eq_ptail = addr;
3060 
3061 	/*
3062 	 * The oldest elements in the queue are on the processing list, subject
3063 	 * to machinations in the if-clauses above.  Push any such elements.
3064 	 */
3065 	eqd_push_list(eqdp, (uintptr_t)eq.eq_ptail);
3066 	return (WALK_NEXT);
3067 }
3068 
3069 static int
3070 eqd_walk_step(mdb_walk_state_t *wsp)
3071 {
3072 	eqd_walk_data_t *eqdp = wsp->walk_data;
3073 	uintptr_t addr;
3074 
3075 	if (eqdp->eqd_qpos == 0)
3076 		return (WALK_DONE);
3077 
3078 	addr = eqdp->eqd_stack[--eqdp->eqd_qpos];
3079 
3080 	if (mdb_vread(eqdp->eqd_buf, eqdp->eqd_size, addr) != eqdp->eqd_size) {
3081 		mdb_warn("failed to read errorq data at %p", addr);
3082 		return (WALK_ERR);
3083 	}
3084 
3085 	return (wsp->walk_callback(addr, eqdp->eqd_buf, wsp->walk_cbdata));
3086 }
3087 
3088 static void
3089 eqd_walk_fini(mdb_walk_state_t *wsp)
3090 {
3091 	eqd_walk_data_t *eqdp = wsp->walk_data;
3092 
3093 	mdb_free(eqdp->eqd_stack, sizeof (uintptr_t) * eqdp->eqd_qlen);
3094 	mdb_free(eqdp->eqd_buf, eqdp->eqd_size);
3095 	mdb_free(eqdp, sizeof (eqd_walk_data_t));
3096 }
3097 
3098 #define	EQKSVAL(eqv, what) (eqv.eq_kstat.what.value.ui64)
3099 
3100 static int
3101 errorq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3102 {
3103 	int i;
3104 	errorq_t eq;
3105 	uint_t opt_v = FALSE;
3106 
3107 	if (!(flags & DCMD_ADDRSPEC)) {
3108 		if (mdb_walk_dcmd("errorq", "errorq", argc, argv) == -1) {
3109 			mdb_warn("can't walk 'errorq'");
3110 			return (DCMD_ERR);
3111 		}
3112 		return (DCMD_OK);
3113 	}
3114 
3115 	i = mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL);
3116 	argc -= i;
3117 	argv += i;
3118 
3119 	if (argc != 0)
3120 		return (DCMD_USAGE);
3121 
3122 	if (opt_v || DCMD_HDRSPEC(flags)) {
3123 		mdb_printf("%<u>%-11s %-16s %1s %1s %1s ",
3124 		    "ADDR", "NAME", "S", "V", "N");
3125 		if (!opt_v) {
3126 			mdb_printf("%7s %7s %7s%</u>\n",
3127 			    "ACCEPT", "DROP", "LOG");
3128 		} else {
3129 			mdb_printf("%5s %6s %6s %3s %16s%</u>\n",
3130 			    "KSTAT", "QLEN", "SIZE", "IPL", "FUNC");
3131 		}
3132 	}
3133 
3134 	if (mdb_vread(&eq, sizeof (eq), addr) != sizeof (eq)) {
3135 		mdb_warn("failed to read errorq at %p", addr);
3136 		return (DCMD_ERR);
3137 	}
3138 
3139 	mdb_printf("%-11p %-16s %c %c %c ", addr, eq.eq_name,
3140 	    (eq.eq_flags & ERRORQ_ACTIVE) ? '+' : '-',
3141 	    (eq.eq_flags & ERRORQ_VITAL) ? '!' : ' ',
3142 	    (eq.eq_flags & ERRORQ_NVLIST) ? '*' : ' ');
3143 
3144 	if (!opt_v) {
3145 		mdb_printf("%7llu %7llu %7llu\n",
3146 		    EQKSVAL(eq, eqk_dispatched) + EQKSVAL(eq, eqk_committed),
3147 		    EQKSVAL(eq, eqk_dropped) + EQKSVAL(eq, eqk_reserve_fail) +
3148 		    EQKSVAL(eq, eqk_commit_fail), EQKSVAL(eq, eqk_logged));
3149 	} else {
3150 		mdb_printf("%5s %6lu %6lu %3u %a\n",
3151 		    "  |  ", eq.eq_qlen, eq.eq_size, eq.eq_ipl, eq.eq_func);
3152 		mdb_printf("%38s\n%41s"
3153 		    "%12s %llu\n"
3154 		    "%53s %llu\n"
3155 		    "%53s %llu\n"
3156 		    "%53s %llu\n"
3157 		    "%53s %llu\n"
3158 		    "%53s %llu\n"
3159 		    "%53s %llu\n"
3160 		    "%53s %llu\n\n",
3161 		    "|", "+-> ",
3162 		    "DISPATCHED",	EQKSVAL(eq, eqk_dispatched),
3163 		    "DROPPED",		EQKSVAL(eq, eqk_dropped),
3164 		    "LOGGED",		EQKSVAL(eq, eqk_logged),
3165 		    "RESERVED",		EQKSVAL(eq, eqk_reserved),
3166 		    "RESERVE FAIL",	EQKSVAL(eq, eqk_reserve_fail),
3167 		    "COMMITTED",	EQKSVAL(eq, eqk_committed),
3168 		    "COMMIT FAIL",	EQKSVAL(eq, eqk_commit_fail),
3169 		    "CANCELLED",	EQKSVAL(eq, eqk_cancelled));
3170 	}
3171 
3172 	return (DCMD_OK);
3173 }
3174 
3175 /*ARGSUSED*/
3176 static int
3177 panicinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3178 {
3179 	cpu_t panic_cpu;
3180 	kthread_t *panic_thread;
3181 	void *panicbuf;
3182 	panic_data_t *pd;
3183 	int i, n;
3184 
3185 	if (!mdb_prop_postmortem) {
3186 		mdb_warn("panicinfo can only be run on a system "
3187 		    "dump; see dumpadm(1M)\n");
3188 		return (DCMD_ERR);
3189 	}
3190 
3191 	if (flags & DCMD_ADDRSPEC || argc != 0)
3192 		return (DCMD_USAGE);
3193 
3194 	if (mdb_readsym(&panic_cpu, sizeof (cpu_t), "panic_cpu") == -1)
3195 		mdb_warn("failed to read 'panic_cpu'");
3196 	else
3197 		mdb_printf("%16s %?d\n", "cpu", panic_cpu.cpu_id);
3198 
3199 	if (mdb_readvar(&panic_thread, "panic_thread") == -1)
3200 		mdb_warn("failed to read 'panic_thread'");
3201 	else
3202 		mdb_printf("%16s %?p\n", "thread", panic_thread);
3203 
3204 	panicbuf = mdb_alloc(PANICBUFSIZE, UM_SLEEP);
3205 	pd = (panic_data_t *)panicbuf;
3206 
3207 	if (mdb_readsym(panicbuf, PANICBUFSIZE, "panicbuf") == -1 ||
3208 	    pd->pd_version != PANICBUFVERS) {
3209 		mdb_warn("failed to read 'panicbuf'");
3210 		mdb_free(panicbuf, PANICBUFSIZE);
3211 		return (DCMD_ERR);
3212 	}
3213 
3214 	mdb_printf("%16s %s\n", "message",  (char *)panicbuf + pd->pd_msgoff);
3215 
3216 	n = (pd->pd_msgoff - (sizeof (panic_data_t) -
3217 	    sizeof (panic_nv_t))) / sizeof (panic_nv_t);
3218 
3219 	for (i = 0; i < n; i++)
3220 		mdb_printf("%16s %?llx\n",
3221 		    pd->pd_nvdata[i].pnv_name, pd->pd_nvdata[i].pnv_value);
3222 
3223 	mdb_free(panicbuf, PANICBUFSIZE);
3224 	return (DCMD_OK);
3225 }
3226 
3227 static const mdb_dcmd_t dcmds[] = {
3228 
3229 	/* from genunix.c */
3230 	{ "addr2smap", ":[offset]", "translate address to smap", addr2smap },
3231 	{ "as2proc", ":", "convert as to proc_t address", as2proc },
3232 	{ "binding_hash_entry", ":", "print driver names hash table entry",
3233 		binding_hash_entry },
3234 	{ "callout", NULL, "print callout table", callout },
3235 	{ "class", NULL, "print process scheduler classes", class },
3236 	{ "cpuinfo", "?[-v]", "print CPUs and runnable threads", cpuinfo },
3237 	{ "did2thread", "? kt_did", "find kernel thread for this id",
3238 		did2thread },
3239 	{ "errorq", "?[-v]", "display kernel error queues", errorq },
3240 	{ "fd", ":[fd num]", "get a file pointer from an fd", fd },
3241 	{ "flipone", ":", "the vik_rev_level 2 special", flipone },
3242 	{ "lminfo", NULL, "print lock manager information", lminfo },
3243 	{ "ndi_event_hdl", "?", "print ndi_event_hdl", ndi_event_hdl },
3244 	{ "panicinfo", NULL, "print panic information", panicinfo },
3245 	{ "pid2proc", "?", "convert PID to proc_t address", pid2proc },
3246 	{ "pmap", ":[-q]", "print process memory map", pmap },
3247 	{ "project", NULL, "display kernel project(s)", project },
3248 	{ "ps", "[-fltzTP]", "list processes (and associated thr,lwp)", ps },
3249 	{ "pgrep", "[-x] [-n | -o] pattern",
3250 		"pattern match against all processes", pgrep },
3251 	{ "ptree", NULL, "print process tree", ptree },
3252 	{ "seg", ":", "print address space segment", seg },
3253 	{ "sysevent", "?[-sv]", "print sysevent pending or sent queue",
3254 		sysevent},
3255 	{ "sysevent_channel", "?", "print sysevent channel database",
3256 		sysevent_channel},
3257 	{ "sysevent_class_list", ":", "print sysevent class list",
3258 		sysevent_class_list},
3259 	{ "sysevent_subclass_list", ":",
3260 		"print sysevent subclass list", sysevent_subclass_list},
3261 	{ "system", NULL, "print contents of /etc/system file", sysfile },
3262 	{ "task", NULL, "display kernel task(s)", task },
3263 	{ "taskq_entry", ":", "display a taskq_ent_t", taskq_ent },
3264 	{ "vnode2path", ":[-F]", "vnode address to pathname", vnode2path },
3265 	{ "vnode2smap", ":[offset]", "translate vnode to smap", vnode2smap },
3266 	{ "whereopen", ":", "given a vnode, dumps procs which have it open",
3267 	    whereopen },
3268 
3269 	/* from zone.c */
3270 	{ "zone", "?", "display kernel zone(s)", zoneprt },
3271 	{ "zsd", ":[zsd key]", "lookup zsd value from a key", zsd },
3272 
3273 	/* from bio.c */
3274 	{ "bufpagefind", ":addr", "find page_t on buf_t list", bufpagefind },
3275 
3276 	/* from contract.c */
3277 	{ "contract", "?", "display a contract", cmd_contract },
3278 	{ "ctevent", ":", "display a contract event", cmd_ctevent },
3279 	{ "ctid", ":", "convert id to a contract pointer", cmd_ctid },
3280 
3281 	/* from cpupart.c */
3282 	{ "cpupart", "?[-v]", "print cpu partition info", cpupart },
3283 
3284 	/* from cyclic.c */
3285 	{ "cyccover", NULL, "dump cyclic coverage information", cyccover },
3286 	{ "cycid", "?", "dump a cyclic id", cycid },
3287 	{ "cycinfo", "?", "dump cyc_cpu info", cycinfo },
3288 	{ "cyclic", ":", "developer information", cyclic },
3289 	{ "cyctrace", "?", "dump cyclic trace buffer", cyctrace },
3290 
3291 	/* from devinfo.c */
3292 	{ "devbindings", "?[-qs] [device-name | major-num]",
3293 	    "print devinfo nodes bound to device-name or major-num",
3294 	    devbindings, devinfo_help },
3295 	{ "devinfo", ":[-qs]", "detailed devinfo of one node", devinfo,
3296 	    devinfo_help },
3297 	{ "devinfo_audit", ":[-v]", "devinfo configuration audit record",
3298 	    devinfo_audit },
3299 	{ "devinfo_audit_log", "?[-v]", "system wide devinfo configuration log",
3300 	    devinfo_audit_log },
3301 	{ "devinfo_audit_node", ":[-v]", "devinfo node configuration history",
3302 	    devinfo_audit_node },
3303 	{ "devinfo2driver", ":", "find driver name for this devinfo node",
3304 	    devinfo2driver },
3305 	{ "devnames", "?[-vm] [num]", "print devnames array", devnames },
3306 	{ "dev2major", "?<dev_t>", "convert dev_t to a major number",
3307 	    dev2major },
3308 	{ "dev2minor", "?<dev_t>", "convert dev_t to a minor number",
3309 	    dev2minor },
3310 	{ "devt", "?<dev_t>", "display a dev_t's major and minor numbers",
3311 	    devt },
3312 	{ "major2name", "?<major-num>", "convert major number to dev name",
3313 	    major2name },
3314 	{ "minornodes", ":", "given a devinfo node, print its minor nodes",
3315 	    minornodes },
3316 	{ "modctl2devinfo", ":", "given a modctl, list its devinfos",
3317 	    modctl2devinfo },
3318 	{ "name2major", "<dev-name>", "convert dev name to major number",
3319 	    name2major },
3320 	{ "prtconf", "?[-vpc]", "print devinfo tree", prtconf, prtconf_help },
3321 	{ "softstate", ":<instance>", "retrieve soft-state pointer",
3322 	    softstate },
3323 	{ "devinfo_fm", ":", "devinfo fault managment configuration",
3324 	    devinfo_fm },
3325 	{ "devinfo_fmce", ":", "devinfo fault managment cache entry",
3326 	    devinfo_fmce},
3327 
3328 	/* from fm.c */
3329 	{ "ereport", "[-v]", "print ereports logged in dump",
3330 	    ereport },
3331 
3332 	/* from findstack.c */
3333 	{ "findstack", ":[-v]", "find kernel thread stack", findstack },
3334 	{ "findstack_debug", NULL, "toggle findstack debugging",
3335 		findstack_debug },
3336 
3337 	/* from kgrep.c + genunix.c */
3338 	{ "kgrep", KGREP_USAGE, "search kernel as for a pointer", kgrep,
3339 		kgrep_help },
3340 
3341 	/* from kmem.c */
3342 	{ "allocdby", ":", "given a thread, print its allocated buffers",
3343 		allocdby },
3344 	{ "bufctl", ":[-vh] [-a addr] [-c caller] [-e earliest] [-l latest] "
3345 		"[-t thd]", "print or filter a bufctl", bufctl, bufctl_help },
3346 	{ "freedby", ":", "given a thread, print its freed buffers", freedby },
3347 	{ "kmalog", "?[ fail | slab ]",
3348 	    "display kmem transaction log and stack traces", kmalog },
3349 	{ "kmastat", "[-kmg]", "kernel memory allocator stats",
3350 	    kmastat },
3351 	{ "kmausers", "?[-ef] [cache ...]", "current medium and large users "
3352 		"of the kmem allocator", kmausers, kmausers_help },
3353 	{ "kmem_cache", "?", "print kernel memory caches", kmem_cache },
3354 	{ "kmem_debug", NULL, "toggle kmem dcmd/walk debugging", kmem_debug },
3355 	{ "kmem_log", "?[-b]", "dump kmem transaction log", kmem_log },
3356 	{ "kmem_verify", "?", "check integrity of kmem-managed memory",
3357 		kmem_verify },
3358 	{ "vmem", "?", "print a vmem_t", vmem },
3359 	{ "vmem_seg", ":[-sv] [-c caller] [-e earliest] [-l latest] "
3360 		"[-m minsize] [-M maxsize] [-t thread] [-T type]",
3361 		"print or filter a vmem_seg", vmem_seg, vmem_seg_help },
3362 	{ "whatis", ":[-abiv]", "given an address, return information", whatis,
3363 		whatis_help },
3364 	{ "whatthread", ":[-v]", "print threads whose stack contains the "
3365 		"given address", whatthread },
3366 
3367 	/* from ldi.c */
3368 	{ "ldi_handle", "?[-i]", "display a layered driver handle",
3369 	    ldi_handle, ldi_handle_help },
3370 	{ "ldi_ident", NULL, "display a layered driver identifier",
3371 	    ldi_ident, ldi_ident_help },
3372 
3373 	/* from leaky.c + leaky_subr.c */
3374 	{ "findleaks", FINDLEAKS_USAGE,
3375 	    "search for potential kernel memory leaks", findleaks,
3376 	    findleaks_help },
3377 
3378 	/* from lgrp.c */
3379 	{ "lgrp", "?[-q] [-p | -Pih]", "display an lgrp", lgrp},
3380 	{ "lgrp_set", "", "display bitmask of lgroups as a list", lgrp_set},
3381 
3382 	/* from log.c */
3383 	{ "msgbuf", "?[-v]", "print most recent console messages", msgbuf },
3384 
3385 	/* from memory.c */
3386 	{ "page", "?", "display a summarized page_t", page },
3387 	{ "memstat", NULL, "display memory usage summary", memstat },
3388 	{ "memlist", "?[-iav]", "display a struct memlist", memlist },
3389 	{ "swapinfo", "?", "display a struct swapinfo", swapinfof },
3390 
3391 	/* from mmd.c */
3392 	{ "multidata", ":[-sv]", "display a summarized multidata_t",
3393 		multidata },
3394 	{ "pattbl", ":", "display a summarized multidata attribute table",
3395 		pattbl },
3396 	{ "pattr2multidata", ":", "print multidata pointer from pattr_t",
3397 		pattr2multidata },
3398 	{ "pdesc2slab", ":", "print pdesc slab pointer from pdesc_t",
3399 		pdesc2slab },
3400 	{ "pdesc_verify", ":", "verify integrity of a pdesc_t", pdesc_verify },
3401 	{ "slab2multidata", ":", "print multidata pointer from pdesc_slab_t",
3402 		slab2multidata },
3403 
3404 	/* from modhash.c */
3405 	{ "modhash", "?[-ceht] [-k key] [-v val] [-i index]",
3406 		"display information about one or all mod_hash structures",
3407 		modhash, modhash_help },
3408 	{ "modent", ":[-k | -v | -t type]",
3409 		"display information about a mod_hash_entry", modent,
3410 		modent_help },
3411 
3412 	/* from net.c */
3413 	{ "mi", ":[-p] [-d | -m]", "filter and display MI object or payload",
3414 		mi },
3415 	{ "netstat", "[-arv] [-f inet | inet6 | unix] [-P tcp | udp]",
3416 		"show network statistics", netstat },
3417 	{ "sonode", "?[-f inet | inet6 | unix | #] "
3418 		"[-t stream | dgram | raw | #] [-p #]",
3419 		"filter and display sonode", sonode },
3420 
3421 	/* from nvpair.c */
3422 	{ NVPAIR_DCMD_NAME, NVPAIR_DCMD_USAGE, NVPAIR_DCMD_DESCR,
3423 		nvpair_print },
3424 	{ NVLIST_DCMD_NAME, NVLIST_DCMD_USAGE, NVLIST_DCMD_DESCR,
3425 		print_nvlist },
3426 
3427 	/* from pg.c */
3428 	{ "pg", "?[-q]", "display a pg", pg},
3429 	/* from group.c */
3430 	{ "group", "?[-q]", "display a group", group},
3431 
3432 	/* from log.c */
3433 	/* from rctl.c */
3434 	{ "rctl_dict", "?", "print systemwide default rctl definitions",
3435 		rctl_dict },
3436 	{ "rctl_list", ":[handle]", "print rctls for the given proc",
3437 		rctl_list },
3438 	{ "rctl", ":[handle]", "print a rctl_t, only if it matches the handle",
3439 		rctl },
3440 	{ "rctl_validate", ":[-v] [-n #]", "test resource control value "
3441 		"sequence", rctl_validate },
3442 
3443 	/* from sobj.c */
3444 	{ "rwlock", ":", "dump out a readers/writer lock", rwlock },
3445 	{ "mutex", ":[-f]", "dump out an adaptive or spin mutex", mutex,
3446 		mutex_help },
3447 	{ "sobj2ts", ":", "perform turnstile lookup on synch object", sobj2ts },
3448 	{ "wchaninfo", "?[-v]", "dump condition variable", wchaninfo },
3449 	{ "turnstile", "?", "display a turnstile", turnstile },
3450 
3451 	/* from stream.c */
3452 	{ "mblk", ":[-q|v] [-f|F flag] [-t|T type] [-l|L|B len] [-d dbaddr]",
3453 		"print an mblk", mblk_prt, mblk_help },
3454 	{ "mblk_verify", "?", "verify integrity of an mblk", mblk_verify },
3455 	{ "mblk2dblk", ":", "convert mblk_t address to dblk_t address",
3456 		mblk2dblk },
3457 	{ "q2otherq", ":", "print peer queue for a given queue", q2otherq },
3458 	{ "q2rdq", ":", "print read queue for a given queue", q2rdq },
3459 	{ "q2syncq", ":", "print syncq for a given queue", q2syncq },
3460 	{ "q2stream", ":", "print stream pointer for a given queue", q2stream },
3461 	{ "q2wrq", ":", "print write queue for a given queue", q2wrq },
3462 	{ "queue", ":[-q|v] [-m mod] [-f flag] [-F flag] [-s syncq_addr]",
3463 		"filter and display STREAM queue", queue, queue_help },
3464 	{ "stdata", ":[-q|v] [-f flag] [-F flag]",
3465 		"filter and display STREAM head", stdata, stdata_help },
3466 	{ "str2mate", ":", "print mate of this stream", str2mate },
3467 	{ "str2wrq", ":", "print write queue of this stream", str2wrq },
3468 	{ "stream", ":", "display STREAM", stream },
3469 	{ "strftevent", ":", "print STREAMS flow trace event", strftevent },
3470 	{ "syncq", ":[-q|v] [-f flag] [-F flag] [-t type] [-T type]",
3471 		"filter and display STREAM sync queue", syncq, syncq_help },
3472 	{ "syncq2q", ":", "print queue for a given syncq", syncq2q },
3473 
3474 	/* from thread.c */
3475 	{ "thread", "?[-bdfimps]", "display a summarized kthread_t", thread,
3476 		thread_help },
3477 	{ "threadlist", "?[-v [count]]",
3478 		"display threads and associated C stack traces", threadlist,
3479 		threadlist_help },
3480 
3481 	/* from tsd.c */
3482 	{ "tsd", ":-k key", "print tsd[key-1] for this thread", ttotsd },
3483 	{ "tsdtot", ":", "find thread with this tsd", tsdtot },
3484 
3485 	/*
3486 	 * typegraph does not work under kmdb, as it requires too much memory
3487 	 * for its internal data structures.
3488 	 */
3489 #ifndef _KMDB
3490 	/* from typegraph.c */
3491 	{ "findlocks", ":", "find locks held by specified thread", findlocks },
3492 	{ "findfalse", "?[-v]", "find potentially falsely shared structures",
3493 		findfalse },
3494 	{ "typegraph", NULL, "build type graph", typegraph },
3495 	{ "istype", ":type", "manually set object type", istype },
3496 	{ "notype", ":", "manually clear object type", notype },
3497 	{ "whattype", ":", "determine object type", whattype },
3498 #endif
3499 
3500 	/* from vfs.c */
3501 	{ "fsinfo", "?[-v]", "print mounted filesystems", fsinfo },
3502 	{ "pfiles", ":[-fp]", "print process file information", pfiles,
3503 		pfiles_help },
3504 
3505 	/* from mdi.c */
3506 	{ "mdipi", NULL, "given a path, dump mdi_pathinfo "
3507 		"and detailed pi_prop list", mdipi },
3508 	{ "mdiprops", NULL, "given a pi_prop, dump the pi_prop list",
3509 		mdiprops },
3510 	{ "mdiphci", NULL, "given a phci, dump mdi_phci and "
3511 		"list all paths", mdiphci },
3512 	{ "mdivhci", NULL, "given a vhci, dump mdi_vhci and list "
3513 		"all phcis", mdivhci },
3514 	{ "mdiclient_paths", NULL, "given a path, walk mdi_pathinfo "
3515 		"client links", mdiclient_paths },
3516 	{ "mdiphci_paths", NULL, "given a path, walk through mdi_pathinfo "
3517 		"phci links", mdiphci_paths },
3518 	{ "mdiphcis", NULL, "given a phci, walk through mdi_phci ph_next links",
3519 		mdiphcis },
3520 
3521 	{ NULL }
3522 };
3523 
3524 static const mdb_walker_t walkers[] = {
3525 
3526 	/* from genunix.c */
3527 	{ "anon", "given an amp, list of anon structures",
3528 		anon_walk_init, anon_walk_step, anon_walk_fini },
3529 	{ "cpu", "walk cpu structures", cpu_walk_init, cpu_walk_step },
3530 	{ "ereportq_dump", "walk list of ereports in dump error queue",
3531 		ereportq_dump_walk_init, ereportq_dump_walk_step, NULL },
3532 	{ "ereportq_pend", "walk list of ereports in pending error queue",
3533 		ereportq_pend_walk_init, ereportq_pend_walk_step, NULL },
3534 	{ "errorq", "walk list of system error queues",
3535 		errorq_walk_init, errorq_walk_step, NULL },
3536 	{ "errorq_data", "walk pending error queue data buffers",
3537 		eqd_walk_init, eqd_walk_step, eqd_walk_fini },
3538 	{ "allfile", "given a proc pointer, list all file pointers",
3539 		file_walk_init, allfile_walk_step, file_walk_fini },
3540 	{ "file", "given a proc pointer, list of open file pointers",
3541 		file_walk_init, file_walk_step, file_walk_fini },
3542 	{ "lock_descriptor", "walk lock_descriptor_t structures",
3543 		ld_walk_init, ld_walk_step, NULL },
3544 	{ "lock_graph", "walk lock graph",
3545 		lg_walk_init, lg_walk_step, NULL },
3546 	{ "port", "given a proc pointer, list of created event ports",
3547 		port_walk_init, port_walk_step, NULL },
3548 	{ "portev", "given a port pointer, list of events in the queue",
3549 		portev_walk_init, portev_walk_step, portev_walk_fini },
3550 	{ "proc", "list of active proc_t structures",
3551 		proc_walk_init, proc_walk_step, proc_walk_fini },
3552 	{ "projects", "walk a list of kernel projects",
3553 		project_walk_init, project_walk_step, NULL },
3554 	{ "seg", "given an as, list of segments",
3555 		seg_walk_init, avl_walk_step, avl_walk_fini },
3556 	{ "sysevent_pend", "walk sysevent pending queue",
3557 		sysevent_pend_walk_init, sysevent_walk_step,
3558 		sysevent_walk_fini},
3559 	{ "sysevent_sent", "walk sysevent sent queue", sysevent_sent_walk_init,
3560 		sysevent_walk_step, sysevent_walk_fini},
3561 	{ "sysevent_channel", "walk sysevent channel subscriptions",
3562 		sysevent_channel_walk_init, sysevent_channel_walk_step,
3563 		sysevent_channel_walk_fini},
3564 	{ "sysevent_class_list", "walk sysevent subscription's class list",
3565 		sysevent_class_list_walk_init, sysevent_class_list_walk_step,
3566 		sysevent_class_list_walk_fini},
3567 	{ "sysevent_subclass_list",
3568 		"walk sysevent subscription's subclass list",
3569 		sysevent_subclass_list_walk_init,
3570 		sysevent_subclass_list_walk_step,
3571 		sysevent_subclass_list_walk_fini},
3572 	{ "task", "given a task pointer, walk its processes",
3573 		task_walk_init, task_walk_step, NULL },
3574 	{ "taskq_entry", "given a taskq_t*, list all taskq_ent_t in the list",
3575 		taskq_walk_init, taskq_walk_step, NULL, NULL },
3576 
3577 	/* from avl.c */
3578 	{ AVL_WALK_NAME, AVL_WALK_DESC,
3579 		avl_walk_init, avl_walk_step, avl_walk_fini },
3580 
3581 	/* from zone.c */
3582 	{ "zone", "walk a list of kernel zones",
3583 		zone_walk_init, zone_walk_step, NULL },
3584 	{ "zsd", "walk list of zsd entries for a zone",
3585 		zsd_walk_init, zsd_walk_step, NULL },
3586 
3587 	/* from bio.c */
3588 	{ "buf", "walk the bio buf hash",
3589 		buf_walk_init, buf_walk_step, buf_walk_fini },
3590 
3591 	/* from contract.c */
3592 	{ "contract", "walk all contracts, or those of the specified type",
3593 		ct_walk_init, generic_walk_step, NULL },
3594 	{ "ct_event", "walk events on a contract event queue",
3595 		ct_event_walk_init, generic_walk_step, NULL },
3596 	{ "ct_listener", "walk contract event queue listeners",
3597 		ct_listener_walk_init, generic_walk_step, NULL },
3598 
3599 	/* from cpupart.c */
3600 	{ "cpupart_cpulist", "given an cpupart_t, walk cpus in partition",
3601 		cpupart_cpulist_walk_init, cpupart_cpulist_walk_step,
3602 		NULL },
3603 	{ "cpupart_walk", "walk the set of cpu partitions",
3604 		cpupart_walk_init, cpupart_walk_step, NULL },
3605 
3606 	/* from ctxop.c */
3607 	{ "ctxop", "walk list of context ops on a thread",
3608 		ctxop_walk_init, ctxop_walk_step, ctxop_walk_fini },
3609 
3610 	/* from cyclic.c */
3611 	{ "cyccpu", "walk per-CPU cyc_cpu structures",
3612 		cyccpu_walk_init, cyccpu_walk_step, NULL },
3613 	{ "cycomni", "for an omnipresent cyclic, walk cyc_omni_cpu list",
3614 		cycomni_walk_init, cycomni_walk_step, NULL },
3615 	{ "cyctrace", "walk cyclic trace buffer",
3616 		cyctrace_walk_init, cyctrace_walk_step, cyctrace_walk_fini },
3617 
3618 	/* from devinfo.c */
3619 	{ "binding_hash", "walk all entries in binding hash table",
3620 		binding_hash_walk_init, binding_hash_walk_step, NULL },
3621 	{ "devinfo", "walk devinfo tree or subtree",
3622 		devinfo_walk_init, devinfo_walk_step, devinfo_walk_fini },
3623 	{ "devinfo_audit_log", "walk devinfo audit system-wide log",
3624 		devinfo_audit_log_walk_init, devinfo_audit_log_walk_step,
3625 		devinfo_audit_log_walk_fini},
3626 	{ "devinfo_audit_node", "walk per-devinfo audit history",
3627 		devinfo_audit_node_walk_init, devinfo_audit_node_walk_step,
3628 		devinfo_audit_node_walk_fini},
3629 	{ "devinfo_children", "walk children of devinfo node",
3630 		devinfo_children_walk_init, devinfo_children_walk_step,
3631 		devinfo_children_walk_fini },
3632 	{ "devinfo_parents", "walk ancestors of devinfo node",
3633 		devinfo_parents_walk_init, devinfo_parents_walk_step,
3634 		devinfo_parents_walk_fini },
3635 	{ "devinfo_siblings", "walk siblings of devinfo node",
3636 		devinfo_siblings_walk_init, devinfo_siblings_walk_step, NULL },
3637 	{ "devi_next", "walk devinfo list",
3638 		NULL, devi_next_walk_step, NULL },
3639 	{ "devnames", "walk devnames array",
3640 		devnames_walk_init, devnames_walk_step, devnames_walk_fini },
3641 	{ "minornode", "given a devinfo node, walk minor nodes",
3642 		minornode_walk_init, minornode_walk_step, NULL },
3643 	{ "softstate",
3644 		"given an i_ddi_soft_state*, list all in-use driver stateps",
3645 		soft_state_walk_init, soft_state_walk_step,
3646 		NULL, NULL },
3647 	{ "softstate_all",
3648 		"given an i_ddi_soft_state*, list all driver stateps",
3649 		soft_state_walk_init, soft_state_all_walk_step,
3650 		NULL, NULL },
3651 	{ "devinfo_fmc",
3652 		"walk a fault management handle cache active list",
3653 		devinfo_fmc_walk_init, devinfo_fmc_walk_step, NULL },
3654 
3655 	/* from kmem.c */
3656 	{ "allocdby", "given a thread, walk its allocated bufctls",
3657 		allocdby_walk_init, allocdby_walk_step, allocdby_walk_fini },
3658 	{ "bufctl", "walk a kmem cache's bufctls",
3659 		bufctl_walk_init, kmem_walk_step, kmem_walk_fini },
3660 	{ "bufctl_history", "walk the available history of a bufctl",
3661 		bufctl_history_walk_init, bufctl_history_walk_step,
3662 		bufctl_history_walk_fini },
3663 	{ "freedby", "given a thread, walk its freed bufctls",
3664 		freedby_walk_init, allocdby_walk_step, allocdby_walk_fini },
3665 	{ "freectl", "walk a kmem cache's free bufctls",
3666 		freectl_walk_init, kmem_walk_step, kmem_walk_fini },
3667 	{ "freectl_constructed", "walk a kmem cache's constructed free bufctls",
3668 		freectl_constructed_walk_init, kmem_walk_step, kmem_walk_fini },
3669 	{ "freemem", "walk a kmem cache's free memory",
3670 		freemem_walk_init, kmem_walk_step, kmem_walk_fini },
3671 	{ "freemem_constructed", "walk a kmem cache's constructed free memory",
3672 		freemem_constructed_walk_init, kmem_walk_step, kmem_walk_fini },
3673 	{ "kmem", "walk a kmem cache",
3674 		kmem_walk_init, kmem_walk_step, kmem_walk_fini },
3675 	{ "kmem_cpu_cache", "given a kmem cache, walk its per-CPU caches",
3676 		kmem_cpu_cache_walk_init, kmem_cpu_cache_walk_step, NULL },
3677 	{ "kmem_hash", "given a kmem cache, walk its allocated hash table",
3678 		kmem_hash_walk_init, kmem_hash_walk_step, kmem_hash_walk_fini },
3679 	{ "kmem_log", "walk the kmem transaction log",
3680 		kmem_log_walk_init, kmem_log_walk_step, kmem_log_walk_fini },
3681 	{ "kmem_slab", "given a kmem cache, walk its slabs",
3682 		kmem_slab_walk_init, kmem_slab_walk_step, NULL },
3683 	{ "kmem_slab_partial",
3684 	    "given a kmem cache, walk its partially allocated slabs (min 1)",
3685 		kmem_slab_walk_partial_init, kmem_slab_walk_step, NULL },
3686 	{ "vmem", "walk vmem structures in pre-fix, depth-first order",
3687 		vmem_walk_init, vmem_walk_step, vmem_walk_fini },
3688 	{ "vmem_alloc", "given a vmem_t, walk its allocated vmem_segs",
3689 		vmem_alloc_walk_init, vmem_seg_walk_step, vmem_seg_walk_fini },
3690 	{ "vmem_free", "given a vmem_t, walk its free vmem_segs",
3691 		vmem_free_walk_init, vmem_seg_walk_step, vmem_seg_walk_fini },
3692 	{ "vmem_postfix", "walk vmem structures in post-fix, depth-first order",
3693 		vmem_walk_init, vmem_postfix_walk_step, vmem_walk_fini },
3694 	{ "vmem_seg", "given a vmem_t, walk all of its vmem_segs",
3695 		vmem_seg_walk_init, vmem_seg_walk_step, vmem_seg_walk_fini },
3696 	{ "vmem_span", "given a vmem_t, walk its spanning vmem_segs",
3697 		vmem_span_walk_init, vmem_seg_walk_step, vmem_seg_walk_fini },
3698 
3699 	/* from ldi.c */
3700 	{ "ldi_handle", "walk the layered driver handle hash",
3701 		ldi_handle_walk_init, ldi_handle_walk_step, NULL },
3702 	{ "ldi_ident", "walk the layered driver identifier hash",
3703 		ldi_ident_walk_init, ldi_ident_walk_step, NULL },
3704 
3705 	/* from leaky.c + leaky_subr.c */
3706 	{ "leak", "given a leaked bufctl or vmem_seg, find leaks w/ same "
3707 	    "stack trace",
3708 		leaky_walk_init, leaky_walk_step, leaky_walk_fini },
3709 	{ "leakbuf", "given a leaked bufctl or vmem_seg, walk buffers for "
3710 	    "leaks w/ same stack trace",
3711 		leaky_walk_init, leaky_buf_walk_step, leaky_walk_fini },
3712 
3713 	/* from lgrp.c */
3714 	{ "lgrp_cpulist", "walk CPUs in a given lgroup",
3715 		lgrp_cpulist_walk_init, lgrp_cpulist_walk_step, NULL },
3716 	{ "lgrptbl", "walk lgroup table",
3717 		lgrp_walk_init, lgrp_walk_step, NULL },
3718 	{ "lgrp_parents", "walk up lgroup lineage from given lgroup",
3719 		lgrp_parents_walk_init, lgrp_parents_walk_step, NULL },
3720 	{ "lgrp_rsrc_mem", "walk lgroup memory resources of given lgroup",
3721 		lgrp_rsrc_mem_walk_init, lgrp_set_walk_step, NULL },
3722 	{ "lgrp_rsrc_cpu", "walk lgroup CPU resources of given lgroup",
3723 		lgrp_rsrc_cpu_walk_init, lgrp_set_walk_step, NULL },
3724 
3725 	/* from group.c */
3726 	{ "group", "walk all elements of a group",
3727 		group_walk_init, group_walk_step, NULL },
3728 
3729 	/* from list.c */
3730 	{ LIST_WALK_NAME, LIST_WALK_DESC,
3731 		list_walk_init, list_walk_step, list_walk_fini },
3732 
3733 	/* from memory.c */
3734 	{ "page", "walk all pages, or those from the specified vnode",
3735 		page_walk_init, page_walk_step, page_walk_fini },
3736 	{ "memlist", "walk specified memlist",
3737 		NULL, memlist_walk_step, NULL },
3738 	{ "swapinfo", "walk swapinfo structures",
3739 		swap_walk_init, swap_walk_step, NULL },
3740 
3741 	/* from mmd.c */
3742 	{ "pattr", "walk pattr_t structures", pattr_walk_init,
3743 		mmdq_walk_step, mmdq_walk_fini },
3744 	{ "pdesc", "walk pdesc_t structures",
3745 		pdesc_walk_init, mmdq_walk_step, mmdq_walk_fini },
3746 	{ "pdesc_slab", "walk pdesc_slab_t structures",
3747 		pdesc_slab_walk_init, mmdq_walk_step, mmdq_walk_fini },
3748 
3749 	/* from modhash.c */
3750 	{ "modhash", "walk list of mod_hash structures", modhash_walk_init,
3751 		modhash_walk_step, NULL },
3752 	{ "modent", "walk list of entries in a given mod_hash",
3753 		modent_walk_init, modent_walk_step, modent_walk_fini },
3754 	{ "modchain", "walk list of entries in a given mod_hash_entry",
3755 		NULL, modchain_walk_step, NULL },
3756 
3757 	/* from net.c */
3758 	{ "ar", "walk ar_t structures using MI",
3759 		mi_payload_walk_init, mi_payload_walk_step,
3760 		mi_payload_walk_fini, &mi_ar_arg },
3761 	{ "icmp", "walk ICMP control structures using MI",
3762 		mi_payload_walk_init, mi_payload_walk_step,
3763 		mi_payload_walk_fini, &mi_icmp_arg },
3764 	{ "ill", "walk ill_t structures using MI",
3765 		mi_payload_walk_init, mi_payload_walk_step,
3766 		mi_payload_walk_fini, &mi_ill_arg },
3767 	{ "mi", "given a MI_O, walk the MI",
3768 		mi_walk_init, mi_walk_step, mi_walk_fini, NULL },
3769 	{ "sonode", "given a sonode, walk its children",
3770 		sonode_walk_init, sonode_walk_step, sonode_walk_fini, NULL },
3771 
3772 	/* from nvpair.c */
3773 	{ NVPAIR_WALKER_NAME, NVPAIR_WALKER_DESCR,
3774 		nvpair_walk_init, nvpair_walk_step, NULL },
3775 
3776 	/* from rctl.c */
3777 	{ "rctl_dict_list", "walk all rctl_dict_entry_t's from rctl_lists",
3778 		rctl_dict_walk_init, rctl_dict_walk_step, NULL },
3779 	{ "rctl_set", "given a rctl_set, walk all rctls", rctl_set_walk_init,
3780 		rctl_set_walk_step, NULL },
3781 	{ "rctl_val", "given a rctl_t, walk all rctl_val entries associated",
3782 		rctl_val_walk_init, rctl_val_walk_step },
3783 
3784 	/* from sobj.c */
3785 	{ "blocked", "walk threads blocked on a given sobj",
3786 		blocked_walk_init, blocked_walk_step, NULL },
3787 	{ "wchan", "given a wchan, list of blocked threads",
3788 		wchan_walk_init, wchan_walk_step, wchan_walk_fini },
3789 
3790 	/* from stream.c */
3791 	{ "b_cont", "walk mblk_t list using b_cont",
3792 		mblk_walk_init, b_cont_step, mblk_walk_fini },
3793 	{ "b_next", "walk mblk_t list using b_next",
3794 		mblk_walk_init, b_next_step, mblk_walk_fini },
3795 	{ "qlink", "walk queue_t list using q_link",
3796 		queue_walk_init, queue_link_step, queue_walk_fini },
3797 	{ "qnext", "walk queue_t list using q_next",
3798 		queue_walk_init, queue_next_step, queue_walk_fini },
3799 	{ "strftblk", "given a dblk_t, walk STREAMS flow trace event list",
3800 		strftblk_walk_init, strftblk_step, strftblk_walk_fini },
3801 	{ "readq", "walk read queue side of stdata",
3802 		str_walk_init, strr_walk_step, str_walk_fini },
3803 	{ "writeq", "walk write queue side of stdata",
3804 		str_walk_init, strw_walk_step, str_walk_fini },
3805 
3806 	/* from thread.c */
3807 	{ "deathrow", "walk threads on both lwp_ and thread_deathrow",
3808 		deathrow_walk_init, deathrow_walk_step, NULL },
3809 	{ "cpu_dispq", "given a cpu_t, walk threads in dispatcher queues",
3810 		cpu_dispq_walk_init, dispq_walk_step, dispq_walk_fini },
3811 	{ "cpupart_dispq",
3812 		"given a cpupart_t, walk threads in dispatcher queues",
3813 		cpupart_dispq_walk_init, dispq_walk_step, dispq_walk_fini },
3814 	{ "lwp_deathrow", "walk lwp_deathrow",
3815 		lwp_deathrow_walk_init, deathrow_walk_step, NULL },
3816 	{ "thread", "global or per-process kthread_t structures",
3817 		thread_walk_init, thread_walk_step, thread_walk_fini },
3818 	{ "thread_deathrow", "walk threads on thread_deathrow",
3819 		thread_deathrow_walk_init, deathrow_walk_step, NULL },
3820 
3821 	/* from tsd.c */
3822 	{ "tsd", "walk list of thread-specific data",
3823 		tsd_walk_init, tsd_walk_step, tsd_walk_fini },
3824 
3825 	/* from tsol.c */
3826 	{ "tnrh", "walk remote host cache structures",
3827 	    tnrh_walk_init, tnrh_walk_step, tnrh_walk_fini },
3828 	{ "tnrhtp", "walk remote host template structures",
3829 	    tnrhtp_walk_init, tnrhtp_walk_step, tnrhtp_walk_fini },
3830 
3831 	/*
3832 	 * typegraph does not work under kmdb, as it requires too much memory
3833 	 * for its internal data structures.
3834 	 */
3835 #ifndef _KMDB
3836 	/* from typegraph.c */
3837 	{ "typeconflict", "walk buffers with conflicting type inferences",
3838 		typegraph_walk_init, typeconflict_walk_step },
3839 	{ "typeunknown", "walk buffers with unknown types",
3840 		typegraph_walk_init, typeunknown_walk_step },
3841 #endif
3842 
3843 	/* from vfs.c */
3844 	{ "vfs", "walk file system list",
3845 		vfs_walk_init, vfs_walk_step },
3846 
3847 	/* from mdi.c */
3848 	{ "mdipi_client_list", "Walker for mdi_pathinfo pi_client_link",
3849 		mdi_pi_client_link_walk_init,
3850 		mdi_pi_client_link_walk_step,
3851 		mdi_pi_client_link_walk_fini },
3852 
3853 	{ "mdipi_phci_list", "Walker for mdi_pathinfo pi_phci_link",
3854 		mdi_pi_phci_link_walk_init,
3855 		mdi_pi_phci_link_walk_step,
3856 		mdi_pi_phci_link_walk_fini },
3857 
3858 	{ "mdiphci_list", "Walker for mdi_phci ph_next link",
3859 		mdi_phci_ph_next_walk_init,
3860 		mdi_phci_ph_next_walk_step,
3861 		mdi_phci_ph_next_walk_fini },
3862 
3863 	{ NULL }
3864 };
3865 
3866 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
3867 
3868 const mdb_modinfo_t *
3869 _mdb_init(void)
3870 {
3871 	if (mdb_readvar(&devinfo_root, "top_devinfo") == -1) {
3872 		mdb_warn("failed to read 'top_devinfo'");
3873 		return (NULL);
3874 	}
3875 
3876 	if (findstack_init() != DCMD_OK)
3877 		return (NULL);
3878 
3879 	kmem_init();
3880 
3881 	return (&modinfo);
3882 }
3883 
3884 void
3885 _mdb_fini(void)
3886 {
3887 	/*
3888 	 * Force ::findleaks to let go any cached memory
3889 	 */
3890 	leaky_cleanup(1);
3891 }
3892