Home | History | Annotate | Download | only in eversholt
      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