Print this page
7085 add support for "if" and "else" statements in dtrace
@@ -19,12 +19,12 @@
* 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.
- * Copyright (c) 2013 by Delphix. All rights reserved.
*/
/*
* DTrace D Language Parser
*
@@ -2135,10 +2135,21 @@
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,11 +2214,10 @@
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)
@@ -3195,12 +3205,13 @@
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
+ } 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,15 +3221,17 @@
*/
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))
+ } else if (!dt_ident_unref(lp->dn_ident)) {
op = DT_TOK_ADD;
- } else if (lp->dn_kind != DT_NODE_AGG)
+ }
+ } 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,49 +3650,38 @@
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 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 &&
- 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 (lp->dn_kind == DT_NODE_IDENT) {
+ dt_idhash_t *dhp = NULL;
- 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 (strcmp(lp->dn_string, "self") == 0) {
+ dhp = dtp->dt_tls;
+ } else if (strcmp(lp->dn_string, "this") == 0) {
+ dhp = yypcb->pcb_locals;
}
-
- /*
- * 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 (dhp != NULL) {
if (rp->dn_kind != DT_NODE_VAR) {
- dt_xcook_ident(rp, yypcb->pcb_locals,
+ dt_xcook_ident(rp, dhp,
DT_IDENT_SCALAR, B_TRUE);
}
if (idflags != 0)
rp = dt_node_cook(rp, idflags);
- dnp->dn_right = dnp->dn_left; /* avoid freeing rp */
+ /* 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,11 +4496,12 @@
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_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,10 +4512,12 @@
{
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,11 +4616,186 @@
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,10 +4901,17 @@
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,10 +4969,11 @@
(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,10 +5020,28 @@
(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);
}
}