--- old/usr/src/lib/libdtrace/common/dt_parser.c	Sun Jun 12 02:31:32 2016
+++ new/usr/src/lib/libdtrace/common/dt_parser.c	Sun Jun 12 02:31:32 2016
@@ -21,8 +21,8 @@
 
 /*
  * 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.
  */
 
 /*
@@ -2137,6 +2137,17 @@
 }
 
 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;
@@ -2205,7 +2216,6 @@
 	dnp->dn_pred = pred;
 	dnp->dn_acts = acts;
 
-	yybegin(YYS_CLAUSE);
 	return (dnp);
 }
 
@@ -3197,8 +3207,9 @@
 				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:
@@ -3212,10 +3223,12 @@
 			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) {
@@ -3639,45 +3652,34 @@
 
 	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 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 (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);
+				if (idflags != 0)
+					rp = dt_node_cook(rp, idflags);
 
-			dnp->dn_right = dnp->dn_left; /* avoid freeing rp */
-			dt_node_free(dnp);
-			return (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);
 
@@ -4496,7 +4498,8 @@
 	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 */
 };
 
 /*
@@ -4511,6 +4514,8 @@
 
 	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;
 
@@ -4613,7 +4618,182 @@
 	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];
@@ -4723,6 +4903,13 @@
 		(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:
@@ -4784,6 +4971,7 @@
 
 		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:
@@ -4834,6 +5022,24 @@
 			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);
