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