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