Print this page
7085 add support for "if" and "else" statements in dtrace

*** 19,30 **** * CDDL HEADER END */ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, Joyent Inc. All rights reserved. - * Copyright (c) 2013 by Delphix. All rights reserved. */ /* * DTrace D Language Parser * --- 19,30 ---- * CDDL HEADER END */ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2014 by Delphix. All rights reserved. * Copyright (c) 2013, Joyent Inc. All rights reserved. */ /* * DTrace D Language Parser *
*** 2135,2144 **** --- 2135,2155 ---- dnp->dn_expr = expr; return (dnp); } dt_node_t * + dt_node_if(dt_node_t *pred, dt_node_t *acts, dt_node_t *else_acts) + { + dt_node_t *dnp = dt_node_alloc(DT_NODE_IF); + dnp->dn_conditional = pred; + dnp->dn_body = acts; + dnp->dn_alternate_body = else_acts; + + return (dnp); + } + + dt_node_t * dt_node_pdesc_by_name(char *spec) { dtrace_hdl_t *dtp = yypcb->pcb_hdl; dt_node_t *dnp;
*** 2203,2213 **** dnp->dn_pdescs = pdescs; dnp->dn_pred = pred; dnp->dn_acts = acts; - yybegin(YYS_CLAUSE); return (dnp); } dt_node_t * dt_node_inline(dt_node_t *expr) --- 2214,2223 ----
*** 3195,3206 **** if (idp == NULL || dt_ident_unref(idp)) dt_xcook_ident(lp, dhp, idkind, B_TRUE); else dt_xcook_ident(lp, dhp, idp->di_kind, B_FALSE); ! } else lp = dnp->dn_left = dt_node_cook(lp, 0); /* * Switch op to '+' for *(E1 + E2) array mode in these cases: * (a) lp is a DT_IDENT_ARRAY variable that has already been * referenced using [] notation (dn_args != NULL). --- 3205,3217 ---- if (idp == NULL || dt_ident_unref(idp)) dt_xcook_ident(lp, dhp, idkind, B_TRUE); else dt_xcook_ident(lp, dhp, idp->di_kind, B_FALSE); ! } else { lp = dnp->dn_left = dt_node_cook(lp, 0); + } /* * Switch op to '+' for *(E1 + E2) array mode in these cases: * (a) lp is a DT_IDENT_ARRAY variable that has already been * referenced using [] notation (dn_args != NULL).
*** 3210,3224 **** */ if (lp->dn_kind == DT_NODE_VAR) { if (lp->dn_ident->di_kind == DT_IDENT_ARRAY) { if (lp->dn_args != NULL) op = DT_TOK_ADD; ! } else if (!dt_ident_unref(lp->dn_ident)) op = DT_TOK_ADD; ! } else if (lp->dn_kind != DT_NODE_AGG) op = DT_TOK_ADD; } switch (op) { case DT_TOK_BAND: case DT_TOK_XOR: case DT_TOK_BOR: --- 3221,3237 ---- */ if (lp->dn_kind == DT_NODE_VAR) { if (lp->dn_ident->di_kind == DT_IDENT_ARRAY) { if (lp->dn_args != NULL) op = DT_TOK_ADD; ! } else if (!dt_ident_unref(lp->dn_ident)) { op = DT_TOK_ADD; ! } ! } else if (lp->dn_kind != DT_NODE_AGG) { op = DT_TOK_ADD; } + } switch (op) { case DT_TOK_BAND: case DT_TOK_XOR: case DT_TOK_BOR:
*** 3637,3685 **** dt_assign_common(dnp); break; case DT_TOK_PTR: /* ! * If the left-hand side of operator -> is the name "self", ! * then we permit a TLS variable to be created or referenced. */ ! if (lp->dn_kind == DT_NODE_IDENT && ! strcmp(lp->dn_string, "self") == 0) { ! if (rp->dn_kind != DT_NODE_VAR) { ! dt_xcook_ident(rp, dtp->dt_tls, ! DT_IDENT_SCALAR, B_TRUE); ! } ! if (idflags != 0) ! rp = dt_node_cook(rp, idflags); ! ! dnp->dn_right = dnp->dn_left; /* avoid freeing rp */ ! dt_node_free(dnp); ! return (rp); } ! ! /* ! * If the left-hand side of operator -> is the name "this", ! * then we permit a local variable to be created or referenced. ! */ ! if (lp->dn_kind == DT_NODE_IDENT && ! strcmp(lp->dn_string, "this") == 0) { if (rp->dn_kind != DT_NODE_VAR) { ! dt_xcook_ident(rp, yypcb->pcb_locals, DT_IDENT_SCALAR, B_TRUE); } if (idflags != 0) rp = dt_node_cook(rp, idflags); ! dnp->dn_right = dnp->dn_left; /* avoid freeing rp */ dt_node_free(dnp); return (rp); } ! /*FALLTHRU*/ - case DT_TOK_DOT: lp = dnp->dn_left = dt_node_cook(lp, DT_IDFLG_REF); if (rp->dn_kind != DT_NODE_IDENT) { xyerror(D_OP_IDENT, "operator %s must be followed by " --- 3650,3687 ---- dt_assign_common(dnp); break; case DT_TOK_PTR: /* ! * If the left-hand side of operator -> is one of the ! * scoping keywords, permit a local or thread ! * variable to be created or referenced. */ ! if (lp->dn_kind == DT_NODE_IDENT) { ! dt_idhash_t *dhp = NULL; ! if (strcmp(lp->dn_string, "self") == 0) { ! dhp = dtp->dt_tls; ! } else if (strcmp(lp->dn_string, "this") == 0) { ! dhp = yypcb->pcb_locals; } ! if (dhp != NULL) { if (rp->dn_kind != DT_NODE_VAR) { ! dt_xcook_ident(rp, dhp, DT_IDENT_SCALAR, B_TRUE); } if (idflags != 0) rp = dt_node_cook(rp, idflags); ! /* avoid freeing rp */ ! dnp->dn_right = dnp->dn_left; dt_node_free(dnp); return (rp); } ! } /*FALLTHRU*/ case DT_TOK_DOT: lp = dnp->dn_left = dt_node_cook(lp, DT_IDFLG_REF); if (rp->dn_kind != DT_NODE_IDENT) { xyerror(D_OP_IDENT, "operator %s must be followed by "
*** 4494,4504 **** dt_cook_inline, /* DT_NODE_INLINE */ dt_cook_member, /* DT_NODE_MEMBER */ dt_cook_xlator, /* DT_NODE_XLATOR */ dt_cook_none, /* DT_NODE_PROBE */ dt_cook_provider, /* DT_NODE_PROVIDER */ ! dt_cook_none /* DT_NODE_PROG */ }; /* * Recursively cook the parse tree starting at the specified node. The idflags * parameter is used to indicate the type of reference (r/w) and is applied to --- 4496,4507 ---- dt_cook_inline, /* DT_NODE_INLINE */ dt_cook_member, /* DT_NODE_MEMBER */ dt_cook_xlator, /* DT_NODE_XLATOR */ dt_cook_none, /* DT_NODE_PROBE */ dt_cook_provider, /* DT_NODE_PROVIDER */ ! dt_cook_none, /* DT_NODE_PROG */ ! dt_cook_none, /* DT_NODE_IF */ }; /* * Recursively cook the parse tree starting at the specified node. The idflags * parameter is used to indicate the type of reference (r/w) and is applied to
*** 4509,4518 **** --- 4512,4523 ---- { int oldlineno = yylineno; yylineno = dnp->dn_line; + assert(dnp->dn_kind < + sizeof (dt_cook_funcs) / sizeof (dt_cook_funcs[0])); dnp = dt_cook_funcs[dnp->dn_kind](dnp, idflags); dnp->dn_flags |= DT_NF_COOKED; if (dnp->dn_kind == DT_NODE_VAR || dnp->dn_kind == DT_NODE_AGG) dnp->dn_ident->di_flags |= idflags;
*** 4611,4621 **** --- 4616,4801 ---- DIF_TF_BYREF : 0; tp->dtdt_pad = 0; tp->dtdt_size = ctf_type_size(dnp->dn_ctfp, dnp->dn_type); } + /* + * Output the parse tree as D. The "-xtree=8" argument will call this + * function to print out the program after any syntactic sugar + * transformations have been applied (e.g. to implement "if"). The + * resulting output can be used to understand the transformations + * applied by these features, or to run such a script on a system that + * does not support these features + * + * Note that the output does not express precisely the same program as + * the input. In particular: + * - Only the clauses are output. #pragma options, variable + * declarations, etc. are excluded. + * - Command argument substitution has already been done, so the output + * will not contain e.g. $$1, but rather the substituted string. + */ void + dt_printd(dt_node_t *dnp, FILE *fp, int depth) + { + dt_node_t *arg; + + switch (dnp->dn_kind) { + case DT_NODE_INT: + (void) fprintf(fp, "0x%llx", (u_longlong_t)dnp->dn_value); + if (!(dnp->dn_flags & DT_NF_SIGNED)) + (void) fprintf(fp, "u"); + break; + + case DT_NODE_STRING: { + char *escd = strchr2esc(dnp->dn_string, strlen(dnp->dn_string)); + (void) fprintf(fp, "\"%s\"", escd); + free(escd); + break; + } + + case DT_NODE_IDENT: + (void) fprintf(fp, "%s", dnp->dn_string); + break; + + case DT_NODE_VAR: + (void) fprintf(fp, "%s%s", + (dnp->dn_ident->di_flags & DT_IDFLG_LOCAL) ? "this->" : + (dnp->dn_ident->di_flags & DT_IDFLG_TLS) ? "self->" : "", + dnp->dn_ident->di_name); + + if (dnp->dn_args != NULL) { + (void) fprintf(fp, "["); + + for (arg = dnp->dn_args; arg != NULL; + arg = arg->dn_list) { + dt_printd(arg, fp, 0); + if (arg->dn_list != NULL) + (void) fprintf(fp, ", "); + } + + (void) fprintf(fp, "]"); + } + break; + + case DT_NODE_SYM: { + const dtrace_syminfo_t *dts = dnp->dn_ident->di_data; + (void) fprintf(fp, "%s`%s", dts->dts_object, dts->dts_name); + break; + } + case DT_NODE_FUNC: + (void) fprintf(fp, "%s(", dnp->dn_ident->di_name); + + for (arg = dnp->dn_args; arg != NULL; arg = arg->dn_list) { + dt_printd(arg, fp, 0); + if (arg->dn_list != NULL) + (void) fprintf(fp, ", "); + } + (void) fprintf(fp, ")"); + break; + + case DT_NODE_OP1: + (void) fprintf(fp, "%s(", opstr(dnp->dn_op)); + dt_printd(dnp->dn_child, fp, 0); + (void) fprintf(fp, ")"); + break; + + case DT_NODE_OP2: + (void) fprintf(fp, "("); + dt_printd(dnp->dn_left, fp, 0); + if (dnp->dn_op == DT_TOK_LPAR) { + (void) fprintf(fp, ")"); + dt_printd(dnp->dn_right, fp, 0); + break; + } + if (dnp->dn_op == DT_TOK_PTR || dnp->dn_op == DT_TOK_DOT || + dnp->dn_op == DT_TOK_LBRAC) + (void) fprintf(fp, "%s", opstr(dnp->dn_op)); + else + (void) fprintf(fp, " %s ", opstr(dnp->dn_op)); + dt_printd(dnp->dn_right, fp, 0); + if (dnp->dn_op == DT_TOK_LBRAC) { + dt_node_t *ln = dnp->dn_right; + while (ln->dn_list != NULL) { + (void) fprintf(fp, ", "); + dt_printd(ln->dn_list, fp, depth); + ln = ln->dn_list; + } + (void) fprintf(fp, "]"); + } + (void) fprintf(fp, ")"); + break; + + case DT_NODE_OP3: + (void) fprintf(fp, "("); + dt_printd(dnp->dn_expr, fp, 0); + (void) fprintf(fp, " ? "); + dt_printd(dnp->dn_left, fp, 0); + (void) fprintf(fp, " : "); + dt_printd(dnp->dn_right, fp, 0); + (void) fprintf(fp, ")"); + break; + + case DT_NODE_DEXPR: + case DT_NODE_DFUNC: + (void) fprintf(fp, "%*s", depth * 8, ""); + dt_printd(dnp->dn_expr, fp, depth + 1); + (void) fprintf(fp, ";\n"); + break; + + case DT_NODE_PDESC: + (void) fprintf(fp, "%s:%s:%s:%s", + dnp->dn_desc->dtpd_provider, dnp->dn_desc->dtpd_mod, + dnp->dn_desc->dtpd_func, dnp->dn_desc->dtpd_name); + break; + + case DT_NODE_CLAUSE: + for (arg = dnp->dn_pdescs; arg != NULL; arg = arg->dn_list) { + dt_printd(arg, fp, 0); + if (arg->dn_list != NULL) + (void) fprintf(fp, ","); + (void) fprintf(fp, "\n"); + } + + if (dnp->dn_pred != NULL) { + (void) fprintf(fp, "/"); + dt_printd(dnp->dn_pred, fp, 0); + (void) fprintf(fp, "/\n"); + } + (void) fprintf(fp, "{\n"); + + for (arg = dnp->dn_acts; arg != NULL; arg = arg->dn_list) + dt_printd(arg, fp, depth + 1); + (void) fprintf(fp, "}\n"); + (void) fprintf(fp, "\n"); + break; + + case DT_NODE_IF: + (void) fprintf(fp, "%*sif (", depth * 8, ""); + dt_printd(dnp->dn_conditional, fp, 0); + (void) fprintf(fp, ") {\n"); + + for (arg = dnp->dn_body; arg != NULL; arg = arg->dn_list) + dt_printd(arg, fp, depth + 1); + if (dnp->dn_alternate_body == NULL) { + (void) fprintf(fp, "%*s}\n", depth * 8, ""); + } else { + (void) fprintf(fp, "%*s} else {\n", depth * 8, ""); + for (arg = dnp->dn_alternate_body; arg != NULL; + arg = arg->dn_list) + dt_printd(arg, fp, depth + 1); + (void) fprintf(fp, "%*s}\n", depth * 8, ""); + } + + break; + + default: + (void) fprintf(fp, "/* bad node %p, kind %d */\n", + (void *)dnp, dnp->dn_kind); + } + } + + void dt_node_printr(dt_node_t *dnp, FILE *fp, int depth) { char n[DT_TYPE_NAMELEN], buf[BUFSIZ], a[8]; const dtrace_syminfo_t *dts; const dt_idnode_t *inp;
*** 4721,4730 **** --- 4901,4917 ---- case DT_NODE_OP2: (void) fprintf(fp, "OP2 %s (%s)\n", opstr(dnp->dn_op), buf); dt_node_printr(dnp->dn_left, fp, depth + 1); dt_node_printr(dnp->dn_right, fp, depth + 1); + if (dnp->dn_op == DT_TOK_LBRAC) { + dt_node_t *ln = dnp->dn_right; + while (ln->dn_list != NULL) { + dt_node_printr(ln->dn_list, fp, depth + 1); + ln = ln->dn_list; + } + } break; case DT_NODE_OP3: (void) fprintf(fp, "OP3 (%s)\n", buf); dt_node_printr(dnp->dn_expr, fp, depth + 1);
*** 4782,4791 **** --- 4969,4979 ---- (void) fprintf(fp, "%*s/\n", depth * 2, ""); } for (arg = dnp->dn_acts; arg != NULL; arg = arg->dn_list) dt_node_printr(arg, fp, depth + 1); + (void) fprintf(fp, "\n"); break; case DT_NODE_INLINE: inp = dnp->dn_ident->di_iarg;
*** 4832,4841 **** --- 5020,5047 ---- (void) fprintf(fp, "PROGRAM attr=%s\n", a); for (arg = dnp->dn_list; arg != NULL; arg = arg->dn_list) dt_node_printr(arg, fp, depth + 1); break; + case DT_NODE_IF: + (void) fprintf(fp, "IF attr=%s CONDITION:\n", a); + + dt_node_printr(dnp->dn_conditional, fp, depth + 1); + + (void) fprintf(fp, "%*sIF BODY: \n", depth * 2, ""); + for (arg = dnp->dn_body; arg != NULL; arg = arg->dn_list) + dt_node_printr(arg, fp, depth + 1); + + if (dnp->dn_alternate_body != NULL) { + (void) fprintf(fp, "%*sIF ELSE: \n", depth * 2, ""); + for (arg = dnp->dn_alternate_body; arg != NULL; + arg = arg->dn_list) + dt_node_printr(arg, fp, depth + 1); + } + + break; + default: (void) fprintf(fp, "<bad node %p, kind %d>\n", (void *)dnp, dnp->dn_kind); } }