10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51717Swesolows * Common Development and Distribution License (the "License"). 61717Swesolows * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 211717Swesolows 220Sstevel@tonic-gate /* 23*4436Sstephh * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate * 260Sstevel@tonic-gate * eval.c -- constraint evaluation module 270Sstevel@tonic-gate * 280Sstevel@tonic-gate * this module evaluates constraints. 290Sstevel@tonic-gate */ 300Sstevel@tonic-gate 310Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include <stdio.h> 340Sstevel@tonic-gate #include <stdlib.h> 350Sstevel@tonic-gate #include <ctype.h> 360Sstevel@tonic-gate #include <string.h> 370Sstevel@tonic-gate #include "alloc.h" 380Sstevel@tonic-gate #include "out.h" 390Sstevel@tonic-gate #include "stable.h" 400Sstevel@tonic-gate #include "literals.h" 410Sstevel@tonic-gate #include "lut.h" 420Sstevel@tonic-gate #include "tree.h" 430Sstevel@tonic-gate #include "ptree.h" 440Sstevel@tonic-gate #include "itree.h" 451414Scindi #include "ipath.h" 460Sstevel@tonic-gate #include "eval.h" 470Sstevel@tonic-gate #include "config.h" 480Sstevel@tonic-gate #include "platform.h" 491414Scindi #include "fme.h" 501414Scindi #include "stats.h" 510Sstevel@tonic-gate 520Sstevel@tonic-gate static struct node *eval_dup(struct node *np, struct lut *ex, 53*4436Sstephh struct node *events[]); 541414Scindi static int check_expr_args(struct evalue *lp, struct evalue *rp, 551414Scindi enum datatype dtype, struct node *np); 56*4436Sstephh static struct node *eval_fru(struct node *np); 57*4436Sstephh static struct node *eval_asru(struct node *np); 580Sstevel@tonic-gate 590Sstevel@tonic-gate /* 600Sstevel@tonic-gate * begins_with -- return true if rhs path begins with everything in lhs path 610Sstevel@tonic-gate */ 620Sstevel@tonic-gate static int 63*4436Sstephh begins_with(struct node *lhs, struct node *rhs, struct lut *ex) 640Sstevel@tonic-gate { 650Sstevel@tonic-gate int lnum; 660Sstevel@tonic-gate int rnum; 67*4436Sstephh struct iterinfo *iterinfop; 680Sstevel@tonic-gate 690Sstevel@tonic-gate if (lhs == NULL) 700Sstevel@tonic-gate return (1); /* yep -- it all matched */ 710Sstevel@tonic-gate 720Sstevel@tonic-gate if (rhs == NULL) 730Sstevel@tonic-gate return (0); /* nope, ran out of rhs first */ 740Sstevel@tonic-gate 750Sstevel@tonic-gate ASSERTeq(lhs->t, T_NAME, ptree_nodetype2str); 760Sstevel@tonic-gate ASSERTeq(rhs->t, T_NAME, ptree_nodetype2str); 770Sstevel@tonic-gate 780Sstevel@tonic-gate if (lhs->u.name.s != rhs->u.name.s) 790Sstevel@tonic-gate return (0); /* nope, different component names */ 800Sstevel@tonic-gate 81*4436Sstephh if (lhs->u.name.child && lhs->u.name.child->t == T_NUM) { 820Sstevel@tonic-gate lnum = (int)lhs->u.name.child->u.ull; 83*4436Sstephh } else if (lhs->u.name.child && lhs->u.name.child->t == T_NAME) { 84*4436Sstephh iterinfop = lut_lookup(ex, (void *)lhs->u.name.child->u.name.s, 85*4436Sstephh NULL); 86*4436Sstephh if (iterinfop != NULL) 87*4436Sstephh lnum = iterinfop->num; 88*4436Sstephh else 89*4436Sstephh out(O_DIE, "begins_with: unexpected lhs child"); 90*4436Sstephh } else { 910Sstevel@tonic-gate out(O_DIE, "begins_with: unexpected lhs child"); 92*4436Sstephh } 930Sstevel@tonic-gate 94*4436Sstephh if (rhs->u.name.child && rhs->u.name.child->t == T_NUM) { 950Sstevel@tonic-gate rnum = (int)rhs->u.name.child->u.ull; 96*4436Sstephh } else if (rhs->u.name.child && rhs->u.name.child->t == T_NAME) { 97*4436Sstephh iterinfop = lut_lookup(ex, (void *)rhs->u.name.child->u.name.s, 98*4436Sstephh NULL); 99*4436Sstephh if (iterinfop != NULL) 100*4436Sstephh rnum = iterinfop->num; 101*4436Sstephh else 102*4436Sstephh out(O_DIE, "begins_with: unexpected rhs child"); 103*4436Sstephh } else { 1040Sstevel@tonic-gate out(O_DIE, "begins_with: unexpected rhs child"); 105*4436Sstephh } 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate if (lnum != rnum) 1080Sstevel@tonic-gate return (0); /* nope, instance numbers were different */ 1090Sstevel@tonic-gate 110*4436Sstephh return (begins_with(lhs->u.name.next, rhs->u.name.next, ex)); 111*4436Sstephh } 112*4436Sstephh 113*4436Sstephh /* 114*4436Sstephh * eval_getname - used by eval_func to evaluate a name, preferably without using 115*4436Sstephh * eval_dup (but if it does have to use eval_dup then the *dupedp flag is set). 116*4436Sstephh */ 117*4436Sstephh static struct node * 118*4436Sstephh eval_getname(struct node *funcnp, struct lut *ex, struct node *events[], 119*4436Sstephh struct node *np, struct lut **globals, 120*4436Sstephh struct config *croot, struct arrow *arrowp, int try, int *dupedp) 121*4436Sstephh { 122*4436Sstephh struct node *nodep; 123*4436Sstephh const char *funcname = funcnp->u.func.s; 124*4436Sstephh struct evalue val; 125*4436Sstephh 126*4436Sstephh if (np->t == T_NAME) 127*4436Sstephh nodep = np; 128*4436Sstephh else if (np->u.func.s == L_fru) 129*4436Sstephh nodep = eval_fru(np->u.func.arglist); 130*4436Sstephh else if (np->u.func.s == L_asru) 131*4436Sstephh nodep = eval_asru(np->u.func.arglist); 132*4436Sstephh else 133*4436Sstephh out(O_DIE, "%s: unexpected type: %s", 134*4436Sstephh funcname, ptree_nodetype2str(np->t)); 135*4436Sstephh if (try) { 136*4436Sstephh if (eval_expr(nodep, ex, events, globals, croot, 137*4436Sstephh arrowp, try, &val) && val.t == NODEPTR) 138*4436Sstephh nodep = (struct node *)(uintptr_t)val.v; 139*4436Sstephh else { 140*4436Sstephh *dupedp = 1; 141*4436Sstephh nodep = eval_dup(nodep, ex, events); 142*4436Sstephh } 143*4436Sstephh } 144*4436Sstephh return (nodep); 1450Sstevel@tonic-gate } 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate /* 1480Sstevel@tonic-gate * evaluate a variety of functions and place result in valuep. return 1 if 1490Sstevel@tonic-gate * function evaluation was successful; 0 if otherwise (e.g., the case of an 1500Sstevel@tonic-gate * invalid argument to the function) 1510Sstevel@tonic-gate */ 1520Sstevel@tonic-gate /*ARGSUSED*/ 1530Sstevel@tonic-gate static int 154*4436Sstephh eval_func(struct node *funcnp, struct lut *ex, struct node *events[], 1550Sstevel@tonic-gate struct node *np, struct lut **globals, 1560Sstevel@tonic-gate struct config *croot, struct arrow *arrowp, int try, struct evalue *valuep) 1570Sstevel@tonic-gate { 1580Sstevel@tonic-gate const char *funcname = funcnp->u.func.s; 159*4436Sstephh int duped_lhs = 0, duped_rhs = 0, duped = 0; 160*4436Sstephh struct node *lhs; 161*4436Sstephh struct node *rhs; 162*4436Sstephh struct config *cp; 163*4436Sstephh struct node *nodep; 164*4436Sstephh char *path; 165*4436Sstephh struct evalue val; 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate if (funcname == L_within) { 1680Sstevel@tonic-gate /* within()'s are not really constraints -- always true */ 1690Sstevel@tonic-gate valuep->t = UINT64; 1700Sstevel@tonic-gate valuep->v = 1; 1710Sstevel@tonic-gate return (1); 1720Sstevel@tonic-gate } else if (funcname == L_is_under) { 173*4436Sstephh lhs = eval_getname(funcnp, ex, events, np->u.expr.left, globals, 174*4436Sstephh croot, arrowp, try, &duped_lhs); 175*4436Sstephh rhs = eval_getname(funcnp, ex, events, np->u.expr.right, 176*4436Sstephh globals, croot, arrowp, try, &duped_rhs); 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate valuep->t = UINT64; 179*4436Sstephh valuep->v = begins_with(lhs, rhs, ex); 1800Sstevel@tonic-gate out(O_ALTFP|O_VERB2|O_NONL, "eval_func:is_under("); 1810Sstevel@tonic-gate ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, lhs); 1820Sstevel@tonic-gate out(O_ALTFP|O_VERB2|O_NONL, ","); 1830Sstevel@tonic-gate ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, rhs); 184*4436Sstephh out(O_ALTFP|O_VERB2|O_NONL, ") returned %d", (int)valuep->v); 1850Sstevel@tonic-gate 186*4436Sstephh if (duped_lhs) 187*4436Sstephh tree_free(lhs); 188*4436Sstephh if (duped_rhs) 189*4436Sstephh tree_free(rhs); 1900Sstevel@tonic-gate return (1); 1912869Sgavinm } else if (funcname == L_confprop || funcname == L_confprop_defined) { 1922318Sstephh const char *s; 1932318Sstephh 1942318Sstephh /* for now s will point to a quote [see addconfigprop()] */ 1952318Sstephh ASSERT(np->u.expr.right->t == T_QUOTE); 1962318Sstephh 197*4436Sstephh nodep = eval_getname(funcnp, ex, events, np->u.expr.left, 198*4436Sstephh globals, croot, arrowp, try, &duped); 199*4436Sstephh if (nodep->u.name.last->u.name.cp != NULL) { 200*4436Sstephh cp = nodep->u.name.last->u.name.cp; 201*4436Sstephh } else { 202*4436Sstephh path = ipath2str(NULL, ipath(nodep)); 203*4436Sstephh cp = config_lookup(croot, path, 0); 204*4436Sstephh FREE((void *)path); 205*4436Sstephh } 2062869Sgavinm if (cp == NULL) { 207*4436Sstephh if (funcname == L_confprop) { 208*4436Sstephh out(O_ALTFP|O_VERB3, "%s: path ", funcname); 209*4436Sstephh ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, nodep); 210*4436Sstephh out(O_ALTFP|O_VERB3, " not found"); 211*4436Sstephh valuep->v = (uintptr_t)stable(""); 212*4436Sstephh valuep->t = STRING; 213*4436Sstephh if (duped) 214*4436Sstephh tree_free(nodep); 215*4436Sstephh return (1); 216*4436Sstephh } else { 2172869Sgavinm valuep->v = 0; 2182869Sgavinm valuep->t = UINT64; 219*4436Sstephh if (duped) 220*4436Sstephh tree_free(nodep); 2212869Sgavinm return (1); 2222869Sgavinm } 2232869Sgavinm } 2242318Sstephh s = config_getprop(cp, np->u.expr.right->u.quote.s); 225*4436Sstephh if (s == NULL && strcmp(np->u.expr.right->u.quote.s, 226*4436Sstephh "class-code") == 0) 227*4436Sstephh s = config_getprop(cp, "CLASS-CODE"); 2282869Sgavinm if (s == NULL) { 229*4436Sstephh if (funcname == L_confprop) { 230*4436Sstephh out(O_ALTFP|O_VERB3|O_NONL, 231*4436Sstephh "%s: \"%s\" not found for path ", 232*4436Sstephh funcname, np->u.expr.right->u.quote.s); 233*4436Sstephh ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, nodep); 234*4436Sstephh valuep->v = (uintptr_t)stable(""); 235*4436Sstephh valuep->t = STRING; 236*4436Sstephh if (duped) 237*4436Sstephh tree_free(nodep); 238*4436Sstephh return (1); 239*4436Sstephh } else { 2402869Sgavinm valuep->v = 0; 2412869Sgavinm valuep->t = UINT64; 242*4436Sstephh if (duped) 243*4436Sstephh tree_free(nodep); 2442869Sgavinm return (1); 2452869Sgavinm } 2462869Sgavinm } 2472869Sgavinm 2482869Sgavinm if (funcname == L_confprop) { 2492869Sgavinm valuep->v = (uintptr_t)stable(s); 2502869Sgavinm valuep->t = STRING; 251*4436Sstephh out(O_ALTFP|O_VERB3|O_NONL, " %s(\"", funcname); 252*4436Sstephh ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, nodep); 253*4436Sstephh out(O_ALTFP|O_VERB3|O_NONL, 254*4436Sstephh "\", \"%s\") = \"%s\" ", 255*4436Sstephh np->u.expr.right->u.quote.s, 2562869Sgavinm (char *)(uintptr_t)valuep->v); 2572869Sgavinm } else { 2582869Sgavinm valuep->v = 1; 2592869Sgavinm valuep->t = UINT64; 2602869Sgavinm } 261*4436Sstephh if (duped) 262*4436Sstephh tree_free(nodep); 263*4436Sstephh return (1); 264*4436Sstephh } else if (funcname == L_is_connected) { 265*4436Sstephh const char *connstrings[] = { "connected", "CONNECTED", NULL }; 266*4436Sstephh struct config *cp[2]; 267*4436Sstephh const char *matchthis[2], *s; 268*4436Sstephh char *nameslist, *w; 269*4436Sstephh int i, j; 270*4436Sstephh 271*4436Sstephh lhs = eval_getname(funcnp, ex, events, np->u.expr.left, globals, 272*4436Sstephh croot, arrowp, try, &duped_lhs); 273*4436Sstephh rhs = eval_getname(funcnp, ex, events, np->u.expr.right, 274*4436Sstephh globals, croot, arrowp, try, &duped_rhs); 275*4436Sstephh path = ipath2str(NULL, ipath(lhs)); 276*4436Sstephh matchthis[1] = stable(path); 277*4436Sstephh if (lhs->u.name.last->u.name.cp != NULL) 278*4436Sstephh cp[0] = lhs->u.name.last->u.name.cp; 279*4436Sstephh else 280*4436Sstephh cp[0] = config_lookup(croot, path, 0); 2812869Sgavinm FREE((void *)path); 282*4436Sstephh path = ipath2str(NULL, ipath(rhs)); 283*4436Sstephh matchthis[0] = stable(path); 284*4436Sstephh if (rhs->u.name.last->u.name.cp != NULL) 285*4436Sstephh cp[1] = rhs->u.name.last->u.name.cp; 286*4436Sstephh else 287*4436Sstephh cp[1] = config_lookup(croot, path, 0); 288*4436Sstephh FREE((void *)path); 289*4436Sstephh if (duped_lhs) 290*4436Sstephh tree_free(lhs); 291*4436Sstephh if (duped_rhs) 292*4436Sstephh tree_free(rhs); 293*4436Sstephh 294*4436Sstephh valuep->t = UINT64; 295*4436Sstephh valuep->v = 0; 296*4436Sstephh if (cp[0] == NULL || cp[1] == NULL) 297*4436Sstephh return (1); 298*4436Sstephh 299*4436Sstephh /* to thine self always be connected */ 300*4436Sstephh if (cp[0] == cp[1]) { 301*4436Sstephh valuep->v = 1; 302*4436Sstephh return (1); 303*4436Sstephh } 304*4436Sstephh 305*4436Sstephh /* 306*4436Sstephh * Extract "connected" property from each cp. Search this 307*4436Sstephh * property for the name associated with the other cp[]. 308*4436Sstephh */ 309*4436Sstephh for (i = 0; i < 2 && valuep->v == 0; i++) { 310*4436Sstephh for (j = 0; connstrings[j] != NULL && valuep->v == 0; 311*4436Sstephh j++) { 312*4436Sstephh s = config_getprop(cp[i], 313*4436Sstephh stable(connstrings[j])); 314*4436Sstephh if (s != NULL) { 315*4436Sstephh nameslist = STRDUP(s); 316*4436Sstephh w = strtok(nameslist, " ,"); 317*4436Sstephh while (w != NULL) { 318*4436Sstephh if (stable(w) == matchthis[i]) { 319*4436Sstephh valuep->v = 1; 320*4436Sstephh break; 321*4436Sstephh } 322*4436Sstephh w = strtok(NULL, " ,"); 323*4436Sstephh } 324*4436Sstephh FREE(nameslist); 325*4436Sstephh } 326*4436Sstephh } 327*4436Sstephh } 3282318Sstephh return (1); 329*4436Sstephh } else if (funcname == L_is_type) { 330*4436Sstephh const char *typestrings[] = { "type", "TYPE", NULL }; 331*4436Sstephh const char *s; 332*4436Sstephh int i; 333*4436Sstephh 334*4436Sstephh nodep = eval_getname(funcnp, ex, events, np, globals, 335*4436Sstephh croot, arrowp, try, &duped); 336*4436Sstephh if (nodep->u.name.last->u.name.cp != NULL) { 337*4436Sstephh cp = nodep->u.name.last->u.name.cp; 338*4436Sstephh } else { 339*4436Sstephh path = ipath2str(NULL, ipath(nodep)); 340*4436Sstephh cp = config_lookup(croot, path, 0); 341*4436Sstephh FREE((void *)path); 342*4436Sstephh } 343*4436Sstephh if (duped) 344*4436Sstephh tree_free(nodep); 345*4436Sstephh 346*4436Sstephh valuep->t = STRING; 347*4436Sstephh valuep->v = (uintptr_t)stable(""); 348*4436Sstephh if (cp == NULL) 349*4436Sstephh return (1); 350*4436Sstephh for (i = 0; typestrings[i] != NULL; i++) { 351*4436Sstephh s = config_getprop(cp, stable(typestrings[i])); 352*4436Sstephh if (s != NULL) { 353*4436Sstephh valuep->v = (uintptr_t)stable(s); 354*4436Sstephh break; 355*4436Sstephh } 356*4436Sstephh } 357*4436Sstephh return (1); 358*4436Sstephh } else if (funcname == L_is_on) { 359*4436Sstephh const char *onstrings[] = { "on", "ON", NULL }; 360*4436Sstephh const char *truestrings[] = { "yes", "YES", "y", "Y", 361*4436Sstephh "true", "TRUE", "t", "T", "1", NULL }; 362*4436Sstephh const char *s; 363*4436Sstephh int i, j; 364*4436Sstephh 365*4436Sstephh nodep = eval_getname(funcnp, ex, events, np, globals, 366*4436Sstephh croot, arrowp, try, &duped); 367*4436Sstephh if (nodep->u.name.last->u.name.cp != NULL) { 368*4436Sstephh cp = nodep->u.name.last->u.name.cp; 369*4436Sstephh } else { 370*4436Sstephh path = ipath2str(NULL, ipath(nodep)); 371*4436Sstephh cp = config_lookup(croot, path, 0); 372*4436Sstephh FREE((void *)path); 373*4436Sstephh } 374*4436Sstephh if (duped) 375*4436Sstephh tree_free(nodep); 376*4436Sstephh 377*4436Sstephh valuep->t = UINT64; 378*4436Sstephh valuep->v = 0; 379*4436Sstephh if (cp == NULL) 380*4436Sstephh return (1); 381*4436Sstephh for (i = 0; onstrings[i] != NULL; i++) { 382*4436Sstephh s = config_getprop(cp, stable(onstrings[i])); 383*4436Sstephh if (s != NULL) { 384*4436Sstephh s = stable(s); 385*4436Sstephh for (j = 0; truestrings[j] != NULL; j++) { 386*4436Sstephh if (s == stable(truestrings[j])) { 387*4436Sstephh valuep->v = 1; 388*4436Sstephh return (1); 389*4436Sstephh } 390*4436Sstephh } 391*4436Sstephh } 392*4436Sstephh } 393*4436Sstephh return (1); 394*4436Sstephh } else if (funcname == L_is_present) { 395*4436Sstephh nodep = eval_getname(funcnp, ex, events, np, globals, 396*4436Sstephh croot, arrowp, try, &duped); 397*4436Sstephh if (nodep->u.name.last->u.name.cp != NULL) { 398*4436Sstephh cp = nodep->u.name.last->u.name.cp; 399*4436Sstephh } else { 400*4436Sstephh path = ipath2str(NULL, ipath(nodep)); 401*4436Sstephh cp = config_lookup(croot, path, 0); 402*4436Sstephh FREE((void *)path); 403*4436Sstephh } 404*4436Sstephh if (duped) 405*4436Sstephh tree_free(nodep); 406*4436Sstephh 407*4436Sstephh valuep->t = UINT64; 408*4436Sstephh valuep->v = 0; 409*4436Sstephh if (cp != NULL) 410*4436Sstephh valuep->v = 1; 411*4436Sstephh return (1); 412*4436Sstephh } else if (funcname == L_count) { 413*4436Sstephh struct stats *statp; 414*4436Sstephh struct istat_entry ent; 415*4436Sstephh 416*4436Sstephh ASSERTinfo(np->t == T_EVENT, ptree_nodetype2str(np->t)); 417*4436Sstephh 418*4436Sstephh nodep = np->u.event.epname; 419*4436Sstephh if (try) { 420*4436Sstephh if (eval_expr(nodep, ex, events, globals, 421*4436Sstephh croot, arrowp, try, &val) && val.t == NODEPTR) 422*4436Sstephh nodep = (struct node *)(uintptr_t)val.v; 423*4436Sstephh else { 424*4436Sstephh duped = 1; 425*4436Sstephh nodep = eval_dup(nodep, ex, events); 426*4436Sstephh } 427*4436Sstephh } 428*4436Sstephh ent.ename = np->u.event.ename->u.name.s; 429*4436Sstephh ent.ipath = ipath(nodep); 430*4436Sstephh valuep->t = UINT64; 431*4436Sstephh if ((statp = (struct stats *) 432*4436Sstephh lut_lookup(Istats, &ent, (lut_cmp)istat_cmp)) == NULL) 433*4436Sstephh valuep->v = 0; 434*4436Sstephh else 435*4436Sstephh valuep->v = stats_counter_value(statp); 436*4436Sstephh if (duped) 437*4436Sstephh tree_free(nodep); 438*4436Sstephh return (1); 439*4436Sstephh } else if (funcname == L_envprop) { 440*4436Sstephh outfl(O_DIE, np->file, np->line, 441*4436Sstephh "eval_func: %s not yet supported", funcname); 4420Sstevel@tonic-gate } 4430Sstevel@tonic-gate 4440Sstevel@tonic-gate if (try) 4450Sstevel@tonic-gate return (0); 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate if (funcname == L_fru) { 4480Sstevel@tonic-gate valuep->t = NODEPTR; 4491717Swesolows valuep->v = (uintptr_t)eval_fru(np); 4500Sstevel@tonic-gate return (1); 4510Sstevel@tonic-gate } else if (funcname == L_asru) { 4520Sstevel@tonic-gate valuep->t = NODEPTR; 4531717Swesolows valuep->v = (uintptr_t)eval_asru(np); 4540Sstevel@tonic-gate return (1); 4551414Scindi } else if (funcname == L_defined) { 4561414Scindi ASSERTeq(np->t, T_GLOBID, ptree_nodetype2str); 4571414Scindi valuep->t = UINT64; 4581414Scindi valuep->v = (lut_lookup(*globals, 4591414Scindi (void *)np->u.globid.s, NULL) != NULL); 4601414Scindi return (1); 4610Sstevel@tonic-gate } else if (funcname == L_call) { 4620Sstevel@tonic-gate return (! platform_call(np, globals, croot, arrowp, valuep)); 4630Sstevel@tonic-gate } else if (funcname == L_payloadprop) { 4641414Scindi outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, 4650Sstevel@tonic-gate "payloadprop(\"%s\") ", np->u.quote.s); 466186Sdb35262 4671414Scindi if (platform_payloadprop(np, valuep)) { 4681414Scindi /* platform_payloadprop() returned false */ 4692869Sgavinm out(O_ALTFP|O_VERB, "payloadprop \"%s\" not found.", 4702869Sgavinm np->u.quote.s); 4711414Scindi return (0); 4721414Scindi } else { 473186Sdb35262 switch (valuep->t) { 474186Sdb35262 case UINT64: 475186Sdb35262 case NODEPTR: 4761414Scindi out(O_ALTFP|O_VERB2, "found: %llu", valuep->v); 477186Sdb35262 break; 478186Sdb35262 case STRING: 4791414Scindi out(O_ALTFP|O_VERB2, "found: \"%s\"", 4801717Swesolows (char *)(uintptr_t)valuep->v); 481186Sdb35262 break; 482186Sdb35262 default: 4831414Scindi out(O_ALTFP|O_VERB2, "found: undefined"); 484186Sdb35262 break; 485186Sdb35262 } 4861414Scindi return (1); 4871414Scindi } 4881414Scindi } else if (funcname == L_setpayloadprop) { 4891414Scindi struct evalue *payloadvalp; 4901414Scindi 4911414Scindi ASSERTinfo(np->t == T_LIST, ptree_nodetype2str(np->t)); 4921414Scindi ASSERTinfo(np->u.expr.left->t == T_QUOTE, 4931414Scindi ptree_nodetype2str(np->u.expr.left->t)); 4941414Scindi 4951414Scindi outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, 4961414Scindi "setpayloadprop: %s: %s=", 4971414Scindi arrowp->tail->myevent->enode->u.event.ename->u.name.s, 4981414Scindi np->u.expr.left->u.quote.s); 4991414Scindi ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np->u.expr.right); 5001414Scindi 5011414Scindi /* 5021414Scindi * allocate a struct evalue to hold the payload property's 5031414Scindi * value, unless we've been here already, in which case we 5041414Scindi * might calculate a different value, but we'll store it 5051414Scindi * in the already-allocated struct evalue. 5061414Scindi */ 5071414Scindi if ((payloadvalp = (struct evalue *)lut_lookup( 5081414Scindi arrowp->tail->myevent->payloadprops, 5091414Scindi (void *)np->u.expr.left->u.quote.s, NULL)) == NULL) { 5101414Scindi payloadvalp = MALLOC(sizeof (*payloadvalp)); 5111414Scindi } 5121414Scindi 513*4436Sstephh if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 5141414Scindi arrowp, try, payloadvalp)) { 5151414Scindi out(O_ALTFP|O_VERB2, " (cannot eval, using zero)"); 5161414Scindi payloadvalp->t = UINT64; 5171414Scindi payloadvalp->v = 0; 5181414Scindi } else { 5191414Scindi if (payloadvalp->t == UINT64) 5201414Scindi out(O_ALTFP|O_VERB2, 5211414Scindi " (%llu)", payloadvalp->v); 5221414Scindi else 5231717Swesolows out(O_ALTFP|O_VERB2, " (\"%s\")", 5241717Swesolows (char *)(uintptr_t)payloadvalp->v); 5251414Scindi } 5261414Scindi 5271414Scindi /* add to table of payload properties for current problem */ 5281414Scindi arrowp->tail->myevent->payloadprops = 5291414Scindi lut_add(arrowp->tail->myevent->payloadprops, 5301414Scindi (void *)np->u.expr.left->u.quote.s, 5311414Scindi (void *)payloadvalp, NULL); 5321414Scindi 5331414Scindi /* function is always true */ 5341414Scindi valuep->t = UINT64; 5351414Scindi valuep->v = 1; 5361414Scindi return (1); 5371414Scindi } else if (funcname == L_payloadprop_defined) { 5381414Scindi outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, 5391414Scindi "payloadprop_defined(\"%s\") ", np->u.quote.s); 5401414Scindi 5411414Scindi if (platform_payloadprop(np, NULL)) { 5421414Scindi /* platform_payloadprop() returned false */ 5431414Scindi valuep->v = 0; 5442869Sgavinm out(O_ALTFP|O_VERB2, "payloadprop_defined: \"%s\" " 5452869Sgavinm "not defined.", np->u.quote.s); 5461414Scindi } else { 5471414Scindi valuep->v = 1; 5481414Scindi out(O_ALTFP|O_VERB2, "found."); 5491414Scindi } 5501414Scindi valuep->t = UINT64; 5511414Scindi return (1); 5521414Scindi } else if (funcname == L_payloadprop_contains) { 5531414Scindi int nvals; 5541414Scindi struct evalue *vals; 5551414Scindi struct evalue cmpval; 5561414Scindi 5571414Scindi ASSERTinfo(np->t == T_LIST, ptree_nodetype2str(np->t)); 5581414Scindi ASSERTinfo(np->u.expr.left->t == T_QUOTE, 5591414Scindi ptree_nodetype2str(np->u.expr.left->t)); 5601414Scindi 5611414Scindi outfl(O_ALTFP|O_VERB2|O_NONL, np->file, np->line, 5621414Scindi "payloadprop_contains(\"%s\", ", 5631414Scindi np->u.expr.left->u.quote.s); 5641414Scindi ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, np->u.expr.right); 5652869Sgavinm out(O_ALTFP|O_VERB2|O_NONL, ") "); 5661414Scindi 5671414Scindi /* evaluate the expression we're comparing against */ 568*4436Sstephh if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 5691414Scindi arrowp, try, &cmpval)) { 5701414Scindi out(O_ALTFP|O_VERB2|O_NONL, 5711414Scindi "(cannot eval, using zero) "); 5721414Scindi cmpval.t = UINT64; 5731414Scindi cmpval.v = 0; 5741414Scindi } else { 5752869Sgavinm switch (cmpval.t) { 5762869Sgavinm case UNDEFINED: 5772869Sgavinm out(O_ALTFP|O_VERB2, "(undefined type)"); 5782869Sgavinm break; 5792869Sgavinm 5802869Sgavinm case UINT64: 5811414Scindi out(O_ALTFP|O_VERB2, 5821414Scindi "(%llu) ", cmpval.v); 5832869Sgavinm break; 5842869Sgavinm 5852869Sgavinm case STRING: 5861414Scindi out(O_ALTFP|O_VERB2, 5871717Swesolows "(\"%s\") ", (char *)(uintptr_t)cmpval.v); 5882869Sgavinm break; 5892869Sgavinm 5902869Sgavinm case NODEPTR: 5912869Sgavinm out(O_ALTFP|O_VERB2|O_NONL, "("); 5922869Sgavinm ptree_name_iter(O_ALTFP|O_VERB2|O_NONL, 5932869Sgavinm (struct node *)(uintptr_t)(cmpval.v)); 5942869Sgavinm out(O_ALTFP|O_VERB2, ") "); 5952869Sgavinm break; 5962869Sgavinm } 5971414Scindi } 5981414Scindi 5991414Scindi /* get the payload values and check for a match */ 6001414Scindi vals = platform_payloadprop_values(np->u.expr.left->u.quote.s, 6011414Scindi &nvals); 6021414Scindi valuep->t = UINT64; 6031414Scindi valuep->v = 0; 6041414Scindi if (nvals == 0) { 6051414Scindi out(O_ALTFP|O_VERB2, "not found."); 606*4436Sstephh return (0); 6071414Scindi } else { 6081414Scindi struct evalue preval; 6091414Scindi int i; 6101414Scindi 6111414Scindi out(O_ALTFP|O_VERB2|O_NONL, "found %d values ", nvals); 6121414Scindi 6131414Scindi for (i = 0; i < nvals; i++) { 6141414Scindi 6151414Scindi preval.t = vals[i].t; 6161414Scindi preval.v = vals[i].v; 6171414Scindi 6181414Scindi if (check_expr_args(&vals[i], &cmpval, 6191414Scindi UNDEFINED, np)) 6201414Scindi continue; 6211414Scindi 6221414Scindi /* 6231414Scindi * If we auto-converted the value to a 6241414Scindi * string, we need to free the 6251414Scindi * original tree value. 6261414Scindi */ 6271414Scindi if (preval.t == NODEPTR && 6281717Swesolows ((struct node *)(uintptr_t)(preval.v))->t == 6291717Swesolows T_NAME) { 6301717Swesolows tree_free((struct node *)(uintptr_t) 6311717Swesolows preval.v); 6321414Scindi } 6331414Scindi 6341414Scindi if (vals[i].v == cmpval.v) { 6351414Scindi valuep->v = 1; 6361414Scindi break; 6371414Scindi } 6381414Scindi } 639186Sdb35262 6401414Scindi if (valuep->v) 6411414Scindi out(O_ALTFP|O_VERB2, "match."); 6421414Scindi else 6431414Scindi out(O_ALTFP|O_VERB2, "no match."); 644186Sdb35262 6451414Scindi for (i = 0; i < nvals; i++) { 6461414Scindi if (vals[i].t == NODEPTR) { 6471717Swesolows tree_free((struct node *)(uintptr_t) 6481717Swesolows vals[i].v); 6491414Scindi break; 6501414Scindi } 651186Sdb35262 } 6521414Scindi FREE(vals); 6531414Scindi } 6541414Scindi return (1); 6551414Scindi } else if (funcname == L_confcall) { 6561414Scindi return (!platform_confcall(np, globals, croot, arrowp, valuep)); 6570Sstevel@tonic-gate } else 6580Sstevel@tonic-gate outfl(O_DIE, np->file, np->line, 6590Sstevel@tonic-gate "eval_func: unexpected func: %s", funcname); 6600Sstevel@tonic-gate /*NOTREACHED*/ 6611717Swesolows return (0); 6620Sstevel@tonic-gate } 6630Sstevel@tonic-gate 664*4436Sstephh /* 665*4436Sstephh * defines for u.expr.temp - these are used for T_OR and T_AND so that if 666*4436Sstephh * we worked out that part of the expression was true or false during an 667*4436Sstephh * earlier eval_expr, then we don't need to dup that part. 668*4436Sstephh */ 6690Sstevel@tonic-gate 670*4436Sstephh #define EXPR_TEMP_BOTH_UNK 0 671*4436Sstephh #define EXPR_TEMP_LHS_UNK 1 672*4436Sstephh #define EXPR_TEMP_RHS_UNK 2 6730Sstevel@tonic-gate 6740Sstevel@tonic-gate static struct node * 675*4436Sstephh eval_dup(struct node *np, struct lut *ex, struct node *events[]) 6760Sstevel@tonic-gate { 6770Sstevel@tonic-gate struct node *newnp; 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate if (np == NULL) 6800Sstevel@tonic-gate return (NULL); 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate switch (np->t) { 6830Sstevel@tonic-gate case T_GLOBID: 6840Sstevel@tonic-gate return (tree_globid(np->u.globid.s, np->file, np->line)); 6850Sstevel@tonic-gate 6860Sstevel@tonic-gate case T_ASSIGN: 6870Sstevel@tonic-gate case T_CONDIF: 6880Sstevel@tonic-gate case T_CONDELSE: 6890Sstevel@tonic-gate case T_NE: 6900Sstevel@tonic-gate case T_EQ: 6910Sstevel@tonic-gate case T_LT: 6920Sstevel@tonic-gate case T_LE: 6930Sstevel@tonic-gate case T_GT: 6940Sstevel@tonic-gate case T_GE: 6950Sstevel@tonic-gate case T_BITAND: 6960Sstevel@tonic-gate case T_BITOR: 6970Sstevel@tonic-gate case T_BITXOR: 6980Sstevel@tonic-gate case T_BITNOT: 6990Sstevel@tonic-gate case T_LSHIFT: 7000Sstevel@tonic-gate case T_RSHIFT: 7010Sstevel@tonic-gate case T_NOT: 7020Sstevel@tonic-gate case T_ADD: 7030Sstevel@tonic-gate case T_SUB: 7040Sstevel@tonic-gate case T_MUL: 7050Sstevel@tonic-gate case T_DIV: 7060Sstevel@tonic-gate case T_MOD: 7070Sstevel@tonic-gate return (tree_expr(np->t, 708*4436Sstephh eval_dup(np->u.expr.left, ex, events), 709*4436Sstephh eval_dup(np->u.expr.right, ex, events))); 710*4436Sstephh case T_LIST: 711*4436Sstephh case T_AND: 712*4436Sstephh switch (np->u.expr.temp) { 713*4436Sstephh case EXPR_TEMP_LHS_UNK: 714*4436Sstephh return (eval_dup(np->u.expr.left, ex, events)); 715*4436Sstephh case EXPR_TEMP_RHS_UNK: 716*4436Sstephh return (eval_dup(np->u.expr.right, ex, events)); 717*4436Sstephh default: 718*4436Sstephh return (tree_expr(np->t, 719*4436Sstephh eval_dup(np->u.expr.left, ex, events), 720*4436Sstephh eval_dup(np->u.expr.right, ex, events))); 721*4436Sstephh } 722*4436Sstephh 723*4436Sstephh case T_OR: 724*4436Sstephh switch (np->u.expr.temp) { 725*4436Sstephh case EXPR_TEMP_LHS_UNK: 726*4436Sstephh return (eval_dup(np->u.expr.left, ex, events)); 727*4436Sstephh case EXPR_TEMP_RHS_UNK: 728*4436Sstephh return (eval_dup(np->u.expr.right, ex, events)); 729*4436Sstephh default: 730*4436Sstephh return (tree_expr(T_OR, 731*4436Sstephh eval_dup(np->u.expr.left, ex, events), 732*4436Sstephh eval_dup(np->u.expr.right, ex, events))); 733*4436Sstephh } 7340Sstevel@tonic-gate 7350Sstevel@tonic-gate case T_NAME: { 7360Sstevel@tonic-gate struct iterinfo *iterinfop; 737*4436Sstephh int got_matchf = 0; 738*4436Sstephh int got_matcht = 0; 739*4436Sstephh struct evalue value; 740*4436Sstephh struct node *np1f, *np2f, *np1t, *np2t, *retp = NULL; 741*4436Sstephh struct node *npstart, *npcont, *npend, *npref, *newnp, *nprest; 7420Sstevel@tonic-gate 743*4436Sstephh /* 744*4436Sstephh * Check if we already have a match of the nonwildcarded path 745*4436Sstephh * in oldepname (check both to and from events). 746*4436Sstephh */ 747*4436Sstephh for (np1f = np, np2f = events[0]->u.event.oldepname; 748*4436Sstephh np1f != NULL && np2f != NULL; 749*4436Sstephh np1f = np1f->u.name.next, np2f = np2f->u.name.next) { 750*4436Sstephh if (strcmp(np1f->u.name.s, np2f->u.name.s) != 0) 751*4436Sstephh break; 752*4436Sstephh if (np1f->u.name.child->t != np2f->u.name.child->t) 753*4436Sstephh break; 754*4436Sstephh if (np1f->u.name.child->t == T_NUM && 755*4436Sstephh np1f->u.name.child->u.ull != 756*4436Sstephh np2f->u.name.child->u.ull) 757*4436Sstephh break; 758*4436Sstephh if (np1f->u.name.child->t == T_NAME && 759*4436Sstephh strcmp(np1f->u.name.child->u.name.s, 760*4436Sstephh np2f->u.name.child->u.name.s) != 0) 761*4436Sstephh break; 762*4436Sstephh got_matchf++; 763*4436Sstephh } 764*4436Sstephh for (np1t = np, np2t = events[1]->u.event.oldepname; 765*4436Sstephh np1t != NULL && np2t != NULL; 766*4436Sstephh np1t = np1t->u.name.next, np2t = np2t->u.name.next) { 767*4436Sstephh if (strcmp(np1t->u.name.s, np2t->u.name.s) != 0) 768*4436Sstephh break; 769*4436Sstephh if (np1t->u.name.child->t != np2t->u.name.child->t) 770*4436Sstephh break; 771*4436Sstephh if (np1t->u.name.child->t == T_NUM && 772*4436Sstephh np1t->u.name.child->u.ull != 773*4436Sstephh np2t->u.name.child->u.ull) 774*4436Sstephh break; 775*4436Sstephh if (np1t->u.name.child->t == T_NAME && 776*4436Sstephh strcmp(np1t->u.name.child->u.name.s, 777*4436Sstephh np2t->u.name.child->u.name.s) != 0) 778*4436Sstephh break; 779*4436Sstephh got_matcht++; 780*4436Sstephh } 781*4436Sstephh nprest = np; 782*4436Sstephh if (got_matchf || got_matcht) { 783*4436Sstephh /* 784*4436Sstephh * so we are wildcarding. Copy ewname in full, plus 785*4436Sstephh * matching section of oldepname. Use whichever gives 786*4436Sstephh * the closest match. 787*4436Sstephh */ 788*4436Sstephh if (got_matchf > got_matcht) { 789*4436Sstephh npstart = events[0]->u.event.ewname; 790*4436Sstephh npcont = events[0]->u.event.oldepname; 791*4436Sstephh npend = np2f; 792*4436Sstephh nprest = np1f; 793*4436Sstephh } else { 794*4436Sstephh npstart = events[1]->u.event.ewname; 795*4436Sstephh npcont = events[1]->u.event.oldepname; 796*4436Sstephh npend = np2t; 797*4436Sstephh nprest = np1t; 798*4436Sstephh } 799*4436Sstephh for (npref = npstart; npref != NULL; 800*4436Sstephh npref = npref->u.name.next) { 801*4436Sstephh newnp = newnode(T_NAME, np->file, np->line); 802*4436Sstephh newnp->u.name.t = npref->u.name.t; 803*4436Sstephh newnp->u.name.s = npref->u.name.s; 804*4436Sstephh newnp->u.name.last = newnp; 805*4436Sstephh newnp->u.name.it = npref->u.name.it; 806*4436Sstephh newnp->u.name.cp = npref->u.name.cp; 807*4436Sstephh newnp->u.name.child = 808*4436Sstephh newnode(T_NUM, np->file, np->line); 809*4436Sstephh if (eval_expr(npref->u.name.child, ex, events, 8100Sstevel@tonic-gate NULL, NULL, NULL, 1, &value) == 0 || 8110Sstevel@tonic-gate value.t != UINT64) { 8120Sstevel@tonic-gate outfl(O_DIE, np->file, np->line, 8130Sstevel@tonic-gate "eval_dup: could not resolve " 8140Sstevel@tonic-gate "iterator of %s", np->u.name.s); 8150Sstevel@tonic-gate } 816*4436Sstephh newnp->u.name.child->u.ull = value.v; 817*4436Sstephh if (retp == NULL) { 818*4436Sstephh retp = newnp; 819*4436Sstephh } else { 820*4436Sstephh retp->u.name.last->u.name.next = newnp; 821*4436Sstephh retp->u.name.last = newnp; 822*4436Sstephh } 8230Sstevel@tonic-gate } 824*4436Sstephh for (npref = npcont; npref != NULL && npref != npend; 825*4436Sstephh npref = npref->u.name.next) { 826*4436Sstephh newnp = newnode(T_NAME, np->file, np->line); 827*4436Sstephh newnp->u.name.t = npref->u.name.t; 828*4436Sstephh newnp->u.name.s = npref->u.name.s; 829*4436Sstephh newnp->u.name.last = newnp; 830*4436Sstephh newnp->u.name.it = npref->u.name.it; 831*4436Sstephh newnp->u.name.cp = npref->u.name.cp; 832*4436Sstephh newnp->u.name.child = 833*4436Sstephh newnode(T_NUM, np->file, np->line); 834*4436Sstephh if (eval_expr(npref->u.name.child, ex, events, 835*4436Sstephh NULL, NULL, NULL, 1, &value) == 0 || 836*4436Sstephh value.t != UINT64) { 837*4436Sstephh outfl(O_DIE, np->file, np->line, 838*4436Sstephh "eval_dup: could not resolve " 839*4436Sstephh "iterator of %s", np->u.name.s); 840*4436Sstephh } 841*4436Sstephh newnp->u.name.child->u.ull = value.v; 842*4436Sstephh if (retp == NULL) { 843*4436Sstephh retp = newnp; 844*4436Sstephh } else { 845*4436Sstephh retp->u.name.last->u.name.next = newnp; 846*4436Sstephh retp->u.name.last = newnp; 847*4436Sstephh } 848*4436Sstephh } 849*4436Sstephh } else { 850*4436Sstephh /* 851*4436Sstephh * not wildcarding - check if explicit iterator 852*4436Sstephh */ 853*4436Sstephh iterinfop = lut_lookup(ex, (void *)np->u.name.s, NULL); 854*4436Sstephh if (iterinfop != NULL) { 855*4436Sstephh /* explicit iterator; not part of pathname */ 856*4436Sstephh newnp = newnode(T_NUM, np->file, np->line); 857*4436Sstephh newnp->u.ull = iterinfop->num; 8580Sstevel@tonic-gate return (newnp); 8590Sstevel@tonic-gate } 8600Sstevel@tonic-gate } 861*4436Sstephh 862*4436Sstephh /* 863*4436Sstephh * finally, whether wildcarding or not, we need to copy the 864*4436Sstephh * remaining part of the path (if any). This must be defined 865*4436Sstephh * absolutely (no more expansion/wildcarding). 866*4436Sstephh */ 867*4436Sstephh for (npref = nprest; npref != NULL; 868*4436Sstephh npref = npref->u.name.next) { 869*4436Sstephh newnp = newnode(T_NAME, np->file, np->line); 870*4436Sstephh newnp->u.name.t = npref->u.name.t; 871*4436Sstephh newnp->u.name.s = npref->u.name.s; 872*4436Sstephh newnp->u.name.last = newnp; 873*4436Sstephh newnp->u.name.it = npref->u.name.it; 874*4436Sstephh newnp->u.name.cp = npref->u.name.cp; 875*4436Sstephh newnp->u.name.child = 876*4436Sstephh newnode(T_NUM, np->file, np->line); 877*4436Sstephh if (eval_expr(npref->u.name.child, ex, events, 878*4436Sstephh NULL, NULL, NULL, 1, &value) == 0 || 879*4436Sstephh value.t != UINT64) { 880*4436Sstephh outfl(O_DIE, np->file, np->line, 881*4436Sstephh "eval_dup: could not resolve " 882*4436Sstephh "iterator of %s", np->u.name.s); 883*4436Sstephh } 884*4436Sstephh newnp->u.name.child->u.ull = value.v; 885*4436Sstephh if (retp == NULL) { 886*4436Sstephh retp = newnp; 887*4436Sstephh } else { 888*4436Sstephh retp->u.name.last->u.name.next = newnp; 889*4436Sstephh retp->u.name.last = newnp; 890*4436Sstephh } 891*4436Sstephh } 892*4436Sstephh return (retp); 8930Sstevel@tonic-gate } 8940Sstevel@tonic-gate 8951414Scindi case T_EVENT: 8961414Scindi newnp = newnode(T_NAME, np->file, np->line); 8971414Scindi 8981414Scindi newnp->u.name.t = np->u.event.ename->u.name.t; 8991414Scindi newnp->u.name.s = np->u.event.ename->u.name.s; 9001414Scindi newnp->u.name.it = np->u.event.ename->u.name.it; 9011414Scindi newnp->u.name.last = newnp; 9021414Scindi 9031414Scindi return (tree_event(newnp, 904*4436Sstephh eval_dup(np->u.event.epname, ex, events), 905*4436Sstephh eval_dup(np->u.event.eexprlist, ex, events))); 9061414Scindi 9070Sstevel@tonic-gate case T_FUNC: 9080Sstevel@tonic-gate return (tree_func(np->u.func.s, 909*4436Sstephh eval_dup(np->u.func.arglist, ex, events), 9100Sstevel@tonic-gate np->file, np->line)); 9110Sstevel@tonic-gate 9120Sstevel@tonic-gate case T_QUOTE: 9130Sstevel@tonic-gate newnp = newnode(T_QUOTE, np->file, np->line); 9140Sstevel@tonic-gate newnp->u.quote.s = np->u.quote.s; 9150Sstevel@tonic-gate return (newnp); 9160Sstevel@tonic-gate 9170Sstevel@tonic-gate case T_NUM: 9180Sstevel@tonic-gate newnp = newnode(T_NUM, np->file, np->line); 9190Sstevel@tonic-gate newnp->u.ull = np->u.ull; 9200Sstevel@tonic-gate return (newnp); 9210Sstevel@tonic-gate 9220Sstevel@tonic-gate default: 9230Sstevel@tonic-gate outfl(O_DIE, np->file, np->line, 9240Sstevel@tonic-gate "eval_dup: unexpected node type: %s", 9250Sstevel@tonic-gate ptree_nodetype2str(np->t)); 9260Sstevel@tonic-gate } 9270Sstevel@tonic-gate /*NOTREACHED*/ 9281717Swesolows return (0); 9290Sstevel@tonic-gate } 9300Sstevel@tonic-gate 9310Sstevel@tonic-gate /* 9320Sstevel@tonic-gate * eval_potential -- see if constraint is potentially true 9330Sstevel@tonic-gate * 9340Sstevel@tonic-gate * this function is used at instance tree creation time to see if 9350Sstevel@tonic-gate * any constraints are already known to be false. if this function 9360Sstevel@tonic-gate * returns false, then the constraint will always be false and there's 9370Sstevel@tonic-gate * no need to include the propagation arrow in the instance tree. 9380Sstevel@tonic-gate * 9390Sstevel@tonic-gate * if this routine returns true, either the constraint is known to 9400Sstevel@tonic-gate * be always true (so there's no point in attaching the constraint 9410Sstevel@tonic-gate * to the propagation arrow in the instance tree), or the constraint 9420Sstevel@tonic-gate * contains "deferred" expressions like global variables or poller calls 9430Sstevel@tonic-gate * and so it must be evaluated during calls to fme_eval(). in this last 9440Sstevel@tonic-gate * case, where a constraint needs to be attached to the propagation arrow 9450Sstevel@tonic-gate * in the instance tree, this routine returns a newly created constraint 9460Sstevel@tonic-gate * in *newc where all the non-deferred things have been filled in. 9470Sstevel@tonic-gate * 9480Sstevel@tonic-gate * so in summary: 9490Sstevel@tonic-gate * 9500Sstevel@tonic-gate * return of false: constraint can never be true, *newc will be NULL. 9510Sstevel@tonic-gate * 9520Sstevel@tonic-gate * return of true with *newc unchanged: constraint will always be true. 9530Sstevel@tonic-gate * 9540Sstevel@tonic-gate * return of true with *newc changed: use new constraint in *newc. 9550Sstevel@tonic-gate * 9560Sstevel@tonic-gate * the lookup table for all explicit iterators, ex, is passed in. 9570Sstevel@tonic-gate * 9580Sstevel@tonic-gate * *newc can either be NULL on entry, or if can contain constraints from 9590Sstevel@tonic-gate * previous calls to eval_potential() (i.e. for building up an instance 9600Sstevel@tonic-gate * tree constraint from several potential constraints). if *newc already 9610Sstevel@tonic-gate * contains constraints, anything added to it will be joined by adding 9620Sstevel@tonic-gate * a T_AND node at the top of *newc. 9630Sstevel@tonic-gate */ 9640Sstevel@tonic-gate int 965*4436Sstephh eval_potential(struct node *np, struct lut *ex, struct node *events[], 9662318Sstephh struct node **newc, struct config *croot) 9670Sstevel@tonic-gate { 9680Sstevel@tonic-gate struct node *newnp; 9690Sstevel@tonic-gate struct evalue value; 9700Sstevel@tonic-gate 971*4436Sstephh if (eval_expr(np, ex, events, NULL, croot, NULL, 1, &value) == 0) { 9720Sstevel@tonic-gate /* 9730Sstevel@tonic-gate * couldn't eval expression because 9740Sstevel@tonic-gate * it contains deferred items. make 9750Sstevel@tonic-gate * a duplicate expression with all the 9760Sstevel@tonic-gate * non-deferred items expanded. 9770Sstevel@tonic-gate */ 978*4436Sstephh newnp = eval_dup(np, ex, events); 9790Sstevel@tonic-gate 9800Sstevel@tonic-gate if (*newc == NULL) { 9810Sstevel@tonic-gate /* 9820Sstevel@tonic-gate * constraint is potentially true if deferred 9830Sstevel@tonic-gate * expression in newnp is true. *newc was NULL 9840Sstevel@tonic-gate * so new constraint is just the one in newnp. 9850Sstevel@tonic-gate */ 9860Sstevel@tonic-gate *newc = newnp; 9870Sstevel@tonic-gate return (1); 9880Sstevel@tonic-gate } else { 9890Sstevel@tonic-gate /* 9900Sstevel@tonic-gate * constraint is potentially true if deferred 9910Sstevel@tonic-gate * expression in newnp is true. *newc already 9920Sstevel@tonic-gate * contained a constraint so add an AND with the 9930Sstevel@tonic-gate * constraint in newnp. 9940Sstevel@tonic-gate */ 9950Sstevel@tonic-gate *newc = tree_expr(T_AND, *newc, newnp); 9960Sstevel@tonic-gate return (1); 9970Sstevel@tonic-gate } 9980Sstevel@tonic-gate } else if (value.t == UNDEFINED) { 9990Sstevel@tonic-gate /* constraint can never be true */ 10000Sstevel@tonic-gate return (0); 10010Sstevel@tonic-gate } else if (value.t == UINT64 && value.v == 0) { 10020Sstevel@tonic-gate /* constraint can never be true */ 10030Sstevel@tonic-gate return (0); 10040Sstevel@tonic-gate } else { 10050Sstevel@tonic-gate /* constraint is always true (nothing deferred to eval) */ 10060Sstevel@tonic-gate return (1); 10070Sstevel@tonic-gate } 10080Sstevel@tonic-gate } 10090Sstevel@tonic-gate 10100Sstevel@tonic-gate static int 10110Sstevel@tonic-gate check_expr_args(struct evalue *lp, struct evalue *rp, enum datatype dtype, 10120Sstevel@tonic-gate struct node *np) 10130Sstevel@tonic-gate { 10141414Scindi /* auto-convert T_NAMES to strings */ 10151717Swesolows if (lp->t == NODEPTR && ((struct node *)(uintptr_t)(lp->v))->t == 10161717Swesolows T_NAME) { 10171717Swesolows char *s = ipath2str(NULL, 10181717Swesolows ipath((struct node *)(uintptr_t)lp->v)); 10191414Scindi lp->t = STRING; 10201717Swesolows lp->v = (uintptr_t)stable(s); 10211414Scindi FREE(s); 10221414Scindi out(O_ALTFP|O_VERB2, "convert lhs path to \"%s\"", 10231717Swesolows (char *)(uintptr_t)lp->v); 10241414Scindi } 10251414Scindi if (rp != NULL && 10261717Swesolows rp->t == NODEPTR && ((struct node *)(uintptr_t)(rp->v))->t == 10271717Swesolows T_NAME) { 10281717Swesolows char *s = ipath2str(NULL, 10291717Swesolows ipath((struct node *)(uintptr_t)rp->v)); 10301414Scindi rp->t = STRING; 10311717Swesolows rp->v = (uintptr_t)stable(s); 10321414Scindi FREE(s); 10331414Scindi out(O_ALTFP|O_VERB2, "convert rhs path to \"%s\"", 10341717Swesolows (char *)(uintptr_t)rp->v); 10351414Scindi } 10361414Scindi 10371414Scindi /* auto-convert strings to numbers */ 10381414Scindi if (dtype == UINT64) { 10391414Scindi if (lp->t == STRING) { 10401414Scindi lp->t = UINT64; 10411717Swesolows lp->v = strtoull((char *)(uintptr_t)lp->v, NULL, 0); 10421414Scindi } 10431414Scindi if (rp != NULL && rp->t == STRING) { 10441414Scindi rp->t = UINT64; 10451717Swesolows rp->v = strtoull((char *)(uintptr_t)rp->v, NULL, 0); 10461414Scindi } 10471414Scindi } 10481414Scindi 10490Sstevel@tonic-gate if (dtype != UNDEFINED && lp->t != dtype) { 1050*4436Sstephh outfl(O_DIE, np->file, np->line, 1051*4436Sstephh "invalid datatype of argument for operation %s", 1052*4436Sstephh ptree_nodetype2str(np->t)); 1053*4436Sstephh /* NOTREACHED */ 10540Sstevel@tonic-gate return (1); 10550Sstevel@tonic-gate } 10560Sstevel@tonic-gate 10570Sstevel@tonic-gate if (rp != NULL && lp->t != rp->t) { 1058*4436Sstephh outfl(O_DIE, np->file, np->line, 1059*4436Sstephh "mismatch in datatype of arguments for operation %s", 1060*4436Sstephh ptree_nodetype2str(np->t)); 1061*4436Sstephh /* NOTREACHED */ 10620Sstevel@tonic-gate return (1); 10630Sstevel@tonic-gate } 10640Sstevel@tonic-gate 10650Sstevel@tonic-gate return (0); 10660Sstevel@tonic-gate } 10670Sstevel@tonic-gate 10680Sstevel@tonic-gate /* 10690Sstevel@tonic-gate * eval_expr -- evaluate expression into *valuep 10700Sstevel@tonic-gate * 10710Sstevel@tonic-gate * the meaning of the return value depends on the input value of try. 10720Sstevel@tonic-gate * 10730Sstevel@tonic-gate * for try == 1: if any deferred items are encounted, bail out and return 10740Sstevel@tonic-gate * false. returns true if we made it through entire expression without 10750Sstevel@tonic-gate * hitting any deferred items. 10760Sstevel@tonic-gate * 10770Sstevel@tonic-gate * for try == 0: return true if all operations were performed successfully. 10780Sstevel@tonic-gate * return false if otherwise. for example, any of the following conditions 10790Sstevel@tonic-gate * will result in a false return value: 10800Sstevel@tonic-gate * - attempted use of an uninitialized global variable 10810Sstevel@tonic-gate * - failure in function evaluation 10820Sstevel@tonic-gate * - illegal arithmetic operation (argument out of range) 10830Sstevel@tonic-gate */ 10840Sstevel@tonic-gate int 1085*4436Sstephh eval_expr(struct node *np, struct lut *ex, struct node *events[], 10860Sstevel@tonic-gate struct lut **globals, struct config *croot, struct arrow *arrowp, 10870Sstevel@tonic-gate int try, struct evalue *valuep) 10880Sstevel@tonic-gate { 10890Sstevel@tonic-gate struct evalue *gval; 10900Sstevel@tonic-gate struct evalue lval; 10910Sstevel@tonic-gate struct evalue rval; 10920Sstevel@tonic-gate 10930Sstevel@tonic-gate if (np == NULL) { 10940Sstevel@tonic-gate valuep->t = UINT64; 10950Sstevel@tonic-gate valuep->v = 1; /* no constraint means "true" */ 10960Sstevel@tonic-gate return (1); 10970Sstevel@tonic-gate } 10980Sstevel@tonic-gate 10990Sstevel@tonic-gate valuep->t = UNDEFINED; 11000Sstevel@tonic-gate 11010Sstevel@tonic-gate switch (np->t) { 11020Sstevel@tonic-gate case T_GLOBID: 11030Sstevel@tonic-gate if (try) 11040Sstevel@tonic-gate return (0); 11050Sstevel@tonic-gate 11060Sstevel@tonic-gate /* 11070Sstevel@tonic-gate * only handle case of getting (and not setting) the value 11080Sstevel@tonic-gate * of a global variable 11090Sstevel@tonic-gate */ 11100Sstevel@tonic-gate gval = lut_lookup(*globals, (void *)np->u.globid.s, NULL); 11110Sstevel@tonic-gate if (gval == NULL) { 11120Sstevel@tonic-gate return (0); 11130Sstevel@tonic-gate } else { 11140Sstevel@tonic-gate valuep->t = gval->t; 11150Sstevel@tonic-gate valuep->v = gval->v; 11160Sstevel@tonic-gate return (1); 11170Sstevel@tonic-gate } 11180Sstevel@tonic-gate 11190Sstevel@tonic-gate case T_ASSIGN: 11200Sstevel@tonic-gate if (try) 11210Sstevel@tonic-gate return (0); 11220Sstevel@tonic-gate 11230Sstevel@tonic-gate /* 11240Sstevel@tonic-gate * first evaluate rhs, then try to store value in lhs which 11250Sstevel@tonic-gate * should be a global variable 11260Sstevel@tonic-gate */ 1127*4436Sstephh if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1128*4436Sstephh arrowp, try, &rval)) 11290Sstevel@tonic-gate return (0); 11300Sstevel@tonic-gate 11310Sstevel@tonic-gate ASSERT(np->u.expr.left->t == T_GLOBID); 11320Sstevel@tonic-gate gval = lut_lookup(*globals, 1133*4436Sstephh (void *)np->u.expr.left->u.globid.s, NULL); 11340Sstevel@tonic-gate 11350Sstevel@tonic-gate if (gval == NULL) { 11360Sstevel@tonic-gate gval = MALLOC(sizeof (*gval)); 11370Sstevel@tonic-gate *globals = lut_add(*globals, 1138*4436Sstephh (void *) np->u.expr.left->u.globid.s, gval, NULL); 11390Sstevel@tonic-gate } 11400Sstevel@tonic-gate 11410Sstevel@tonic-gate gval->t = rval.t; 11420Sstevel@tonic-gate gval->v = rval.v; 11431414Scindi 11441414Scindi if (gval->t == UINT64) { 11451414Scindi out(O_ALTFP|O_VERB2, 11461414Scindi "assign $%s=%llu", 11471414Scindi np->u.expr.left->u.globid.s, gval->v); 11481414Scindi } else { 11491414Scindi out(O_ALTFP|O_VERB2, 11501414Scindi "assign $%s=\"%s\"", 11511717Swesolows np->u.expr.left->u.globid.s, 11521717Swesolows (char *)(uintptr_t)gval->v); 11531414Scindi } 11541414Scindi 11551414Scindi /* 11561414Scindi * but always return true -- an assignment should not 11571414Scindi * cause a constraint to be false. 11581414Scindi */ 11591414Scindi valuep->t = UINT64; 11601414Scindi valuep->v = 1; 11610Sstevel@tonic-gate return (1); 11620Sstevel@tonic-gate 11630Sstevel@tonic-gate case T_EQ: 11640Sstevel@tonic-gate #define IMPLICIT_ASSIGN_IN_EQ 11650Sstevel@tonic-gate #ifdef IMPLICIT_ASSIGN_IN_EQ 11660Sstevel@tonic-gate /* 11670Sstevel@tonic-gate * if lhs is an uninitialized global variable, perform 11680Sstevel@tonic-gate * an assignment. 11690Sstevel@tonic-gate * 11700Sstevel@tonic-gate * one insidious side effect of implicit assignment is 11710Sstevel@tonic-gate * that the "==" operator does not return a Boolean if 11720Sstevel@tonic-gate * implicit assignment was performed. 11730Sstevel@tonic-gate */ 11740Sstevel@tonic-gate if (try == 0 && 11750Sstevel@tonic-gate np->u.expr.left->t == T_GLOBID && 11760Sstevel@tonic-gate (gval = lut_lookup(*globals, 1177*4436Sstephh (void *)np->u.expr.left->u.globid.s, NULL)) == NULL) { 1178*4436Sstephh if (!eval_expr(np->u.expr.right, ex, events, globals, 1179*4436Sstephh croot, arrowp, try, &rval)) 11800Sstevel@tonic-gate return (0); 11810Sstevel@tonic-gate 11820Sstevel@tonic-gate gval = MALLOC(sizeof (*gval)); 11830Sstevel@tonic-gate *globals = lut_add(*globals, 1184*4436Sstephh (void *) np->u.expr.left->u.globid.s, 1185*4436Sstephh gval, NULL); 11860Sstevel@tonic-gate 11870Sstevel@tonic-gate gval->t = rval.t; 11880Sstevel@tonic-gate gval->v = rval.v; 11890Sstevel@tonic-gate valuep->t = rval.t; 11900Sstevel@tonic-gate valuep->v = rval.v; 11910Sstevel@tonic-gate return (1); 11920Sstevel@tonic-gate } 11930Sstevel@tonic-gate #endif /* IMPLICIT_ASSIGN_IN_EQ */ 11940Sstevel@tonic-gate 1195*4436Sstephh if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1196*4436Sstephh arrowp, try, &lval)) 1197*4436Sstephh return (0); 1198*4436Sstephh if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1199*4436Sstephh arrowp, try, &rval)) 12000Sstevel@tonic-gate return (0); 1201*4436Sstephh if (rval.t == UINT64 || lval.t == UINT64) { 1202*4436Sstephh if (check_expr_args(&lval, &rval, UINT64, np)) 1203*4436Sstephh return (0); 1204*4436Sstephh } else { 1205*4436Sstephh if (check_expr_args(&lval, &rval, UNDEFINED, np)) 1206*4436Sstephh return (0); 1207*4436Sstephh } 12080Sstevel@tonic-gate 12090Sstevel@tonic-gate valuep->t = UINT64; 12100Sstevel@tonic-gate valuep->v = (lval.v == rval.v); 12110Sstevel@tonic-gate return (1); 12120Sstevel@tonic-gate 12130Sstevel@tonic-gate case T_LT: 1214*4436Sstephh if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1215*4436Sstephh arrowp, try, &lval)) 12160Sstevel@tonic-gate return (0); 1217*4436Sstephh if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1218*4436Sstephh arrowp, try, &rval)) 12190Sstevel@tonic-gate return (0); 12201414Scindi if (check_expr_args(&lval, &rval, UINT64, np)) 12210Sstevel@tonic-gate return (0); 12220Sstevel@tonic-gate 12230Sstevel@tonic-gate valuep->t = UINT64; 12240Sstevel@tonic-gate valuep->v = (lval.v < rval.v); 12250Sstevel@tonic-gate return (1); 12260Sstevel@tonic-gate 12270Sstevel@tonic-gate case T_LE: 1228*4436Sstephh if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1229*4436Sstephh arrowp, try, &lval)) 12300Sstevel@tonic-gate return (0); 1231*4436Sstephh if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1232*4436Sstephh arrowp, try, &rval)) 12330Sstevel@tonic-gate return (0); 12341414Scindi if (check_expr_args(&lval, &rval, UINT64, np)) 12350Sstevel@tonic-gate return (0); 12360Sstevel@tonic-gate 12370Sstevel@tonic-gate valuep->t = UINT64; 12380Sstevel@tonic-gate valuep->v = (lval.v <= rval.v); 12390Sstevel@tonic-gate return (1); 12400Sstevel@tonic-gate 12410Sstevel@tonic-gate case T_GT: 1242*4436Sstephh if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1243*4436Sstephh arrowp, try, &lval)) 12440Sstevel@tonic-gate return (0); 1245*4436Sstephh if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1246*4436Sstephh arrowp, try, &rval)) 12470Sstevel@tonic-gate return (0); 12481414Scindi if (check_expr_args(&lval, &rval, UINT64, np)) 12490Sstevel@tonic-gate return (0); 12500Sstevel@tonic-gate 12510Sstevel@tonic-gate valuep->t = UINT64; 12520Sstevel@tonic-gate valuep->v = (lval.v > rval.v); 12530Sstevel@tonic-gate return (1); 12540Sstevel@tonic-gate 12550Sstevel@tonic-gate case T_GE: 1256*4436Sstephh if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1257*4436Sstephh arrowp, try, &lval)) 12580Sstevel@tonic-gate return (0); 1259*4436Sstephh if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1260*4436Sstephh arrowp, try, &rval)) 12610Sstevel@tonic-gate return (0); 12621414Scindi if (check_expr_args(&lval, &rval, UINT64, np)) 12630Sstevel@tonic-gate return (0); 12640Sstevel@tonic-gate 12650Sstevel@tonic-gate valuep->t = UINT64; 12660Sstevel@tonic-gate valuep->v = (lval.v >= rval.v); 12670Sstevel@tonic-gate return (1); 12680Sstevel@tonic-gate 12690Sstevel@tonic-gate case T_BITAND: 1270*4436Sstephh if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1271*4436Sstephh arrowp, try, &lval)) 12720Sstevel@tonic-gate return (0); 1273*4436Sstephh if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1274*4436Sstephh arrowp, try, &rval)) 12750Sstevel@tonic-gate return (0); 12760Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UINT64, np)) 12770Sstevel@tonic-gate return (0); 12780Sstevel@tonic-gate 12790Sstevel@tonic-gate valuep->t = lval.t; 12800Sstevel@tonic-gate valuep->v = (lval.v & rval.v); 12810Sstevel@tonic-gate return (1); 12820Sstevel@tonic-gate 12830Sstevel@tonic-gate case T_BITOR: 1284*4436Sstephh if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1285*4436Sstephh arrowp, try, &lval)) 12860Sstevel@tonic-gate return (0); 1287*4436Sstephh if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1288*4436Sstephh arrowp, try, &rval)) 12890Sstevel@tonic-gate return (0); 12900Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UINT64, np)) 12910Sstevel@tonic-gate return (0); 12920Sstevel@tonic-gate 12930Sstevel@tonic-gate valuep->t = lval.t; 12940Sstevel@tonic-gate valuep->v = (lval.v | rval.v); 12950Sstevel@tonic-gate return (1); 12960Sstevel@tonic-gate 12970Sstevel@tonic-gate case T_BITXOR: 1298*4436Sstephh if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1299*4436Sstephh arrowp, try, &lval)) 13000Sstevel@tonic-gate return (0); 1301*4436Sstephh if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1302*4436Sstephh arrowp, try, &rval)) 13030Sstevel@tonic-gate return (0); 13040Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UINT64, np)) 13050Sstevel@tonic-gate return (0); 13060Sstevel@tonic-gate 13070Sstevel@tonic-gate valuep->t = lval.t; 13080Sstevel@tonic-gate valuep->v = (lval.v ^ rval.v); 13090Sstevel@tonic-gate return (1); 13100Sstevel@tonic-gate 13110Sstevel@tonic-gate case T_BITNOT: 1312*4436Sstephh if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1313*4436Sstephh arrowp, try, &lval)) 13140Sstevel@tonic-gate return (0); 13150Sstevel@tonic-gate ASSERT(np->u.expr.right == NULL); 13160Sstevel@tonic-gate if (check_expr_args(&lval, NULL, UINT64, np)) 13170Sstevel@tonic-gate return (0); 13180Sstevel@tonic-gate 13190Sstevel@tonic-gate valuep->t = UINT64; 13200Sstevel@tonic-gate valuep->v = ~ lval.v; 13210Sstevel@tonic-gate return (1); 13220Sstevel@tonic-gate 13230Sstevel@tonic-gate case T_LSHIFT: 1324*4436Sstephh if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1325*4436Sstephh arrowp, try, &lval)) 13260Sstevel@tonic-gate return (0); 1327*4436Sstephh if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1328*4436Sstephh arrowp, try, &rval)) 13290Sstevel@tonic-gate return (0); 13300Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UINT64, np)) 13310Sstevel@tonic-gate return (0); 13320Sstevel@tonic-gate 13330Sstevel@tonic-gate valuep->t = UINT64; 13340Sstevel@tonic-gate valuep->v = (lval.v << rval.v); 13350Sstevel@tonic-gate return (1); 13360Sstevel@tonic-gate 13370Sstevel@tonic-gate case T_RSHIFT: 1338*4436Sstephh if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1339*4436Sstephh arrowp, try, &lval)) 13400Sstevel@tonic-gate return (0); 1341*4436Sstephh if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1342*4436Sstephh arrowp, try, &rval)) 13430Sstevel@tonic-gate return (0); 13440Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UINT64, np)) 13450Sstevel@tonic-gate return (0); 13460Sstevel@tonic-gate 13470Sstevel@tonic-gate valuep->t = UINT64; 13480Sstevel@tonic-gate valuep->v = (lval.v >> rval.v); 13490Sstevel@tonic-gate return (1); 13500Sstevel@tonic-gate 13510Sstevel@tonic-gate case T_CONDIF: { 13520Sstevel@tonic-gate struct node *retnp; 13530Sstevel@tonic-gate int dotrue = 0; 13540Sstevel@tonic-gate 13550Sstevel@tonic-gate /* 13560Sstevel@tonic-gate * evaluate 13570Sstevel@tonic-gate * expression ? stmtA [ : stmtB ] 13580Sstevel@tonic-gate * 13590Sstevel@tonic-gate * first see if expression is true or false, then determine 13600Sstevel@tonic-gate * if stmtA (or stmtB, if it exists) should be evaluated. 13610Sstevel@tonic-gate * 13620Sstevel@tonic-gate * "dotrue = 1" means stmtA should be evaluated. 13630Sstevel@tonic-gate */ 1364*4436Sstephh if (eval_expr(np->u.expr.left, ex, events, globals, croot, 1365*4436Sstephh arrowp, try, &lval) && 13660Sstevel@tonic-gate lval.t != UNDEFINED && lval.v != 0) 13670Sstevel@tonic-gate dotrue = 1; 13680Sstevel@tonic-gate 13690Sstevel@tonic-gate ASSERT(np->u.expr.right != NULL); 13700Sstevel@tonic-gate if (np->u.expr.right->t == T_CONDELSE) { 13710Sstevel@tonic-gate if (dotrue) 13720Sstevel@tonic-gate retnp = np->u.expr.right->u.expr.left; 13730Sstevel@tonic-gate else 13740Sstevel@tonic-gate retnp = np->u.expr.right->u.expr.right; 13750Sstevel@tonic-gate } else { 13760Sstevel@tonic-gate /* no ELSE clause */ 13770Sstevel@tonic-gate if (dotrue) 13780Sstevel@tonic-gate retnp = np->u.expr.right; 13790Sstevel@tonic-gate else { 1380*4436Sstephh outfl(O_DIE, np->file, np->line, 1381*4436Sstephh "eval_expr: missing condelse"); 13820Sstevel@tonic-gate } 13830Sstevel@tonic-gate } 13840Sstevel@tonic-gate 1385*4436Sstephh if (!eval_expr(retnp, ex, events, globals, croot, 1386*4436Sstephh arrowp, try, valuep)) 13870Sstevel@tonic-gate return (0); 13880Sstevel@tonic-gate return (1); 13890Sstevel@tonic-gate } 13900Sstevel@tonic-gate 13910Sstevel@tonic-gate case T_CONDELSE: 13920Sstevel@tonic-gate /* 13930Sstevel@tonic-gate * shouldn't get here, since T_CONDELSE is supposed to be 13940Sstevel@tonic-gate * evaluated as part of T_CONDIF 13950Sstevel@tonic-gate */ 13960Sstevel@tonic-gate out(O_ALTFP|O_DIE, "eval_expr: wrong context for operation %s", 13970Sstevel@tonic-gate ptree_nodetype2str(np->t)); 1398*4436Sstephh /*NOTREACHED*/ 13990Sstevel@tonic-gate 14000Sstevel@tonic-gate case T_NE: 1401*4436Sstephh if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1402*4436Sstephh arrowp, try, &lval)) 1403*4436Sstephh return (0); 1404*4436Sstephh if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1405*4436Sstephh arrowp, try, &rval)) 14060Sstevel@tonic-gate return (0); 1407*4436Sstephh if (rval.t == UINT64 || lval.t == UINT64) { 1408*4436Sstephh if (check_expr_args(&lval, &rval, UINT64, np)) 1409*4436Sstephh return (0); 1410*4436Sstephh } else { 1411*4436Sstephh if (check_expr_args(&lval, &rval, UNDEFINED, np)) 1412*4436Sstephh return (0); 1413*4436Sstephh } 14140Sstevel@tonic-gate 14150Sstevel@tonic-gate valuep->t = UINT64; 14160Sstevel@tonic-gate valuep->v = (lval.v != rval.v); 14170Sstevel@tonic-gate return (1); 14180Sstevel@tonic-gate 14190Sstevel@tonic-gate case T_LIST: 14200Sstevel@tonic-gate case T_AND: 1421*4436Sstephh if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1422*4436Sstephh arrowp, try, valuep)) { 14233159Sstephh /* 14243159Sstephh * if lhs is unknown, still check rhs. If that 14253159Sstephh * is false we can return false irrespectice of lhs 14263159Sstephh */ 1427*4436Sstephh if (!eval_expr(np->u.expr.right, ex, events, globals, 1428*4436Sstephh croot, arrowp, try, valuep)) { 1429*4436Sstephh np->u.expr.temp = EXPR_TEMP_BOTH_UNK; 14303159Sstephh return (0); 1431*4436Sstephh } 1432*4436Sstephh if (valuep->v != 0) { 1433*4436Sstephh np->u.expr.temp = EXPR_TEMP_LHS_UNK; 14343159Sstephh return (0); 1435*4436Sstephh } 14363159Sstephh } 14370Sstevel@tonic-gate if (valuep->v == 0) { 14380Sstevel@tonic-gate valuep->t = UINT64; 14390Sstevel@tonic-gate return (1); 14400Sstevel@tonic-gate } 1441*4436Sstephh if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1442*4436Sstephh arrowp, try, valuep)) { 1443*4436Sstephh np->u.expr.temp = EXPR_TEMP_RHS_UNK; 14440Sstevel@tonic-gate return (0); 1445*4436Sstephh } 14460Sstevel@tonic-gate valuep->t = UINT64; 14470Sstevel@tonic-gate valuep->v = valuep->v == 0 ? 0 : 1; 14480Sstevel@tonic-gate return (1); 14490Sstevel@tonic-gate 14500Sstevel@tonic-gate case T_OR: 1451*4436Sstephh if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1452*4436Sstephh arrowp, try, valuep)) { 14533159Sstephh /* 14543159Sstephh * if lhs is unknown, still check rhs. If that 14553159Sstephh * is true we can return true irrespectice of lhs 14563159Sstephh */ 1457*4436Sstephh if (!eval_expr(np->u.expr.right, ex, events, globals, 1458*4436Sstephh croot, arrowp, try, valuep)) { 1459*4436Sstephh np->u.expr.temp = EXPR_TEMP_BOTH_UNK; 14603159Sstephh return (0); 1461*4436Sstephh } 1462*4436Sstephh if (valuep->v == 0) { 1463*4436Sstephh np->u.expr.temp = EXPR_TEMP_LHS_UNK; 14643159Sstephh return (0); 1465*4436Sstephh } 14663159Sstephh } 14670Sstevel@tonic-gate if (valuep->v != 0) { 14680Sstevel@tonic-gate valuep->t = UINT64; 14690Sstevel@tonic-gate valuep->v = 1; 14700Sstevel@tonic-gate return (1); 14710Sstevel@tonic-gate } 1472*4436Sstephh if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1473*4436Sstephh arrowp, try, valuep)) { 1474*4436Sstephh np->u.expr.temp = EXPR_TEMP_RHS_UNK; 14750Sstevel@tonic-gate return (0); 1476*4436Sstephh } 14770Sstevel@tonic-gate valuep->t = UINT64; 14780Sstevel@tonic-gate valuep->v = valuep->v == 0 ? 0 : 1; 14790Sstevel@tonic-gate return (1); 14800Sstevel@tonic-gate 14810Sstevel@tonic-gate case T_NOT: 1482*4436Sstephh if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1483*4436Sstephh arrowp, try, valuep)) 14840Sstevel@tonic-gate return (0); 14850Sstevel@tonic-gate valuep->t = UINT64; 14860Sstevel@tonic-gate valuep->v = ! valuep->v; 14870Sstevel@tonic-gate return (1); 14880Sstevel@tonic-gate 14890Sstevel@tonic-gate case T_ADD: 1490*4436Sstephh if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1491*4436Sstephh arrowp, try, &lval)) 14920Sstevel@tonic-gate return (0); 1493*4436Sstephh if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1494*4436Sstephh arrowp, try, &rval)) 14950Sstevel@tonic-gate return (0); 14960Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UINT64, np)) 14970Sstevel@tonic-gate return (0); 14980Sstevel@tonic-gate 14990Sstevel@tonic-gate valuep->t = lval.t; 15000Sstevel@tonic-gate valuep->v = lval.v + rval.v; 15010Sstevel@tonic-gate return (1); 15020Sstevel@tonic-gate 15030Sstevel@tonic-gate case T_SUB: 1504*4436Sstephh if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1505*4436Sstephh arrowp, try, &lval)) 15060Sstevel@tonic-gate return (0); 1507*4436Sstephh if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1508*4436Sstephh arrowp, try, &rval)) 15090Sstevel@tonic-gate return (0); 15100Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UINT64, np)) 15110Sstevel@tonic-gate return (0); 15120Sstevel@tonic-gate 15130Sstevel@tonic-gate /* since valuep is unsigned, return false if lval.v < rval.v */ 15140Sstevel@tonic-gate if (lval.v < rval.v) { 1515*4436Sstephh outfl(O_DIE, np->file, np->line, 1516*4436Sstephh "eval_expr: T_SUB result is out of range"); 15170Sstevel@tonic-gate } 15180Sstevel@tonic-gate 15190Sstevel@tonic-gate valuep->t = lval.t; 15200Sstevel@tonic-gate valuep->v = lval.v - rval.v; 15210Sstevel@tonic-gate return (1); 15220Sstevel@tonic-gate 15230Sstevel@tonic-gate case T_MUL: 1524*4436Sstephh if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1525*4436Sstephh arrowp, try, &lval)) 15260Sstevel@tonic-gate return (0); 1527*4436Sstephh if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1528*4436Sstephh arrowp, try, &rval)) 15290Sstevel@tonic-gate return (0); 15300Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UINT64, np)) 15310Sstevel@tonic-gate return (0); 15320Sstevel@tonic-gate 15330Sstevel@tonic-gate valuep->t = lval.t; 15340Sstevel@tonic-gate valuep->v = lval.v * rval.v; 15350Sstevel@tonic-gate return (1); 15360Sstevel@tonic-gate 15370Sstevel@tonic-gate case T_DIV: 1538*4436Sstephh if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1539*4436Sstephh arrowp, try, &lval)) 15400Sstevel@tonic-gate return (0); 1541*4436Sstephh if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1542*4436Sstephh arrowp, try, &rval)) 15430Sstevel@tonic-gate return (0); 15440Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UINT64, np)) 15450Sstevel@tonic-gate return (0); 15460Sstevel@tonic-gate 15470Sstevel@tonic-gate /* return false if dividing by zero */ 15480Sstevel@tonic-gate if (rval.v == 0) { 1549*4436Sstephh outfl(O_DIE, np->file, np->line, 1550*4436Sstephh "eval_expr: T_DIV division by zero"); 15510Sstevel@tonic-gate } 15520Sstevel@tonic-gate 15530Sstevel@tonic-gate valuep->t = lval.t; 15540Sstevel@tonic-gate valuep->v = lval.v / rval.v; 15550Sstevel@tonic-gate return (1); 15560Sstevel@tonic-gate 15570Sstevel@tonic-gate case T_MOD: 1558*4436Sstephh if (!eval_expr(np->u.expr.left, ex, events, globals, croot, 1559*4436Sstephh arrowp, try, &lval)) 15600Sstevel@tonic-gate return (0); 1561*4436Sstephh if (!eval_expr(np->u.expr.right, ex, events, globals, croot, 1562*4436Sstephh arrowp, try, &rval)) 15630Sstevel@tonic-gate return (0); 15640Sstevel@tonic-gate if (check_expr_args(&lval, &rval, UINT64, np)) 15650Sstevel@tonic-gate return (0); 15660Sstevel@tonic-gate 15670Sstevel@tonic-gate /* return false if dividing by zero */ 15680Sstevel@tonic-gate if (rval.v == 0) { 1569*4436Sstephh outfl(O_DIE, np->file, np->line, 1570*4436Sstephh "eval_expr: T_MOD division by zero"); 15710Sstevel@tonic-gate } 15720Sstevel@tonic-gate 15730Sstevel@tonic-gate valuep->t = lval.t; 15740Sstevel@tonic-gate valuep->v = lval.v % rval.v; 15750Sstevel@tonic-gate return (1); 15760Sstevel@tonic-gate 15770Sstevel@tonic-gate case T_NAME: 15780Sstevel@tonic-gate if (try) { 15790Sstevel@tonic-gate struct iterinfo *iterinfop; 1580*4436Sstephh struct node *np1, *np2; 1581*4436Sstephh int i, gotmatch = 0; 15820Sstevel@tonic-gate 15830Sstevel@tonic-gate /* 1584*4436Sstephh * Check if we have an exact match of the nonwildcarded 1585*4436Sstephh * path in oldepname - if so we can just use the 1586*4436Sstephh * full wildcarded path in epname. 15870Sstevel@tonic-gate */ 1588*4436Sstephh for (i = 0; i < 1; i++) { 1589*4436Sstephh for (np1 = np, 1590*4436Sstephh np2 = events[i]->u.event.oldepname; 1591*4436Sstephh np1 != NULL && np2 != NULL; 1592*4436Sstephh np1 = np1->u.name.next, 1593*4436Sstephh np2 = np2->u.name.next) { 1594*4436Sstephh if (strcmp(np1->u.name.s, 1595*4436Sstephh np2->u.name.s) != 0) 1596*4436Sstephh break; 1597*4436Sstephh if (np1->u.name.child->t != 1598*4436Sstephh np2->u.name.child->t) 1599*4436Sstephh break; 1600*4436Sstephh if (np1->u.name.child->t == T_NUM && 1601*4436Sstephh np1->u.name.child->u.ull != 1602*4436Sstephh np2->u.name.child->u.ull) 1603*4436Sstephh break; 1604*4436Sstephh if (np1->u.name.child->t == T_NAME && 1605*4436Sstephh strcmp(np1->u.name.child->u.name.s, 1606*4436Sstephh np2->u.name.child->u.name.s) != 0) 1607*4436Sstephh break; 1608*4436Sstephh gotmatch++; 1609*4436Sstephh } 1610*4436Sstephh if (np1 == NULL && np2 == NULL) { 1611*4436Sstephh valuep->t = NODEPTR; 1612*4436Sstephh valuep->v = (uintptr_t) 1613*4436Sstephh events[i]->u.event.epname; 1614*4436Sstephh return (1); 1615*4436Sstephh } 16160Sstevel@tonic-gate } 1617*4436Sstephh if (!gotmatch) { 1618*4436Sstephh /* 1619*4436Sstephh * we're not wildcarding. However at 1620*4436Sstephh * itree_create() time, we can also expand 1621*4436Sstephh * simple iterators - so check for those. 1622*4436Sstephh */ 1623*4436Sstephh iterinfop = lut_lookup(ex, (void *)np->u.name.s, 1624*4436Sstephh NULL); 1625*4436Sstephh if (iterinfop != NULL) { 1626*4436Sstephh valuep->t = UINT64; 1627*4436Sstephh valuep->v = 1628*4436Sstephh (unsigned long long)iterinfop->num; 1629*4436Sstephh return (1); 1630*4436Sstephh } 1631*4436Sstephh } 1632*4436Sstephh /* 1633*4436Sstephh * For anything else we'll have to wait for eval_dup(). 1634*4436Sstephh */ 16350Sstevel@tonic-gate return (0); 16360Sstevel@tonic-gate } 16370Sstevel@tonic-gate 16380Sstevel@tonic-gate /* return address of struct node */ 16390Sstevel@tonic-gate valuep->t = NODEPTR; 16401717Swesolows valuep->v = (uintptr_t)np; 16410Sstevel@tonic-gate return (1); 16420Sstevel@tonic-gate 16430Sstevel@tonic-gate case T_QUOTE: 16440Sstevel@tonic-gate valuep->t = STRING; 16451717Swesolows valuep->v = (uintptr_t)np->u.quote.s; 16460Sstevel@tonic-gate return (1); 16470Sstevel@tonic-gate 16480Sstevel@tonic-gate case T_FUNC: 1649*4436Sstephh return (eval_func(np, ex, events, np->u.func.arglist, 1650*4436Sstephh globals, croot, arrowp, try, valuep)); 16510Sstevel@tonic-gate 16520Sstevel@tonic-gate case T_NUM: 16530Sstevel@tonic-gate valuep->t = UINT64; 16540Sstevel@tonic-gate valuep->v = np->u.ull; 16550Sstevel@tonic-gate return (1); 16560Sstevel@tonic-gate 16570Sstevel@tonic-gate default: 16580Sstevel@tonic-gate outfl(O_DIE, np->file, np->line, 16590Sstevel@tonic-gate "eval_expr: unexpected node type: %s", 16600Sstevel@tonic-gate ptree_nodetype2str(np->t)); 16610Sstevel@tonic-gate } 16620Sstevel@tonic-gate /*NOTREACHED*/ 16631717Swesolows return (0); 16640Sstevel@tonic-gate } 16650Sstevel@tonic-gate 16660Sstevel@tonic-gate /* 16670Sstevel@tonic-gate * eval_fru() and eval_asru() don't do much, but are called from a number 16680Sstevel@tonic-gate * of places. 16690Sstevel@tonic-gate */ 1670*4436Sstephh static struct node * 16710Sstevel@tonic-gate eval_fru(struct node *np) 16720Sstevel@tonic-gate { 16730Sstevel@tonic-gate ASSERT(np->t == T_NAME); 16740Sstevel@tonic-gate return (np); 16750Sstevel@tonic-gate } 16760Sstevel@tonic-gate 1677*4436Sstephh static struct node * 16780Sstevel@tonic-gate eval_asru(struct node *np) 16790Sstevel@tonic-gate { 16800Sstevel@tonic-gate ASSERT(np->t == T_NAME); 16810Sstevel@tonic-gate return (np); 16820Sstevel@tonic-gate } 1683