xref: /illumos-gate/usr/src/cmd/fm/modules/common/eversholt/eft_mdb.c (revision 20a7641f9918de8574b8b3b47dbe35c4bfc78df1)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright 2019 Joyent, Inc.
27  */
28 
29 #include <sys/mdb_modapi.h>
30 
31 #include <lut.h>
32 #include <itree.h>
33 #include "ipath_impl.h"
34 #include "lut_impl.h"
35 #include "config_impl.h"
36 #include "stats_impl.h"
37 
38 #define	LUT_SIZE_INIT	300
39 #define	LUT_SIZE_INCR	100
40 
41 struct lut_cp {
42 	uintptr_t lutcp_addr;
43 	struct lut lutcp_lut;
44 };
45 
46 #define	LCPSZ	sizeof (struct lut_cp)
47 
48 struct lut_dump_desc {
49 	struct lut_cp *ld_array;
50 	int ld_arraysz;
51 	int ld_nents;
52 };
53 
54 static void
55 lut_dump_array_alloc(struct lut_dump_desc *lddp)
56 {
57 	struct lut_cp *new;
58 
59 	if (lddp->ld_array == NULL) {
60 		lddp->ld_arraysz = LUT_SIZE_INIT;
61 		lddp->ld_array = mdb_zalloc(LUT_SIZE_INIT * LCPSZ, UM_SLEEP);
62 		return;
63 	}
64 
65 	new = mdb_zalloc((lddp->ld_arraysz + LUT_SIZE_INCR) * LCPSZ, UM_SLEEP);
66 	bcopy(lddp->ld_array, new, lddp->ld_arraysz * LCPSZ);
67 	mdb_free(lddp->ld_array, lddp->ld_arraysz * LCPSZ);
68 	lddp->ld_array = new;
69 	lddp->ld_arraysz += LUT_SIZE_INCR;
70 }
71 
72 static void
73 lut_dump_array_free(struct lut_dump_desc *lddp)
74 {
75 	if (lddp->ld_array != NULL) {
76 		mdb_free(lddp->ld_array, lddp->ld_arraysz * LCPSZ);
77 		lddp->ld_array = NULL;
78 	}
79 }
80 
81 static void
82 lut_collect_addent(uintptr_t addr, struct lut *ent, struct lut_dump_desc *lddp)
83 {
84 	struct lut_cp *lcp;
85 
86 	if (lddp->ld_nents == lddp->ld_arraysz)
87 		lut_dump_array_alloc(lddp);
88 
89 	lcp = &lddp->ld_array[lddp->ld_nents++];
90 
91 	lcp->lutcp_addr = addr;
92 	bcopy(ent, &lcp->lutcp_lut, sizeof (struct lut));
93 }
94 
95 static int
96 eft_lut_walk(uintptr_t root, struct lut_dump_desc *lddp)
97 {
98 	struct lut lutent;
99 
100 	if (root) {
101 		if (mdb_vread(&lutent, sizeof (struct lut), root) !=
102 		    sizeof (struct lut)) {
103 			mdb_warn("failed to read struct lut at %p", root);
104 			return (WALK_ERR);
105 		}
106 
107 		if (eft_lut_walk((uintptr_t)lutent.lut_left, lddp) != WALK_NEXT)
108 			return (WALK_ERR);
109 
110 		lut_collect_addent(root, &lutent, lddp);
111 
112 		if (eft_lut_walk((uintptr_t)lutent.lut_right, lddp) !=
113 		    WALK_NEXT)
114 			return (WALK_ERR);
115 	}
116 	return (WALK_NEXT);
117 }
118 
119 static int
120 lut_collect(uintptr_t addr, struct lut_dump_desc *lddp)
121 {
122 	lut_dump_array_alloc(lddp);
123 
124 	if (eft_lut_walk(addr, lddp) != WALK_NEXT) {
125 		lut_dump_array_free(lddp);
126 		return (WALK_ERR);
127 	} else {
128 		return (WALK_NEXT);	/* caller must free dump array */
129 	}
130 }
131 
132 static int
133 lut_walk_init(mdb_walk_state_t *wsp)
134 {
135 	if (wsp->walk_addr == 0) {
136 		mdb_warn("lut walker requires a lut table address\n");
137 		return (WALK_ERR);
138 	}
139 
140 	wsp->walk_data = mdb_zalloc(sizeof (struct lut_dump_desc), UM_SLEEP);
141 	wsp->walk_arg = 0;
142 
143 	if (lut_collect(wsp->walk_addr, wsp->walk_data) == WALK_NEXT) {
144 		return (WALK_NEXT);
145 	} else {
146 		mdb_warn("failed to suck in full lut\n");
147 		mdb_free(wsp->walk_data, sizeof (struct lut_dump_desc));
148 		return (WALK_ERR);
149 	}
150 }
151 
152 static int
153 lut_walk_step(mdb_walk_state_t *wsp)
154 {
155 	struct lut_dump_desc *lddp = wsp->walk_data;
156 	int *ip = (int *)&wsp->walk_arg;
157 	struct lut_cp *lcp = &lddp->ld_array[*ip];
158 
159 	if (*ip == lddp->ld_nents)
160 		return (WALK_DONE);
161 
162 	++*ip;
163 
164 	return (wsp->walk_callback(lcp->lutcp_addr, &lcp->lutcp_lut,
165 	    wsp->walk_cbdata));
166 }
167 
168 static int
169 ipath_walk_init(mdb_walk_state_t *wsp)
170 {
171 	struct ipath *ipath;
172 
173 	ipath = mdb_alloc(sizeof (struct ipath), UM_SLEEP);
174 
175 	if (mdb_vread((void *)ipath, sizeof (struct ipath),
176 	    wsp->walk_addr) != sizeof (struct ipath)) {
177 		mdb_warn("failed to read struct ipath at %p", wsp->walk_addr);
178 		return (WALK_ERR);
179 	}
180 	wsp->walk_data = (void *)ipath;
181 
182 	if (ipath->s == NULL)
183 		return (WALK_DONE);
184 	else
185 		return (WALK_NEXT);
186 }
187 
188 static void
189 ipath_walk_fini(mdb_walk_state_t *wsp)
190 {
191 	mdb_free(wsp->walk_data, sizeof (struct ipath));
192 }
193 
194 static int
195 ipath_walk_step(mdb_walk_state_t *wsp)
196 {
197 	int status;
198 	struct ipath *ipath = (struct ipath *)wsp->walk_data;
199 	struct ipath *ip = (struct ipath *)wsp->walk_addr;
200 
201 	if (ip == NULL || ipath->s == NULL)
202 		return (WALK_DONE);
203 
204 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
205 	    wsp->walk_cbdata);
206 
207 	wsp->walk_addr = (uintptr_t)(ip + 1);
208 
209 	if (mdb_vread(wsp->walk_data, sizeof (struct ipath),
210 	    wsp->walk_addr) != sizeof (struct ipath)) {
211 		mdb_warn("failed to read struct ipath at %p", wsp->walk_addr);
212 		return (WALK_ERR);
213 	}
214 
215 	return (status);
216 }
217 
218 static void
219 lut_walk_fini(mdb_walk_state_t *wsp)
220 {
221 	struct lut_dump_desc *lddp = wsp->walk_data;
222 
223 	lut_dump_array_free(lddp);
224 	mdb_free(lddp, sizeof (struct lut_dump_desc));
225 }
226 
227 /*ARGSUSED*/
228 static int
229 ipath_node(uintptr_t addr, const void *data, void *arg)
230 {
231 	struct ipath *ipath = (struct ipath *)data;
232 	char buf[128];
233 
234 	if (mdb_readstr(buf, (size_t)sizeof (buf), (uintptr_t)ipath->s) < 0)
235 		(void) mdb_snprintf(buf, (size_t)sizeof (buf), "<%p>",
236 		    ipath->s);
237 
238 	mdb_printf("/%s=%d", buf, ipath->i);
239 	return (DCMD_OK);
240 }
241 
242 /*ARGSUSED*/
243 static int
244 ipath(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
245 {
246 	if (argc)
247 		return (DCMD_USAGE);
248 	if (!(flags & DCMD_ADDRSPEC))
249 		addr = mdb_get_dot();
250 	if (mdb_pwalk("eft_ipath", ipath_node, NULL, addr) != 0)
251 		return (DCMD_ERR);
252 	return (DCMD_OK);
253 }
254 
255 /*ARGSUSED*/
256 static int
257 eft_count(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
258 {
259 	struct lut lut;
260 	struct istat_entry istat_entry;
261 	struct stats count;
262 	GElf_Sym sym;
263 	char buf[128];
264 
265 	if (argc)
266 		return (DCMD_USAGE);
267 	if (!(flags & DCMD_ADDRSPEC)) {
268 		if (mdb_lookup_by_obj(MDB_OBJ_EVERY, "Istats", &sym) == -1 ||
269 		    sym.st_size != sizeof (addr))
270 			return (DCMD_ERR);
271 		if (mdb_vread(&addr, sizeof (addr),
272 		    (uintptr_t)sym.st_value) != sizeof (addr))
273 			return (DCMD_ERR);
274 		if (addr == 0)
275 			return (DCMD_OK);
276 		if (mdb_pwalk_dcmd("lut", "eft_count", argc, argv, addr) != 0)
277 			return (DCMD_ERR);
278 		return (DCMD_OK);
279 	}
280 
281 	if (mdb_vread(&lut, sizeof (struct lut), addr) != sizeof (struct lut)) {
282 		mdb_warn("failed to read struct lut at %p", addr);
283 		return (DCMD_ERR);
284 	}
285 	if (mdb_vread(&istat_entry, sizeof (struct istat_entry),
286 	    (uintptr_t)lut.lut_lhs) != sizeof (struct istat_entry)) {
287 		mdb_warn("failed to read struct istat_entry at %p", addr);
288 		return (DCMD_ERR);
289 	}
290 	if (mdb_vread(&count, sizeof (struct stats),
291 	    (uintptr_t)lut.lut_rhs) != sizeof (struct stats)) {
292 		mdb_warn("failed to read struct stats at %p", addr);
293 		return (DCMD_ERR);
294 	}
295 
296 	if (mdb_readstr(buf, (size_t)sizeof (buf),
297 	    (uintptr_t)istat_entry.ename) < 0)
298 		(void) mdb_snprintf(buf, (size_t)sizeof (buf), "<%p>",
299 		    istat_entry.ename);
300 
301 	mdb_printf("%s@", buf);
302 	(void) ipath((uintptr_t)istat_entry.ipath, DCMD_ADDRSPEC, 0, NULL);
303 	mdb_printf(" %d\n", count.fmd_stats.fmds_value.i32);
304 	return (DCMD_OK);
305 }
306 
307 /*ARGSUSED*/
308 static int
309 eft_time(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
310 {
311 	unsigned long long val;
312 	unsigned long long ull;
313 	int opt_p = 0;
314 
315 	if (!(flags & DCMD_ADDRSPEC))
316 		addr = mdb_get_dot();
317 	ull = addr;
318 	if (argc) {
319 		if (mdb_getopts(argc, argv,
320 		    'l', MDB_OPT_UINT64, &ull,
321 		    'p', MDB_OPT_SETBITS, TRUE, &opt_p, MDB_OPT_UINT64,
322 		    NULL) != argc) {
323 			return (DCMD_USAGE);
324 		}
325 	}
326 	if (opt_p) {
327 		if (mdb_vread(&ull, sizeof (ull), addr) != sizeof (ull)) {
328 			mdb_warn("failed to read timeval at %p", addr);
329 			return (DCMD_ERR);
330 		}
331 	}
332 #define	NOREMAINDER(den, num, val) (((val) = ((den) / (num))) * (num) == (den))
333 	if (ull == 0)
334 		mdb_printf("0us");
335 	else if (ull >= TIMEVAL_EVENTUALLY)
336 		mdb_printf("infinity");
337 	else if (NOREMAINDER(ull, 1000000000ULL*60*60*24*365, val))
338 		mdb_printf("%lluyear%s", val, (val == 1) ? "" : "s");
339 	else if (NOREMAINDER(ull, 1000000000ULL*60*60*24*30, val))
340 		mdb_printf("%llumonth%s", val, (val == 1) ? "" : "s");
341 	else if (NOREMAINDER(ull, 1000000000ULL*60*60*24*7, val))
342 		mdb_printf("%lluweek%s", val, (val == 1) ? "" : "s");
343 	else if (NOREMAINDER(ull, 1000000000ULL*60*60*24, val))
344 		mdb_printf("%lluday%s", val, (val == 1) ? "" : "s");
345 	else if (NOREMAINDER(ull, 1000000000ULL*60*60, val))
346 		mdb_printf("%lluhour%s", val, (val == 1) ? "" : "s");
347 	else if (NOREMAINDER(ull, 1000000000ULL*60, val))
348 		mdb_printf("%lluminute%s", val, (val == 1) ? "" : "s");
349 	else if (NOREMAINDER(ull, 1000000000ULL, val))
350 		mdb_printf("%llusecond%s", val, (val == 1) ? "" : "s");
351 	else if (NOREMAINDER(ull, 1000000ULL, val))
352 		mdb_printf("%llums", val);
353 	else if (NOREMAINDER(ull, 1000ULL, val))
354 		mdb_printf("%lluus", val);
355 	else
356 		mdb_printf("%lluns", ull);
357 
358 	return (DCMD_OK);
359 }
360 
361 /*ARGSUSED*/
362 static int
363 eft_node(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
364 {
365 	struct node node;
366 	int opt_v = 0;
367 	char buf[128];
368 
369 	if (!(flags & DCMD_ADDRSPEC))
370 		addr = mdb_get_dot();
371 	if (argc) {
372 		if (mdb_getopts(argc, argv,
373 		    'v', MDB_OPT_SETBITS, TRUE, &opt_v,
374 		    NULL) != argc) {
375 			return (DCMD_USAGE);
376 		}
377 	}
378 	if (addr == 0)
379 		return (DCMD_OK);
380 	if (mdb_vread(&node, sizeof (node), addr) != sizeof (node)) {
381 		mdb_warn("failed to read struct node at %p", addr);
382 		return (DCMD_ERR);
383 	}
384 	if (opt_v) {
385 		if (mdb_readstr(buf, (size_t)sizeof (buf),
386 		    (uintptr_t)node.file) < 0)
387 			(void) mdb_snprintf(buf, (size_t)sizeof (buf), "<%p>",
388 			    node.file);
389 
390 		mdb_printf("%s len %d\n", buf, node.line);
391 	}
392 	switch (node.t) {
393 	case T_NOTHING:			/* used to keep going on error cases */
394 		mdb_printf("nothing");
395 		break;
396 	case T_NAME:			/* identifiers, sometimes chained */
397 		if (mdb_readstr(buf, (size_t)sizeof (buf),
398 		    (uintptr_t)node.u.name.s) < 0)
399 			(void) mdb_snprintf(buf, (size_t)sizeof (buf), "<%p>",
400 			    node.u.name.s);
401 
402 		mdb_printf("%s", buf);
403 		if (node.u.name.cp) {
404 			struct config cp;
405 			if (mdb_vread(&cp, sizeof (cp),
406 			    (uintptr_t)node.u.name.cp) != sizeof (cp)) {
407 				mdb_warn("failed to read struct config at %p",
408 				    node.u.name.cp);
409 				return (DCMD_ERR);
410 			}
411 			mdb_printf("%d", cp.num);
412 		} else if (node.u.name.it == IT_HORIZONTAL) {
413 			if (node.u.name.child && !node.u.name.childgen) {
414 				mdb_printf("<");
415 				(void) eft_node((uintptr_t)node.u.name.child,
416 				    DCMD_ADDRSPEC, 0, NULL);
417 				mdb_printf(">");
418 			} else {
419 				mdb_printf("<> ");
420 			}
421 		} else if (node.u.name.child) {
422 			mdb_printf("[");
423 			(void) eft_node((uintptr_t)node.u.name.child,
424 			    DCMD_ADDRSPEC, 0, NULL);
425 			mdb_printf("]");
426 		}
427 		if (node.u.name.next) {
428 			if (node.u.name.it == IT_ENAME)
429 				mdb_printf(".");
430 			else
431 				mdb_printf("/");
432 			(void) eft_node((uintptr_t)node.u.name.next,
433 			    DCMD_ADDRSPEC, 0, NULL);
434 		}
435 		break;
436 	case T_GLOBID:			/* globals (e.g. $a) */
437 		if (mdb_readstr(buf, (size_t)sizeof (buf),
438 		    (uintptr_t)node.u.globid.s) < 0)
439 			(void) mdb_snprintf(buf, (size_t)sizeof (buf), "<%p>",
440 			    node.u.globid.s);
441 
442 		mdb_printf("$%s", buf);
443 		break;
444 	case T_EVENT:			/* class@path{expr} */
445 		(void) eft_node((uintptr_t)node.u.event.ename, DCMD_ADDRSPEC, 0,
446 		    NULL);
447 		mdb_printf("@");
448 		(void) eft_node((uintptr_t)node.u.event.epname, DCMD_ADDRSPEC,
449 		    0, NULL);
450 		if (node.u.event.eexprlist) {
451 			mdb_printf(" { ");
452 			(void) eft_node((uintptr_t)node.u.event.eexprlist,
453 			    DCMD_ADDRSPEC, 0, NULL);
454 			mdb_printf(" }");
455 		}
456 		break;
457 	case T_ENGINE:			/* upset threshold engine (e.g. SERD) */
458 		mdb_printf("engine ");
459 		(void) eft_node((uintptr_t)node.u.event.ename, DCMD_ADDRSPEC, 0,
460 		    NULL);
461 		break;
462 	case T_ASRU:			/* ASRU declaration */
463 		mdb_printf("asru ");
464 		(void) eft_node((uintptr_t)node.u.stmt.np, DCMD_ADDRSPEC, 0,
465 		    NULL);
466 		if (node.u.stmt.nvpairs) {
467 			mdb_printf(" ");
468 			(void) eft_node((uintptr_t)node.u.stmt.nvpairs,
469 			    DCMD_ADDRSPEC, 0, NULL);
470 
471 		}
472 		break;
473 	case T_FRU:			/* FRU declaration */
474 		mdb_printf("fru ");
475 		(void) eft_node((uintptr_t)node.u.stmt.np, DCMD_ADDRSPEC, 0,
476 		    NULL);
477 		if (node.u.stmt.nvpairs) {
478 			mdb_printf(" ");
479 			(void) eft_node((uintptr_t)node.u.stmt.nvpairs,
480 			    DCMD_ADDRSPEC, 0, NULL);
481 
482 		}
483 		break;
484 	case T_TIMEVAL:			/* num w/time suffix (ns internally) */
485 		{
486 			mdb_arg_t mdb_arg[2];
487 			mdb_arg[0].a_type = MDB_TYPE_STRING;
488 			mdb_arg[0].a_un.a_str = "-l";
489 			mdb_arg[1].a_type = MDB_TYPE_IMMEDIATE;
490 			mdb_arg[1].a_un.a_val = node.u.ull;
491 			(void) eft_time((uintptr_t)0, 0, 2, mdb_arg);
492 			break;
493 		}
494 	case T_NUM:			/* num (ull internally) */
495 		mdb_printf("%llu", node.u.ull);
496 		break;
497 	case T_QUOTE:			/* quoted string */
498 		if (mdb_readstr(buf, (size_t)sizeof (buf),
499 		    (uintptr_t)node.u.quote.s) < 0)
500 			(void) mdb_snprintf(buf, (size_t)sizeof (buf), "<%p>",
501 			    node.u.quote.s);
502 
503 		mdb_printf("\"%s\"", buf);
504 		break;
505 	case T_FUNC:			/* func(arglist) */
506 		if (mdb_readstr(buf, (size_t)sizeof (buf),
507 		    (uintptr_t)node.u.func.s) < 0)
508 			(void) mdb_snprintf(buf, (size_t)sizeof (buf), "<%p>",
509 			    node.u.func.s);
510 
511 		mdb_printf("%s(", buf);
512 		(void) eft_node((uintptr_t)node.u.func.arglist, DCMD_ADDRSPEC,
513 		    0, NULL);
514 		mdb_printf(")");
515 		break;
516 	case T_NVPAIR:			/* name=value pair in decl */
517 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
518 		    NULL);
519 		mdb_printf(" = ");
520 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
521 		    NULL);
522 		break;
523 	case T_ASSIGN:			/* assignment statement */
524 		mdb_printf("(");
525 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
526 		    NULL);
527 		mdb_printf(" = ");
528 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
529 		    NULL);
530 		mdb_printf(")");
531 		break;
532 	case T_CONDIF:			/* a and T_CONDELSE in (a ? b : c ) */
533 		mdb_printf("(");
534 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
535 		    NULL);
536 		mdb_printf(" ? ");
537 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
538 		    NULL);
539 		mdb_printf(")");
540 		break;
541 	case T_CONDELSE:		/* lists b and c in (a ? b : c ) */
542 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
543 		    NULL);
544 		mdb_printf(" : ");
545 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
546 		    NULL);
547 		break;
548 	case T_NOT:			/* boolean ! operator */
549 		mdb_printf("!");
550 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
551 		    NULL);
552 		break;
553 	case T_AND:			/* boolean && operator */
554 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
555 		    NULL);
556 		mdb_printf(" && ");
557 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
558 		    NULL);
559 		break;
560 	case T_OR:			/* boolean || operator */
561 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
562 		    NULL);
563 		mdb_printf(" || ");
564 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
565 		    NULL);
566 		break;
567 	case T_EQ:			/* boolean == operator */
568 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
569 		    NULL);
570 		mdb_printf(" == ");
571 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
572 		    NULL);
573 		break;
574 	case T_NE:			/* boolean != operator */
575 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
576 		    NULL);
577 		mdb_printf(" != ");
578 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
579 		    NULL);
580 		break;
581 	case T_SUB:			/* integer - operator */
582 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
583 		    NULL);
584 		mdb_printf(" - ");
585 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
586 		    NULL);
587 		break;
588 	case T_ADD:			/* integer + operator */
589 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
590 		    NULL);
591 		mdb_printf(" + ");
592 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
593 		    NULL);
594 		break;
595 	case T_MUL:			/* integer * operator */
596 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
597 		    NULL);
598 		mdb_printf(" * ");
599 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
600 		    NULL);
601 		break;
602 	case T_DIV:			/* integer / operator */
603 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
604 		    NULL);
605 		mdb_printf(" / ");
606 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
607 		    NULL);
608 		break;
609 	case T_MOD:			/* integer % operator */
610 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
611 		    NULL);
612 		mdb_printf(" % ");
613 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
614 		    NULL);
615 		break;
616 	case T_LT:			/* boolean < operator */
617 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
618 		    NULL);
619 		mdb_printf(" < ");
620 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
621 		    NULL);
622 		break;
623 	case T_LE:			/* boolean <= operator */
624 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
625 		    NULL);
626 		mdb_printf(" <= ");
627 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
628 		    NULL);
629 		break;
630 	case T_GT:			/* boolean > operator */
631 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
632 		    NULL);
633 		mdb_printf(" > ");
634 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
635 		    NULL);
636 		break;
637 	case T_GE:			/* boolean >= operator */
638 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
639 		    NULL);
640 		mdb_printf(" >= ");
641 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
642 		    NULL);
643 		break;
644 	case T_BITAND:			/* bitwise & operator */
645 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
646 		    NULL);
647 		mdb_printf(" & ");
648 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
649 		    NULL);
650 		break;
651 	case T_BITOR:			/* bitwise | operator */
652 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
653 		    NULL);
654 		mdb_printf(" | ");
655 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
656 		    NULL);
657 		break;
658 	case T_BITXOR:			/* bitwise ^ operator */
659 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
660 		    NULL);
661 		mdb_printf(" ^ ");
662 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
663 		    NULL);
664 		break;
665 	case T_BITNOT:			/* bitwise ~ operator */
666 		mdb_printf(" ~");
667 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
668 		    NULL);
669 		break;
670 	case T_LSHIFT:			/* bitwise << operator */
671 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
672 		    NULL);
673 		mdb_printf(" << ");
674 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
675 		    NULL);
676 		break;
677 	case T_RSHIFT:			/* bitwise >> operator */
678 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
679 		    NULL);
680 		mdb_printf(" >> ");
681 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
682 		    NULL);
683 		break;
684 	case T_ARROW:			/* lhs (N)->(K) rhs */
685 		(void) eft_node((uintptr_t)node.u.arrow.lhs, DCMD_ADDRSPEC, 0,
686 		    NULL);
687 		if (node.u.arrow.nnp) {
688 			mdb_printf("(");
689 			(void) eft_node((uintptr_t)node.u.arrow.nnp,
690 			    DCMD_ADDRSPEC, 0, NULL);
691 			mdb_printf(")");
692 		}
693 		mdb_printf("->");
694 		if (node.u.arrow.knp) {
695 			mdb_printf("(");
696 			(void) eft_node((uintptr_t)node.u.arrow.knp,
697 			    DCMD_ADDRSPEC, 0, NULL);
698 			mdb_printf(")");
699 		}
700 		(void) eft_node((uintptr_t)node.u.arrow.rhs, DCMD_ADDRSPEC, 0,
701 		    NULL);
702 		break;
703 	case T_LIST:			/* comma-separated list */
704 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
705 		    NULL);
706 		mdb_printf(", ");
707 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
708 		    NULL);
709 		break;
710 	case T_FAULT:			/* fault declaration */
711 		mdb_printf("fault.");
712 		(void) eft_node((uintptr_t)node.u.stmt.np, DCMD_ADDRSPEC, 0,
713 		    NULL);
714 		if (node.u.stmt.nvpairs) {
715 			mdb_printf(" ");
716 			(void) eft_node((uintptr_t)node.u.stmt.nvpairs,
717 			    DCMD_ADDRSPEC, 0, NULL);
718 
719 		}
720 		break;
721 	case T_UPSET:			/* upset declaration */
722 		mdb_printf("upset.");
723 		(void) eft_node((uintptr_t)node.u.stmt.np, DCMD_ADDRSPEC, 0,
724 		    NULL);
725 		if (node.u.stmt.nvpairs) {
726 			mdb_printf(" ");
727 			(void) eft_node((uintptr_t)node.u.stmt.nvpairs,
728 			    DCMD_ADDRSPEC, 0, NULL);
729 
730 		}
731 		break;
732 	case T_DEFECT:			/* defect declaration */
733 		mdb_printf("defect.");
734 		(void) eft_node((uintptr_t)node.u.stmt.np, DCMD_ADDRSPEC, 0,
735 		    NULL);
736 		if (node.u.stmt.nvpairs) {
737 			mdb_printf(" ");
738 			(void) eft_node((uintptr_t)node.u.stmt.nvpairs,
739 			    DCMD_ADDRSPEC, 0, NULL);
740 
741 		}
742 		break;
743 	case T_ERROR:			/* error declaration */
744 		mdb_printf("error.");
745 		(void) eft_node((uintptr_t)node.u.stmt.np, DCMD_ADDRSPEC, 0,
746 		    NULL);
747 		if (node.u.stmt.nvpairs) {
748 			mdb_printf(" ");
749 			(void) eft_node((uintptr_t)node.u.stmt.nvpairs,
750 			    DCMD_ADDRSPEC, 0, NULL);
751 
752 		}
753 		break;
754 	case T_EREPORT:			/* ereport declaration */
755 		mdb_printf("ereport.");
756 		(void) eft_node((uintptr_t)node.u.stmt.np, DCMD_ADDRSPEC, 0,
757 		    NULL);
758 		if (node.u.stmt.nvpairs) {
759 			mdb_printf(" ");
760 			(void) eft_node((uintptr_t)node.u.stmt.nvpairs,
761 			    DCMD_ADDRSPEC, 0, NULL);
762 
763 		}
764 		break;
765 	case T_SERD:			/* SERD engine declaration */
766 		mdb_printf("serd.");
767 		(void) eft_node((uintptr_t)node.u.stmt.np, DCMD_ADDRSPEC, 0,
768 		    NULL);
769 		if (node.u.stmt.nvpairs) {
770 			mdb_printf(" ");
771 			(void) eft_node((uintptr_t)node.u.stmt.nvpairs,
772 			    DCMD_ADDRSPEC, 0, NULL);
773 
774 		} else if (node.u.stmt.lutp) {
775 			if (mdb_pwalk_dcmd("lut", "eft_node", 0, NULL,
776 			    (uintptr_t)node.u.stmt.lutp) != 0)
777 				return (DCMD_ERR);
778 		}
779 		break;
780 	case T_STAT:			/* STAT engine declaration */
781 		mdb_printf("stat.");
782 		(void) eft_node((uintptr_t)node.u.stmt.np, DCMD_ADDRSPEC, 0,
783 		    NULL);
784 		if (node.u.stmt.nvpairs) {
785 			mdb_printf(" ");
786 			(void) eft_node((uintptr_t)node.u.stmt.nvpairs,
787 			    DCMD_ADDRSPEC, 0, NULL);
788 
789 		} else if (node.u.stmt.lutp) {
790 			if (mdb_pwalk_dcmd("lut", "eft_node", 0, NULL,
791 			    (uintptr_t)node.u.stmt.lutp) != 0)
792 				return (DCMD_ERR);
793 		}
794 		break;
795 	case T_PROP:			/* prop statement */
796 		mdb_printf("prop ");
797 		(void) eft_node((uintptr_t)node.u.stmt.np, DCMD_ADDRSPEC, 0,
798 		    NULL);
799 		break;
800 	case T_MASK:			/* mask statement */
801 		mdb_printf("mask ");
802 		(void) eft_node((uintptr_t)node.u.stmt.np, DCMD_ADDRSPEC, 0,
803 		    NULL);
804 		break;
805 	case T_CONFIG:			/* config statement */
806 		mdb_printf("config ");
807 		(void) eft_node((uintptr_t)node.u.stmt.np, DCMD_ADDRSPEC, 0,
808 		    NULL);
809 		if (node.u.stmt.nvpairs) {
810 			mdb_printf(" ");
811 			(void) eft_node((uintptr_t)node.u.stmt.nvpairs,
812 			    DCMD_ADDRSPEC, 0, NULL);
813 
814 		}
815 		break;
816 	default:
817 		mdb_printf("not a eversholt node\n");
818 		break;
819 	}
820 	return (DCMD_OK);
821 }
822 
823 static const mdb_walker_t walkers[] = {
824 	{ "lut", "walk a lookup table", lut_walk_init, lut_walk_step,
825 	    lut_walk_fini, NULL },
826 	{ "eft_ipath", "walk ipath", ipath_walk_init, ipath_walk_step,
827 	    ipath_walk_fini, NULL },
828 	{ NULL, NULL, NULL, NULL, NULL, NULL }
829 };
830 
831 static const mdb_dcmd_t dcmds[] = {
832 	{ "eft_ipath", "?", "print an ipath", ipath },
833 	{ "eft_count", "?", "print eversholt stats", eft_count },
834 	{ "eft_node", "?[-v]", "print eversholt node", eft_node },
835 	{ "eft_time", "?[-p][-l time]", "print eversholt timeval", eft_time },
836 	{ NULL }
837 };
838 
839 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
840 
841 const mdb_modinfo_t *
842 _mdb_init(void)
843 {
844 	return (&modinfo);
845 }
846