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