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