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