xref: /titanic_52/usr/src/cmd/fm/fmd/common/fmd_mdb.c (revision af28f636873b7156cfd73ceffa927658cca33fd0)
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 (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #include <sys/mdb_modapi.h>
27 #include <limits.h>
28 
29 #include <fmd_trace.h>
30 #include <fmd_module.h>
31 #include <fmd_thread.h>
32 #include <fmd_ustat.h>
33 #include <fmd_event.h>
34 #include <fmd_case.h>
35 #include <fmd_buf.h>
36 #include <fmd_asru.h>
37 #include <fmd_ckpt.h>
38 #include <fmd_timerq.h>
39 #include <fmd_xprt.h>
40 
41 #include <fmd.h>
42 
43 typedef struct trwalk_state {
44 	struct trwalk_state *trw_next;
45 	fmd_tracebuf_t trw_data;
46 	pthread_t trw_tid;
47 	uintptr_t trw_base;
48 	const fmd_tracerec_t *trw_stop;
49 	fmd_tracerec_t *trw_xrec;
50 } trwalk_state_t;
51 
52 typedef struct hashwalk_data {
53 	uintptr_t *hw_hash;
54 	uint_t hw_hashlen;
55 	uint_t hw_hashidx;
56 	const char *hw_name;
57 	void *hw_data;
58 	size_t hw_size;
59 	size_t hw_next;
60 } hashwalk_data_t;
61 
62 static int fmd_stat(uintptr_t, uint_t, int, const mdb_arg_t *);
63 static int fmd_ustat(uintptr_t, uint_t, int, const mdb_arg_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;
309 	size_t len = sizeof (uintptr_t) * hashlen;
310 
311 	if (len == 0) {
312 		mdb_warn("failed to walk hash: invalid hash length\n");
313 		return (WALK_ERR);
314 	}
315 
316 	hwp = mdb_alloc(sizeof (hashwalk_data_t), UM_SLEEP);
317 	hwp->hw_hash = mdb_zalloc(len, UM_SLEEP);
318 	(void) mdb_vread(hwp->hw_hash, len, addr);
319 	hwp->hw_hashlen = hashlen;
320 	hwp->hw_hashidx = 0;
321 	hwp->hw_name = name;
322 	hwp->hw_data = mdb_zalloc(size, UM_SLEEP);
323 	hwp->hw_size = size;
324 	hwp->hw_next = next;
325 
326 	wsp->walk_addr = hwp->hw_hash[0];
327 	wsp->walk_data = hwp;
328 
329 	return (WALK_NEXT);
330 }
331 
332 static int
333 hash_walk_step(mdb_walk_state_t *wsp)
334 {
335 	hashwalk_data_t *hwp = wsp->walk_data;
336 	int rv;
337 
338 	while (wsp->walk_addr == NULL) {
339 		if (++hwp->hw_hashidx < hwp->hw_hashlen)
340 			wsp->walk_addr = hwp->hw_hash[hwp->hw_hashidx];
341 		else
342 			return (WALK_DONE);
343 	}
344 
345 	if (mdb_vread(hwp->hw_data, hwp->hw_size, wsp->walk_addr) == -1) {
346 		mdb_warn("failed to read %s at %p",
347 		    hwp->hw_name, wsp->walk_addr);
348 		return (WALK_ERR);
349 	}
350 
351 	rv = wsp->walk_callback(wsp->walk_addr, hwp->hw_data, wsp->walk_cbdata);
352 	wsp->walk_addr = *(uintptr_t *)((uintptr_t)hwp->hw_data + hwp->hw_next);
353 	return (rv);
354 }
355 
356 static void
357 hash_walk_fini(mdb_walk_state_t *wsp)
358 {
359 	hashwalk_data_t *hwp = wsp->walk_data;
360 
361 	mdb_free(hwp->hw_hash, sizeof (uintptr_t) * hwp->hw_hashlen);
362 	mdb_free(hwp->hw_data, hwp->hw_size);
363 	mdb_free(hwp, sizeof (hashwalk_data_t));
364 }
365 
366 static int
367 ustat_walk_init(mdb_walk_state_t *wsp)
368 {
369 	fmd_ustat_t us;
370 
371 	if (mdb_vread(&us, sizeof (us), wsp->walk_addr) != sizeof (us)) {
372 		mdb_warn("failed to read fmd_ustat_t at %p", wsp->walk_addr);
373 		return (WALK_ERR);
374 	}
375 
376 	return (hash_walk_init(wsp,
377 	    (uintptr_t)us.us_hash, us.us_hashlen, NULL, 0, 0));
378 }
379 
380 static int
381 ustat_walk_step(mdb_walk_state_t *wsp)
382 {
383 	hashwalk_data_t *hwp = wsp->walk_data;
384 	fmd_ustat_elem_t ue;
385 	fmd_stat_t s;
386 
387 	while (wsp->walk_addr == NULL) {
388 		if (++hwp->hw_hashidx < hwp->hw_hashlen)
389 			wsp->walk_addr = hwp->hw_hash[hwp->hw_hashidx];
390 		else
391 			return (WALK_DONE);
392 	}
393 
394 	if (mdb_vread(&ue, sizeof (ue), wsp->walk_addr) != sizeof (ue) ||
395 	    mdb_vread(&s, sizeof (s), (uintptr_t)ue.use_stat) != sizeof (s)) {
396 		mdb_warn("failed to read stat element at %p", wsp->walk_addr);
397 		return (WALK_ERR);
398 	}
399 
400 	wsp->walk_addr = (uintptr_t)ue.use_next;
401 
402 	return (wsp->walk_callback(
403 	    (uintptr_t)ue.use_stat, &s, wsp->walk_cbdata));
404 }
405 
406 struct fmd_cmd_data {
407 	int argc;
408 	const mdb_arg_t *argv;
409 };
410 
411 /* ARGSUSED */
412 static int
413 module_ustat(uintptr_t addr, const void *data, void *wsp)
414 {
415 	fmd_module_t *modp = (fmd_module_t *)data;
416 	char name[PATH_MAX];
417 	const struct fmd_cmd_data *udp = wsp;
418 
419 	if (mdb_readstr(name, sizeof (name), (uintptr_t)modp->mod_name) <= 0)
420 		(void) mdb_snprintf(name, sizeof (name), "<%p>",
421 		    modp->mod_name);
422 	mdb_printf("%s\n", name);
423 	(void) fmd_ustat((uintptr_t)modp->mod_ustat,
424 	    DCMD_ADDRSPEC | DCMD_LOOPFIRST, udp->argc, udp->argv);
425 	return (WALK_NEXT);
426 }
427 
428 static int
429 fmd_ustat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
430 {
431 	if (!(flags & DCMD_ADDRSPEC)) {
432 		struct fmd_cmd_data ud;
433 
434 		ud.argc = argc;
435 		ud.argv = argv;
436 		if (mdb_walk("fmd_module", module_ustat, &ud) == -1) {
437 			mdb_warn("failed to walk 'fmd_module'");
438 			return (DCMD_ERR);
439 		}
440 		return (DCMD_OK);
441 	}
442 
443 	if (mdb_pwalk_dcmd("fmd_ustat", "fmd_stat", argc, argv, addr) != 0) {
444 		mdb_warn("failed to walk fmd_ustat at %p", addr);
445 		return (DCMD_ERR);
446 	}
447 
448 	return (DCMD_OK);
449 }
450 
451 /* ARGSUSED */
452 static int
453 module_stat(uintptr_t addr, const void *data, void *wsp)
454 {
455 	fmd_module_t *modp = (fmd_module_t *)data;
456 	char name[PATH_MAX];
457 	const struct fmd_cmd_data *udp = wsp;
458 	fmd_modstat_t *mod_stats;
459 
460 	if (mdb_readstr(name, sizeof (name), (uintptr_t)modp->mod_name) <= 0) {
461 		(void) mdb_snprintf(name, sizeof (name), "<%p>",
462 		    modp->mod_name);
463 	}
464 	mdb_printf("%s\n", name);
465 	mod_stats = modp->mod_stats;
466 	(void) fmd_stat((uintptr_t)&mod_stats->ms_loadtime,
467 	    DCMD_ADDRSPEC | DCMD_LOOPFIRST, udp->argc, udp->argv);
468 	(void) fmd_stat((uintptr_t)&mod_stats->ms_snaptime,
469 	    DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv);
470 	(void) fmd_stat((uintptr_t)&mod_stats->ms_accepted,
471 	    DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv);
472 	(void) fmd_stat((uintptr_t)&mod_stats->ms_debugdrop,
473 	    DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv);
474 	(void) fmd_stat((uintptr_t)&mod_stats->ms_memtotal,
475 	    DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv);
476 	(void) fmd_stat((uintptr_t)&mod_stats->ms_memlimit,
477 	    DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv);
478 	(void) fmd_stat((uintptr_t)&mod_stats->ms_buftotal,
479 	    DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv);
480 	(void) fmd_stat((uintptr_t)&mod_stats->ms_buflimit,
481 	    DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv);
482 	(void) fmd_stat((uintptr_t)&mod_stats->ms_thrtotal,
483 	    DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv);
484 	(void) fmd_stat((uintptr_t)&mod_stats->ms_thrlimit,
485 	    DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv);
486 	(void) fmd_stat((uintptr_t)&mod_stats->ms_caseopen,
487 	    DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv);
488 	(void) fmd_stat((uintptr_t)&mod_stats->ms_casesolved,
489 	    DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv);
490 	(void) fmd_stat((uintptr_t)&mod_stats->ms_caseclosed,
491 	    DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv);
492 	(void) fmd_stat((uintptr_t)&mod_stats->ms_ckpt_save,
493 	    DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv);
494 	(void) fmd_stat((uintptr_t)&mod_stats->ms_ckpt_restore,
495 	    DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv);
496 	(void) fmd_stat((uintptr_t)&mod_stats->ms_ckpt_zeroed,
497 	    DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv);
498 	(void) fmd_stat((uintptr_t)&mod_stats->ms_ckpt_cnt,
499 	    DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv);
500 	(void) fmd_stat((uintptr_t)&mod_stats->ms_ckpt_time,
501 	    DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv);
502 	(void) fmd_stat((uintptr_t)&mod_stats->ms_xprtopen,
503 	    DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv);
504 	(void) fmd_stat((uintptr_t)&mod_stats->ms_xprtlimit,
505 	    DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv);
506 	(void) fmd_stat((uintptr_t)&mod_stats->ms_xprtqlimit,
507 	    DCMD_ADDRSPEC | DCMD_LOOP, udp->argc, udp->argv);
508 	return (WALK_NEXT);
509 }
510 
511 /*ARGSUSED*/
512 static int
513 fmd_stat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
514 {
515 	char buf[512];
516 	fmd_stat_t s;
517 
518 	if (argc != 0)
519 		return (DCMD_USAGE);
520 
521 	if (DCMD_HDRSPEC(flags))
522 		mdb_printf("%<u>%-11s %-4s %-32s %s%</u>\n",
523 		    "ADDR", "TYPE", "NAME", "VALUE");
524 
525 	if (!(flags & DCMD_ADDRSPEC)) {
526 		struct fmd_cmd_data ud;
527 
528 		ud.argc = argc;
529 		ud.argv = argv;
530 
531 		if (mdb_walk("fmd_module", module_stat, &ud) == -1) {
532 			mdb_warn("failed to walk 'fmd_module'");
533 			return (DCMD_ERR);
534 		}
535 		return (DCMD_OK);
536 	}
537 
538 	if (mdb_vread(&s, sizeof (s), addr) != sizeof (s)) {
539 		mdb_warn("failed to read statistic at %p", addr);
540 		return (DCMD_ERR);
541 	}
542 
543 	switch (s.fmds_type) {
544 	case FMD_TYPE_BOOL:
545 		mdb_printf("%-11p %-4s %-32s %s\n", addr, "bool",
546 		    s.fmds_name, s.fmds_value.bool ? "true" : "false");
547 		break;
548 	case FMD_TYPE_INT32:
549 		mdb_printf("%-11p %-4s %-32s %d\n", addr, "i32",
550 		    s.fmds_name, s.fmds_value.i32);
551 		break;
552 	case FMD_TYPE_UINT32:
553 		mdb_printf("%-11p %-4s %-32s %u\n", addr, "ui32",
554 		    s.fmds_name, s.fmds_value.i32);
555 		break;
556 	case FMD_TYPE_INT64:
557 		mdb_printf("%-11p %-4s %-32s %lld\n", addr, "i64",
558 		    s.fmds_name, s.fmds_value.i64);
559 		break;
560 	case FMD_TYPE_UINT64:
561 		mdb_printf("%-11p %-4s %-32s %llu\n", addr, "ui64",
562 		    s.fmds_name, s.fmds_value.ui64);
563 		break;
564 	case FMD_TYPE_STRING:
565 		if (mdb_readstr(buf, sizeof (buf),
566 		    (uintptr_t)s.fmds_value.str) < 0) {
567 			(void) mdb_snprintf(buf, sizeof (buf), "<%p>",
568 			    s.fmds_value.str);
569 		}
570 		mdb_printf("%-11p %-4s %-32s %s\n", addr, "str",
571 		    s.fmds_name, buf);
572 		break;
573 	case FMD_TYPE_TIME:
574 		mdb_printf("%-11p %-4s %-32s %llu\n", addr, "time",
575 		    s.fmds_name, s.fmds_value.ui64);
576 		break;
577 	case FMD_TYPE_SIZE:
578 		mdb_printf("%-11p %-4s %-32s %llu\n", addr, "size",
579 		    s.fmds_name, s.fmds_value.ui64);
580 		break;
581 	default:
582 		mdb_printf("%-11p %-4u %-32s ???\n", addr,
583 		    s.fmds_type, s.fmds_name);
584 		break;
585 	}
586 
587 	return (DCMD_OK);
588 }
589 
590 /*ARGSUSED*/
591 static int
592 fmd_event(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
593 {
594 	char type[16], name[16];
595 	fmd_event_impl_t ev;
596 
597 	if (argc != 0)
598 		return (DCMD_USAGE);
599 
600 	if (mdb_vread(&ev, sizeof (ev), addr) != sizeof (ev)) {
601 		mdb_warn("failed to read fmd_event at %p", addr);
602 		return (DCMD_ERR);
603 	}
604 
605 	if (DCMD_HDRSPEC(flags)) {
606 		mdb_printf("%<u>%-11s %-4s %-5s %-3s %-?s%</u>\n",
607 		    "ADDR", "TYPE", "STATE", "REF", "NVPAIR");
608 	}
609 
610 	switch (ev.ev_type) {
611 	case FMD_EVT_PROTOCOL:
612 		(void) strcpy(type, "PROT");
613 		break;
614 	case FMD_EVT_GC:
615 		(void) strcpy(type, "GC");
616 		break;
617 	case FMD_EVT_CLOSE:
618 		(void) strcpy(type, "CLSE");
619 		break;
620 	case FMD_EVT_TIMEOUT:
621 		(void) strcpy(type, "TIME");
622 		break;
623 	case FMD_EVT_STATS:
624 		(void) strcpy(type, "STAT");
625 		break;
626 	case FMD_EVT_PUBLISH:
627 		(void) strcpy(type, "PUBL");
628 		break;
629 	case FMD_EVT_TOPO:
630 		(void) strcpy(type, "TOPO");
631 		break;
632 	default:
633 		(void) mdb_snprintf(type, sizeof (type), "%u", ev.ev_type);
634 	}
635 
636 	switch (ev.ev_state) {
637 	case FMD_EVS_RECEIVED:
638 		(void) strcpy(name, "RECVD");
639 		break;
640 	case FMD_EVS_ACCEPTED:
641 		(void) strcpy(name, "ACCPT");
642 		break;
643 	case FMD_EVS_DISCARDED:
644 		(void) strcpy(name, "DSCRD");
645 		break;
646 	case FMD_EVS_DIAGNOSED:
647 		(void) strcpy(name, "DIAGN");
648 		break;
649 	default:
650 		(void) mdb_snprintf(name, sizeof (name), "%u", ev.ev_state);
651 	}
652 
653 	mdb_printf("%-11p %-4s %-5s %-3u %p\n",
654 	    addr, type, name, ev.ev_refs, ev.ev_nvl);
655 
656 	return (DCMD_OK);
657 }
658 
659 static int
660 thread_walk_init(mdb_walk_state_t *wsp)
661 {
662 	fmd_t F;
663 
664 	if (mdb_readvar(&F, "fmd") != sizeof (F)) {
665 		mdb_warn("failed to read fmd meta-data");
666 		return (WALK_ERR);
667 	}
668 
669 	wsp->walk_addr = (uintptr_t)F.d_thr_list.l_next;
670 	return (WALK_NEXT);
671 }
672 
673 static int
674 thread_walk_step(mdb_walk_state_t *wsp)
675 {
676 	uintptr_t addr = wsp->walk_addr;
677 	fmd_thread_t t;
678 
679 	if (addr == NULL)
680 		return (WALK_DONE);
681 
682 	if (mdb_vread(&t, sizeof (t), addr) != sizeof (t)) {
683 		mdb_warn("failed to read fmd_thread at %p", addr);
684 		return (WALK_ERR);
685 	}
686 
687 	wsp->walk_addr = (uintptr_t)t.thr_list.l_next;
688 	return (wsp->walk_callback(addr, &t, wsp->walk_cbdata));
689 }
690 
691 static int
692 fmd_thread(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
693 {
694 	fmd_thread_t thr;
695 
696 	if (!(flags & DCMD_ADDRSPEC))
697 		return (mdb_walk_dcmd("fmd_thread", "fmd_thread", argc, argv));
698 
699 	if (argc != 0)
700 		return (DCMD_USAGE);
701 
702 	if (mdb_vread(&thr, sizeof (thr), addr) != sizeof (thr)) {
703 		mdb_warn("failed to read fmd_thread at %p", addr);
704 		return (DCMD_ERR);
705 	}
706 
707 	if (DCMD_HDRSPEC(flags)) {
708 		mdb_printf("%<u>%-11s %-11s %-8s %-16s%</u>\n",
709 		    "ADDR", "MOD", "TID", "FUNC");
710 	}
711 
712 	mdb_printf("%-11p %-11p %-8u %a\n",
713 	    addr, thr.thr_mod, thr.thr_tid, thr.thr_func);
714 
715 	return (DCMD_OK);
716 }
717 
718 static int
719 mod_walk_init(mdb_walk_state_t *wsp)
720 {
721 	fmd_t F;
722 
723 	if (mdb_readvar(&F, "fmd") != sizeof (F)) {
724 		mdb_warn("failed to read fmd meta-data");
725 		return (WALK_ERR);
726 	}
727 
728 	wsp->walk_addr = (uintptr_t)F.d_mod_list.l_next;
729 	return (WALK_NEXT);
730 }
731 
732 static int
733 mod_walk_step(mdb_walk_state_t *wsp)
734 {
735 	uintptr_t addr = wsp->walk_addr;
736 	fmd_module_t m;
737 
738 	if (addr == NULL)
739 		return (WALK_DONE);
740 
741 	if (mdb_vread(&m, sizeof (m), addr) != sizeof (m)) {
742 		mdb_warn("failed to read fmd_module at %p", addr);
743 		return (WALK_ERR);
744 	}
745 
746 	wsp->walk_addr = (uintptr_t)m.mod_list.l_next;
747 	return (wsp->walk_callback(addr, &m, wsp->walk_cbdata));
748 }
749 
750 static int
751 fmd_module(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
752 {
753 	fmd_module_t mod;
754 	char name[PATH_MAX];
755 
756 	if (!(flags & DCMD_ADDRSPEC))
757 		return (mdb_walk_dcmd("fmd_module", "fmd_module", argc, argv));
758 
759 	if (argc != 0)
760 		return (DCMD_USAGE);
761 
762 	if (mdb_vread(&mod, sizeof (mod), addr) != sizeof (mod)) {
763 		mdb_warn("failed to read fmd_module at %p", addr);
764 		return (DCMD_ERR);
765 	}
766 
767 	if (DCMD_HDRSPEC(flags)) {
768 		mdb_printf("%<u>%-11s %-16s %-11s %-4s %-?s %-16s%</u>\n",
769 		    "ADDR", "OPS", "DATA", "FLAG", "USTAT", "NAME");
770 	}
771 
772 	if (mdb_readstr(name, sizeof (name), (uintptr_t)mod.mod_name) <= 0)
773 		(void) mdb_snprintf(name, sizeof (name), "<%p>", mod.mod_name);
774 
775 	mdb_printf("%-11p %-16a %-11p 0x%02x %-?p %s\n", addr,
776 	    mod.mod_ops, mod.mod_data, mod.mod_flags, mod.mod_ustat, name);
777 
778 	return (DCMD_OK);
779 }
780 
781 static int
782 case_walk_init(mdb_walk_state_t *wsp)
783 {
784 	fmd_module_t mod;
785 	fmd_case_hash_t ch;
786 	fmd_t F;
787 
788 	if (wsp->walk_addr != NULL) {
789 		if (mdb_vread(&mod, sizeof (mod), wsp->walk_addr) == -1) {
790 			mdb_warn("failed to read module at %p", wsp->walk_addr);
791 			return (WALK_ERR);
792 		}
793 
794 		wsp->walk_addr = (uintptr_t)mod.mod_cases.l_next;
795 		return (WALK_NEXT);
796 	}
797 
798 	if (mdb_readvar(&F, "fmd") != sizeof (F) ||
799 	    mdb_vread(&ch, sizeof (ch), (uintptr_t)F.d_cases) != sizeof (ch)) {
800 		mdb_warn("failed to read fmd meta-data");
801 		return (WALK_ERR);
802 	}
803 
804 	return (hash_walk_init(wsp, (uintptr_t)ch.ch_hash, ch.ch_hashlen,
805 	    "fmd_case", sizeof (fmd_case_impl_t),
806 	    OFFSETOF(fmd_case_impl_t, ci_next)));
807 }
808 
809 static int
810 case_walk_step(mdb_walk_state_t *wsp)
811 {
812 	uintptr_t addr = wsp->walk_addr;
813 	fmd_case_impl_t ci;
814 
815 	if (wsp->walk_data != NULL)
816 		return (hash_walk_step(wsp));
817 
818 	if (addr == NULL)
819 		return (WALK_DONE);
820 
821 	if (mdb_vread(&ci, sizeof (ci), addr) != sizeof (ci)) {
822 		mdb_warn("failed to read fmd_case at %p", addr);
823 		return (WALK_ERR);
824 	}
825 
826 	wsp->walk_addr = (uintptr_t)ci.ci_list.l_next;
827 	return (wsp->walk_callback(addr, &ci, wsp->walk_cbdata));
828 }
829 
830 static void
831 case_walk_fini(mdb_walk_state_t *wsp)
832 {
833 	if (wsp->walk_data != NULL)
834 		hash_walk_fini(wsp);
835 }
836 
837 static int
838 fmd_case(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
839 {
840 	char uuid[48], name[16];
841 	fmd_case_impl_t ci;
842 
843 	if (!(flags & DCMD_ADDRSPEC)) {
844 		if (mdb_walk_dcmd("fmd_case", "fmd_case", argc, argv) != 0) {
845 			mdb_warn("failed to walk fmd_case hash");
846 			return (DCMD_ERR);
847 		}
848 		return (DCMD_OK);
849 	}
850 
851 	if (mdb_vread(&ci, sizeof (ci), addr) != sizeof (ci)) {
852 		mdb_warn("failed to read fmd_case at %p", addr);
853 		return (DCMD_ERR);
854 	}
855 
856 	if (DCMD_HDRSPEC(flags)) {
857 		mdb_printf("%<u>%-11s %-5s %-3s %-?s %-36s%</u>\n",
858 		    "ADDR", "STATE", "REF", "DATA", "UUID");
859 	}
860 
861 	if (mdb_readstr(uuid, sizeof (uuid), (uintptr_t)ci.ci_uuid) <= 0)
862 		(void) mdb_snprintf(uuid, sizeof (uuid), "<%p>", ci.ci_uuid);
863 
864 	switch (ci.ci_state) {
865 	case FMD_CASE_UNSOLVED:
866 		(void) strcpy(name, "UNSLV");
867 		break;
868 	case FMD_CASE_SOLVED:
869 		(void) strcpy(name, "SOLVE");
870 		break;
871 	case FMD_CASE_CLOSE_WAIT:
872 		(void) strcpy(name, "CWAIT");
873 		break;
874 	case FMD_CASE_CLOSED:
875 		(void) strcpy(name, "CLOSE");
876 		break;
877 	case FMD_CASE_REPAIRED:
878 		(void) strcpy(name, "RPAIR");
879 		break;
880 	default:
881 		(void) mdb_snprintf(name, sizeof (name), "%u", ci.ci_state);
882 	}
883 
884 	mdb_printf("%-11p %-5s %-3u %-?p %s\n",
885 	    addr, name, ci.ci_refs, ci.ci_data, uuid);
886 
887 	return (DCMD_OK);
888 }
889 
890 static int
891 buf_walk_init(mdb_walk_state_t *wsp)
892 {
893 	fmd_buf_hash_t bh;
894 
895 	if (mdb_vread(&bh, sizeof (bh), wsp->walk_addr) != sizeof (bh)) {
896 		mdb_warn("failed to read fmd_buf_hash_t at %p", wsp->walk_addr);
897 		return (WALK_ERR);
898 	}
899 
900 	return (hash_walk_init(wsp, (uintptr_t)bh.bh_hash, bh.bh_hashlen,
901 	    "fmd_buf", sizeof (fmd_buf_t), OFFSETOF(fmd_buf_t, buf_next)));
902 }
903 
904 /*ARGSUSED*/
905 static int
906 fmd_buf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
907 {
908 	char name[PATH_MAX];
909 	fmd_buf_t b;
910 
911 	if (argc != 0 || !(flags & DCMD_ADDRSPEC))
912 		return (DCMD_USAGE);
913 
914 	if (mdb_vread(&b, sizeof (b), addr) != sizeof (b)) {
915 		mdb_warn("failed to read fmd_buf at %p", addr);
916 		return (DCMD_ERR);
917 	}
918 
919 	if (DCMD_HDRSPEC(flags)) {
920 		mdb_printf("%<u>%-11s %-32s %-5s %-?s %s%</u>\n",
921 		    "ADDR", "NAME", "FLAGS", "DATA", "SIZE");
922 	}
923 
924 	if (mdb_readstr(name, sizeof (name), (uintptr_t)b.buf_name) <= 0)
925 		(void) mdb_snprintf(name, sizeof (name), "<%p>", b.buf_name);
926 
927 	mdb_printf("%-11p %-32s %-#5x %-?p %lu\n",
928 	    addr, name, b.buf_flags, b.buf_data, b.buf_size);
929 
930 	return (DCMD_OK);
931 }
932 
933 static int
934 serd_walk_init(mdb_walk_state_t *wsp)
935 {
936 	fmd_serd_hash_t sh;
937 
938 	if (mdb_vread(&sh, sizeof (sh), wsp->walk_addr) != sizeof (sh)) {
939 		mdb_warn("failed to read fmd_serd_hash at %p", wsp->walk_addr);
940 		return (WALK_ERR);
941 	}
942 
943 	return (hash_walk_init(wsp, (uintptr_t)sh.sh_hash, sh.sh_hashlen,
944 	    "fmd_serd_eng", sizeof (fmd_serd_eng_t),
945 	    OFFSETOF(fmd_serd_eng_t, sg_next)));
946 }
947 
948 /* ARGSUSED */
949 static int
950 module_serd(uintptr_t addr, const void *data, void *wsp)
951 {
952 	fmd_module_t *modp = (fmd_module_t *)data;
953 
954 	if (modp->mod_serds.sh_count != 0) {
955 		modp = (fmd_module_t *)addr;
956 		(void) mdb_pwalk_dcmd("fmd_serd", "fmd_serd", 0, 0,
957 		    (uintptr_t)&modp->mod_serds);
958 	}
959 	return (WALK_NEXT);
960 }
961 
962 /*ARGSUSED*/
963 static int
964 fmd_serd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
965 {
966 	char name[PATH_MAX];
967 	fmd_serd_eng_t sg;
968 
969 	if (argc != 0)
970 		return (DCMD_USAGE);
971 	if (!(flags & DCMD_ADDRSPEC)) {
972 		if (mdb_walk("fmd_module", module_serd, 0) == -1) {
973 			mdb_warn("failed to walk 'fmd_module'");
974 			return (DCMD_ERR);
975 		}
976 		return (DCMD_OK);
977 	}
978 
979 	if (mdb_vread(&sg, sizeof (sg), addr) != sizeof (sg)) {
980 		mdb_warn("failed to read fmd_serd_eng at %p", addr);
981 		return (DCMD_ERR);
982 	}
983 
984 	if (DCMD_HDRSPEC(flags)) {
985 		mdb_printf("%<u>%-11s %-32s %-3s F >%-2s %-16s%</u>\n",
986 		    "ADDR", "NAME", "CNT", "N", "T");
987 	}
988 
989 	if (mdb_readstr(name, sizeof (name), (uintptr_t)sg.sg_name) <= 0)
990 		(void) mdb_snprintf(name, sizeof (name), "<%p>", sg.sg_name);
991 
992 	mdb_printf("%-11p %-32s %-3u %c >%-2u %lluns\n",
993 	    addr, name, sg.sg_count, (sg.sg_flags & FMD_SERD_FIRED) ? 'F' : ' ',
994 	    sg.sg_n, (u_longlong_t)sg.sg_t);
995 
996 	return (DCMD_OK);
997 }
998 
999 static int
1000 asru_walk_init(mdb_walk_state_t *wsp)
1001 {
1002 	fmd_asru_hash_t ah;
1003 	fmd_t F;
1004 
1005 	if (wsp->walk_addr == NULL && mdb_readvar(&F, "fmd") != sizeof (F)) {
1006 		mdb_warn("failed to read fmd meta-data");
1007 		return (WALK_ERR);
1008 	}
1009 
1010 	if (wsp->walk_addr == NULL)
1011 		wsp->walk_addr = (uintptr_t)F.d_asrus;
1012 
1013 	if (mdb_vread(&ah, sizeof (ah), wsp->walk_addr) != sizeof (ah)) {
1014 		mdb_warn("failed to read asru_hash at %p", wsp->walk_addr);
1015 		return (WALK_ERR);
1016 	}
1017 
1018 	return (hash_walk_init(wsp, (uintptr_t)ah.ah_hash, ah.ah_hashlen,
1019 	    "fmd_asru", sizeof (fmd_asru_t), OFFSETOF(fmd_asru_t, asru_next)));
1020 }
1021 
1022 static int
1023 fmd_asru(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1024 {
1025 	char uuid[48], name[PATH_MAX];
1026 	fmd_asru_t a;
1027 
1028 	if (!(flags & DCMD_ADDRSPEC)) {
1029 		if (mdb_walk_dcmd("fmd_asru", "fmd_asru", argc, argv) != 0) {
1030 			mdb_warn("failed to walk fmd_asru hash");
1031 			return (DCMD_ERR);
1032 		}
1033 		return (DCMD_OK);
1034 	}
1035 
1036 	if (mdb_vread(&a, sizeof (a), addr) != sizeof (a)) {
1037 		mdb_warn("failed to read fmd_asru at %p", addr);
1038 		return (DCMD_ERR);
1039 	}
1040 
1041 	if (DCMD_HDRSPEC(flags))
1042 		mdb_printf("%<u>%-8s %-36s %s%</u>\n", "ADDR", "UUID", "NAME");
1043 
1044 	if (mdb_readstr(uuid, sizeof (uuid), (uintptr_t)a.asru_uuid) <= 0)
1045 		(void) mdb_snprintf(uuid, sizeof (uuid), "<%p>", a.asru_uuid);
1046 	if (mdb_readstr(name, sizeof (name), (uintptr_t)a.asru_name) <= 0)
1047 		(void) mdb_snprintf(name, sizeof (name), "<%p>", a.asru_name);
1048 
1049 	mdb_printf("%-8p %-36s %s\n", addr, uuid, name);
1050 	return (DCMD_OK);
1051 }
1052 
1053 static int
1054 al_walk_init(mdb_walk_state_t *wsp)
1055 {
1056 	fmd_asru_hash_t ah;
1057 	fmd_t F;
1058 
1059 	if (wsp->walk_addr == NULL && mdb_readvar(&F, "fmd") != sizeof (F)) {
1060 		mdb_warn("failed to read fmd meta-data");
1061 		return (WALK_ERR);
1062 	}
1063 
1064 	if (wsp->walk_addr == NULL)
1065 		wsp->walk_addr = (uintptr_t)F.d_asrus;
1066 
1067 	if (mdb_vread(&ah, sizeof (ah), wsp->walk_addr) != sizeof (ah)) {
1068 		mdb_warn("failed to read asru_hash at %p", wsp->walk_addr);
1069 		return (WALK_ERR);
1070 	}
1071 
1072 	return (hash_walk_init(wsp, (uintptr_t)ah.ah_rsrc_hash, ah.ah_hashlen,
1073 	    "fmd_asru_link", sizeof (fmd_asru_link_t), OFFSETOF(fmd_asru_link_t,
1074 	    al_rsrc_next)));
1075 }
1076 
1077 static int
1078 fmd_asru_link(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1079 {
1080 	char uuid[48], name[PATH_MAX];
1081 	fmd_asru_link_t a;
1082 
1083 	if (!(flags & DCMD_ADDRSPEC)) {
1084 		if (mdb_walk_dcmd("fmd_asru_link", "fmd_asru_link", argc,
1085 		    argv) != 0) {
1086 			mdb_warn("failed to walk fmd_asru_link hash");
1087 			return (DCMD_ERR);
1088 		}
1089 		return (DCMD_OK);
1090 	}
1091 
1092 	if (mdb_vread(&a, sizeof (a), addr) != sizeof (a)) {
1093 		mdb_warn("failed to read fmd_asru_link at %p", addr);
1094 		return (DCMD_ERR);
1095 	}
1096 
1097 	if (DCMD_HDRSPEC(flags))
1098 		mdb_printf("%<u>%-8s %-36s %s%</u>\n", "ADDR", "UUID", "NAME");
1099 
1100 	if (mdb_readstr(uuid, sizeof (uuid), (uintptr_t)a.al_uuid) <= 0)
1101 		(void) mdb_snprintf(uuid, sizeof (uuid), "<%p>", a.al_uuid);
1102 	if (mdb_readstr(name, sizeof (name), (uintptr_t)a.al_rsrc_name) <= 0)
1103 		(void) mdb_snprintf(name, sizeof (name), "<%p>",
1104 		    a.al_rsrc_name);
1105 
1106 	mdb_printf("%-8p %-36s %s\n", addr, uuid, name);
1107 	return (DCMD_OK);
1108 }
1109 
1110 /*ARGSUSED*/
1111 static int
1112 fcf_hdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1113 {
1114 	fcf_hdr_t h;
1115 
1116 	if (argc != 0)
1117 		return (DCMD_USAGE);
1118 
1119 	if (!(flags & DCMD_ADDRSPEC))
1120 		addr = 0; /* assume base of file in file target */
1121 
1122 	if (mdb_vread(&h, sizeof (h), addr) != sizeof (h)) {
1123 		mdb_warn("failed to read header at %p", addr);
1124 		return (DCMD_ERR);
1125 	}
1126 
1127 	mdb_printf("fcfh_ident.id_magic = 0x%x, %c, %c, %c\n",
1128 	    h.fcfh_ident[FCF_ID_MAG0], h.fcfh_ident[FCF_ID_MAG1],
1129 	    h.fcfh_ident[FCF_ID_MAG2], h.fcfh_ident[FCF_ID_MAG3]);
1130 
1131 	switch (h.fcfh_ident[FCF_ID_MODEL]) {
1132 	case FCF_MODEL_ILP32:
1133 		mdb_printf("fcfh_ident.id_model = ILP32\n");
1134 		break;
1135 	case FCF_MODEL_LP64:
1136 		mdb_printf("fcfh_ident.id_model = LP64\n");
1137 		break;
1138 	default:
1139 		mdb_printf("fcfh_ident.id_model = 0x%x\n",
1140 		    h.fcfh_ident[FCF_ID_MODEL]);
1141 	}
1142 
1143 	switch (h.fcfh_ident[FCF_ID_ENCODING]) {
1144 	case FCF_ENCODE_LSB:
1145 		mdb_printf("fcfh_ident.id_encoding = LSB\n");
1146 		break;
1147 	case FCF_ENCODE_MSB:
1148 		mdb_printf("fcfh_ident.id_encoding = MSB\n");
1149 		break;
1150 	default:
1151 		mdb_printf("fcfh_ident.id_encoding = 0x%x\n",
1152 		    h.fcfh_ident[FCF_ID_ENCODING]);
1153 	}
1154 
1155 	mdb_printf("fcfh_ident.id_version = %u\n",
1156 	    h.fcfh_ident[FCF_ID_VERSION]);
1157 
1158 	mdb_printf("fcfh_flags = 0x%x\n", h.fcfh_flags);
1159 	mdb_printf("fcfh_hdrsize = %u\n", h.fcfh_hdrsize);
1160 	mdb_printf("fcfh_secsize = %u\n", h.fcfh_secsize);
1161 	mdb_printf("fcfh_secnum = %u\n", h.fcfh_secnum);
1162 	mdb_printf("fcfh_secoff = %llu\n", h.fcfh_secoff);
1163 	mdb_printf("fcfh_filesz = %llu\n", h.fcfh_filesz);
1164 	mdb_printf("fcfh_cgen = %llu\n", h.fcfh_cgen);
1165 
1166 	return (DCMD_OK);
1167 }
1168 
1169 static int fcf_sec(uintptr_t, uint_t, int, const mdb_arg_t *);
1170 /*ARGSUSED*/
1171 static int
1172 fcf_sec_one(uintptr_t addr, void *ignored, uint_t *secp)
1173 {
1174 
1175 	mdb_printf("%3d ", (*secp)++);
1176 	(void) fcf_sec(addr, DCMD_ADDRSPEC | DCMD_LOOP, 0, NULL);
1177 	return (WALK_NEXT);
1178 }
1179 
1180 /*ARGSUSED*/
1181 static int
1182 fcf_sec(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1183 {
1184 	static const char *const types[] = {
1185 		"none",		/* FCF_SECT_NONE */
1186 		"strtab",	/* FCF_SECT_STRTAB */
1187 		"module",	/* FCF_SECT_MODULE */
1188 		"case",		/* FCF_SECT_CASE */
1189 		"bufs",		/* FCF_SECT_BUFS */
1190 		"buffer",	/* FCF_SECT_BUFFER */
1191 		"serd",		/* FCF_SECT_SERD */
1192 		"events",	/* FCF_SECT_EVENTS */
1193 		"nvlists",	/* FCF_SECT_NVLISTS */
1194 	};
1195 
1196 	uint_t sec = 0;
1197 	fcf_sec_t s;
1198 
1199 	if (!(flags & DCMD_ADDRSPEC))
1200 		mdb_printf("%<u>%-3s ", "NDX");
1201 
1202 	if (!(flags & DCMD_ADDRSPEC) || DCMD_HDRSPEC(flags)) {
1203 		mdb_printf("%<u>%?s %-10s %-5s %-5s %-5s %-6s %-5s%</u>\n",
1204 		    "ADDR", "TYPE", "ALIGN", "FLAGS", "ENTSZ", "OFF", "SIZE");
1205 	}
1206 
1207 	if (!(flags & DCMD_ADDRSPEC)) {
1208 		if (mdb_walk("fcf_sec", (mdb_walk_cb_t)fcf_sec_one, &sec) < 0) {
1209 			mdb_warn("failed to walk fcf_sec");
1210 			return (DCMD_ERR);
1211 		}
1212 		return (DCMD_OK);
1213 	}
1214 
1215 	if (argc != 0)
1216 		return (DCMD_USAGE);
1217 
1218 	if (mdb_vread(&s, sizeof (s), addr) != sizeof (s)) {
1219 		mdb_warn("failed to read section header at %p", addr);
1220 		return (DCMD_ERR);
1221 	}
1222 
1223 	mdb_printf("%?p ", addr);
1224 
1225 	if (s.fcfs_type < sizeof (types) / sizeof (types[0]))
1226 		mdb_printf("%-10s ", types[s.fcfs_type]);
1227 	else
1228 		mdb_printf("%-10u ", s.fcfs_type);
1229 
1230 	mdb_printf("%-5u %-#5x %-#5x %-6llx %-#5llx\n", s.fcfs_align,
1231 	    s.fcfs_flags, s.fcfs_entsize, s.fcfs_offset, s.fcfs_size);
1232 
1233 	return (DCMD_OK);
1234 }
1235 
1236 static int
1237 fcf_sec_walk_init(mdb_walk_state_t *wsp)
1238 {
1239 	fcf_hdr_t h, *hp;
1240 	size_t size;
1241 
1242 	if (mdb_vread(&h, sizeof (h), wsp->walk_addr) != sizeof (h)) {
1243 		mdb_warn("failed to read FCF header at %p", wsp->walk_addr);
1244 		return (WALK_ERR);
1245 	}
1246 
1247 	size = sizeof (fcf_hdr_t) + sizeof (fcf_sec_t) * h.fcfh_secnum;
1248 	hp = mdb_alloc(size, UM_SLEEP);
1249 
1250 	if (mdb_vread(hp, size, wsp->walk_addr) != size) {
1251 		mdb_warn("failed to read FCF sections at %p", wsp->walk_addr);
1252 		mdb_free(hp, size);
1253 		return (WALK_ERR);
1254 	}
1255 
1256 	wsp->walk_data = hp;
1257 	wsp->walk_arg = 0;
1258 
1259 	return (WALK_NEXT);
1260 }
1261 
1262 static int
1263 fcf_sec_walk_step(mdb_walk_state_t *wsp)
1264 {
1265 	uint_t i = (uint_t)wsp->walk_arg;
1266 	size_t off = sizeof (fcf_hdr_t) + sizeof (fcf_sec_t) * i;
1267 	fcf_hdr_t *hp = wsp->walk_data;
1268 	fcf_sec_t *sp = (fcf_sec_t *)((uintptr_t)hp + off);
1269 
1270 	if (i >= hp->fcfh_secnum)
1271 		return (WALK_DONE);
1272 
1273 	wsp->walk_arg = (void *)(i + 1);
1274 	return (wsp->walk_callback(wsp->walk_addr + off, sp, wsp->walk_cbdata));
1275 }
1276 
1277 static void
1278 fcf_sec_walk_fini(mdb_walk_state_t *wsp)
1279 {
1280 	fcf_hdr_t *hp = wsp->walk_data;
1281 	mdb_free(hp, sizeof (fcf_hdr_t) + sizeof (fcf_sec_t) * hp->fcfh_secnum);
1282 }
1283 
1284 /*ARGSUSED*/
1285 static int
1286 fcf_case(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1287 {
1288 	fcf_case_t fcfc;
1289 
1290 	if (argc != 0)
1291 		return (DCMD_USAGE);
1292 
1293 	if (mdb_vread(&fcfc, sizeof (fcfc), addr) != sizeof (fcfc)) {
1294 		mdb_warn("failed to read case at %p", addr);
1295 		return (DCMD_ERR);
1296 	}
1297 
1298 	mdb_printf("fcfc_uuid = 0x%x\n", fcfc.fcfc_uuid);
1299 	mdb_printf("fcfc_state = %u\n", fcfc.fcfc_state);
1300 	mdb_printf("fcfc_bufs = %u\n", fcfc.fcfc_bufs);
1301 	mdb_printf("fcfc_events = %u\n", fcfc.fcfc_events);
1302 	mdb_printf("fcfc_suspects = %u\n", fcfc.fcfc_suspects);
1303 
1304 	return (DCMD_OK);
1305 }
1306 
1307 /*ARGSUSED*/
1308 static int
1309 fcf_event(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1310 {
1311 	fcf_event_t fcfe;
1312 
1313 	if (argc != 0)
1314 		return (DCMD_USAGE);
1315 
1316 	if (mdb_vread(&fcfe, sizeof (fcfe), addr) != sizeof (fcfe)) {
1317 		mdb_warn("failed to read event at %p", addr);
1318 		return (DCMD_ERR);
1319 	}
1320 
1321 	mdb_printf("fcfe_todsec = %llu (%Y)\n",
1322 	    fcfe.fcfe_todsec, (time_t)fcfe.fcfe_todsec);
1323 	mdb_printf("fcfe_todnsec = %llu\n", fcfe.fcfe_todnsec);
1324 	mdb_printf("fcfe_major = %u\n", fcfe.fcfe_major);
1325 	mdb_printf("fcfe_minor = %u\n", fcfe.fcfe_minor);
1326 	mdb_printf("fcfe_inode = %llu\n", fcfe.fcfe_inode);
1327 	mdb_printf("fcfe_offset = %llu\n", fcfe.fcfe_offset);
1328 
1329 	return (DCMD_OK);
1330 }
1331 
1332 /*ARGSUSED*/
1333 static int
1334 fcf_serd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1335 {
1336 	fcf_serd_t fcfd;
1337 
1338 	if (argc != 0)
1339 		return (DCMD_USAGE);
1340 
1341 	if (mdb_vread(&fcfd, sizeof (fcfd), addr) != sizeof (fcfd)) {
1342 		mdb_warn("failed to read serd at %p", addr);
1343 		return (DCMD_ERR);
1344 	}
1345 
1346 	mdb_printf("fcfd_name = 0x%x\n", fcfd.fcfd_name);
1347 	mdb_printf("fcfd_events = %u\n", fcfd.fcfd_events);
1348 	mdb_printf("fcfd_n = >%u\n", fcfd.fcfd_n);
1349 	mdb_printf("fcfd_t = %lluns\n", fcfd.fcfd_t);
1350 
1351 	return (DCMD_OK);
1352 }
1353 
1354 static int
1355 tmq_walk_init(mdb_walk_state_t *wsp)
1356 {
1357 	fmd_timerq_t tmq;
1358 	fmd_t F;
1359 
1360 	if (wsp->walk_addr == NULL && mdb_readvar(&F, "fmd") != sizeof (F)) {
1361 		mdb_warn("failed to read fmd meta-data");
1362 		return (WALK_ERR);
1363 	}
1364 
1365 	if (wsp->walk_addr == NULL)
1366 		wsp->walk_addr = (uintptr_t)F.d_timers;
1367 
1368 	if (mdb_vread(&tmq, sizeof (tmq), wsp->walk_addr) != sizeof (tmq)) {
1369 		mdb_warn("failed to read timerq at %p", wsp->walk_addr);
1370 		return (WALK_ERR);
1371 	}
1372 
1373 	wsp->walk_addr = (uintptr_t)tmq.tmq_list.l_next;
1374 	return (WALK_NEXT);
1375 }
1376 
1377 static int
1378 tmq_walk_step(mdb_walk_state_t *wsp)
1379 {
1380 	uintptr_t addr = wsp->walk_addr;
1381 	fmd_timer_t tmr;
1382 
1383 	if (addr == NULL)
1384 		return (WALK_DONE);
1385 
1386 	if (mdb_vread(&tmr, sizeof (tmr), addr) != sizeof (tmr)) {
1387 		mdb_warn("failed to read fmd_timer at %p", addr);
1388 		return (WALK_ERR);
1389 	}
1390 
1391 	wsp->walk_addr = (uintptr_t)tmr.tmr_list.l_next;
1392 	return (wsp->walk_callback(addr, &tmr, wsp->walk_cbdata));
1393 }
1394 
1395 static int
1396 fmd_timer(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1397 {
1398 	char name[32], func[MDB_SYM_NAMLEN];
1399 	fmd_timer_t t;
1400 
1401 	if (!(flags & DCMD_ADDRSPEC)) {
1402 		if (mdb_walk_dcmd("fmd_timerq", "fmd_timer", argc, argv) != 0) {
1403 			mdb_warn("failed to walk fmd_timerq");
1404 			return (DCMD_ERR);
1405 		}
1406 		return (DCMD_OK);
1407 	}
1408 
1409 	if (mdb_vread(&t, sizeof (t), addr) != sizeof (t)) {
1410 		mdb_warn("failed to read fmd_timer at %p", addr);
1411 		return (DCMD_ERR);
1412 	}
1413 
1414 	if (DCMD_HDRSPEC(flags)) {
1415 		mdb_printf("%<u>%-8s %-20s %-4s %-18s %-8s %s%</u>\n",
1416 		    "ADDR", "MODULE", "ID", "HRTIME", "ARG", "FUNC");
1417 	}
1418 
1419 	if (mdb_readstr(name, sizeof (name), (uintptr_t)
1420 	    t.tmr_ids + OFFSETOF(fmd_idspace_t, ids_name)) <= 0)
1421 		(void) mdb_snprintf(name, sizeof (name), "<%p>", t.tmr_ids);
1422 
1423 	if (mdb_lookup_by_addr((uintptr_t)t.tmr_func, MDB_SYM_FUZZY,
1424 	    func, sizeof (func), NULL) != 0)
1425 		(void) mdb_snprintf(func, sizeof (func), "<%p>", t.tmr_func);
1426 
1427 	mdb_printf("%-8p %-20s %4d 0x%-16llx %-8p %s\n",
1428 	    addr, name, t.tmr_id, t.tmr_hrt, t.tmr_arg, func);
1429 	return (DCMD_OK);
1430 }
1431 
1432 static int
1433 xprt_walk_init(mdb_walk_state_t *wsp)
1434 {
1435 	fmd_module_t m;
1436 
1437 	if (wsp->walk_addr == NULL) {
1438 		mdb_warn("transport walker requires fmd_module_t address\n");
1439 		return (WALK_ERR);
1440 	}
1441 
1442 	if (mdb_vread(&m, sizeof (m), wsp->walk_addr) != sizeof (m)) {
1443 		mdb_warn("failed to read module at %p", wsp->walk_addr);
1444 		return (WALK_ERR);
1445 	}
1446 
1447 	wsp->walk_addr = (uintptr_t)m.mod_transports.l_next;
1448 	return (WALK_NEXT);
1449 }
1450 
1451 static int
1452 xprt_walk_step(mdb_walk_state_t *wsp)
1453 {
1454 	uintptr_t addr = wsp->walk_addr;
1455 	fmd_xprt_impl_t xi;
1456 
1457 	if (addr == NULL)
1458 		return (WALK_DONE);
1459 
1460 	if (mdb_vread(&xi, sizeof (xi), addr) != sizeof (xi)) {
1461 		mdb_warn("failed to read fmd_xprt at %p", addr);
1462 		return (WALK_ERR);
1463 	}
1464 
1465 	wsp->walk_addr = (uintptr_t)xi.xi_list.l_next;
1466 	return (wsp->walk_callback(addr, &xi, wsp->walk_cbdata));
1467 }
1468 
1469 static int
1470 xpc_walk_init(mdb_walk_state_t *wsp)
1471 {
1472 	fmd_xprt_class_hash_t xch;
1473 
1474 	if (mdb_vread(&xch, sizeof (xch), wsp->walk_addr) != sizeof (xch)) {
1475 		mdb_warn("failed to read fmd_xprt_class_hash at %p",
1476 		    wsp->walk_addr);
1477 		return (WALK_ERR);
1478 	}
1479 
1480 	return (hash_walk_init(wsp, (uintptr_t)xch.xch_hash, xch.xch_hashlen,
1481 	    "fmd_xprt_class", sizeof (fmd_xprt_class_t),
1482 	    OFFSETOF(fmd_xprt_class_t, xc_next)));
1483 }
1484 
1485 /*ARGSUSED*/
1486 static int
1487 fmd_xprt_class(uintptr_t addr, const void *data, void *arg)
1488 {
1489 	const fmd_xprt_class_t *xcp = data;
1490 	char name[1024];
1491 
1492 	if (mdb_readstr(name, sizeof (name), (uintptr_t)xcp->xc_class) <= 0)
1493 		(void) mdb_snprintf(name, sizeof (name), "<%p>", xcp->xc_class);
1494 
1495 	mdb_printf("%-8p %-4u %s\n", addr, xcp->xc_refs, name);
1496 	return (WALK_NEXT);
1497 }
1498 
1499 static int
1500 fmd_xprt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1501 {
1502 	uint_t opt_s = FALSE, opt_l = FALSE, opt_r = FALSE, opt_u = FALSE;
1503 	fmd_xprt_impl_t xi;
1504 
1505 	if (mdb_getopts(argc, argv,
1506 	    'l', MDB_OPT_SETBITS, TRUE, &opt_l,
1507 	    'r', MDB_OPT_SETBITS, TRUE, &opt_r,
1508 	    's', MDB_OPT_SETBITS, TRUE, &opt_s,
1509 	    'u', MDB_OPT_SETBITS, TRUE, &opt_u, NULL) != argc)
1510 		return (DCMD_USAGE);
1511 
1512 	if (!(flags & DCMD_ADDRSPEC)) {
1513 		if (mdb_walk_dcmd("fmd_xprt", "fmd_xprt", argc, argv) != 0) {
1514 			mdb_warn("failed to walk fmd_xprt");
1515 			return (DCMD_ERR);
1516 		}
1517 		return (DCMD_OK);
1518 	}
1519 
1520 	if (mdb_vread(&xi, sizeof (xi), addr) != sizeof (xi)) {
1521 		mdb_warn("failed to read fmd_xprt at %p", addr);
1522 		return (DCMD_ERR);
1523 	}
1524 
1525 	if (DCMD_HDRSPEC(flags)) {
1526 		mdb_printf("%<u>%-8s %-4s %-4s %-5s %s%</u>\n",
1527 		    "ADDR", "ID", "VERS", "FLAGS", "STATE");
1528 	}
1529 
1530 	mdb_printf("%-8p %-4d %-4u %-5x %a\n",
1531 	    addr, xi.xi_id, xi.xi_version, xi.xi_flags, xi.xi_state);
1532 
1533 	if (opt_l | opt_s) {
1534 		(void) mdb_inc_indent(4);
1535 		mdb_printf("Local subscriptions requested by peer:\n");
1536 		mdb_printf("%<u>%-8s %-4s %s%</u>\n", "ADDR", "REFS", "CLASS");
1537 		(void) mdb_pwalk("fmd_xprt_class", fmd_xprt_class, &xi,
1538 		    addr + OFFSETOF(fmd_xprt_impl_t, xi_lsub));
1539 		(void) mdb_dec_indent(4);
1540 	}
1541 
1542 	if (opt_r | opt_s) {
1543 		(void) mdb_inc_indent(4);
1544 		mdb_printf("Remote subscriptions requested of peer:\n");
1545 		mdb_printf("%<u>%-8s %-4s %s%</u>\n", "ADDR", "REFS", "CLASS");
1546 		(void) mdb_pwalk("fmd_xprt_class", fmd_xprt_class, &xi,
1547 		    addr + OFFSETOF(fmd_xprt_impl_t, xi_rsub));
1548 		(void) mdb_dec_indent(4);
1549 	}
1550 
1551 	if (opt_u | opt_s) {
1552 		(void) mdb_inc_indent(4);
1553 		mdb_printf("Pending unsubscription acknowledgements:\n");
1554 		mdb_printf("%<u>%-8s %-4s %s%</u>\n", "ADDR", "REFS", "CLASS");
1555 		(void) mdb_pwalk("fmd_xprt_class", fmd_xprt_class, &xi,
1556 		    addr + OFFSETOF(fmd_xprt_impl_t, xi_usub));
1557 		(void) mdb_dec_indent(4);
1558 	}
1559 
1560 	return (DCMD_OK);
1561 }
1562 
1563 static int
1564 tsnap_walk_init(mdb_walk_state_t *wsp)
1565 {
1566 	fmd_t F;
1567 
1568 	if (mdb_readvar(&F, "fmd") != sizeof (F)) {
1569 		mdb_warn("failed to read fmd meta-data");
1570 		return (WALK_ERR);
1571 	}
1572 
1573 	wsp->walk_addr = (uintptr_t)F.d_topo_list.l_next;
1574 	return (WALK_NEXT);
1575 }
1576 
1577 static int
1578 tsnap_walk_step(mdb_walk_state_t *wsp)
1579 {
1580 	uintptr_t addr = wsp->walk_addr;
1581 	fmd_topo_t ftp;
1582 
1583 	if (addr == NULL)
1584 		return (WALK_DONE);
1585 
1586 	if (mdb_vread(&ftp, sizeof (ftp), addr) != sizeof (ftp)) {
1587 		mdb_warn("failed to read fmd_topo_t at %p", addr);
1588 		return (WALK_ERR);
1589 	}
1590 
1591 	wsp->walk_addr = (uintptr_t)ftp.ft_list.l_next;
1592 	return (wsp->walk_callback(addr, &ftp, wsp->walk_cbdata));
1593 }
1594 
1595 static int
1596 mq_walk_init(mdb_walk_state_t *wsp)
1597 {
1598 	fmd_module_t m;
1599 	struct fmd_eventq eq;
1600 
1601 	if (wsp->walk_addr == NULL) {
1602 		mdb_warn("NULL fmd_module_t passed in");
1603 		return (WALK_ERR);
1604 	}
1605 
1606 	if (mdb_vread(&m, sizeof (m), wsp->walk_addr) != sizeof (m)) {
1607 		mdb_warn("failed to read fmd_module_t at %p", wsp->walk_addr);
1608 		return (WALK_ERR);
1609 	}
1610 	if (mdb_vread(&eq, sizeof (eq), (uintptr_t)m.mod_queue)
1611 	    != sizeof (eq)) {
1612 		mdb_warn("failed to read fmd_eventq at %p", wsp->walk_addr);
1613 		return (WALK_ERR);
1614 	}
1615 
1616 	wsp->walk_addr = (uintptr_t)eq.eq_list.l_next;
1617 
1618 	return (WALK_NEXT);
1619 }
1620 
1621 static int
1622 mq_walk_step(mdb_walk_state_t *wsp)
1623 {
1624 	uintptr_t addr = wsp->walk_addr;
1625 	fmd_eventqelem_t eqe;
1626 
1627 	if (addr == NULL)
1628 		return (WALK_DONE);
1629 
1630 	if (mdb_vread(&eqe, sizeof (eqe), addr) != sizeof (eqe)) {
1631 		mdb_warn("failed to read fmd_eventqelem_t at %p", addr);
1632 		return (WALK_ERR);
1633 	}
1634 
1635 	wsp->walk_addr = (uintptr_t)eqe.eqe_list.l_next;
1636 	return (wsp->walk_callback(addr, &eqe, wsp->walk_cbdata));
1637 }
1638 
1639 static const mdb_dcmd_t dcmds[] = {
1640 	{ "fcf_case", "?", "print a FCF case", fcf_case },
1641 	{ "fcf_event", "?", "print a FCF event", fcf_event },
1642 	{ "fcf_hdr", "?", "print a FCF header", fcf_hdr },
1643 	{ "fcf_sec", ":", "print a FCF section header", fcf_sec },
1644 	{ "fcf_serd", "?", "print a FCF serd engine", fcf_serd },
1645 	{ "fmd_trace", "?[-cs]", "display thread trace buffer(s)", fmd_trace },
1646 	{ "fmd_ustat", "[:]", "display statistics collection", fmd_ustat },
1647 	{ "fmd_stat", "[:]", "display statistic structure", fmd_stat },
1648 	{ "fmd_event", NULL, "display event structure", fmd_event },
1649 	{ "fmd_thread", "?", "display thread or list of threads", fmd_thread },
1650 	{ "fmd_module", "?", "display module or list of modules", fmd_module },
1651 	{ "fmd_case", ":", "display case file structure", fmd_case },
1652 	{ "fmd_buf", ":", "display buffer structure", fmd_buf },
1653 	{ "fmd_serd", "[:]", "display serd engine structure", fmd_serd },
1654 	{ "fmd_asru", "?", "display asru resource structure", fmd_asru },
1655 	{ "fmd_asru_link", "?", "display resource structure", fmd_asru_link },
1656 	{ "fmd_timer", "?", "display pending timer(s)", fmd_timer },
1657 	{ "fmd_xprt", "?[-lrsu]", "display event transport(s)", fmd_xprt },
1658 	{ NULL }
1659 };
1660 
1661 static const mdb_walker_t walkers[] = {
1662 	{ "fcf_sec", "walk FCF section header table given header address",
1663 		fcf_sec_walk_init, fcf_sec_walk_step, fcf_sec_walk_fini },
1664 	{ "fmd_trace", "walk per-thread trace buffers",
1665 		trwalk_init, trwalk_step, trwalk_fini },
1666 	{ "fmd_ustat", "walk per-collection statistics",
1667 		ustat_walk_init, ustat_walk_step, hash_walk_fini },
1668 	{ "fmd_thread", "walk list of all fmd_thread_t's",
1669 		thread_walk_init, thread_walk_step, NULL },
1670 	{ "fmd_module", "walk list of all fmd_module_t's",
1671 		mod_walk_init, mod_walk_step, NULL },
1672 	{ "fmd_case", "walk per-module case objects",
1673 		case_walk_init, case_walk_step, case_walk_fini },
1674 	{ "fmd_buf", "walk per-buf_hash buffers",
1675 		buf_walk_init, hash_walk_step, hash_walk_fini },
1676 	{ "fmd_serd", "walk per-serd_hash engines",
1677 		serd_walk_init, hash_walk_step, hash_walk_fini },
1678 	{ "fmd_asru", "walk asru resource hash",
1679 		asru_walk_init, hash_walk_step, hash_walk_fini },
1680 	{ "fmd_asru_link", "walk resource hash",
1681 		al_walk_init, hash_walk_step, hash_walk_fini },
1682 	{ "fmd_timerq", "walk timer queue",
1683 		tmq_walk_init, tmq_walk_step, NULL },
1684 	{ "fmd_xprt", "walk per-module list of transports",
1685 		xprt_walk_init, xprt_walk_step, NULL },
1686 	{ "fmd_xprt_class", "walk hash table of subscription classes",
1687 		xpc_walk_init, hash_walk_step, hash_walk_fini },
1688 	{ "fmd_topo", "walk fmd's list of topo snapshots",
1689 		tsnap_walk_init, tsnap_walk_step, NULL },
1690 	{ "fmd_mod_queue", "walk per-module event queue",
1691 		mq_walk_init, mq_walk_step, NULL },
1692 	{ NULL, NULL, NULL, NULL, NULL }
1693 };
1694 
1695 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
1696 
1697 const mdb_modinfo_t *
1698 _mdb_init(void)
1699 {
1700 	return (&modinfo);
1701 }
1702