xref: /illumos-gate/usr/src/cmd/fm/fmd/common/fmd_mdb.c (revision 3d63ea05)
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 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/mdb_modapi.h>
30 
31 #include <fmd_trace.h>
32 #include <fmd_module.h>
33 #include <fmd_thread.h>
34 #include <fmd_ustat.h>
35 #include <fmd_event.h>
36 #include <fmd_case.h>
37 #include <fmd_buf.h>
38 #include <fmd_asru.h>
39 #include <fmd_ckpt.h>
40 #include <fmd_timerq.h>
41 #include <fmd_xprt.h>
42 
43 #include <fmd.h>
44 
45 typedef struct trwalk_state {
46 	struct trwalk_state *trw_next;
47 	fmd_tracebuf_t trw_data;
48 	pthread_t trw_tid;
49 	uintptr_t trw_base;
50 	const fmd_tracerec_t *trw_stop;
51 	fmd_tracerec_t *trw_xrec;
52 } trwalk_state_t;
53 
54 typedef struct hashwalk_data {
55 	uintptr_t *hw_hash;
56 	uint_t hw_hashlen;
57 	uint_t hw_hashidx;
58 	const char *hw_name;
59 	void *hw_data;
60 	size_t hw_size;
61 	size_t hw_next;
62 } hashwalk_data_t;
63 
64 static int
65 trwalk_init(mdb_walk_state_t *wsp)
66 {
67 	uintptr_t addr;
68 	fmd_thread_t thr;
69 	fmd_t F;
70 
71 	if (wsp->walk_addr != NULL) {
72 		mdb_warn("fmd_trace only supports global walks\n");
73 		return (WALK_ERR);
74 	}
75 
76 	if (mdb_readvar(&F, "fmd") != sizeof (F)) {
77 		mdb_warn("failed to read fmd meta-data");
78 		return (WALK_ERR);
79 	}
80 
81 	for (addr = (uintptr_t)F.d_thr_list.l_next; addr != NULL;
82 	    addr = (uintptr_t)thr.thr_list.l_next) {
83 
84 		size_t len, ptr_off, end_off;
85 		fmd_tracerec_t *buf;
86 		trwalk_state_t *t;
87 
88 		if (mdb_vread(&thr, sizeof (thr), addr) != sizeof (thr)) {
89 			mdb_warn("failed to read thread at %p "
90 			    "(some trace data will be unavailable)", addr);
91 			break;
92 		}
93 
94 		t = mdb_zalloc(sizeof (trwalk_state_t), UM_SLEEP);
95 		t->trw_next = wsp->walk_data;
96 		wsp->walk_data = t;
97 
98 		(void) mdb_vread(&t->trw_data,
99 		    sizeof (t->trw_data), (uintptr_t)thr.thr_trdata);
100 
101 		if (t->trw_data.tb_recs == 0)
102 			continue; /* no trace buffer allocated for thread */
103 
104 		len = t->trw_data.tb_recs * t->trw_data.tb_size;
105 		buf = mdb_alloc(len, UM_SLEEP);
106 
107 		t->trw_tid = thr.thr_tid;
108 		t->trw_base = (uintptr_t)t->trw_data.tb_buf;
109 
110 		if (mdb_vread(buf, len, t->trw_base) == -1) {
111 			mdb_warn("failed to read buffer for t%u", t->trw_tid);
112 			bzero(buf, len);
113 		}
114 
115 		end_off = (uintptr_t)t->trw_data.tb_end - t->trw_base;
116 		ptr_off = (uintptr_t)t->trw_data.tb_ptr - t->trw_base;
117 
118 		t->trw_data.tb_buf = buf;
119 		t->trw_data.tb_end = (void *)((uintptr_t)buf + end_off);
120 		t->trw_data.tb_ptr = (void *)((uintptr_t)buf + ptr_off);
121 
122 		if (t->trw_data.tb_ptr < t->trw_data.tb_buf ||
123 		    t->trw_data.tb_ptr > t->trw_data.tb_end) {
124 			mdb_warn("trace record ptr for t%u is corrupt "
125 			    "(some data may be unavailable)\n", t->trw_tid);
126 			t->trw_data.tb_ptr = t->trw_data.tb_buf;
127 		}
128 
129 		t->trw_stop = t->trw_data.tb_ptr;
130 		t->trw_xrec = mdb_alloc(
131 		    t->trw_data.tb_size + sizeof (uintptr_t), UM_SLEEP);
132 	}
133 
134 	return (WALK_NEXT);
135 }
136 
137 static fmd_tracerec_t *
138 trwalk_nextrec(trwalk_state_t *t)
139 {
140 	if (t->trw_stop == NULL)
141 		return (t->trw_data.tb_ptr);
142 
143 	if (t->trw_data.tb_ptr == t->trw_data.tb_buf)
144 		t->trw_data.tb_ptr = t->trw_data.tb_end;
145 	else
146 		t->trw_data.tb_ptr = (fmd_tracerec_t *)
147 		    ((uintptr_t)t->trw_data.tb_ptr - t->trw_data.tb_size);
148 
149 	if (t->trw_data.tb_ptr == t->trw_stop)
150 		t->trw_stop = NULL; /* mark buffer as empty */
151 
152 	return (t->trw_data.tb_ptr);
153 }
154 
155 static int
156 trwalk_step(mdb_walk_state_t *wsp)
157 {
158 	trwalk_state_t *t, *oldest_t;
159 	hrtime_t oldest_time = 0;
160 	fmd_tracerec_t *trp;
161 	int status;
162 
163 	for (t = wsp->walk_data; t != NULL; t = t->trw_next) {
164 		for (trp = t->trw_data.tb_ptr; t->trw_stop != NULL &&
165 		    trp->tr_time == 0; trp = trwalk_nextrec(t))
166 			continue;
167 
168 		if (t->trw_stop == NULL)
169 			continue; /* buffer has been emptied */
170 
171 		if (trp->tr_time > oldest_time) {
172 			oldest_time = trp->tr_time;
173 			oldest_t = t;
174 		}
175 	}
176 
177 	if (oldest_time == 0)
178 		return (WALK_DONE);
179 
180 	t = oldest_t;
181 	trp = t->trw_data.tb_ptr;
182 
183 	bcopy(trp, t->trw_xrec, t->trw_data.tb_size);
184 	t->trw_xrec->tr_depth = MIN(trp->tr_depth, t->trw_data.tb_frames);
185 	t->trw_xrec->tr_stack[t->trw_xrec->tr_depth] = t->trw_tid;
186 
187 	status = wsp->walk_callback((uintptr_t)trp - (uintptr_t)
188 	    t->trw_data.tb_buf + t->trw_base, t->trw_xrec, wsp->walk_cbdata);
189 
190 	(void) trwalk_nextrec(t);
191 	return (status);
192 }
193 
194 static void
195 trwalk_fini(mdb_walk_state_t *wsp)
196 {
197 	trwalk_state_t *t, *u;
198 
199 	for (t = wsp->walk_data; t != NULL; t = u) {
200 		u = t->trw_next;
201 		mdb_free(t->trw_data.tb_buf,
202 		    t->trw_data.tb_recs * t->trw_data.tb_size);
203 		mdb_free(t->trw_xrec, t->trw_data.tb_size + sizeof (uintptr_t));
204 		mdb_free(t, sizeof (trwalk_state_t));
205 	}
206 }
207 
208 /*ARGSUSED*/
209 static int
210 trprint_msg(uintptr_t addr, const fmd_tracerec_t *trp, uintptr_t tid)
211 {
212 	if (tid == 0)
213 		mdb_printf("%3lu ", trp->tr_stack[trp->tr_depth]);
214 	else if (trp->tr_stack[trp->tr_depth] != tid)
215 		return (WALK_NEXT);
216 
217 	mdb_printf("%016llx %04x %-5u %s\n",
218 	    trp->tr_time, 1 << trp->tr_tag, trp->tr_errno, trp->tr_msg);
219 
220 	return (WALK_NEXT);
221 }
222 
223 /*ARGSUSED*/
224 static int
225 trprint_cpp(uintptr_t addr, const fmd_tracerec_t *trp, uintptr_t tid)
226 {
227 	char file[64];
228 
229 	if (tid == 0)
230 		mdb_printf("%3lu ", trp->tr_stack[trp->tr_depth]);
231 	else if (trp->tr_stack[trp->tr_depth] != tid)
232 		return (WALK_NEXT);
233 
234 	if (mdb_readstr(file, sizeof (file), (uintptr_t)trp->tr_file) <= 0)
235 		(void) strcpy(file, "???");
236 
237 	mdb_printf("%016llx %04x %s: %u\n",
238 	    trp->tr_time, 1 << trp->tr_tag, file, trp->tr_line);
239 
240 	return (WALK_NEXT);
241 }
242 
243 static void
244 trprint_stack(const fmd_tracerec_t *trp)
245 {
246 	uint8_t i;
247 
248 	for (i = 0; i < trp->tr_depth; i++)
249 		mdb_printf("\t%a\n", trp->tr_stack[i]);
250 
251 	if (trp->tr_depth != 0)
252 		mdb_printf("\n");
253 }
254 
255 static int
256 trprint_msg_stack(uintptr_t addr, const fmd_tracerec_t *trp, uintptr_t tid)
257 {
258 	int status = trprint_msg(addr, trp, tid);
259 	trprint_stack(trp);
260 	return (status);
261 }
262 
263 static int
264 trprint_cpp_stack(uintptr_t addr, const fmd_tracerec_t *trp, uintptr_t tid)
265 {
266 	int status = trprint_cpp(addr, trp, tid);
267 	trprint_stack(trp);
268 	return (status);
269 }
270 
271 static int
272 fmd_trace(uintptr_t tid, uint_t flags, int argc, const mdb_arg_t *argv)
273 {
274 	int (*func)(uintptr_t, const fmd_tracerec_t *, uintptr_t);
275 	uint_t opt_c = FALSE, opt_s = FALSE;
276 
277 	if (mdb_getopts(argc, argv,
278 	    'c', MDB_OPT_SETBITS, TRUE, &opt_c,
279 	    's', MDB_OPT_SETBITS, TRUE, &opt_s, NULL) != argc)
280 		return (DCMD_USAGE);
281 
282 	if (!(flags & DCMD_ADDRSPEC)) {
283 		mdb_printf("TID ");
284 		tid = 0;
285 	}
286 
287 	if (opt_c) {
288 		mdb_printf("%-16s %-4s FILE:LINE\n", "TIME", "TAG");
289 		func = opt_s ? trprint_cpp_stack : trprint_cpp;
290 	} else {
291 		mdb_printf("%-16s %-4s %-5s MSG\n", "TIME", "TAG", "ERRNO");
292 		func = opt_s ? trprint_msg_stack : trprint_msg;
293 	}
294 
295 	if (mdb_walk("fmd_trace", (mdb_walk_cb_t)func, (void *)tid) == -1) {
296 		mdb_warn("failed to walk fmd_trace");
297 		return (DCMD_ERR);
298 	}
299 
300 	return (DCMD_OK);
301 }
302 
303 static int
304 hash_walk_init(mdb_walk_state_t *wsp, uintptr_t addr, uint_t hashlen,
305     const char *name, size_t size, size_t next)
306 {
307 	hashwalk_data_t *hwp;
308 	size_t len = sizeof (uintptr_t) * hashlen;
309 
310 	if (len == 0) {
311 		mdb_warn("failed to walk hash: invalid hash length\n");
312 		return (WALK_ERR);
313 	}
314 
315 	hwp = mdb_alloc(sizeof (hashwalk_data_t), UM_SLEEP);
316 	hwp->hw_hash = mdb_zalloc(len, UM_SLEEP);
317 	(void) mdb_vread(hwp->hw_hash, len, addr);
318 	hwp->hw_hashlen = hashlen;
319 	hwp->hw_hashidx = 0;
320 	hwp->hw_name = name;
321 	hwp->hw_data = mdb_zalloc(size, UM_SLEEP);
322 	hwp->hw_size = size;
323 	hwp->hw_next = next;
324 
325 	wsp->walk_addr = hwp->hw_hash[0];
326 	wsp->walk_data = hwp;
327 
328 	return (WALK_NEXT);
329 }
330 
331 static int
332 hash_walk_step(mdb_walk_state_t *wsp)
333 {
334 	hashwalk_data_t *hwp = wsp->walk_data;
335 	int rv;
336 
337 	while (wsp->walk_addr == NULL) {
338 		if (++hwp->hw_hashidx < hwp->hw_hashlen)
339 			wsp->walk_addr = hwp->hw_hash[hwp->hw_hashidx];
340 		else
341 			return (WALK_DONE);
342 	}
343 
344 	if (mdb_vread(hwp->hw_data, hwp->hw_size, wsp->walk_addr) == -1) {
345 		mdb_warn("failed to read %s at %p",
346 		    hwp->hw_name, wsp->walk_addr);
347 		return (WALK_ERR);
348 	}
349 
350 	rv = wsp->walk_callback(wsp->walk_addr, hwp->hw_data, wsp->walk_cbdata);
351 	wsp->walk_addr = *(uintptr_t *)((uintptr_t)hwp->hw_data + hwp->hw_next);
352 	return (rv);
353 }
354 
355 static void
356 hash_walk_fini(mdb_walk_state_t *wsp)
357 {
358 	hashwalk_data_t *hwp = wsp->walk_data;
359 
360 	mdb_free(hwp->hw_hash, sizeof (uintptr_t) * hwp->hw_hashlen);
361 	mdb_free(hwp->hw_data, hwp->hw_size);
362 	mdb_free(hwp, sizeof (hashwalk_data_t));
363 }
364 
365 static int
366 ustat_walk_init(mdb_walk_state_t *wsp)
367 {
368 	fmd_ustat_t us;
369 
370 	if (mdb_vread(&us, sizeof (us), wsp->walk_addr) != sizeof (us)) {
371 		mdb_warn("failed to read fmd_ustat_t at %p", wsp->walk_addr);
372 		return (WALK_ERR);
373 	}
374 
375 	return (hash_walk_init(wsp,
376 	    (uintptr_t)us.us_hash, us.us_hashlen, NULL, 0, 0));
377 }
378 
379 static int
380 ustat_walk_step(mdb_walk_state_t *wsp)
381 {
382 	hashwalk_data_t *hwp = wsp->walk_data;
383 	fmd_ustat_elem_t ue;
384 	fmd_stat_t s;
385 
386 	while (wsp->walk_addr == NULL) {
387 		if (++hwp->hw_hashidx < hwp->hw_hashlen)
388 			wsp->walk_addr = hwp->hw_hash[hwp->hw_hashidx];
389 		else
390 			return (WALK_DONE);
391 	}
392 
393 	if (mdb_vread(&ue, sizeof (ue), wsp->walk_addr) != sizeof (ue) ||
394 	    mdb_vread(&s, sizeof (s), (uintptr_t)ue.use_stat) != sizeof (s)) {
395 		mdb_warn("failed to read stat element at %p", wsp->walk_addr);
396 		return (WALK_ERR);
397 	}
398 
399 	wsp->walk_addr = (uintptr_t)ue.use_next;
400 
401 	return (wsp->walk_callback(
402 	    (uintptr_t)ue.use_stat, &s, wsp->walk_cbdata));
403 }
404 
405 static int
406 fmd_ustat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
407 {
408 	if (!(flags & DCMD_ADDRSPEC))
409 		return (DCMD_USAGE);
410 
411 	if (mdb_pwalk_dcmd("fmd_ustat", "fmd_stat", argc, argv, addr) != 0) {
412 		mdb_warn("failed to walk fmd_ustat at %p", addr);
413 		return (DCMD_ERR);
414 	}
415 
416 	return (DCMD_OK);
417 }
418 
419 /*ARGSUSED*/
420 static int
421 fmd_stat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
422 {
423 	char buf[512];
424 	fmd_stat_t s;
425 
426 	if (!(flags & DCMD_ADDRSPEC) || argc != 0)
427 		return (DCMD_USAGE);
428 
429 	if (DCMD_HDRSPEC(flags))
430 		mdb_printf("%<u>%-11s %-4s %-32s %s%</u>\n",
431 		    "ADDR", "TYPE", "NAME", "VALUE");
432 
433 	if (mdb_vread(&s, sizeof (s), addr) != sizeof (s)) {
434 		mdb_warn("failed to read statistic at %p", addr);
435 		return (DCMD_ERR);
436 	}
437 
438 	switch (s.fmds_type) {
439 	case FMD_TYPE_BOOL:
440 		mdb_printf("%-11p %-4s %-32s %s\n", addr, "bool",
441 		    s.fmds_name, s.fmds_value.bool ? "true" : "false");
442 		break;
443 	case FMD_TYPE_INT32:
444 		mdb_printf("%-11p %-4s %-32s %d\n", addr, "i32",
445 		    s.fmds_name, s.fmds_value.i32);
446 		break;
447 	case FMD_TYPE_UINT32:
448 		mdb_printf("%-11p %-4s %-32s %u\n", addr, "ui32",
449 		    s.fmds_name, s.fmds_value.i32);
450 		break;
451 	case FMD_TYPE_INT64:
452 		mdb_printf("%-11p %-4s %-32s %lld\n", addr, "i64",
453 		    s.fmds_name, s.fmds_value.i64);
454 		break;
455 	case FMD_TYPE_UINT64:
456 		mdb_printf("%-11p %-4s %-32s %llu\n", addr, "ui64",
457 		    s.fmds_name, s.fmds_value.ui64);
458 		break;
459 	case FMD_TYPE_STRING:
460 		if (mdb_readstr(buf, sizeof (buf),
461 		    (uintptr_t)s.fmds_value.str) < 0) {
462 			(void) mdb_snprintf(buf, sizeof (buf), "<%p>",
463 			    s.fmds_value.str);
464 		}
465 		mdb_printf("%-11p %-4s %-32s %s\n", addr, "str",
466 		    s.fmds_name, buf);
467 		break;
468 	case FMD_TYPE_TIME:
469 		mdb_printf("%-11p %-4s %-32s %llu\n", addr, "time",
470 		    s.fmds_name, s.fmds_value.ui64);
471 		break;
472 	case FMD_TYPE_SIZE:
473 		mdb_printf("%-11p %-4s %-32s %llu\n", addr, "size",
474 		    s.fmds_name, s.fmds_value.ui64);
475 		break;
476 	default:
477 		mdb_printf("%-11p %-4u %-32s ???\n", addr,
478 		    s.fmds_type, s.fmds_name);
479 		break;
480 	}
481 
482 	return (DCMD_OK);
483 }
484 
485 /*ARGSUSED*/
486 static int
487 fmd_event(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
488 {
489 	char type[16], name[16];
490 	fmd_event_impl_t ev;
491 
492 	if (argc != 0)
493 		return (DCMD_USAGE);
494 
495 	if (mdb_vread(&ev, sizeof (ev), addr) != sizeof (ev)) {
496 		mdb_warn("failed to read fmd_event at %p", addr);
497 		return (DCMD_ERR);
498 	}
499 
500 	if (DCMD_HDRSPEC(flags)) {
501 		mdb_printf("%<u>%-11s %-4s %-5s %-3s %-?s%</u>\n",
502 		    "ADDR", "TYPE", "STATE", "REF", "NVPAIR");
503 	}
504 
505 	switch (ev.ev_type) {
506 	case FMD_EVT_PROTOCOL:
507 		(void) strcpy(type, "PROT");
508 		break;
509 	case FMD_EVT_GC:
510 		(void) strcpy(type, "GC");
511 		break;
512 	case FMD_EVT_CLOSE:
513 		(void) strcpy(type, "CLSE");
514 		break;
515 	case FMD_EVT_TIMEOUT:
516 		(void) strcpy(type, "TIME");
517 		break;
518 	case FMD_EVT_STATS:
519 		(void) strcpy(type, "STAT");
520 		break;
521 	case FMD_EVT_PUBLISH:
522 		(void) strcpy(type, "PUBL");
523 		break;
524 	case FMD_EVT_TOPO:
525 		(void) strcpy(type, "TOPO");
526 		break;
527 	default:
528 		(void) mdb_snprintf(type, sizeof (type), "%u", ev.ev_type);
529 	}
530 
531 	switch (ev.ev_state) {
532 	case FMD_EVS_RECEIVED:
533 		(void) strcpy(name, "RECVD");
534 		break;
535 	case FMD_EVS_ACCEPTED:
536 		(void) strcpy(name, "ACCPT");
537 		break;
538 	case FMD_EVS_DISCARDED:
539 		(void) strcpy(name, "DSCRD");
540 		break;
541 	case FMD_EVS_DIAGNOSED:
542 		(void) strcpy(name, "DIAGN");
543 		break;
544 	default:
545 		(void) mdb_snprintf(name, sizeof (name), "%u", ev.ev_state);
546 	}
547 
548 	mdb_printf("%-11p %-4s %-5s %-3u %p\n",
549 	    addr, type, name, ev.ev_refs, ev.ev_nvl);
550 
551 	return (DCMD_OK);
552 }
553 
554 static int
555 thread_walk_init(mdb_walk_state_t *wsp)
556 {
557 	fmd_t F;
558 
559 	if (mdb_readvar(&F, "fmd") != sizeof (F)) {
560 		mdb_warn("failed to read fmd meta-data");
561 		return (WALK_ERR);
562 	}
563 
564 	wsp->walk_addr = (uintptr_t)F.d_thr_list.l_next;
565 	return (WALK_NEXT);
566 }
567 
568 static int
569 thread_walk_step(mdb_walk_state_t *wsp)
570 {
571 	uintptr_t addr = wsp->walk_addr;
572 	fmd_thread_t t;
573 
574 	if (addr == NULL)
575 		return (WALK_DONE);
576 
577 	if (mdb_vread(&t, sizeof (t), addr) != sizeof (t)) {
578 		mdb_warn("failed to read fmd_thread at %p", addr);
579 		return (WALK_ERR);
580 	}
581 
582 	wsp->walk_addr = (uintptr_t)t.thr_list.l_next;
583 	return (wsp->walk_callback(addr, &t, wsp->walk_cbdata));
584 }
585 
586 static int
587 fmd_thread(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
588 {
589 	fmd_thread_t thr;
590 
591 	if (!(flags & DCMD_ADDRSPEC))
592 		return (mdb_walk_dcmd("fmd_thread", "fmd_thread", argc, argv));
593 
594 	if (argc != 0)
595 		return (DCMD_USAGE);
596 
597 	if (mdb_vread(&thr, sizeof (thr), addr) != sizeof (thr)) {
598 		mdb_warn("failed to read fmd_thread at %p", addr);
599 		return (DCMD_ERR);
600 	}
601 
602 	if (DCMD_HDRSPEC(flags)) {
603 		mdb_printf("%<u>%-11s %-11s %-8s %-16s%</u>\n",
604 		    "ADDR", "MOD", "TID", "FUNC");
605 	}
606 
607 	mdb_printf("%-11p %-11p %-8u %a\n",
608 	    addr, thr.thr_mod, thr.thr_tid, thr.thr_func);
609 
610 	return (DCMD_OK);
611 }
612 
613 static int
614 mod_walk_init(mdb_walk_state_t *wsp)
615 {
616 	fmd_t F;
617 
618 	if (mdb_readvar(&F, "fmd") != sizeof (F)) {
619 		mdb_warn("failed to read fmd meta-data");
620 		return (WALK_ERR);
621 	}
622 
623 	wsp->walk_addr = (uintptr_t)F.d_mod_list.l_next;
624 	return (WALK_NEXT);
625 }
626 
627 static int
628 mod_walk_step(mdb_walk_state_t *wsp)
629 {
630 	uintptr_t addr = wsp->walk_addr;
631 	fmd_module_t m;
632 
633 	if (addr == NULL)
634 		return (WALK_DONE);
635 
636 	if (mdb_vread(&m, sizeof (m), addr) != sizeof (m)) {
637 		mdb_warn("failed to read fmd_module at %p", addr);
638 		return (WALK_ERR);
639 	}
640 
641 	wsp->walk_addr = (uintptr_t)m.mod_list.l_next;
642 	return (wsp->walk_callback(addr, &m, wsp->walk_cbdata));
643 }
644 
645 static int
646 fmd_module(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
647 {
648 	fmd_module_t mod;
649 	char name[256];
650 
651 	if (!(flags & DCMD_ADDRSPEC))
652 		return (mdb_walk_dcmd("fmd_module", "fmd_module", argc, argv));
653 
654 	if (argc != 0)
655 		return (DCMD_USAGE);
656 
657 	if (mdb_vread(&mod, sizeof (mod), addr) != sizeof (mod)) {
658 		mdb_warn("failed to read fmd_module at %p", addr);
659 		return (DCMD_ERR);
660 	}
661 
662 	if (DCMD_HDRSPEC(flags)) {
663 		mdb_printf("%<u>%-11s %-16s %-11s %-4s %-?s %-16s%</u>\n",
664 		    "ADDR", "OPS", "DATA", "FLAG", "USTAT", "NAME");
665 	}
666 
667 	if (mdb_readstr(name, sizeof (name), (uintptr_t)mod.mod_name) <= 0)
668 		(void) mdb_snprintf(name, sizeof (name), "<%p>", mod.mod_name);
669 
670 	mdb_printf("%-11p %-16a %-11p 0x%02x %-?p %s\n", addr,
671 	    mod.mod_ops, mod.mod_data, mod.mod_flags, mod.mod_ustat, name);
672 
673 	return (DCMD_OK);
674 }
675 
676 static int
677 case_walk_init(mdb_walk_state_t *wsp)
678 {
679 	fmd_module_t mod;
680 	fmd_case_hash_t ch;
681 	fmd_t F;
682 
683 	if (wsp->walk_addr != NULL) {
684 		if (mdb_vread(&mod, sizeof (mod), wsp->walk_addr) == -1) {
685 			mdb_warn("failed to read module at %p", wsp->walk_addr);
686 			return (WALK_ERR);
687 		}
688 
689 		wsp->walk_addr = (uintptr_t)mod.mod_cases.l_next;
690 		return (WALK_NEXT);
691 	}
692 
693 	if (mdb_readvar(&F, "fmd") != sizeof (F) ||
694 	    mdb_vread(&ch, sizeof (ch), (uintptr_t)F.d_cases) != sizeof (ch)) {
695 		mdb_warn("failed to read fmd meta-data");
696 		return (WALK_ERR);
697 	}
698 
699 	return (hash_walk_init(wsp, (uintptr_t)ch.ch_hash, ch.ch_hashlen,
700 	    "fmd_case", sizeof (fmd_case_impl_t),
701 	    OFFSETOF(fmd_case_impl_t, ci_next)));
702 }
703 
704 static int
705 case_walk_step(mdb_walk_state_t *wsp)
706 {
707 	uintptr_t addr = wsp->walk_addr;
708 	fmd_case_impl_t ci;
709 
710 	if (wsp->walk_data != NULL)
711 		return (hash_walk_step(wsp));
712 
713 	if (addr == NULL)
714 		return (WALK_DONE);
715 
716 	if (mdb_vread(&ci, sizeof (ci), addr) != sizeof (ci)) {
717 		mdb_warn("failed to read fmd_case at %p", addr);
718 		return (WALK_ERR);
719 	}
720 
721 	wsp->walk_addr = (uintptr_t)ci.ci_list.l_next;
722 	return (wsp->walk_callback(addr, &ci, wsp->walk_cbdata));
723 }
724 
725 static void
726 case_walk_fini(mdb_walk_state_t *wsp)
727 {
728 	if (wsp->walk_data != NULL)
729 		hash_walk_fini(wsp);
730 }
731 
732 static int
733 fmd_case(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
734 {
735 	char uuid[48], name[16];
736 	fmd_case_impl_t ci;
737 
738 	if (!(flags & DCMD_ADDRSPEC)) {
739 		if (mdb_walk_dcmd("fmd_case", "fmd_case", argc, argv) != 0) {
740 			mdb_warn("failed to walk fmd_case hash");
741 			return (DCMD_ERR);
742 		}
743 		return (DCMD_OK);
744 	}
745 
746 	if (mdb_vread(&ci, sizeof (ci), addr) != sizeof (ci)) {
747 		mdb_warn("failed to read fmd_case at %p", addr);
748 		return (DCMD_ERR);
749 	}
750 
751 	if (DCMD_HDRSPEC(flags)) {
752 		mdb_printf("%<u>%-11s %-5s %-3s %-?s %-36s%</u>\n",
753 		    "ADDR", "STATE", "REF", "DATA", "UUID");
754 	}
755 
756 	if (mdb_readstr(uuid, sizeof (uuid), (uintptr_t)ci.ci_uuid) <= 0)
757 		(void) mdb_snprintf(uuid, sizeof (uuid), "<%p>", ci.ci_uuid);
758 
759 	switch (ci.ci_state) {
760 	case FMD_CASE_UNSOLVED:
761 		(void) strcpy(name, "UNSLV");
762 		break;
763 	case FMD_CASE_SOLVED:
764 		(void) strcpy(name, "SOLVE");
765 		break;
766 	case FMD_CASE_CLOSE_WAIT:
767 		(void) strcpy(name, "CWAIT");
768 		break;
769 	case FMD_CASE_CLOSED:
770 		(void) strcpy(name, "CLOSE");
771 		break;
772 	case FMD_CASE_REPAIRED:
773 		(void) strcpy(name, "RPAIR");
774 		break;
775 	default:
776 		(void) mdb_snprintf(name, sizeof (name), "%u", ci.ci_state);
777 	}
778 
779 	mdb_printf("%-11p %-5s %-3u %-?p %s\n",
780 	    addr, name, ci.ci_refs, ci.ci_data, uuid);
781 
782 	return (DCMD_OK);
783 }
784 
785 static int
786 buf_walk_init(mdb_walk_state_t *wsp)
787 {
788 	fmd_buf_hash_t bh;
789 
790 	if (mdb_vread(&bh, sizeof (bh), wsp->walk_addr) != sizeof (bh)) {
791 		mdb_warn("failed to read fmd_buf_hash_t at %p", wsp->walk_addr);
792 		return (WALK_ERR);
793 	}
794 
795 	return (hash_walk_init(wsp, (uintptr_t)bh.bh_hash, bh.bh_hashlen,
796 	    "fmd_buf", sizeof (fmd_buf_t), OFFSETOF(fmd_buf_t, buf_next)));
797 }
798 
799 /*ARGSUSED*/
800 static int
801 fmd_buf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
802 {
803 	char name[256];
804 	fmd_buf_t b;
805 
806 	if (argc != 0 || !(flags & DCMD_ADDRSPEC))
807 		return (DCMD_USAGE);
808 
809 	if (mdb_vread(&b, sizeof (b), addr) != sizeof (b)) {
810 		mdb_warn("failed to read fmd_buf at %p", addr);
811 		return (DCMD_ERR);
812 	}
813 
814 	if (DCMD_HDRSPEC(flags)) {
815 		mdb_printf("%<u>%-11s %-32s %-5s %-?s %s%</u>\n",
816 		    "ADDR", "NAME", "FLAGS", "DATA", "SIZE");
817 	}
818 
819 	if (mdb_readstr(name, sizeof (name), (uintptr_t)b.buf_name) <= 0)
820 		(void) mdb_snprintf(name, sizeof (name), "<%p>", b.buf_name);
821 
822 	mdb_printf("%-11p %-32s %-#5x %-?p %lu\n",
823 	    addr, name, b.buf_flags, b.buf_data, b.buf_size);
824 
825 	return (DCMD_OK);
826 }
827 
828 static int
829 serd_walk_init(mdb_walk_state_t *wsp)
830 {
831 	fmd_serd_hash_t sh;
832 
833 	if (mdb_vread(&sh, sizeof (sh), wsp->walk_addr) != sizeof (sh)) {
834 		mdb_warn("failed to read fmd_serd_hash at %p", wsp->walk_addr);
835 		return (WALK_ERR);
836 	}
837 
838 	return (hash_walk_init(wsp, (uintptr_t)sh.sh_hash, sh.sh_hashlen,
839 	    "fmd_serd_eng", sizeof (fmd_serd_eng_t),
840 	    OFFSETOF(fmd_serd_eng_t, sg_next)));
841 }
842 
843 /*ARGSUSED*/
844 static int
845 fmd_serd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
846 {
847 	char name[256];
848 	fmd_serd_eng_t sg;
849 
850 	if (argc != 0 || !(flags & DCMD_ADDRSPEC))
851 		return (DCMD_USAGE);
852 
853 	if (mdb_vread(&sg, sizeof (sg), addr) != sizeof (sg)) {
854 		mdb_warn("failed to read fmd_serd_eng at %p", addr);
855 		return (DCMD_ERR);
856 	}
857 
858 	if (DCMD_HDRSPEC(flags)) {
859 		mdb_printf("%<u>%-11s %-32s %-3s F >%-2s %-16s%</u>\n",
860 		    "ADDR", "NAME", "CNT", "N", "T");
861 	}
862 
863 	if (mdb_readstr(name, sizeof (name), (uintptr_t)sg.sg_name) <= 0)
864 		(void) mdb_snprintf(name, sizeof (name), "<%p>", sg.sg_name);
865 
866 	mdb_printf("%-11p %-32s %-3u %c >%-2u %lluns\n",
867 	    addr, name, sg.sg_count, (sg.sg_flags & FMD_SERD_FIRED) ? 'F' : ' ',
868 	    sg.sg_n, (u_longlong_t)sg.sg_t);
869 
870 	return (DCMD_OK);
871 }
872 
873 static int
874 asru_walk_init(mdb_walk_state_t *wsp)
875 {
876 	fmd_asru_hash_t ah;
877 	fmd_t F;
878 
879 	if (wsp->walk_addr == NULL && mdb_readvar(&F, "fmd") != sizeof (F)) {
880 		mdb_warn("failed to read fmd meta-data");
881 		return (WALK_ERR);
882 	}
883 
884 	if (wsp->walk_addr == NULL)
885 		wsp->walk_addr = (uintptr_t)F.d_asrus;
886 
887 	if (mdb_vread(&ah, sizeof (ah), wsp->walk_addr) != sizeof (ah)) {
888 		mdb_warn("failed to read asru_hash at %p", wsp->walk_addr);
889 		return (WALK_ERR);
890 	}
891 
892 	return (hash_walk_init(wsp, (uintptr_t)ah.ah_hash, ah.ah_hashlen,
893 	    "fmd_asru", sizeof (fmd_asru_t), OFFSETOF(fmd_asru_t, asru_next)));
894 }
895 
896 static int
897 fmd_asru(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
898 {
899 	char uuid[48], name[256];
900 	fmd_asru_t a;
901 
902 	if (!(flags & DCMD_ADDRSPEC)) {
903 		if (mdb_walk_dcmd("fmd_asru", "fmd_asru", argc, argv) != 0) {
904 			mdb_warn("failed to walk fmd_asru hash");
905 			return (DCMD_ERR);
906 		}
907 		return (DCMD_OK);
908 	}
909 
910 	if (mdb_vread(&a, sizeof (a), addr) != sizeof (a)) {
911 		mdb_warn("failed to read fmd_asru at %p", addr);
912 		return (DCMD_ERR);
913 	}
914 
915 	if (DCMD_HDRSPEC(flags))
916 		mdb_printf("%<u>%-8s %-36s %s%</u>\n", "ADDR", "UUID", "NAME");
917 
918 	if (mdb_readstr(uuid, sizeof (uuid), (uintptr_t)a.asru_uuid) <= 0)
919 		(void) mdb_snprintf(uuid, sizeof (uuid), "<%p>", a.asru_uuid);
920 	if (mdb_readstr(name, sizeof (name), (uintptr_t)a.asru_name) <= 0)
921 		(void) mdb_snprintf(name, sizeof (name), "<%p>", a.asru_name);
922 
923 	mdb_printf("%-8p %-36s %s\n", addr, uuid, name);
924 	return (DCMD_OK);
925 }
926 
927 /*ARGSUSED*/
928 static int
929 fcf_hdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
930 {
931 	fcf_hdr_t h;
932 
933 	if (argc != 0)
934 		return (DCMD_USAGE);
935 
936 	if (!(flags & DCMD_ADDRSPEC))
937 		addr = 0; /* assume base of file in file target */
938 
939 	if (mdb_vread(&h, sizeof (h), addr) != sizeof (h)) {
940 		mdb_warn("failed to read header at %p", addr);
941 		return (DCMD_ERR);
942 	}
943 
944 	mdb_printf("fcfh_ident.id_magic = 0x%x, %c, %c, %c\n",
945 	    h.fcfh_ident[FCF_ID_MAG0], h.fcfh_ident[FCF_ID_MAG1],
946 	    h.fcfh_ident[FCF_ID_MAG2], h.fcfh_ident[FCF_ID_MAG3]);
947 
948 	switch (h.fcfh_ident[FCF_ID_MODEL]) {
949 	case FCF_MODEL_ILP32:
950 		mdb_printf("fcfh_ident.id_model = ILP32\n");
951 		break;
952 	case FCF_MODEL_LP64:
953 		mdb_printf("fcfh_ident.id_model = LP64\n");
954 		break;
955 	default:
956 		mdb_printf("fcfh_ident.id_model = 0x%x\n",
957 		    h.fcfh_ident[FCF_ID_MODEL]);
958 	}
959 
960 	switch (h.fcfh_ident[FCF_ID_ENCODING]) {
961 	case FCF_ENCODE_LSB:
962 		mdb_printf("fcfh_ident.id_encoding = LSB\n");
963 		break;
964 	case FCF_ENCODE_MSB:
965 		mdb_printf("fcfh_ident.id_encoding = MSB\n");
966 		break;
967 	default:
968 		mdb_printf("fcfh_ident.id_encoding = 0x%x\n",
969 		    h.fcfh_ident[FCF_ID_ENCODING]);
970 	}
971 
972 	mdb_printf("fcfh_ident.id_version = %u\n",
973 	    h.fcfh_ident[FCF_ID_VERSION]);
974 
975 	mdb_printf("fcfh_flags = 0x%x\n", h.fcfh_flags);
976 	mdb_printf("fcfh_hdrsize = %u\n", h.fcfh_hdrsize);
977 	mdb_printf("fcfh_secsize = %u\n", h.fcfh_secsize);
978 	mdb_printf("fcfh_secnum = %u\n", h.fcfh_secnum);
979 	mdb_printf("fcfh_secoff = %llu\n", h.fcfh_secoff);
980 	mdb_printf("fcfh_filesz = %llu\n", h.fcfh_filesz);
981 	mdb_printf("fcfh_cgen = %llu\n", h.fcfh_cgen);
982 
983 	return (DCMD_OK);
984 }
985 
986 /*ARGSUSED*/
987 static int
988 fcf_sec_one(uintptr_t addr, void *ignored, uint_t *secp)
989 {
990 	static int fcf_sec(uintptr_t, uint_t, int, const mdb_arg_t *);
991 
992 	mdb_printf("%3d ", (*secp)++);
993 	(void) fcf_sec(addr, DCMD_ADDRSPEC | DCMD_LOOP, 0, NULL);
994 	return (WALK_NEXT);
995 }
996 
997 /*ARGSUSED*/
998 static int
999 fcf_sec(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1000 {
1001 	static const char *const types[] = {
1002 		"none",		/* FCF_SECT_NONE */
1003 		"strtab",	/* FCF_SECT_STRTAB */
1004 		"module",	/* FCF_SECT_MODULE */
1005 		"case",		/* FCF_SECT_CASE */
1006 		"bufs",		/* FCF_SECT_BUFS */
1007 		"buffer",	/* FCF_SECT_BUFFER */
1008 		"serd",		/* FCF_SECT_SERD */
1009 		"events",	/* FCF_SECT_EVENTS */
1010 		"nvlists",	/* FCF_SECT_NVLISTS */
1011 	};
1012 
1013 	uint_t sec = 0;
1014 	fcf_sec_t s;
1015 
1016 	if (!(flags & DCMD_ADDRSPEC))
1017 		mdb_printf("%<u>%-3s ", "NDX");
1018 
1019 	if (!(flags & DCMD_ADDRSPEC) || DCMD_HDRSPEC(flags)) {
1020 		mdb_printf("%<u>%?s %-10s %-5s %-5s %-5s %-6s %-5s%</u>\n",
1021 		    "ADDR", "TYPE", "ALIGN", "FLAGS", "ENTSZ", "OFF", "SIZE");
1022 	}
1023 
1024 	if (!(flags & DCMD_ADDRSPEC)) {
1025 		if (mdb_walk("fcf_sec", (mdb_walk_cb_t)fcf_sec_one, &sec) < 0) {
1026 			mdb_warn("failed to walk fcf_sec");
1027 			return (DCMD_ERR);
1028 		}
1029 		return (DCMD_OK);
1030 	}
1031 
1032 	if (argc != 0)
1033 		return (DCMD_USAGE);
1034 
1035 	if (mdb_vread(&s, sizeof (s), addr) != sizeof (s)) {
1036 		mdb_warn("failed to read section header at %p", addr);
1037 		return (DCMD_ERR);
1038 	}
1039 
1040 	mdb_printf("%?p ", addr);
1041 
1042 	if (s.fcfs_type < sizeof (types) / sizeof (types[0]))
1043 		mdb_printf("%-10s ", types[s.fcfs_type]);
1044 	else
1045 		mdb_printf("%-10u ", s.fcfs_type);
1046 
1047 	mdb_printf("%-5u %-#5x %-#5x %-6llx %-#5llx\n", s.fcfs_align,
1048 	    s.fcfs_flags, s.fcfs_entsize, s.fcfs_offset, s.fcfs_size);
1049 
1050 	return (DCMD_OK);
1051 }
1052 
1053 static int
1054 fcf_sec_walk_init(mdb_walk_state_t *wsp)
1055 {
1056 	fcf_hdr_t h, *hp;
1057 	size_t size;
1058 
1059 	if (mdb_vread(&h, sizeof (h), wsp->walk_addr) != sizeof (h)) {
1060 		mdb_warn("failed to read FCF header at %p", wsp->walk_addr);
1061 		return (WALK_ERR);
1062 	}
1063 
1064 	size = sizeof (fcf_hdr_t) + sizeof (fcf_sec_t) * h.fcfh_secnum;
1065 	hp = mdb_alloc(size, UM_SLEEP);
1066 
1067 	if (mdb_vread(hp, size, wsp->walk_addr) != size) {
1068 		mdb_warn("failed to read FCF sections at %p", wsp->walk_addr);
1069 		mdb_free(hp, size);
1070 		return (WALK_ERR);
1071 	}
1072 
1073 	wsp->walk_data = hp;
1074 	wsp->walk_arg = 0;
1075 
1076 	return (WALK_NEXT);
1077 }
1078 
1079 static int
1080 fcf_sec_walk_step(mdb_walk_state_t *wsp)
1081 {
1082 	uint_t i = (uint_t)wsp->walk_arg;
1083 	size_t off = sizeof (fcf_hdr_t) + sizeof (fcf_sec_t) * i;
1084 	fcf_hdr_t *hp = wsp->walk_data;
1085 	fcf_sec_t *sp = (fcf_sec_t *)((uintptr_t)hp + off);
1086 
1087 	if (i >= hp->fcfh_secnum)
1088 		return (WALK_DONE);
1089 
1090 	wsp->walk_arg = (void *)(i + 1);
1091 	return (wsp->walk_callback(wsp->walk_addr + off, sp, wsp->walk_cbdata));
1092 }
1093 
1094 static void
1095 fcf_sec_walk_fini(mdb_walk_state_t *wsp)
1096 {
1097 	fcf_hdr_t *hp = wsp->walk_data;
1098 	mdb_free(hp, sizeof (fcf_hdr_t) + sizeof (fcf_sec_t) * hp->fcfh_secnum);
1099 }
1100 
1101 /*ARGSUSED*/
1102 static int
1103 fcf_case(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1104 {
1105 	fcf_case_t fcfc;
1106 
1107 	if (argc != 0)
1108 		return (DCMD_USAGE);
1109 
1110 	if (mdb_vread(&fcfc, sizeof (fcfc), addr) != sizeof (fcfc)) {
1111 		mdb_warn("failed to read case at %p", addr);
1112 		return (DCMD_ERR);
1113 	}
1114 
1115 	mdb_printf("fcfc_uuid = 0x%x\n", fcfc.fcfc_uuid);
1116 	mdb_printf("fcfc_state = %u\n", fcfc.fcfc_state);
1117 	mdb_printf("fcfc_bufs = %u\n", fcfc.fcfc_bufs);
1118 	mdb_printf("fcfc_events = %u\n", fcfc.fcfc_events);
1119 	mdb_printf("fcfc_suspects = %u\n", fcfc.fcfc_suspects);
1120 
1121 	return (DCMD_OK);
1122 }
1123 
1124 /*ARGSUSED*/
1125 static int
1126 fcf_event(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1127 {
1128 	fcf_event_t fcfe;
1129 
1130 	if (argc != 0)
1131 		return (DCMD_USAGE);
1132 
1133 	if (mdb_vread(&fcfe, sizeof (fcfe), addr) != sizeof (fcfe)) {
1134 		mdb_warn("failed to read event at %p", addr);
1135 		return (DCMD_ERR);
1136 	}
1137 
1138 	mdb_printf("fcfe_todsec = %llu (%Y)\n",
1139 	    fcfe.fcfe_todsec, (time_t)fcfe.fcfe_todsec);
1140 	mdb_printf("fcfe_todnsec = %llu\n", fcfe.fcfe_todnsec);
1141 	mdb_printf("fcfe_major = %u\n", fcfe.fcfe_major);
1142 	mdb_printf("fcfe_minor = %u\n", fcfe.fcfe_minor);
1143 	mdb_printf("fcfe_inode = %llu\n", fcfe.fcfe_inode);
1144 	mdb_printf("fcfe_offset = %llu\n", fcfe.fcfe_offset);
1145 
1146 	return (DCMD_OK);
1147 }
1148 
1149 /*ARGSUSED*/
1150 static int
1151 fcf_serd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1152 {
1153 	fcf_serd_t fcfd;
1154 
1155 	if (argc != 0)
1156 		return (DCMD_USAGE);
1157 
1158 	if (mdb_vread(&fcfd, sizeof (fcfd), addr) != sizeof (fcfd)) {
1159 		mdb_warn("failed to read serd at %p", addr);
1160 		return (DCMD_ERR);
1161 	}
1162 
1163 	mdb_printf("fcfd_name = 0x%x\n", fcfd.fcfd_name);
1164 	mdb_printf("fcfd_events = %u\n", fcfd.fcfd_events);
1165 	mdb_printf("fcfd_n = >%u\n", fcfd.fcfd_n);
1166 	mdb_printf("fcfd_t = %lluns\n", fcfd.fcfd_t);
1167 
1168 	return (DCMD_OK);
1169 }
1170 
1171 static int
1172 tmq_walk_init(mdb_walk_state_t *wsp)
1173 {
1174 	fmd_timerq_t tmq;
1175 	fmd_t F;
1176 
1177 	if (wsp->walk_addr == NULL && mdb_readvar(&F, "fmd") != sizeof (F)) {
1178 		mdb_warn("failed to read fmd meta-data");
1179 		return (WALK_ERR);
1180 	}
1181 
1182 	if (wsp->walk_addr == NULL)
1183 		wsp->walk_addr = (uintptr_t)F.d_timers;
1184 
1185 	if (mdb_vread(&tmq, sizeof (tmq), wsp->walk_addr) != sizeof (tmq)) {
1186 		mdb_warn("failed to read timerq at %p", wsp->walk_addr);
1187 		return (WALK_ERR);
1188 	}
1189 
1190 	wsp->walk_addr = (uintptr_t)tmq.tmq_list.l_next;
1191 	return (WALK_NEXT);
1192 }
1193 
1194 static int
1195 tmq_walk_step(mdb_walk_state_t *wsp)
1196 {
1197 	uintptr_t addr = wsp->walk_addr;
1198 	fmd_timer_t tmr;
1199 
1200 	if (addr == NULL)
1201 		return (WALK_DONE);
1202 
1203 	if (mdb_vread(&tmr, sizeof (tmr), addr) != sizeof (tmr)) {
1204 		mdb_warn("failed to read fmd_timer at %p", addr);
1205 		return (WALK_ERR);
1206 	}
1207 
1208 	wsp->walk_addr = (uintptr_t)tmr.tmr_list.l_next;
1209 	return (wsp->walk_callback(addr, &tmr, wsp->walk_cbdata));
1210 }
1211 
1212 static int
1213 fmd_timer(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1214 {
1215 	char name[32], func[MDB_SYM_NAMLEN];
1216 	fmd_timer_t t;
1217 
1218 	if (!(flags & DCMD_ADDRSPEC)) {
1219 		if (mdb_walk_dcmd("fmd_timerq", "fmd_timer", argc, argv) != 0) {
1220 			mdb_warn("failed to walk fmd_timerq");
1221 			return (DCMD_ERR);
1222 		}
1223 		return (DCMD_OK);
1224 	}
1225 
1226 	if (mdb_vread(&t, sizeof (t), addr) != sizeof (t)) {
1227 		mdb_warn("failed to read fmd_timer at %p", addr);
1228 		return (DCMD_ERR);
1229 	}
1230 
1231 	if (DCMD_HDRSPEC(flags)) {
1232 		mdb_printf("%<u>%-8s %-20s %-4s %-18s %-8s %s%</u>\n",
1233 		    "ADDR", "MODULE", "ID", "HRTIME", "ARG", "FUNC");
1234 	}
1235 
1236 	if (mdb_readstr(name, sizeof (name), (uintptr_t)
1237 	    t.tmr_ids + OFFSETOF(fmd_idspace_t, ids_name)) <= 0)
1238 		(void) mdb_snprintf(name, sizeof (name), "<%p>", t.tmr_ids);
1239 
1240 	if (mdb_lookup_by_addr((uintptr_t)t.tmr_func, MDB_SYM_FUZZY,
1241 	    func, sizeof (func), NULL) != 0)
1242 		(void) mdb_snprintf(func, sizeof (func), "<%p>", t.tmr_func);
1243 
1244 	mdb_printf("%-8p %-20s %4d 0x%-16llx %-8p %s\n",
1245 	    addr, name, t.tmr_id, t.tmr_hrt, t.tmr_arg, func);
1246 	return (DCMD_OK);
1247 }
1248 
1249 static int
1250 xprt_walk_init(mdb_walk_state_t *wsp)
1251 {
1252 	fmd_module_t m;
1253 
1254 	if (wsp->walk_addr == NULL) {
1255 		mdb_warn("transport walker requires fmd_module_t address\n");
1256 		return (WALK_ERR);
1257 	}
1258 
1259 	if (mdb_vread(&m, sizeof (m), wsp->walk_addr) != sizeof (m)) {
1260 		mdb_warn("failed to read module at %p", wsp->walk_addr);
1261 		return (WALK_ERR);
1262 	}
1263 
1264 	wsp->walk_addr = (uintptr_t)m.mod_transports.l_next;
1265 	return (WALK_NEXT);
1266 }
1267 
1268 static int
1269 xprt_walk_step(mdb_walk_state_t *wsp)
1270 {
1271 	uintptr_t addr = wsp->walk_addr;
1272 	fmd_xprt_impl_t xi;
1273 
1274 	if (addr == NULL)
1275 		return (WALK_DONE);
1276 
1277 	if (mdb_vread(&xi, sizeof (xi), addr) != sizeof (xi)) {
1278 		mdb_warn("failed to read fmd_xprt at %p", addr);
1279 		return (WALK_ERR);
1280 	}
1281 
1282 	wsp->walk_addr = (uintptr_t)xi.xi_list.l_next;
1283 	return (wsp->walk_callback(addr, &xi, wsp->walk_cbdata));
1284 }
1285 
1286 static int
1287 xpc_walk_init(mdb_walk_state_t *wsp)
1288 {
1289 	fmd_xprt_class_hash_t xch;
1290 
1291 	if (mdb_vread(&xch, sizeof (xch), wsp->walk_addr) != sizeof (xch)) {
1292 		mdb_warn("failed to read fmd_xprt_class_hash at %p",
1293 		    wsp->walk_addr);
1294 		return (WALK_ERR);
1295 	}
1296 
1297 	return (hash_walk_init(wsp, (uintptr_t)xch.xch_hash, xch.xch_hashlen,
1298 	    "fmd_xprt_class", sizeof (fmd_xprt_class_t),
1299 	    OFFSETOF(fmd_xprt_class_t, xc_next)));
1300 }
1301 
1302 /*ARGSUSED*/
1303 static int
1304 fmd_xprt_class(uintptr_t addr, const void *data, void *arg)
1305 {
1306 	const fmd_xprt_class_t *xcp = data;
1307 	char name[1024];
1308 
1309 	if (mdb_readstr(name, sizeof (name), (uintptr_t)xcp->xc_class) <= 0)
1310 		(void) mdb_snprintf(name, sizeof (name), "<%p>", xcp->xc_class);
1311 
1312 	mdb_printf("%-8p %-4u %s\n", addr, xcp->xc_refs, name);
1313 	return (WALK_NEXT);
1314 }
1315 
1316 static int
1317 fmd_xprt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1318 {
1319 	uint_t opt_s = FALSE, opt_l = FALSE, opt_r = FALSE, opt_u = FALSE;
1320 	fmd_xprt_impl_t xi;
1321 
1322 	if (mdb_getopts(argc, argv,
1323 	    'l', MDB_OPT_SETBITS, TRUE, &opt_l,
1324 	    'r', MDB_OPT_SETBITS, TRUE, &opt_r,
1325 	    's', MDB_OPT_SETBITS, TRUE, &opt_s,
1326 	    'u', MDB_OPT_SETBITS, TRUE, &opt_u, NULL) != argc)
1327 		return (DCMD_USAGE);
1328 
1329 	if (!(flags & DCMD_ADDRSPEC)) {
1330 		if (mdb_walk_dcmd("fmd_xprt", "fmd_xprt", argc, argv) != 0) {
1331 			mdb_warn("failed to walk fmd_xprt");
1332 			return (DCMD_ERR);
1333 		}
1334 		return (DCMD_OK);
1335 	}
1336 
1337 	if (mdb_vread(&xi, sizeof (xi), addr) != sizeof (xi)) {
1338 		mdb_warn("failed to read fmd_xprt at %p", addr);
1339 		return (DCMD_ERR);
1340 	}
1341 
1342 	if (DCMD_HDRSPEC(flags)) {
1343 		mdb_printf("%<u>%-8s %-4s %-4s %-5s %s%</u>\n",
1344 		    "ADDR", "ID", "VERS", "FLAGS", "STATE");
1345 	}
1346 
1347 	mdb_printf("%-8p %-4d %-4u %-5x %a\n",
1348 	    addr, xi.xi_id, xi.xi_version, xi.xi_flags, xi.xi_state);
1349 
1350 	if (opt_l | opt_s) {
1351 		(void) mdb_inc_indent(4);
1352 		mdb_printf("Local subscriptions requested by peer:\n");
1353 		mdb_printf("%<u>%-8s %-4s %s%</u>\n", "ADDR", "REFS", "CLASS");
1354 		(void) mdb_pwalk("fmd_xprt_class", fmd_xprt_class, &xi,
1355 		    addr + OFFSETOF(fmd_xprt_impl_t, xi_lsub));
1356 		(void) mdb_dec_indent(4);
1357 	}
1358 
1359 	if (opt_r | opt_s) {
1360 		(void) mdb_inc_indent(4);
1361 		mdb_printf("Remote subscriptions requested of peer:\n");
1362 		mdb_printf("%<u>%-8s %-4s %s%</u>\n", "ADDR", "REFS", "CLASS");
1363 		(void) mdb_pwalk("fmd_xprt_class", fmd_xprt_class, &xi,
1364 		    addr + OFFSETOF(fmd_xprt_impl_t, xi_rsub));
1365 		(void) mdb_dec_indent(4);
1366 	}
1367 
1368 	if (opt_u | opt_s) {
1369 		(void) mdb_inc_indent(4);
1370 		mdb_printf("Pending unsubscription acknowledgements:\n");
1371 		mdb_printf("%<u>%-8s %-4s %s%</u>\n", "ADDR", "REFS", "CLASS");
1372 		(void) mdb_pwalk("fmd_xprt_class", fmd_xprt_class, &xi,
1373 		    addr + OFFSETOF(fmd_xprt_impl_t, xi_usub));
1374 		(void) mdb_dec_indent(4);
1375 	}
1376 
1377 	return (DCMD_OK);
1378 }
1379 
1380 static const mdb_dcmd_t dcmds[] = {
1381 	{ "fcf_case", "?", "print a FCF case", fcf_case },
1382 	{ "fcf_event", "?", "print a FCF event", fcf_event },
1383 	{ "fcf_hdr", "?", "print a FCF header", fcf_hdr },
1384 	{ "fcf_sec", ":", "print a FCF section header", fcf_sec },
1385 	{ "fcf_serd", "?", "print a FCF serd engine", fcf_serd },
1386 	{ "fmd_trace", "?[-cs]", "display thread trace buffer(s)", fmd_trace },
1387 	{ "fmd_ustat", ":", "display statistics collection", fmd_ustat },
1388 	{ "fmd_stat", ":", "display statistic structure", fmd_stat },
1389 	{ "fmd_event", NULL, "display event structure", fmd_event },
1390 	{ "fmd_thread", "?", "display thread or list of threads", fmd_thread },
1391 	{ "fmd_module", "?", "display module or list of modules", fmd_module },
1392 	{ "fmd_case", ":", "display case file structure", fmd_case },
1393 	{ "fmd_buf", ":", "display buffer structure", fmd_buf },
1394 	{ "fmd_serd", ":", "display serd engine structure", fmd_serd },
1395 	{ "fmd_asru", "?", "display asru resource structure", fmd_asru },
1396 	{ "fmd_timer", "?", "display pending timer(s)", fmd_timer },
1397 	{ "fmd_xprt", "?[-lrsu]", "display event transport(s)", fmd_xprt },
1398 	{ NULL }
1399 };
1400 
1401 static const mdb_walker_t walkers[] = {
1402 	{ "fcf_sec", "walk FCF section header table given header address",
1403 		fcf_sec_walk_init, fcf_sec_walk_step, fcf_sec_walk_fini },
1404 	{ "fmd_trace", "walk per-thread trace buffers",
1405 		trwalk_init, trwalk_step, trwalk_fini },
1406 	{ "fmd_ustat", "walk per-collection statistics",
1407 		ustat_walk_init, ustat_walk_step, hash_walk_fini },
1408 	{ "fmd_thread", "walk list of all fmd_thread_t's",
1409 		thread_walk_init, thread_walk_step, NULL },
1410 	{ "fmd_module", "walk list of all fmd_module_t's",
1411 		mod_walk_init, mod_walk_step, NULL },
1412 	{ "fmd_case", "walk per-module case objects",
1413 		case_walk_init, case_walk_step, case_walk_fini },
1414 	{ "fmd_buf", "walk per-buf_hash buffers",
1415 		buf_walk_init, hash_walk_step, hash_walk_fini },
1416 	{ "fmd_serd", "walk per-serd_hash engines",
1417 		serd_walk_init, hash_walk_step, hash_walk_fini },
1418 	{ "fmd_asru", "walk asru resource hash",
1419 		asru_walk_init, hash_walk_step, hash_walk_fini },
1420 	{ "fmd_timerq", "walk timer queue",
1421 		tmq_walk_init, tmq_walk_step, NULL },
1422 	{ "fmd_xprt", "walk per-module list of transports",
1423 		xprt_walk_init, xprt_walk_step, NULL },
1424 	{ "fmd_xprt_class", "walk hash table of subscription classes",
1425 		xpc_walk_init, hash_walk_step, hash_walk_fini },
1426 	{ NULL, NULL, NULL, NULL, NULL }
1427 };
1428 
1429 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
1430 
1431 const mdb_modinfo_t *
1432 _mdb_init(void)
1433 {
1434 	return (&modinfo);
1435 }
1436