xref: /illumos-gate/usr/src/cmd/fm/modules/common/eversholt/eft_mdb.c (revision 8b80e8cb6855118d46f605e91b5ed4ce83417395)
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 2007 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 <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 == NULL) {
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 	mdb_readstr(buf, (size_t)sizeof (buf), (uintptr_t)ipath->s);
235 	buf[sizeof (buf) - 1] = 0;
236 	mdb_printf("/%s=%d", buf, ipath->i);
237 	return (DCMD_OK);
238 }
239 
240 /*ARGSUSED*/
241 static int
242 ipath(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
243 {
244 	if (argc)
245 		return (DCMD_USAGE);
246 	if (!(flags & DCMD_ADDRSPEC))
247 		addr = mdb_get_dot();
248 	if (mdb_pwalk("eft_ipath", ipath_node, NULL, addr) != 0)
249 		return (DCMD_ERR);
250 	return (DCMD_OK);
251 }
252 
253 /*ARGSUSED*/
254 static int
255 eft_count(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
256 {
257 	struct lut lut;
258 	struct istat_entry istat_entry;
259 	struct stats count;
260 	GElf_Sym sym;
261 	char buf[128];
262 
263 	if (argc)
264 		return (DCMD_USAGE);
265 	if (!(flags & DCMD_ADDRSPEC)) {
266 		if (mdb_lookup_by_obj(MDB_OBJ_EVERY, "Istats", &sym) == -1 ||
267 		    sym.st_size != sizeof (addr))
268 			return (DCMD_ERR);
269 		if (mdb_vread(&addr, sizeof (addr),
270 		    (uintptr_t)sym.st_value) != sizeof (addr))
271 			return (DCMD_ERR);
272 		if (addr == NULL)
273 			return (DCMD_OK);
274 		if (mdb_pwalk_dcmd("lut", "eft_count", argc, argv, addr) != 0)
275 			return (DCMD_ERR);
276 		return (DCMD_OK);
277 	}
278 
279 	if (mdb_vread(&lut, sizeof (struct lut), addr) != sizeof (struct lut)) {
280 		mdb_warn("failed to read struct lut at %p", addr);
281 		return (DCMD_ERR);
282 	}
283 	if (mdb_vread(&istat_entry, sizeof (struct istat_entry),
284 	    (uintptr_t)lut.lut_lhs) != sizeof (struct istat_entry)) {
285 		mdb_warn("failed to read struct istat_entry at %p", addr);
286 		return (DCMD_ERR);
287 	}
288 	if (mdb_vread(&count, sizeof (struct stats),
289 	    (uintptr_t)lut.lut_rhs) != sizeof (struct stats)) {
290 		mdb_warn("failed to read struct stats at %p", addr);
291 		return (DCMD_ERR);
292 	}
293 
294 	mdb_readstr(buf, (size_t)sizeof (buf), (uintptr_t)istat_entry.ename);
295 	buf[sizeof (buf) - 1] = 0;
296 	mdb_printf("%s@", buf);
297 	(void) ipath((uintptr_t)istat_entry.ipath, DCMD_ADDRSPEC, 0, NULL);
298 	mdb_printf(" %d\n", count.fmd_stats.fmds_value.i32);
299 	return (DCMD_OK);
300 }
301 
302 /*ARGSUSED*/
303 static int
304 eft_time(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
305 {
306 	unsigned long long val;
307 	unsigned long long ull;
308 	int opt_p = 0;
309 
310 	if (!(flags & DCMD_ADDRSPEC))
311 		addr = mdb_get_dot();
312 	ull = addr;
313 	if (argc) {
314 		if (mdb_getopts(argc, argv,
315 		    'l', MDB_OPT_UINT64, &ull,
316 		    'p', MDB_OPT_SETBITS, TRUE, &opt_p,
317 		    MDB_OPT_UINT64) != argc) {
318 			return (DCMD_USAGE);
319 		}
320 	}
321 	if (opt_p) {
322 		if (mdb_vread(&ull, sizeof (ull), addr) != sizeof (ull)) {
323 			mdb_warn("failed to read timeval at %p", addr);
324 			return (DCMD_ERR);
325 		}
326 	}
327 #define	NOREMAINDER(den, num, val) (((val) = ((den) / (num))) * (num) == (den))
328 	if (ull == 0)
329 		mdb_printf("0us");
330 	else if (ull >= TIMEVAL_EVENTUALLY)
331 		mdb_printf("infinity");
332 	else if (NOREMAINDER(ull, 1000000000ULL*60*60*24*365, val))
333 		mdb_printf("%lluyear%s", val, (val == 1) ? "" : "s");
334 	else if (NOREMAINDER(ull, 1000000000ULL*60*60*24*30, val))
335 		mdb_printf("%llumonth%s", val, (val == 1) ? "" : "s");
336 	else if (NOREMAINDER(ull, 1000000000ULL*60*60*24*7, val))
337 		mdb_printf("%lluweek%s", val, (val == 1) ? "" : "s");
338 	else if (NOREMAINDER(ull, 1000000000ULL*60*60*24, val))
339 		mdb_printf("%lluday%s", val, (val == 1) ? "" : "s");
340 	else if (NOREMAINDER(ull, 1000000000ULL*60*60, val))
341 		mdb_printf("%lluhour%s", val, (val == 1) ? "" : "s");
342 	else if (NOREMAINDER(ull, 1000000000ULL*60, val))
343 		mdb_printf("%lluminute%s", val, (val == 1) ? "" : "s");
344 	else if (NOREMAINDER(ull, 1000000000ULL, val))
345 		mdb_printf("%llusecond%s", val, (val == 1) ? "" : "s");
346 	else if (NOREMAINDER(ull, 1000000ULL, val))
347 		mdb_printf("%llums", val);
348 	else if (NOREMAINDER(ull, 1000ULL, val))
349 		mdb_printf("%lluus", val);
350 	else
351 		mdb_printf("%lluns", ull);
352 
353 	return (DCMD_OK);
354 }
355 
356 /*ARGSUSED*/
357 static int
358 eft_node(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
359 {
360 	struct node node;
361 	int opt_v = 0;
362 	char buf[128];
363 
364 	if (!(flags & DCMD_ADDRSPEC))
365 		addr = mdb_get_dot();
366 	if (argc) {
367 		if (mdb_getopts(argc, argv,
368 		    'v', MDB_OPT_SETBITS, TRUE, &opt_v,
369 		    NULL) != argc) {
370 			return (DCMD_USAGE);
371 		}
372 	}
373 	if (addr == NULL)
374 		return (DCMD_OK);
375 	if (mdb_vread(&node, sizeof (node), addr) != sizeof (node)) {
376 		mdb_warn("failed to read struct node at %p", addr);
377 		return (DCMD_ERR);
378 	}
379 	if (opt_v) {
380 		mdb_readstr(buf, (size_t)sizeof (buf), (uintptr_t)node.file);
381 		buf[sizeof (buf) - 1] = 0;
382 		mdb_printf("%s len %d\n", buf, node.line);
383 	}
384 	switch (node.t) {
385 	case T_NOTHING:			/* used to keep going on error cases */
386 		mdb_printf("nothing");
387 		break;
388 	case T_NAME:			/* identifiers, sometimes chained */
389 		mdb_readstr(buf, (size_t)sizeof (buf),
390 		    (uintptr_t)node.u.name.s);
391 		buf[sizeof (buf) - 1] = 0;
392 		mdb_printf("%s", buf);
393 		if (node.u.name.cp) {
394 			struct config cp;
395 			if (mdb_vread(&cp, sizeof (cp),
396 			    (uintptr_t)node.u.name.cp) != sizeof (cp)) {
397 				mdb_warn("failed to read struct config at %p",
398 				    node.u.name.cp);
399 				return (DCMD_ERR);
400 			}
401 			mdb_printf("%d", cp.num);
402 		} else if (node.u.name.it == IT_HORIZONTAL) {
403 			if (node.u.name.child && !node.u.name.childgen) {
404 				mdb_printf("<");
405 				(void) eft_node((uintptr_t)node.u.name.child,
406 				    DCMD_ADDRSPEC, 0, NULL);
407 				mdb_printf(">");
408 			} else {
409 				mdb_printf("<> ");
410 			}
411 		} else if (node.u.name.child) {
412 			mdb_printf("[");
413 			(void) eft_node((uintptr_t)node.u.name.child,
414 			    DCMD_ADDRSPEC, 0, NULL);
415 			mdb_printf("]");
416 		}
417 		if (node.u.name.next) {
418 			if (node.u.name.it == IT_ENAME)
419 				mdb_printf(".");
420 			else
421 				mdb_printf("/");
422 			(void) eft_node((uintptr_t)node.u.name.next,
423 			    DCMD_ADDRSPEC, 0, NULL);
424 		}
425 		break;
426 	case T_GLOBID:			/* globals (e.g. $a) */
427 		mdb_readstr(buf, (size_t)sizeof (buf),
428 		    (uintptr_t)node.u.globid.s);
429 		buf[sizeof (buf) - 1] = 0;
430 		mdb_printf("$%s", buf);
431 		break;
432 	case T_EVENT:			/* class@path{expr} */
433 		(void) eft_node((uintptr_t)node.u.event.ename, DCMD_ADDRSPEC, 0,
434 		    NULL);
435 		mdb_printf("@");
436 		(void) eft_node((uintptr_t)node.u.event.epname, DCMD_ADDRSPEC,
437 		    0, NULL);
438 		if (node.u.event.eexprlist) {
439 			mdb_printf(" { ");
440 			(void) eft_node((uintptr_t)node.u.event.eexprlist,
441 			    DCMD_ADDRSPEC, 0, NULL);
442 			mdb_printf(" }");
443 		}
444 		break;
445 	case T_ENGINE:			/* upset threshold engine (e.g. SERD) */
446 		mdb_printf("engine ");
447 		(void) eft_node((uintptr_t)node.u.event.ename, DCMD_ADDRSPEC, 0,
448 		    NULL);
449 		break;
450 	case T_ASRU:			/* ASRU declaration */
451 		mdb_printf("asru ");
452 		(void) eft_node((uintptr_t)node.u.stmt.np, DCMD_ADDRSPEC, 0,
453 		    NULL);
454 		if (node.u.stmt.nvpairs) {
455 			mdb_printf(" ");
456 			(void) eft_node((uintptr_t)node.u.stmt.nvpairs,
457 			    DCMD_ADDRSPEC, 0, NULL);
458 
459 		}
460 		break;
461 	case T_FRU:			/* FRU declaration */
462 		mdb_printf("fru ");
463 		(void) eft_node((uintptr_t)node.u.stmt.np, DCMD_ADDRSPEC, 0,
464 		    NULL);
465 		if (node.u.stmt.nvpairs) {
466 			mdb_printf(" ");
467 			(void) eft_node((uintptr_t)node.u.stmt.nvpairs,
468 			    DCMD_ADDRSPEC, 0, NULL);
469 
470 		}
471 		break;
472 	case T_TIMEVAL:			/* num w/time suffix (ns internally) */
473 		{
474 			mdb_arg_t mdb_arg[2];
475 			mdb_arg[0].a_type = MDB_TYPE_STRING;
476 			mdb_arg[0].a_un.a_str = "-l";
477 			mdb_arg[1].a_type = MDB_TYPE_IMMEDIATE;
478 			mdb_arg[1].a_un.a_val = node.u.ull;
479 			(void) eft_time((uintptr_t)0, 0, 2, mdb_arg);
480 			break;
481 		}
482 	case T_NUM:			/* num (ull internally) */
483 		mdb_printf("%llu", node.u.ull);
484 		break;
485 	case T_QUOTE:			/* quoted string */
486 		mdb_readstr(buf, (size_t)sizeof (buf),
487 		    (uintptr_t)node.u.quote.s);
488 		buf[sizeof (buf) - 1] = 0;
489 		mdb_printf("\"%s\"", buf);
490 		break;
491 	case T_FUNC:			/* func(arglist) */
492 		mdb_readstr(buf, (size_t)sizeof (buf),
493 		    (uintptr_t)node.u.func.s);
494 		buf[sizeof (buf) - 1] = 0;
495 		mdb_printf("%s(", buf);
496 		(void) eft_node((uintptr_t)node.u.func.arglist, DCMD_ADDRSPEC,
497 		    0, NULL);
498 		mdb_printf(")");
499 		break;
500 	case T_NVPAIR:			/* name=value pair in decl */
501 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
502 		    NULL);
503 		mdb_printf(" = ");
504 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
505 		    NULL);
506 		break;
507 	case T_ASSIGN:			/* assignment statement */
508 		mdb_printf("(");
509 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
510 		    NULL);
511 		mdb_printf(" = ");
512 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
513 		    NULL);
514 		mdb_printf(")");
515 		break;
516 	case T_CONDIF:			/* a and T_CONDELSE in (a ? b : c ) */
517 		mdb_printf("(");
518 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
519 		    NULL);
520 		mdb_printf(" ? ");
521 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
522 		    NULL);
523 		mdb_printf(")");
524 		break;
525 	case T_CONDELSE:		/* lists b and c in (a ? b : c ) */
526 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
527 		    NULL);
528 		mdb_printf(" : ");
529 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
530 		    NULL);
531 		break;
532 	case T_NOT:			/* boolean ! operator */
533 		mdb_printf("!");
534 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
535 		    NULL);
536 		break;
537 	case T_AND:			/* boolean && operator */
538 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
539 		    NULL);
540 		mdb_printf(" && ");
541 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
542 		    NULL);
543 		break;
544 	case T_OR:			/* boolean || operator */
545 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
546 		    NULL);
547 		mdb_printf(" || ");
548 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
549 		    NULL);
550 		break;
551 	case T_EQ:			/* boolean == operator */
552 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
553 		    NULL);
554 		mdb_printf(" == ");
555 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
556 		    NULL);
557 		break;
558 	case T_NE:			/* boolean != operator */
559 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
560 		    NULL);
561 		mdb_printf(" != ");
562 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
563 		    NULL);
564 		break;
565 	case T_SUB:			/* integer - operator */
566 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
567 		    NULL);
568 		mdb_printf(" - ");
569 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
570 		    NULL);
571 		break;
572 	case T_ADD:			/* integer + operator */
573 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
574 		    NULL);
575 		mdb_printf(" + ");
576 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
577 		    NULL);
578 		break;
579 	case T_MUL:			/* integer * operator */
580 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
581 		    NULL);
582 		mdb_printf(" * ");
583 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
584 		    NULL);
585 		break;
586 	case T_DIV:			/* integer / operator */
587 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
588 		    NULL);
589 		mdb_printf(" / ");
590 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
591 		    NULL);
592 		break;
593 	case T_MOD:			/* integer % operator */
594 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
595 		    NULL);
596 		mdb_printf(" % ");
597 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
598 		    NULL);
599 		break;
600 	case T_LT:			/* boolean < operator */
601 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
602 		    NULL);
603 		mdb_printf(" < ");
604 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
605 		    NULL);
606 		break;
607 	case T_LE:			/* boolean <= operator */
608 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
609 		    NULL);
610 		mdb_printf(" <= ");
611 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
612 		    NULL);
613 		break;
614 	case T_GT:			/* boolean > operator */
615 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
616 		    NULL);
617 		mdb_printf(" > ");
618 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
619 		    NULL);
620 		break;
621 	case T_GE:			/* boolean >= operator */
622 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
623 		    NULL);
624 		mdb_printf(" >= ");
625 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
626 		    NULL);
627 		break;
628 	case T_BITAND:			/* bitwise & operator */
629 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
630 		    NULL);
631 		mdb_printf(" & ");
632 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
633 		    NULL);
634 		break;
635 	case T_BITOR:			/* bitwise | operator */
636 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
637 		    NULL);
638 		mdb_printf(" | ");
639 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
640 		    NULL);
641 		break;
642 	case T_BITXOR:			/* bitwise ^ operator */
643 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
644 		    NULL);
645 		mdb_printf(" ^ ");
646 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
647 		    NULL);
648 		break;
649 	case T_BITNOT:			/* bitwise ~ operator */
650 		mdb_printf(" ~");
651 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
652 		    NULL);
653 		break;
654 	case T_LSHIFT:			/* bitwise << operator */
655 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
656 		    NULL);
657 		mdb_printf(" << ");
658 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
659 		    NULL);
660 		break;
661 	case T_RSHIFT:			/* bitwise >> operator */
662 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
663 		    NULL);
664 		mdb_printf(" >> ");
665 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
666 		    NULL);
667 		break;
668 	case T_ARROW:			/* lhs (N)->(K) rhs */
669 		(void) eft_node((uintptr_t)node.u.arrow.lhs, DCMD_ADDRSPEC, 0,
670 		    NULL);
671 		if (node.u.arrow.nnp) {
672 			mdb_printf("(");
673 			(void) eft_node((uintptr_t)node.u.arrow.nnp,
674 			    DCMD_ADDRSPEC, 0, NULL);
675 			mdb_printf(")");
676 		}
677 		mdb_printf("->");
678 		if (node.u.arrow.knp) {
679 			mdb_printf("(");
680 			(void) eft_node((uintptr_t)node.u.arrow.knp,
681 			    DCMD_ADDRSPEC, 0, NULL);
682 			mdb_printf(")");
683 		}
684 		(void) eft_node((uintptr_t)node.u.arrow.rhs, DCMD_ADDRSPEC, 0,
685 		    NULL);
686 		break;
687 	case T_LIST:			/* comma-separated list */
688 		(void) eft_node((uintptr_t)node.u.expr.left, DCMD_ADDRSPEC, 0,
689 		    NULL);
690 		mdb_printf(", ");
691 		(void) eft_node((uintptr_t)node.u.expr.right, DCMD_ADDRSPEC, 0,
692 		    NULL);
693 		break;
694 	case T_FAULT:			/* fault declaration */
695 		mdb_printf("fault.");
696 		(void) eft_node((uintptr_t)node.u.stmt.np, DCMD_ADDRSPEC, 0,
697 		    NULL);
698 		if (node.u.stmt.nvpairs) {
699 			mdb_printf(" ");
700 			(void) eft_node((uintptr_t)node.u.stmt.nvpairs,
701 			    DCMD_ADDRSPEC, 0, NULL);
702 
703 		}
704 		break;
705 	case T_UPSET:			/* upset declaration */
706 		mdb_printf("upset.");
707 		(void) eft_node((uintptr_t)node.u.stmt.np, DCMD_ADDRSPEC, 0,
708 		    NULL);
709 		if (node.u.stmt.nvpairs) {
710 			mdb_printf(" ");
711 			(void) eft_node((uintptr_t)node.u.stmt.nvpairs,
712 			    DCMD_ADDRSPEC, 0, NULL);
713 
714 		}
715 		break;
716 	case T_DEFECT:			/* defect declaration */
717 		mdb_printf("defect.");
718 		(void) eft_node((uintptr_t)node.u.stmt.np, DCMD_ADDRSPEC, 0,
719 		    NULL);
720 		if (node.u.stmt.nvpairs) {
721 			mdb_printf(" ");
722 			(void) eft_node((uintptr_t)node.u.stmt.nvpairs,
723 			    DCMD_ADDRSPEC, 0, NULL);
724 
725 		}
726 		break;
727 	case T_ERROR:			/* error declaration */
728 		mdb_printf("error.");
729 		(void) eft_node((uintptr_t)node.u.stmt.np, DCMD_ADDRSPEC, 0,
730 		    NULL);
731 		if (node.u.stmt.nvpairs) {
732 			mdb_printf(" ");
733 			(void) eft_node((uintptr_t)node.u.stmt.nvpairs,
734 			    DCMD_ADDRSPEC, 0, NULL);
735 
736 		}
737 		break;
738 	case T_EREPORT:			/* ereport declaration */
739 		mdb_printf("ereport.");
740 		(void) eft_node((uintptr_t)node.u.stmt.np, DCMD_ADDRSPEC, 0,
741 		    NULL);
742 		if (node.u.stmt.nvpairs) {
743 			mdb_printf(" ");
744 			(void) eft_node((uintptr_t)node.u.stmt.nvpairs,
745 			    DCMD_ADDRSPEC, 0, NULL);
746 
747 		}
748 		break;
749 	case T_SERD:			/* SERD engine declaration */
750 		mdb_printf("serd.");
751 		(void) eft_node((uintptr_t)node.u.stmt.np, DCMD_ADDRSPEC, 0,
752 		    NULL);
753 		if (node.u.stmt.nvpairs) {
754 			mdb_printf(" ");
755 			(void) eft_node((uintptr_t)node.u.stmt.nvpairs,
756 			    DCMD_ADDRSPEC, 0, NULL);
757 
758 		} else if (node.u.stmt.lutp) {
759 			if (mdb_pwalk_dcmd("lut", "eft_node", 0, NULL,
760 			    (uintptr_t)node.u.stmt.lutp) != 0)
761 				return (DCMD_ERR);
762 		}
763 		break;
764 	case T_STAT:			/* STAT engine declaration */
765 		mdb_printf("stat.");
766 		(void) eft_node((uintptr_t)node.u.stmt.np, DCMD_ADDRSPEC, 0,
767 		    NULL);
768 		if (node.u.stmt.nvpairs) {
769 			mdb_printf(" ");
770 			(void) eft_node((uintptr_t)node.u.stmt.nvpairs,
771 			    DCMD_ADDRSPEC, 0, NULL);
772 
773 		} else if (node.u.stmt.lutp) {
774 			if (mdb_pwalk_dcmd("lut", "eft_node", 0, NULL,
775 			    (uintptr_t)node.u.stmt.lutp) != 0)
776 				return (DCMD_ERR);
777 		}
778 		break;
779 	case T_PROP:			/* prop statement */
780 		mdb_printf("prop ");
781 		(void) eft_node((uintptr_t)node.u.stmt.np, DCMD_ADDRSPEC, 0,
782 		    NULL);
783 		break;
784 	case T_MASK:			/* mask statement */
785 		mdb_printf("mask ");
786 		(void) eft_node((uintptr_t)node.u.stmt.np, DCMD_ADDRSPEC, 0,
787 		    NULL);
788 		break;
789 	case T_CONFIG:			/* config statement */
790 		mdb_printf("config ");
791 		(void) eft_node((uintptr_t)node.u.stmt.np, DCMD_ADDRSPEC, 0,
792 		    NULL);
793 		if (node.u.stmt.nvpairs) {
794 			mdb_printf(" ");
795 			(void) eft_node((uintptr_t)node.u.stmt.nvpairs,
796 			    DCMD_ADDRSPEC, 0, NULL);
797 
798 		}
799 		break;
800 	default:
801 		mdb_printf("not a eversholt node\n");
802 		break;
803 	}
804 	return (DCMD_OK);
805 }
806 
807 static const mdb_walker_t walkers[] = {
808 	{ "lut", "walk a lookup table", lut_walk_init, lut_walk_step,
809 	    lut_walk_fini, NULL },
810 	{ "eft_ipath", "walk ipath", ipath_walk_init, ipath_walk_step,
811 	    ipath_walk_fini, NULL },
812 	{ NULL, NULL, NULL, NULL, NULL, NULL }
813 };
814 
815 static const mdb_dcmd_t dcmds[] = {
816 	{ "eft_ipath", "?", "print an ipath", ipath },
817 	{ "eft_count", "?", "print eversholt stats", eft_count },
818 	{ "eft_node", "?[-v]", "print eversholt node", eft_node },
819 	{ "eft_time", "?[-p][-l time]", "print eversholt timeval", eft_time },
820 	{ NULL }
821 };
822 
823 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
824 
825 const mdb_modinfo_t *
826 _mdb_init(void)
827 {
828 	return (&modinfo);
829 }
830