1*0af8f00bSMatthew Ahrens /* 2*0af8f00bSMatthew Ahrens * CDDL HEADER START 3*0af8f00bSMatthew Ahrens * 4*0af8f00bSMatthew Ahrens * This file and its contents are supplied under the terms of the 5*0af8f00bSMatthew Ahrens * Common Development and Distribution License ("CDDL"), version 1.0. 6*0af8f00bSMatthew Ahrens * You may only use this file in accordance with the terms of version 7*0af8f00bSMatthew Ahrens * 1.0 of the CDDL. 8*0af8f00bSMatthew Ahrens * 9*0af8f00bSMatthew Ahrens * A full copy of the text of the CDDL should have accompanied this 10*0af8f00bSMatthew Ahrens * source. A copy of the CDDL is also available via the Internet at 11*0af8f00bSMatthew Ahrens * http://www.illumos.org/license/CDDL. 12*0af8f00bSMatthew Ahrens * 13*0af8f00bSMatthew Ahrens * CDDL HEADER END 14*0af8f00bSMatthew Ahrens */ 15*0af8f00bSMatthew Ahrens 16*0af8f00bSMatthew Ahrens /* 17*0af8f00bSMatthew Ahrens * Copyright (c) 2012, 2016 by Delphix. All rights reserved. 18*0af8f00bSMatthew Ahrens */ 19*0af8f00bSMatthew Ahrens 20*0af8f00bSMatthew Ahrens /* 21*0af8f00bSMatthew Ahrens * Syntactic sugar features are implemented by transforming the D parse tree 22*0af8f00bSMatthew Ahrens * such that it only uses the subset of D that is supported by the rest of the 23*0af8f00bSMatthew Ahrens * compiler / the kernel. A clause containing these language features is 24*0af8f00bSMatthew Ahrens * referred to as a "super-clause", and its transformation typically entails 25*0af8f00bSMatthew Ahrens * creating several "sub-clauses" to implement it. For diagnosability, the 26*0af8f00bSMatthew Ahrens * sub-clauses will be printed if the "-xtree=8" flag is specified. 27*0af8f00bSMatthew Ahrens * 28*0af8f00bSMatthew Ahrens * Currently, the only syntactic sugar feature is "if/else" statements. Each 29*0af8f00bSMatthew Ahrens * basic block (e.g. the body of the "if" and "else" statements, and the 30*0af8f00bSMatthew Ahrens * statements before and after) is turned into its own sub-clause, with a 31*0af8f00bSMatthew Ahrens * predicate that causes it to be executed only if the code flows to this point. 32*0af8f00bSMatthew Ahrens * Nested if/else statements are supported. 33*0af8f00bSMatthew Ahrens * 34*0af8f00bSMatthew Ahrens * This infrastructure is designed to accommodate other syntactic sugar features 35*0af8f00bSMatthew Ahrens * in the future. 36*0af8f00bSMatthew Ahrens */ 37*0af8f00bSMatthew Ahrens 38*0af8f00bSMatthew Ahrens #include <sys/types.h> 39*0af8f00bSMatthew Ahrens #include <sys/wait.h> 40*0af8f00bSMatthew Ahrens #include <sys/sysmacros.h> 41*0af8f00bSMatthew Ahrens 42*0af8f00bSMatthew Ahrens #include <assert.h> 43*0af8f00bSMatthew Ahrens #include <strings.h> 44*0af8f00bSMatthew Ahrens #include <stdlib.h> 45*0af8f00bSMatthew Ahrens #include <stdio.h> 46*0af8f00bSMatthew Ahrens #include <ctype.h> 47*0af8f00bSMatthew Ahrens #include <dt_module.h> 48*0af8f00bSMatthew Ahrens #include <dt_program.h> 49*0af8f00bSMatthew Ahrens #include <dt_provider.h> 50*0af8f00bSMatthew Ahrens #include <dt_printf.h> 51*0af8f00bSMatthew Ahrens #include <dt_pid.h> 52*0af8f00bSMatthew Ahrens #include <dt_grammar.h> 53*0af8f00bSMatthew Ahrens #include <dt_ident.h> 54*0af8f00bSMatthew Ahrens #include <dt_string.h> 55*0af8f00bSMatthew Ahrens #include <dt_impl.h> 56*0af8f00bSMatthew Ahrens 57*0af8f00bSMatthew Ahrens typedef struct dt_sugar_parse { 58*0af8f00bSMatthew Ahrens dtrace_hdl_t *dtsp_dtp; /* dtrace handle */ 59*0af8f00bSMatthew Ahrens dt_node_t *dtsp_pdescs; /* probe descriptions */ 60*0af8f00bSMatthew Ahrens int dtsp_num_conditions; /* number of condition variables */ 61*0af8f00bSMatthew Ahrens int dtsp_num_ifs; /* number of "if" statements */ 62*0af8f00bSMatthew Ahrens dt_node_t *dtsp_clause_list; /* list of clauses */ 63*0af8f00bSMatthew Ahrens } dt_sugar_parse_t; 64*0af8f00bSMatthew Ahrens 65*0af8f00bSMatthew Ahrens static void dt_sugar_visit_stmts(dt_sugar_parse_t *, dt_node_t *, int); 66*0af8f00bSMatthew Ahrens 67*0af8f00bSMatthew Ahrens /* 68*0af8f00bSMatthew Ahrens * Return a node for "self->%error". 69*0af8f00bSMatthew Ahrens * 70*0af8f00bSMatthew Ahrens * Note that the "%" is part of the variable name, and is included so that 71*0af8f00bSMatthew Ahrens * this variable name can not collide with any user-specified variable. 72*0af8f00bSMatthew Ahrens * 73*0af8f00bSMatthew Ahrens * This error variable is used to keep track of if there has been an error 74*0af8f00bSMatthew Ahrens * in any of the sub-clauses, and is used to prevent execution of subsequent 75*0af8f00bSMatthew Ahrens * sub-clauses following an error. 76*0af8f00bSMatthew Ahrens */ 77*0af8f00bSMatthew Ahrens static dt_node_t * 78*0af8f00bSMatthew Ahrens dt_sugar_new_error_var(void) 79*0af8f00bSMatthew Ahrens { 80*0af8f00bSMatthew Ahrens return (dt_node_op2(DT_TOK_PTR, dt_node_ident(strdup("self")), 81*0af8f00bSMatthew Ahrens dt_node_ident(strdup("%error")))); 82*0af8f00bSMatthew Ahrens } 83*0af8f00bSMatthew Ahrens 84*0af8f00bSMatthew Ahrens /* 85*0af8f00bSMatthew Ahrens * Append this clause to the clause list. 86*0af8f00bSMatthew Ahrens */ 87*0af8f00bSMatthew Ahrens static void 88*0af8f00bSMatthew Ahrens dt_sugar_append_clause(dt_sugar_parse_t *dp, dt_node_t *clause) 89*0af8f00bSMatthew Ahrens { 90*0af8f00bSMatthew Ahrens dp->dtsp_clause_list = dt_node_link(dp->dtsp_clause_list, clause); 91*0af8f00bSMatthew Ahrens } 92*0af8f00bSMatthew Ahrens 93*0af8f00bSMatthew Ahrens /* 94*0af8f00bSMatthew Ahrens * Prepend this clause to the clause list. 95*0af8f00bSMatthew Ahrens */ 96*0af8f00bSMatthew Ahrens static void 97*0af8f00bSMatthew Ahrens dt_sugar_prepend_clause(dt_sugar_parse_t *dp, dt_node_t *clause) 98*0af8f00bSMatthew Ahrens { 99*0af8f00bSMatthew Ahrens dp->dtsp_clause_list = dt_node_link(clause, dp->dtsp_clause_list); 100*0af8f00bSMatthew Ahrens } 101*0af8f00bSMatthew Ahrens 102*0af8f00bSMatthew Ahrens /* 103*0af8f00bSMatthew Ahrens * Return a node for "this->%condition_<condid>", or NULL if condid==0. 104*0af8f00bSMatthew Ahrens * 105*0af8f00bSMatthew Ahrens * Note that the "%" is part of the variable name, and is included so that 106*0af8f00bSMatthew Ahrens * this variable name can not collide with any user-specified variable. 107*0af8f00bSMatthew Ahrens */ 108*0af8f00bSMatthew Ahrens static dt_node_t * 109*0af8f00bSMatthew Ahrens dt_sugar_new_condition_var(int condid) 110*0af8f00bSMatthew Ahrens { 111*0af8f00bSMatthew Ahrens char *str; 112*0af8f00bSMatthew Ahrens 113*0af8f00bSMatthew Ahrens if (condid == 0) 114*0af8f00bSMatthew Ahrens return (NULL); 115*0af8f00bSMatthew Ahrens assert(condid > 0); 116*0af8f00bSMatthew Ahrens 117*0af8f00bSMatthew Ahrens (void) asprintf(&str, "%%condition_%d", ABS(condid)); 118*0af8f00bSMatthew Ahrens return (dt_node_op2(DT_TOK_PTR, dt_node_ident(strdup("this")), 119*0af8f00bSMatthew Ahrens dt_node_ident(str))); 120*0af8f00bSMatthew Ahrens } 121*0af8f00bSMatthew Ahrens 122*0af8f00bSMatthew Ahrens /* 123*0af8f00bSMatthew Ahrens * Return new clause to evaluate predicate and set newcond. condid is 124*0af8f00bSMatthew Ahrens * the condition that we are already under, or 0 if none. 125*0af8f00bSMatthew Ahrens * The new clause will be of the form: 126*0af8f00bSMatthew Ahrens * 127*0af8f00bSMatthew Ahrens * dp_pdescs 128*0af8f00bSMatthew Ahrens * /!self->%error/ 129*0af8f00bSMatthew Ahrens * { 130*0af8f00bSMatthew Ahrens * this->%condition_<newcond> = 131*0af8f00bSMatthew Ahrens * (this->%condition_<condid> && pred); 132*0af8f00bSMatthew Ahrens * } 133*0af8f00bSMatthew Ahrens * 134*0af8f00bSMatthew Ahrens * Note: if condid==0, we will instead do "... = (1 && pred)", to effectively 135*0af8f00bSMatthew Ahrens * convert the pred to a boolean. 136*0af8f00bSMatthew Ahrens * 137*0af8f00bSMatthew Ahrens * Note: Unless an error has been encountered, we always set the condition 138*0af8f00bSMatthew Ahrens * variable (either to 0 or 1). This lets us avoid resetting the condition 139*0af8f00bSMatthew Ahrens * variables back to 0 when the super-clause completes. 140*0af8f00bSMatthew Ahrens */ 141*0af8f00bSMatthew Ahrens static dt_node_t * 142*0af8f00bSMatthew Ahrens dt_sugar_new_condition_impl(dt_sugar_parse_t *dp, 143*0af8f00bSMatthew Ahrens dt_node_t *pred, int condid, int newcond) 144*0af8f00bSMatthew Ahrens { 145*0af8f00bSMatthew Ahrens dt_node_t *value, *body, *newpred; 146*0af8f00bSMatthew Ahrens 147*0af8f00bSMatthew Ahrens /* predicate is !self->%error */ 148*0af8f00bSMatthew Ahrens newpred = dt_node_op1(DT_TOK_LNEG, dt_sugar_new_error_var()); 149*0af8f00bSMatthew Ahrens 150*0af8f00bSMatthew Ahrens if (condid == 0) { 151*0af8f00bSMatthew Ahrens /* 152*0af8f00bSMatthew Ahrens * value is (1 && pred) 153*0af8f00bSMatthew Ahrens * 154*0af8f00bSMatthew Ahrens * Note, D doesn't allow a probe-local "this" variable to 155*0af8f00bSMatthew Ahrens * be reused as a different type, even from a different probe. 156*0af8f00bSMatthew Ahrens * Therefore, value can't simply be <pred>, because then 157*0af8f00bSMatthew Ahrens * its type could be different when we reuse this condid 158*0af8f00bSMatthew Ahrens * in a different meta-clause. 159*0af8f00bSMatthew Ahrens */ 160*0af8f00bSMatthew Ahrens value = dt_node_op2(DT_TOK_LAND, dt_node_int(1), pred); 161*0af8f00bSMatthew Ahrens } else { 162*0af8f00bSMatthew Ahrens /* value is (this->%condition_<condid> && pred) */ 163*0af8f00bSMatthew Ahrens value = dt_node_op2(DT_TOK_LAND, 164*0af8f00bSMatthew Ahrens dt_sugar_new_condition_var(condid), pred); 165*0af8f00bSMatthew Ahrens } 166*0af8f00bSMatthew Ahrens 167*0af8f00bSMatthew Ahrens /* body is "this->%condition_<retval> = <value>;" */ 168*0af8f00bSMatthew Ahrens body = dt_node_statement(dt_node_op2(DT_TOK_ASGN, 169*0af8f00bSMatthew Ahrens dt_sugar_new_condition_var(newcond), value)); 170*0af8f00bSMatthew Ahrens 171*0af8f00bSMatthew Ahrens return (dt_node_clause(dp->dtsp_pdescs, newpred, body)); 172*0af8f00bSMatthew Ahrens } 173*0af8f00bSMatthew Ahrens 174*0af8f00bSMatthew Ahrens /* 175*0af8f00bSMatthew Ahrens * Generate a new clause to evaluate predicate and set a new condition variable, 176*0af8f00bSMatthew Ahrens * whose ID will be returned. The new clause will be appended to 177*0af8f00bSMatthew Ahrens * dp_first_new_clause. 178*0af8f00bSMatthew Ahrens */ 179*0af8f00bSMatthew Ahrens static int 180*0af8f00bSMatthew Ahrens dt_sugar_new_condition(dt_sugar_parse_t *dp, dt_node_t *pred, int condid) 181*0af8f00bSMatthew Ahrens { 182*0af8f00bSMatthew Ahrens dp->dtsp_num_conditions++; 183*0af8f00bSMatthew Ahrens dt_sugar_append_clause(dp, dt_sugar_new_condition_impl(dp, 184*0af8f00bSMatthew Ahrens pred, condid, dp->dtsp_num_conditions)); 185*0af8f00bSMatthew Ahrens return (dp->dtsp_num_conditions); 186*0af8f00bSMatthew Ahrens } 187*0af8f00bSMatthew Ahrens 188*0af8f00bSMatthew Ahrens /* 189*0af8f00bSMatthew Ahrens * Visit the specified node and all of its descendants. Currently this is only 190*0af8f00bSMatthew Ahrens * used to count the number of "if" statements (dtsp_num_ifs). 191*0af8f00bSMatthew Ahrens */ 192*0af8f00bSMatthew Ahrens static void 193*0af8f00bSMatthew Ahrens dt_sugar_visit_all(dt_sugar_parse_t *dp, dt_node_t *dnp) 194*0af8f00bSMatthew Ahrens { 195*0af8f00bSMatthew Ahrens dt_node_t *arg; 196*0af8f00bSMatthew Ahrens 197*0af8f00bSMatthew Ahrens switch (dnp->dn_kind) { 198*0af8f00bSMatthew Ahrens case DT_NODE_FREE: 199*0af8f00bSMatthew Ahrens case DT_NODE_INT: 200*0af8f00bSMatthew Ahrens case DT_NODE_STRING: 201*0af8f00bSMatthew Ahrens case DT_NODE_SYM: 202*0af8f00bSMatthew Ahrens case DT_NODE_TYPE: 203*0af8f00bSMatthew Ahrens case DT_NODE_PROBE: 204*0af8f00bSMatthew Ahrens case DT_NODE_PDESC: 205*0af8f00bSMatthew Ahrens case DT_NODE_IDENT: 206*0af8f00bSMatthew Ahrens break; 207*0af8f00bSMatthew Ahrens 208*0af8f00bSMatthew Ahrens case DT_NODE_FUNC: 209*0af8f00bSMatthew Ahrens for (arg = dnp->dn_args; arg != NULL; arg = arg->dn_list) 210*0af8f00bSMatthew Ahrens dt_sugar_visit_all(dp, arg); 211*0af8f00bSMatthew Ahrens break; 212*0af8f00bSMatthew Ahrens 213*0af8f00bSMatthew Ahrens case DT_NODE_OP1: 214*0af8f00bSMatthew Ahrens dt_sugar_visit_all(dp, dnp->dn_child); 215*0af8f00bSMatthew Ahrens break; 216*0af8f00bSMatthew Ahrens 217*0af8f00bSMatthew Ahrens case DT_NODE_OP2: 218*0af8f00bSMatthew Ahrens dt_sugar_visit_all(dp, dnp->dn_left); 219*0af8f00bSMatthew Ahrens dt_sugar_visit_all(dp, dnp->dn_right); 220*0af8f00bSMatthew Ahrens if (dnp->dn_op == DT_TOK_LBRAC) { 221*0af8f00bSMatthew Ahrens dt_node_t *ln = dnp->dn_right; 222*0af8f00bSMatthew Ahrens while (ln->dn_list != NULL) { 223*0af8f00bSMatthew Ahrens dt_sugar_visit_all(dp, ln->dn_list); 224*0af8f00bSMatthew Ahrens ln = ln->dn_list; 225*0af8f00bSMatthew Ahrens } 226*0af8f00bSMatthew Ahrens } 227*0af8f00bSMatthew Ahrens break; 228*0af8f00bSMatthew Ahrens 229*0af8f00bSMatthew Ahrens case DT_NODE_OP3: 230*0af8f00bSMatthew Ahrens dt_sugar_visit_all(dp, dnp->dn_expr); 231*0af8f00bSMatthew Ahrens dt_sugar_visit_all(dp, dnp->dn_left); 232*0af8f00bSMatthew Ahrens dt_sugar_visit_all(dp, dnp->dn_right); 233*0af8f00bSMatthew Ahrens break; 234*0af8f00bSMatthew Ahrens 235*0af8f00bSMatthew Ahrens case DT_NODE_DEXPR: 236*0af8f00bSMatthew Ahrens case DT_NODE_DFUNC: 237*0af8f00bSMatthew Ahrens dt_sugar_visit_all(dp, dnp->dn_expr); 238*0af8f00bSMatthew Ahrens break; 239*0af8f00bSMatthew Ahrens 240*0af8f00bSMatthew Ahrens case DT_NODE_AGG: 241*0af8f00bSMatthew Ahrens for (arg = dnp->dn_aggtup; arg != NULL; arg = arg->dn_list) 242*0af8f00bSMatthew Ahrens dt_sugar_visit_all(dp, arg); 243*0af8f00bSMatthew Ahrens 244*0af8f00bSMatthew Ahrens if (dnp->dn_aggfun) 245*0af8f00bSMatthew Ahrens dt_sugar_visit_all(dp, dnp->dn_aggfun); 246*0af8f00bSMatthew Ahrens break; 247*0af8f00bSMatthew Ahrens 248*0af8f00bSMatthew Ahrens case DT_NODE_CLAUSE: 249*0af8f00bSMatthew Ahrens for (arg = dnp->dn_pdescs; arg != NULL; arg = arg->dn_list) 250*0af8f00bSMatthew Ahrens dt_sugar_visit_all(dp, arg); 251*0af8f00bSMatthew Ahrens 252*0af8f00bSMatthew Ahrens if (dnp->dn_pred != NULL) 253*0af8f00bSMatthew Ahrens dt_sugar_visit_all(dp, dnp->dn_pred); 254*0af8f00bSMatthew Ahrens 255*0af8f00bSMatthew Ahrens for (arg = dnp->dn_acts; arg != NULL; arg = arg->dn_list) 256*0af8f00bSMatthew Ahrens dt_sugar_visit_all(dp, arg); 257*0af8f00bSMatthew Ahrens break; 258*0af8f00bSMatthew Ahrens 259*0af8f00bSMatthew Ahrens case DT_NODE_INLINE: { 260*0af8f00bSMatthew Ahrens const dt_idnode_t *inp = dnp->dn_ident->di_iarg; 261*0af8f00bSMatthew Ahrens 262*0af8f00bSMatthew Ahrens dt_sugar_visit_all(dp, inp->din_root); 263*0af8f00bSMatthew Ahrens break; 264*0af8f00bSMatthew Ahrens } 265*0af8f00bSMatthew Ahrens case DT_NODE_MEMBER: 266*0af8f00bSMatthew Ahrens if (dnp->dn_membexpr) 267*0af8f00bSMatthew Ahrens dt_sugar_visit_all(dp, dnp->dn_membexpr); 268*0af8f00bSMatthew Ahrens break; 269*0af8f00bSMatthew Ahrens 270*0af8f00bSMatthew Ahrens case DT_NODE_XLATOR: 271*0af8f00bSMatthew Ahrens for (arg = dnp->dn_members; arg != NULL; arg = arg->dn_list) 272*0af8f00bSMatthew Ahrens dt_sugar_visit_all(dp, arg); 273*0af8f00bSMatthew Ahrens break; 274*0af8f00bSMatthew Ahrens 275*0af8f00bSMatthew Ahrens case DT_NODE_PROVIDER: 276*0af8f00bSMatthew Ahrens for (arg = dnp->dn_probes; arg != NULL; arg = arg->dn_list) 277*0af8f00bSMatthew Ahrens dt_sugar_visit_all(dp, arg); 278*0af8f00bSMatthew Ahrens break; 279*0af8f00bSMatthew Ahrens 280*0af8f00bSMatthew Ahrens case DT_NODE_PROG: 281*0af8f00bSMatthew Ahrens for (arg = dnp->dn_list; arg != NULL; arg = arg->dn_list) 282*0af8f00bSMatthew Ahrens dt_sugar_visit_all(dp, arg); 283*0af8f00bSMatthew Ahrens break; 284*0af8f00bSMatthew Ahrens 285*0af8f00bSMatthew Ahrens case DT_NODE_IF: 286*0af8f00bSMatthew Ahrens dp->dtsp_num_ifs++; 287*0af8f00bSMatthew Ahrens dt_sugar_visit_all(dp, dnp->dn_conditional); 288*0af8f00bSMatthew Ahrens 289*0af8f00bSMatthew Ahrens for (arg = dnp->dn_body; arg != NULL; arg = arg->dn_list) 290*0af8f00bSMatthew Ahrens dt_sugar_visit_all(dp, arg); 291*0af8f00bSMatthew Ahrens for (arg = dnp->dn_alternate_body; arg != NULL; 292*0af8f00bSMatthew Ahrens arg = arg->dn_list) 293*0af8f00bSMatthew Ahrens dt_sugar_visit_all(dp, arg); 294*0af8f00bSMatthew Ahrens 295*0af8f00bSMatthew Ahrens break; 296*0af8f00bSMatthew Ahrens 297*0af8f00bSMatthew Ahrens default: 298*0af8f00bSMatthew Ahrens (void) dnerror(dnp, D_UNKNOWN, "bad node %p, kind %d\n", 299*0af8f00bSMatthew Ahrens (void *)dnp, dnp->dn_kind); 300*0af8f00bSMatthew Ahrens } 301*0af8f00bSMatthew Ahrens } 302*0af8f00bSMatthew Ahrens 303*0af8f00bSMatthew Ahrens /* 304*0af8f00bSMatthew Ahrens * Return a new clause which resets the error variable to zero: 305*0af8f00bSMatthew Ahrens * 306*0af8f00bSMatthew Ahrens * dp_pdescs{ self->%error = 0; } 307*0af8f00bSMatthew Ahrens * 308*0af8f00bSMatthew Ahrens * This clause will be executed at the beginning of each meta-clause, to 309*0af8f00bSMatthew Ahrens * ensure the error variable is unset (in case the previous meta-clause 310*0af8f00bSMatthew Ahrens * failed). 311*0af8f00bSMatthew Ahrens */ 312*0af8f00bSMatthew Ahrens static dt_node_t * 313*0af8f00bSMatthew Ahrens dt_sugar_new_clearerror_clause(dt_sugar_parse_t *dp) 314*0af8f00bSMatthew Ahrens { 315*0af8f00bSMatthew Ahrens dt_node_t *stmt = dt_node_statement(dt_node_op2(DT_TOK_ASGN, 316*0af8f00bSMatthew Ahrens dt_sugar_new_error_var(), dt_node_int(0))); 317*0af8f00bSMatthew Ahrens return (dt_node_clause(dp->dtsp_pdescs, NULL, stmt)); 318*0af8f00bSMatthew Ahrens } 319*0af8f00bSMatthew Ahrens 320*0af8f00bSMatthew Ahrens /* 321*0af8f00bSMatthew Ahrens * Evaluate the conditional, and recursively visit the body of the "if" 322*0af8f00bSMatthew Ahrens * statement (and the "else", if present). 323*0af8f00bSMatthew Ahrens */ 324*0af8f00bSMatthew Ahrens static void 325*0af8f00bSMatthew Ahrens dt_sugar_do_if(dt_sugar_parse_t *dp, dt_node_t *if_stmt, int precondition) 326*0af8f00bSMatthew Ahrens { 327*0af8f00bSMatthew Ahrens int newid; 328*0af8f00bSMatthew Ahrens 329*0af8f00bSMatthew Ahrens assert(if_stmt->dn_kind == DT_NODE_IF); 330*0af8f00bSMatthew Ahrens 331*0af8f00bSMatthew Ahrens /* condition */ 332*0af8f00bSMatthew Ahrens newid = dt_sugar_new_condition(dp, 333*0af8f00bSMatthew Ahrens if_stmt->dn_conditional, precondition); 334*0af8f00bSMatthew Ahrens 335*0af8f00bSMatthew Ahrens /* body of if */ 336*0af8f00bSMatthew Ahrens dt_sugar_visit_stmts(dp, if_stmt->dn_body, newid); 337*0af8f00bSMatthew Ahrens 338*0af8f00bSMatthew Ahrens /* 339*0af8f00bSMatthew Ahrens * Visit the body of the "else" statement, if present. Note that we 340*0af8f00bSMatthew Ahrens * generate a new condition which is the inverse of the previous 341*0af8f00bSMatthew Ahrens * condition. 342*0af8f00bSMatthew Ahrens */ 343*0af8f00bSMatthew Ahrens if (if_stmt->dn_alternate_body != NULL) { 344*0af8f00bSMatthew Ahrens dt_node_t *pred = 345*0af8f00bSMatthew Ahrens dt_node_op1(DT_TOK_LNEG, dt_sugar_new_condition_var(newid)); 346*0af8f00bSMatthew Ahrens dt_sugar_visit_stmts(dp, if_stmt->dn_alternate_body, 347*0af8f00bSMatthew Ahrens dt_sugar_new_condition(dp, pred, precondition)); 348*0af8f00bSMatthew Ahrens } 349*0af8f00bSMatthew Ahrens } 350*0af8f00bSMatthew Ahrens 351*0af8f00bSMatthew Ahrens /* 352*0af8f00bSMatthew Ahrens * Generate a new clause to evaluate the statements based on the condition. 353*0af8f00bSMatthew Ahrens * The new clause will be appended to dp_first_new_clause. 354*0af8f00bSMatthew Ahrens * 355*0af8f00bSMatthew Ahrens * dp_pdescs 356*0af8f00bSMatthew Ahrens * /!self->%error && this->%condition_<condid>/ 357*0af8f00bSMatthew Ahrens * { 358*0af8f00bSMatthew Ahrens * stmts 359*0af8f00bSMatthew Ahrens * } 360*0af8f00bSMatthew Ahrens */ 361*0af8f00bSMatthew Ahrens static void 362*0af8f00bSMatthew Ahrens dt_sugar_new_basic_block(dt_sugar_parse_t *dp, int condid, dt_node_t *stmts) 363*0af8f00bSMatthew Ahrens { 364*0af8f00bSMatthew Ahrens dt_node_t *pred = NULL; 365*0af8f00bSMatthew Ahrens 366*0af8f00bSMatthew Ahrens if (condid == 0) { 367*0af8f00bSMatthew Ahrens /* 368*0af8f00bSMatthew Ahrens * Don't bother with !error on the first clause, because if 369*0af8f00bSMatthew Ahrens * there is only one clause, we don't add the prelude to 370*0af8f00bSMatthew Ahrens * zero out %error. 371*0af8f00bSMatthew Ahrens */ 372*0af8f00bSMatthew Ahrens if (dp->dtsp_num_conditions != 0) { 373*0af8f00bSMatthew Ahrens pred = dt_node_op1(DT_TOK_LNEG, 374*0af8f00bSMatthew Ahrens dt_sugar_new_error_var()); 375*0af8f00bSMatthew Ahrens } 376*0af8f00bSMatthew Ahrens } else { 377*0af8f00bSMatthew Ahrens pred = dt_node_op2(DT_TOK_LAND, 378*0af8f00bSMatthew Ahrens dt_node_op1(DT_TOK_LNEG, dt_sugar_new_error_var()), 379*0af8f00bSMatthew Ahrens dt_sugar_new_condition_var(condid)); 380*0af8f00bSMatthew Ahrens } 381*0af8f00bSMatthew Ahrens dt_sugar_append_clause(dp, 382*0af8f00bSMatthew Ahrens dt_node_clause(dp->dtsp_pdescs, pred, stmts)); 383*0af8f00bSMatthew Ahrens } 384*0af8f00bSMatthew Ahrens 385*0af8f00bSMatthew Ahrens /* 386*0af8f00bSMatthew Ahrens * Visit all the statements in this list, and break them into basic blocks, 387*0af8f00bSMatthew Ahrens * generating new clauses for "if" and "else" statements. 388*0af8f00bSMatthew Ahrens */ 389*0af8f00bSMatthew Ahrens static void 390*0af8f00bSMatthew Ahrens dt_sugar_visit_stmts(dt_sugar_parse_t *dp, dt_node_t *stmts, int precondition) 391*0af8f00bSMatthew Ahrens { 392*0af8f00bSMatthew Ahrens dt_node_t *stmt; 393*0af8f00bSMatthew Ahrens dt_node_t *prev_stmt = NULL; 394*0af8f00bSMatthew Ahrens dt_node_t *next_stmt; 395*0af8f00bSMatthew Ahrens dt_node_t *first_stmt_in_basic_block = NULL; 396*0af8f00bSMatthew Ahrens 397*0af8f00bSMatthew Ahrens for (stmt = stmts; stmt != NULL; stmt = next_stmt) { 398*0af8f00bSMatthew Ahrens next_stmt = stmt->dn_list; 399*0af8f00bSMatthew Ahrens 400*0af8f00bSMatthew Ahrens if (stmt->dn_kind != DT_NODE_IF) { 401*0af8f00bSMatthew Ahrens if (first_stmt_in_basic_block == NULL) 402*0af8f00bSMatthew Ahrens first_stmt_in_basic_block = stmt; 403*0af8f00bSMatthew Ahrens prev_stmt = stmt; 404*0af8f00bSMatthew Ahrens continue; 405*0af8f00bSMatthew Ahrens } 406*0af8f00bSMatthew Ahrens 407*0af8f00bSMatthew Ahrens /* 408*0af8f00bSMatthew Ahrens * Remove this and following statements from the previous 409*0af8f00bSMatthew Ahrens * clause. 410*0af8f00bSMatthew Ahrens */ 411*0af8f00bSMatthew Ahrens if (prev_stmt != NULL) 412*0af8f00bSMatthew Ahrens prev_stmt->dn_list = NULL; 413*0af8f00bSMatthew Ahrens 414*0af8f00bSMatthew Ahrens /* 415*0af8f00bSMatthew Ahrens * Generate clause for statements preceding the "if" 416*0af8f00bSMatthew Ahrens */ 417*0af8f00bSMatthew Ahrens if (first_stmt_in_basic_block != NULL) { 418*0af8f00bSMatthew Ahrens dt_sugar_new_basic_block(dp, precondition, 419*0af8f00bSMatthew Ahrens first_stmt_in_basic_block); 420*0af8f00bSMatthew Ahrens } 421*0af8f00bSMatthew Ahrens 422*0af8f00bSMatthew Ahrens dt_sugar_do_if(dp, stmt, precondition); 423*0af8f00bSMatthew Ahrens 424*0af8f00bSMatthew Ahrens first_stmt_in_basic_block = NULL; 425*0af8f00bSMatthew Ahrens 426*0af8f00bSMatthew Ahrens prev_stmt = stmt; 427*0af8f00bSMatthew Ahrens } 428*0af8f00bSMatthew Ahrens 429*0af8f00bSMatthew Ahrens /* generate clause for statements after last "if". */ 430*0af8f00bSMatthew Ahrens if (first_stmt_in_basic_block != NULL) { 431*0af8f00bSMatthew Ahrens dt_sugar_new_basic_block(dp, precondition, 432*0af8f00bSMatthew Ahrens first_stmt_in_basic_block); 433*0af8f00bSMatthew Ahrens } 434*0af8f00bSMatthew Ahrens } 435*0af8f00bSMatthew Ahrens 436*0af8f00bSMatthew Ahrens /* 437*0af8f00bSMatthew Ahrens * Generate a new clause which will set the error variable when an error occurs. 438*0af8f00bSMatthew Ahrens * Only one of these clauses is created per program (e.g. script file). 439*0af8f00bSMatthew Ahrens * The clause is: 440*0af8f00bSMatthew Ahrens * 441*0af8f00bSMatthew Ahrens * dtrace:::ERROR{ self->%error = 1; } 442*0af8f00bSMatthew Ahrens */ 443*0af8f00bSMatthew Ahrens static dt_node_t * 444*0af8f00bSMatthew Ahrens dt_sugar_makeerrorclause(void) 445*0af8f00bSMatthew Ahrens { 446*0af8f00bSMatthew Ahrens dt_node_t *acts, *pdesc; 447*0af8f00bSMatthew Ahrens 448*0af8f00bSMatthew Ahrens pdesc = dt_node_pdesc_by_name(strdup("dtrace:::ERROR")); 449*0af8f00bSMatthew Ahrens 450*0af8f00bSMatthew Ahrens acts = dt_node_statement(dt_node_op2(DT_TOK_ASGN, 451*0af8f00bSMatthew Ahrens dt_sugar_new_error_var(), dt_node_int(1))); 452*0af8f00bSMatthew Ahrens 453*0af8f00bSMatthew Ahrens return (dt_node_clause(pdesc, NULL, acts)); 454*0af8f00bSMatthew Ahrens } 455*0af8f00bSMatthew Ahrens 456*0af8f00bSMatthew Ahrens /* 457*0af8f00bSMatthew Ahrens * Transform the super-clause into straight-D, returning the new list of 458*0af8f00bSMatthew Ahrens * sub-clauses. 459*0af8f00bSMatthew Ahrens */ 460*0af8f00bSMatthew Ahrens dt_node_t * 461*0af8f00bSMatthew Ahrens dt_compile_sugar(dtrace_hdl_t *dtp, dt_node_t *clause) 462*0af8f00bSMatthew Ahrens { 463*0af8f00bSMatthew Ahrens dt_sugar_parse_t dp = { 0 }; 464*0af8f00bSMatthew Ahrens int condid = 0; 465*0af8f00bSMatthew Ahrens 466*0af8f00bSMatthew Ahrens dp.dtsp_dtp = dtp; 467*0af8f00bSMatthew Ahrens dp.dtsp_pdescs = clause->dn_pdescs; 468*0af8f00bSMatthew Ahrens 469*0af8f00bSMatthew Ahrens /* make dt_node_int() generate an "int"-typed integer */ 470*0af8f00bSMatthew Ahrens yyintdecimal = B_TRUE; 471*0af8f00bSMatthew Ahrens yyintsuffix[0] = '\0'; 472*0af8f00bSMatthew Ahrens yyintprefix = 0; 473*0af8f00bSMatthew Ahrens 474*0af8f00bSMatthew Ahrens dt_sugar_visit_all(&dp, clause); 475*0af8f00bSMatthew Ahrens 476*0af8f00bSMatthew Ahrens if (dp.dtsp_num_ifs == 0 && dp.dtsp_num_conditions == 0) { 477*0af8f00bSMatthew Ahrens /* 478*0af8f00bSMatthew Ahrens * There is nothing that modifies the number of clauses. Use 479*0af8f00bSMatthew Ahrens * the existing clause as-is, with its predicate intact. This 480*0af8f00bSMatthew Ahrens * ensures that in the absence of D sugar, the body of the 481*0af8f00bSMatthew Ahrens * clause can create a variable that is referenced in the 482*0af8f00bSMatthew Ahrens * predicate. 483*0af8f00bSMatthew Ahrens */ 484*0af8f00bSMatthew Ahrens dt_sugar_append_clause(&dp, dt_node_clause(clause->dn_pdescs, 485*0af8f00bSMatthew Ahrens clause->dn_pred, clause->dn_acts)); 486*0af8f00bSMatthew Ahrens } else { 487*0af8f00bSMatthew Ahrens if (clause->dn_pred != NULL) { 488*0af8f00bSMatthew Ahrens condid = dt_sugar_new_condition(&dp, 489*0af8f00bSMatthew Ahrens clause->dn_pred, condid); 490*0af8f00bSMatthew Ahrens } 491*0af8f00bSMatthew Ahrens 492*0af8f00bSMatthew Ahrens if (clause->dn_acts == NULL) { 493*0af8f00bSMatthew Ahrens /* 494*0af8f00bSMatthew Ahrens * dt_sugar_visit_stmts() does not emit a clause with 495*0af8f00bSMatthew Ahrens * an empty body (e.g. if there's an empty "if" body), 496*0af8f00bSMatthew Ahrens * but we need the empty body here so that we 497*0af8f00bSMatthew Ahrens * continue to get the default tracing action. 498*0af8f00bSMatthew Ahrens */ 499*0af8f00bSMatthew Ahrens dt_sugar_new_basic_block(&dp, condid, NULL); 500*0af8f00bSMatthew Ahrens } else { 501*0af8f00bSMatthew Ahrens dt_sugar_visit_stmts(&dp, clause->dn_acts, condid); 502*0af8f00bSMatthew Ahrens } 503*0af8f00bSMatthew Ahrens } 504*0af8f00bSMatthew Ahrens 505*0af8f00bSMatthew Ahrens if (dp.dtsp_num_conditions != 0) { 506*0af8f00bSMatthew Ahrens dt_sugar_prepend_clause(&dp, 507*0af8f00bSMatthew Ahrens dt_sugar_new_clearerror_clause(&dp)); 508*0af8f00bSMatthew Ahrens } 509*0af8f00bSMatthew Ahrens 510*0af8f00bSMatthew Ahrens if (dp.dtsp_clause_list != NULL && 511*0af8f00bSMatthew Ahrens dp.dtsp_clause_list->dn_list != NULL && !dtp->dt_has_sugar) { 512*0af8f00bSMatthew Ahrens dtp->dt_has_sugar = B_TRUE; 513*0af8f00bSMatthew Ahrens dt_sugar_prepend_clause(&dp, dt_sugar_makeerrorclause()); 514*0af8f00bSMatthew Ahrens } 515*0af8f00bSMatthew Ahrens return (dp.dtsp_clause_list); 516*0af8f00bSMatthew Ahrens } 517