17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
5c9d6cd7jhaslam * Common Development and Distribution License (the "License").
6c9d6cd7jhaslam * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
21900524fahl
227c478bdstevel@tonic-gate/*
23c9a6ea2Bryan Cantrill * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24c3bd3abMatthew Ahrens * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
25a386cc1Robert Mustacchi * Copyright (c) 2013, Joyent Inc. All rights reserved.
2667a4bb8Gary Mills * Copyright 2015 Gary Mills
277c478bdstevel@tonic-gate */
287c478bdstevel@tonic-gate
297c478bdstevel@tonic-gate/*
307c478bdstevel@tonic-gate * DTrace D Language Compiler
317c478bdstevel@tonic-gate *
327c478bdstevel@tonic-gate * The code in this source file implements the main engine for the D language
337c478bdstevel@tonic-gate * compiler.  The driver routine for the compiler is dt_compile(), below.  The
347c478bdstevel@tonic-gate * compiler operates on either stdio FILEs or in-memory strings as its input
357c478bdstevel@tonic-gate * and can produce either dtrace_prog_t structures from a D program or a single
367c478bdstevel@tonic-gate * dtrace_difo_t structure from a D expression.  Multiple entry points are
377c478bdstevel@tonic-gate * provided as wrappers around dt_compile() for the various input/output pairs.
387c478bdstevel@tonic-gate * The compiler itself is implemented across the following source files:
397c478bdstevel@tonic-gate *
407c478bdstevel@tonic-gate * dt_lex.l - lex scanner
417c478bdstevel@tonic-gate * dt_grammar.y - yacc grammar
427c478bdstevel@tonic-gate * dt_parser.c - parse tree creation and semantic checking
437c478bdstevel@tonic-gate * dt_decl.c - declaration stack processing
447c478bdstevel@tonic-gate * dt_xlator.c - D translator lookup and creation
457c478bdstevel@tonic-gate * dt_ident.c - identifier and symbol table routines
467c478bdstevel@tonic-gate * dt_pragma.c - #pragma processing and D pragmas
477c478bdstevel@tonic-gate * dt_printf.c - D printf() and printa() argument checking and processing
487c478bdstevel@tonic-gate * dt_cc.c - compiler driver and dtrace_prog_t construction
497c478bdstevel@tonic-gate * dt_cg.c - DIF code generator
507c478bdstevel@tonic-gate * dt_as.c - DIF assembler
517c478bdstevel@tonic-gate * dt_dof.c - dtrace_prog_t -> DOF conversion
527c478bdstevel@tonic-gate *
537c478bdstevel@tonic-gate * Several other source files provide collections of utility routines used by
547c478bdstevel@tonic-gate * these major files.  The compiler itself is implemented in multiple passes:
557c478bdstevel@tonic-gate *
567c478bdstevel@tonic-gate * (1) The input program is scanned and parsed by dt_lex.l and dt_grammar.y
577c478bdstevel@tonic-gate *     and parse tree nodes are constructed using the routines in dt_parser.c.
587c478bdstevel@tonic-gate *     This node construction pass is described further in dt_parser.c.
597c478bdstevel@tonic-gate *
607c478bdstevel@tonic-gate * (2) The parse tree is "cooked" by assigning each clause a context (see the
617c478bdstevel@tonic-gate *     routine dt_setcontext(), below) based on its probe description and then
627c478bdstevel@tonic-gate *     recursively descending the tree performing semantic checking.  The cook
637c478bdstevel@tonic-gate *     routines are also implemented in dt_parser.c and described there.
647c478bdstevel@tonic-gate *
657c478bdstevel@tonic-gate * (3) For actions that are DIF expression statements, the DIF code generator
667c478bdstevel@tonic-gate *     and assembler are invoked to create a finished DIFO for the statement.
677c478bdstevel@tonic-gate *
687c478bdstevel@tonic-gate * (4) The dtrace_prog_t data structures for the program clauses and actions
697c478bdstevel@tonic-gate *     are built, containing pointers to any DIFOs created in step (3).
707c478bdstevel@tonic-gate *
717c478bdstevel@tonic-gate * (5) The caller invokes a routine in dt_dof.c to convert the finished program
727c478bdstevel@tonic-gate *     into DOF format for use in anonymous tracing or enabling in the kernel.
737c478bdstevel@tonic-gate *
747c478bdstevel@tonic-gate * In the implementation, steps 2-4 are intertwined in that they are performed
757c478bdstevel@tonic-gate * in order for each clause as part of a loop that executes over the clauses.
767c478bdstevel@tonic-gate *
777c478bdstevel@tonic-gate * The D compiler currently implements nearly no optimization.  The compiler
787c478bdstevel@tonic-gate * implements integer constant folding as part of pass (1), and a set of very
797c478bdstevel@tonic-gate * simple peephole optimizations as part of pass (3).  As with any C compiler,
807c478bdstevel@tonic-gate * a large number of optimizations are possible on both the intermediate data
817c478bdstevel@tonic-gate * structures and the generated DIF code.  These possibilities should be
827c478bdstevel@tonic-gate * investigated in the context of whether they will have any substantive effect
837c478bdstevel@tonic-gate * on the overall DTrace probe effect before they are undertaken.
847c478bdstevel@tonic-gate */
857c478bdstevel@tonic-gate
867c478bdstevel@tonic-gate#include <sys/types.h>
877c478bdstevel@tonic-gate#include <sys/wait.h>
882b6389eBryan Cantrill#include <sys/sysmacros.h>
897c478bdstevel@tonic-gate
907c478bdstevel@tonic-gate#include <assert.h>
917c478bdstevel@tonic-gate#include <strings.h>
927c478bdstevel@tonic-gate#include <signal.h>
937c478bdstevel@tonic-gate#include <unistd.h>
947c478bdstevel@tonic-gate#include <stdlib.h>
957c478bdstevel@tonic-gate#include <stdio.h>
967c478bdstevel@tonic-gate#include <errno.h>
977c478bdstevel@tonic-gate#include <ucontext.h>
987c478bdstevel@tonic-gate#include <limits.h>
997c478bdstevel@tonic-gate#include <ctype.h>
1007c478bdstevel@tonic-gate#include <dirent.h>
1017c478bdstevel@tonic-gate#include <dt_module.h>
1021a7c1b7mws#include <dt_program.h>
1037c478bdstevel@tonic-gate#include <dt_provider.h>
1047c478bdstevel@tonic-gate#include <dt_printf.h>
1057c478bdstevel@tonic-gate#include <dt_pid.h>
1067c478bdstevel@tonic-gate#include <dt_grammar.h>
1077c478bdstevel@tonic-gate#include <dt_ident.h>
1087c478bdstevel@tonic-gate#include <dt_string.h>
1097c478bdstevel@tonic-gate#include <dt_impl.h>
1107c478bdstevel@tonic-gate
1117c478bdstevel@tonic-gatestatic const dtrace_diftype_t dt_void_rtype = {
1127c478bdstevel@tonic-gate	DIF_TYPE_CTF, CTF_K_INTEGER, 0, 0, 0
1137c478bdstevel@tonic-gate};
1147c478bdstevel@tonic-gate
1157c478bdstevel@tonic-gatestatic const dtrace_diftype_t dt_int_rtype = {
1167c478bdstevel@tonic-gate	DIF_TYPE_CTF, CTF_K_INTEGER, 0, 0, sizeof (uint64_t)
1177c478bdstevel@tonic-gate};
1187c478bdstevel@tonic-gate
119c9d6cd7jhaslamstatic void *dt_compile(dtrace_hdl_t *, int, dtrace_probespec_t, void *,
120c9d6cd7jhaslam    uint_t, int, char *const[], FILE *, const char *);
121c9d6cd7jhaslam
1227c478bdstevel@tonic-gate/*ARGSUSED*/
1237c478bdstevel@tonic-gatestatic int
1247c478bdstevel@tonic-gatedt_idreset(dt_idhash_t *dhp, dt_ident_t *idp, void *ignored)
1257c478bdstevel@tonic-gate{
1267c478bdstevel@tonic-gate	idp->di_flags &= ~(DT_IDFLG_REF | DT_IDFLG_MOD |
1277c478bdstevel@tonic-gate	    DT_IDFLG_DIFR | DT_IDFLG_DIFW);
1287c478bdstevel@tonic-gate	return (0);
1297c478bdstevel@tonic-gate}
1307c478bdstevel@tonic-gate
1317c478bdstevel@tonic-gate/*ARGSUSED*/
1327c478bdstevel@tonic-gatestatic int
1337c478bdstevel@tonic-gatedt_idpragma(dt_idhash_t *dhp, dt_ident_t *idp, void *ignored)
1347c478bdstevel@tonic-gate{
1357c478bdstevel@tonic-gate	yylineno = idp->di_lineno;
1367c478bdstevel@tonic-gate	xyerror(D_PRAGMA_UNUSED, "unused #pragma %s\n", (char *)idp->di_iarg);
1377c478bdstevel@tonic-gate	return (0);
1387c478bdstevel@tonic-gate}
1397c478bdstevel@tonic-gate
1407c478bdstevel@tonic-gatestatic dtrace_stmtdesc_t *
1417c478bdstevel@tonic-gatedt_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp,
1427c478bdstevel@tonic-gate    dtrace_attribute_t descattr, dtrace_attribute_t stmtattr)
1437c478bdstevel@tonic-gate{
1447c478bdstevel@tonic-gate	dtrace_stmtdesc_t *sdp = dtrace_stmt_create(dtp, edp);
1457c478bdstevel@tonic-gate
1467c478bdstevel@tonic-gate	if (sdp == NULL)
1477c478bdstevel@tonic-gate		longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
1487c478bdstevel@tonic-gate
1497c478bdstevel@tonic-gate	assert(yypcb->pcb_stmt == NULL);
1507c478bdstevel@tonic-gate	yypcb->pcb_stmt = sdp;
1517c478bdstevel@tonic-gate
1527c478bdstevel@tonic-gate	sdp->dtsd_descattr = descattr;
1537c478bdstevel@tonic-gate	sdp->dtsd_stmtattr = stmtattr;
1547c478bdstevel@tonic-gate
1557c478bdstevel@tonic-gate	return (sdp);
1567c478bdstevel@tonic-gate}
1577c478bdstevel@tonic-gate
1587c478bdstevel@tonic-gatestatic dtrace_actdesc_t *
1597c478bdstevel@tonic-gatedt_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
1607c478bdstevel@tonic-gate{
1617c478bdstevel@tonic-gate	dtrace_actdesc_t *new;
1627c478bdstevel@tonic-gate
1637c478bdstevel@tonic-gate	if ((new = dtrace_stmt_action(dtp, sdp)) == NULL)
1647c478bdstevel@tonic-gate		longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
1657c478bdstevel@tonic-gate
1667c478bdstevel@tonic-gate	return (new);
1677c478bdstevel@tonic-gate}
1687c478bdstevel@tonic-gate
1697c478bdstevel@tonic-gate/*
1707c478bdstevel@tonic-gate * Utility function to determine if a given action description is destructive.
1717c478bdstevel@tonic-gate * The dtdo_destructive bit is set for us by the DIF assembler (see dt_as.c).
1727c478bdstevel@tonic-gate */
1737c478bdstevel@tonic-gatestatic int
1747c478bdstevel@tonic-gatedt_action_destructive(const dtrace_actdesc_t *ap)
1757c478bdstevel@tonic-gate{
1767c478bdstevel@tonic-gate	return (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind) || (ap->dtad_kind ==
1777c478bdstevel@tonic-gate	    DTRACEACT_DIFEXPR && ap->dtad_difo->dtdo_destructive));
1787c478bdstevel@tonic-gate}
1797c478bdstevel@tonic-gate
1807c478bdstevel@tonic-gatestatic void
1817c478bdstevel@tonic-gatedt_stmt_append(dtrace_stmtdesc_t *sdp, const dt_node_t *dnp)
1827c478bdstevel@tonic-gate{
1837c478bdstevel@tonic-gate	dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
1847c478bdstevel@tonic-gate	dtrace_actdesc_t *ap, *tap;
1857c478bdstevel@tonic-gate	int commit = 0;
1867c478bdstevel@tonic-gate	int speculate = 0;
1877c478bdstevel@tonic-gate	int datarec = 0;
1887c478bdstevel@tonic-gate
1897c478bdstevel@tonic-gate	/*
1907c478bdstevel@tonic-gate	 * Make sure that the new statement jibes with the rest of the ECB.
1917c478bdstevel@tonic-gate	 */
1927c478bdstevel@tonic-gate	for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
1937c478bdstevel@tonic-gate		if (ap->dtad_kind == DTRACEACT_COMMIT) {
1947c478bdstevel@tonic-gate			if (commit) {
1957c478bdstevel@tonic-gate				dnerror(dnp, D_COMM_COMM, "commit( ) may "
1967c478bdstevel@tonic-gate				    "not follow commit( )\n");
1977c478bdstevel@tonic-gate			}
1987c478bdstevel@tonic-gate
1997c478bdstevel@tonic-gate			if (datarec) {
2007c478bdstevel@tonic-gate				dnerror(dnp, D_COMM_DREC, "commit( ) may "
2017c478bdstevel@tonic-gate				    "not follow data-recording action(s)\n");
2027c478bdstevel@tonic-gate			}
2037c478bdstevel@tonic-gate
2047c478bdstevel@tonic-gate			for (tap = ap; tap != NULL; tap = tap->dtad_next) {
2057c478bdstevel@tonic-gate				if (!DTRACEACT_ISAGG(tap->dtad_kind))
2067c478bdstevel@tonic-gate					continue;
2077c478bdstevel@tonic-gate
2087c478bdstevel@tonic-gate				dnerror(dnp, D_AGG_COMM, "aggregating actions "
2097c478bdstevel@tonic-gate				    "may not follow commit( )\n");
2107c478bdstevel@tonic-gate			}
2117c478bdstevel@tonic-gate
2127c478bdstevel@tonic-gate			commit = 1;
2137c478bdstevel@tonic-gate			continue;
2147c478bdstevel@tonic-gate		}
2157c478bdstevel@tonic-gate
2167c478bdstevel@tonic-gate		if (ap->dtad_kind == DTRACEACT_SPECULATE) {
2177c478bdstevel@tonic-gate			if (speculate) {
2187c478bdstevel@tonic-gate				dnerror(dnp, D_SPEC_SPEC, "speculate( ) may "
2197c478bdstevel@tonic-gate				    "not follow speculate( )\n");
2207c478bdstevel@tonic-gate			}
2217c478bdstevel@tonic-gate
2227c478bdstevel@tonic-gate			if (commit) {
2237c478bdstevel@tonic-gate				dnerror(dnp, D_SPEC_COMM, "speculate( ) may "
2247c478bdstevel@tonic-gate				    "not follow commit( )\n");
2257c478bdstevel@tonic-gate			}
2267c478bdstevel@tonic-gate
2277c478bdstevel@tonic-gate			if (datarec) {
2287c478bdstevel@tonic-gate				dnerror(dnp, D_SPEC_DREC, "speculate( ) may "
2297c478bdstevel@tonic-gate				    "not follow data-recording action(s)\n");
2307c478bdstevel@tonic-gate			}
2317c478bdstevel@tonic-gate
2327c478bdstevel@tonic-gate			speculate = 1;
2337c478bdstevel@tonic-gate			continue;
2347c478bdstevel@tonic-gate		}
2357c478bdstevel@tonic-gate
2367c478bdstevel@tonic-gate		if (DTRACEACT_ISAGG(ap->dtad_kind)) {
2377c478bdstevel@tonic-gate			if (speculate) {
2387c478bdstevel@tonic-gate				dnerror(dnp, D_AGG_SPEC, "aggregating actions "
2397c478bdstevel@tonic-gate				    "may not follow speculate( )\n");
2407c478bdstevel@tonic-gate			}
2417c478bdstevel@tonic-gate
2427c478bdstevel@tonic-gate			datarec = 1;
2437c478bdstevel@tonic-gate			continue;
2447c478bdstevel@tonic-gate		}
2457c478bdstevel@tonic-gate
2467c478bdstevel@tonic-gate		if (speculate) {
2477c478bdstevel@tonic-gate			if (dt_action_destructive(ap)) {
2487c478bdstevel@tonic-gate				dnerror(dnp, D_ACT_SPEC, "destructive actions "
2497c478bdstevel@tonic-gate				    "may not follow speculate( )\n");
2507c478bdstevel@tonic-gate			}
2517c478bdstevel@tonic-gate
2527c478bdstevel@tonic-gate			if (ap->dtad_kind == DTRACEACT_EXIT) {
2537c478bdstevel@tonic-gate				dnerror(dnp, D_EXIT_SPEC, "exit( ) may not "
2547c478bdstevel@tonic-gate				    "follow speculate( )\n");
2557c478bdstevel@tonic-gate			}
2567c478bdstevel@tonic-gate		}
2577c478bdstevel@tonic-gate
2587c478bdstevel@tonic-gate		/*
2597c478bdstevel@tonic-gate		 * Exclude all non data-recording actions.
2607c478bdstevel@tonic-gate		 */
2617c478bdstevel@tonic-gate		if (dt_action_destructive(ap) ||
2627c478bdstevel@tonic-gate		    ap->dtad_kind == DTRACEACT_DISCARD)
2637c478bdstevel@tonic-gate			continue;
2647c478bdstevel@tonic-gate
2657c478bdstevel@tonic-gate		if (ap->dtad_kind == DTRACEACT_DIFEXPR &&
2667c478bdstevel@tonic-gate		    ap->dtad_difo->dtdo_rtype.dtdt_kind == DIF_TYPE_CTF &&
2677c478bdstevel@tonic-gate		    ap->dtad_difo->dtdo_rtype.dtdt_size == 0)
2687c478bdstevel@tonic-gate			continue;
2697c478bdstevel@tonic-gate
2707c478bdstevel@tonic-gate		if (commit) {
2717c478bdstevel@tonic-gate			dnerror(dnp, D_DREC_COMM, "data-recording actions "
2727c478bdstevel@tonic-gate			    "may not follow commit( )\n");
2737c478bdstevel@tonic-gate		}
2747c478bdstevel@tonic-gate
2757c478bdstevel@tonic-gate		if (!speculate)
2767c478bdstevel@tonic-gate			datarec = 1;
2777c478bdstevel@tonic-gate	}
2787c478bdstevel@tonic-gate
2797c478bdstevel@tonic-gate	if (dtrace_stmt_add(yypcb->pcb_hdl, yypcb->pcb_prog, sdp) != 0)
2807c478bdstevel@tonic-gate		longjmp(yypcb->pcb_jmpbuf, dtrace_errno(yypcb->pcb_hdl));
2817c478bdstevel@tonic-gate
2827c478bdstevel@tonic-gate	if (yypcb->pcb_stmt == sdp)
2837c478bdstevel@tonic-gate		yypcb->pcb_stmt = NULL;
2847c478bdstevel@tonic-gate}
2857c478bdstevel@tonic-gate
2867c478bdstevel@tonic-gate/*
2877c478bdstevel@tonic-gate * For the first element of an aggregation tuple or for printa(), we create a
2887c478bdstevel@tonic-gate * simple DIF program that simply returns the immediate value that is the ID
2897c478bdstevel@tonic-gate * of the aggregation itself.  This could be optimized in the future by
2907c478bdstevel@tonic-gate * creating a new in-kernel dtad_kind that just returns an integer.
2917c478bdstevel@tonic-gate */
2927c478bdstevel@tonic-gatestatic void
2937c478bdstevel@tonic-gatedt_action_difconst(dtrace_actdesc_t *ap, uint_t id, dtrace_actkind_t kind)
2947c478bdstevel@tonic-gate{
2951a7c1b7mws	dtrace_hdl_t *dtp = yypcb->pcb_hdl;
2961a7c1b7mws	dtrace_difo_t *dp = dt_zalloc(dtp, sizeof (dtrace_difo_t));
2977c478bdstevel@tonic-gate
2987c478bdstevel@tonic-gate	if (dp == NULL)
2997c478bdstevel@tonic-gate		longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
3007c478bdstevel@tonic-gate
3011a7c1b7mws	dp->dtdo_buf = dt_alloc(dtp, sizeof (dif_instr_t) * 2);
3021a7c1b7mws	dp->dtdo_inttab = dt_alloc(dtp, sizeof (uint64_t));
3037c478bdstevel@tonic-gate
3047c478bdstevel@tonic-gate	if (dp->dtdo_buf == NULL || dp->dtdo_inttab == NULL) {
3051a7c1b7mws		dt_difo_free(dtp, dp);
3067c478bdstevel@tonic-gate		longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
3077c478bdstevel@tonic-gate	}
3087c478bdstevel@tonic-gate
3097c478bdstevel@tonic-gate	dp->dtdo_buf[0] = DIF_INSTR_SETX(0, 1); /* setx	DIF_INTEGER[0], %r1 */
3107c478bdstevel@tonic-gate	dp->dtdo_buf[1] = DIF_INSTR_RET(1);	/* ret	%r1 */
3117c478bdstevel@tonic-gate	dp->dtdo_len = 2;
3127c478bdstevel@tonic-gate	dp->dtdo_inttab[0] = id;
3137c478bdstevel@tonic-gate	dp->dtdo_intlen = 1;
3147c478bdstevel@tonic-gate	dp->dtdo_rtype = dt_int_rtype;
3157c478bdstevel@tonic-gate
3167c478bdstevel@tonic-gate	ap->dtad_difo = dp;
3177c478bdstevel@tonic-gate	ap->dtad_kind = kind;
3187c478bdstevel@tonic-gate}
3197c478bdstevel@tonic-gate
3207c478bdstevel@tonic-gatestatic void
3217c478bdstevel@tonic-gatedt_action_clear(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
3227c478bdstevel@tonic-gate{
3237c478bdstevel@tonic-gate	dt_ident_t *aid;
3247c478bdstevel@tonic-gate	dtrace_actdesc_t *ap;
3257c478bdstevel@tonic-gate	dt_node_t *anp;
3267c478bdstevel@tonic-gate
3277c478bdstevel@tonic-gate	char n[DT_TYPE_NAMELEN];
3287c478bdstevel@tonic-gate	int argc = 0;
3297c478bdstevel@tonic-gate
3307c478bdstevel@tonic-gate	for (anp = dnp->dn_args; anp != NULL; anp = anp->dn_list)
3317c478bdstevel@tonic-gate		argc++; /* count up arguments for error messages below */
3327c478bdstevel@tonic-gate
3337c478bdstevel@tonic-gate	if (argc != 1) {
3347c478bdstevel@tonic-gate		dnerror(dnp, D_CLEAR_PROTO,
3357c478bdstevel@tonic-gate		    "%s( ) prototype mismatch: %d args passed, 1 expected\n",
3367c478bdstevel@tonic-gate		    dnp->dn_ident->di_name, argc);
3377c478bdstevel@tonic-gate	}
3387c478bdstevel@tonic-gate
3397c478bdstevel@tonic-gate	anp = dnp->dn_args;
3407c478bdstevel@tonic-gate	assert(anp != NULL);
3417c478bdstevel@tonic-gate
3427c478bdstevel@tonic-gate	if (anp->dn_kind != DT_NODE_AGG) {
3437c478bdstevel@tonic-gate		dnerror(dnp, D_CLEAR_AGGARG,
3447c478bdstevel@tonic-gate		    "%s( ) argument #1 is incompatible with prototype:\n"
3457c478bdstevel@tonic-gate		    "\tprototype: aggregation\n\t argument: %s\n",
3467c478bdstevel@tonic-gate		    dnp->dn_ident->di_name,
3477c478bdstevel@tonic-gate		    dt_node_type_name(anp, n, sizeof (n)));
3487c478bdstevel@tonic-gate	}
3497c478bdstevel@tonic-gate
3507c478bdstevel@tonic-gate	aid = anp->dn_ident;
3517c478bdstevel@tonic-gate
3527c478bdstevel@tonic-gate	if (aid->di_gen == dtp->dt_gen && !(aid->di_flags & DT_IDFLG_MOD)) {
3537c478bdstevel@tonic-gate		dnerror(dnp, D_CLEAR_AGGBAD,
3547c478bdstevel@tonic-gate		    "undefined aggregation: @%s\n", aid->di_name);
3557c478bdstevel@tonic-gate	}
3567c478bdstevel@tonic-gate
3577c478bdstevel@tonic-gate	ap = dt_stmt_action(dtp, sdp);
3587c478bdstevel@tonic-gate	dt_action_difconst(ap, anp->dn_ident->di_id, DTRACEACT_LIBACT);
3597c478bdstevel@tonic-gate	ap->dtad_arg = DT_ACT_CLEAR;
3607c478bdstevel@tonic-gate}
3617c478bdstevel@tonic-gate
3627c478bdstevel@tonic-gatestatic void
3637c478bdstevel@tonic-gatedt_action_normalize(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
3647c478bdstevel@tonic-gate{
3657c478bdstevel@tonic-gate	dt_ident_t *aid;
3667c478bdstevel@tonic-gate	dtrace_actdesc_t *ap;
3677c478bdstevel@tonic-gate	dt_node_t *anp, *normal;
3687c478bdstevel@tonic-gate	int denormal = (strcmp(dnp->dn_ident->di_name, "denormalize") == 0);
3697c478bdstevel@tonic-gate
3707c478bdstevel@tonic-gate	char n[DT_TYPE_NAMELEN];
3717c478bdstevel@tonic-gate	int argc = 0;
3727c478bdstevel@tonic-gate
3737c478bdstevel@tonic-gate	for (anp = dnp->dn_args; anp != NULL; anp = anp->dn_list)
3747c478bdstevel@tonic-gate		argc++; /* count up arguments for error messages below */
3757c478bdstevel@tonic-gate
3767c478bdstevel@tonic-gate	if ((denormal && argc != 1) || (!denormal && argc != 2)) {
3777c478bdstevel@tonic-gate		dnerror(dnp, D_NORMALIZE_PROTO,
3787c478bdstevel@tonic-gate		    "%s( ) prototype mismatch: %d args passed, %d expected\n",
3797c478bdstevel@tonic-gate		    dnp->dn_ident->di_name, argc, denormal ? 1 : 2);
3807c478bdstevel@tonic-gate	}
3817c478bdstevel@tonic-gate
3827c478bdstevel@tonic-gate	anp = dnp->dn_args;
3837c478bdstevel@tonic-gate	assert(anp != NULL);
3847c478bdstevel@tonic-gate
3857c478bdstevel@tonic-gate	if (anp->dn_kind != DT_NODE_AGG) {
3867c478bdstevel@tonic-gate		dnerror(dnp, D_NORMALIZE_AGGARG,
3877c478bdstevel@tonic-gate		    "%s( ) argument #1 is incompatible with prototype:\n"
3887c478bdstevel@tonic-gate		    "\tprototype: aggregation\n\t argument: %s\n",
3897c478bdstevel@tonic-gate		    dnp->dn_ident->di_name,
3907c478bdstevel@tonic-gate		    dt_node_type_name(anp, n, sizeof (n)));
3917c478bdstevel@tonic-gate	}
3927c478bdstevel@tonic-gate
3937c478bdstevel@tonic-gate	if ((normal = anp->dn_list) != NULL && !dt_node_is_scalar(normal)) {
3947c478bdstevel@tonic-gate		dnerror(dnp, D_NORMALIZE_SCALAR,
3957c478bdstevel@tonic-gate		    "%s( ) argument #2 must be of scalar type\n",
3967c478bdstevel@tonic-gate		    dnp->dn_ident->di_name);
3977c478bdstevel@tonic-gate	}
3987c478bdstevel@tonic-gate
3997c478bdstevel@tonic-gate	aid = anp->dn_ident;
4007c478bdstevel@tonic-gate
4017c478bdstevel@tonic-gate	if (aid->di_gen == dtp->dt_gen && !(aid->di_flags & DT_IDFLG_MOD)) {
4027c478bdstevel@tonic-gate		dnerror(dnp, D_NORMALIZE_AGGBAD,
4037c478bdstevel@tonic-gate		    "undefined aggregation: @%s\n", aid->di_name);
4047c478bdstevel@tonic-gate	}
4057c478bdstevel@tonic-gate
4067c478bdstevel@tonic-gate	ap = dt_stmt_action(dtp, sdp);
4077c478bdstevel@tonic-gate	dt_action_difconst(ap, anp->dn_ident->di_id, DTRACEACT_LIBACT);
4087c478bdstevel@tonic-gate
4097c478bdstevel@tonic-gate	if (denormal) {
4107c478bdstevel@tonic-gate		ap->dtad_arg = DT_ACT_DENORMALIZE;
4117c478bdstevel@tonic-gate		return;
4127c478bdstevel@tonic-gate	}
4137c478bdstevel@tonic-gate
4147c478bdstevel@tonic-gate	ap->dtad_arg = DT_ACT_NORMALIZE;
4157c478bdstevel@tonic-gate
4167c478bdstevel@tonic-gate	assert(normal != NULL);
4177c478bdstevel@tonic-gate	ap = dt_stmt_action(dtp, sdp);
4187c478bdstevel@tonic-gate	dt_cg(yypcb, normal);
4197c478bdstevel@tonic-gate
4207c478bdstevel@tonic-gate	ap->dtad_difo = dt_as(yypcb);
4217c478bdstevel@tonic-gate	ap->dtad_kind = DTRACEACT_LIBACT;
4227c478bdstevel@tonic-gate	ap->dtad_arg = DT_ACT_NORMALIZE;
4237c478bdstevel@tonic-gate}
4247c478bdstevel@tonic-gate
4257c478bdstevel@tonic-gatestatic void
4267c478bdstevel@tonic-gatedt_action_trunc(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
4277c478bdstevel@tonic-gate{
4287c478bdstevel@tonic-gate	dt_ident_t *aid;
4297c478bdstevel@tonic-gate	dtrace_actdesc_t *ap;
4307c478bdstevel@tonic-gate	dt_node_t *anp, *trunc;
4317c478bdstevel@tonic-gate
4327c478bdstevel@tonic-gate	char n[DT_TYPE_NAMELEN];
4337c478bdstevel@tonic-gate	int argc = 0;
4347c478bdstevel@tonic-gate
4357c478bdstevel@tonic-gate	for (anp = dnp->dn_args; anp != NULL; anp = anp->dn_list)
4367c478bdstevel@tonic-gate		argc++; /* count up arguments for error messages below */
4377c478bdstevel@tonic-gate
4387c478bdstevel@tonic-gate	if (argc > 2 || argc < 1) {
4397c478bdstevel@tonic-gate		dnerror(dnp, D_TRUNC_PROTO,
4407c478bdstevel@tonic-gate		    "%s( ) prototype mismatch: %d args passed, %s expected\n",
4417c478bdstevel@tonic-gate		    dnp->dn_ident->di_name, argc,
4427c478bdstevel@tonic-gate		    argc < 1 ? "at least 1" : "no more than 2");
4437c478bdstevel@tonic-gate	}
4447c478bdstevel@tonic-gate
4457c478bdstevel@tonic-gate	anp = dnp->dn_args;
4467c478bdstevel@tonic-gate	assert(anp != NULL);
4477c478bdstevel@tonic-gate	trunc = anp->dn_list;
4487c478bdstevel@tonic-gate
4497c478bdstevel@tonic-gate	if (anp->dn_kind != DT_NODE_AGG) {
4507c478bdstevel@tonic-gate		dnerror(dnp, D_TRUNC_AGGARG,
4517c478bdstevel@tonic-gate		    "%s( ) argument #1 is incompatible with prototype:\n"
4527c478bdstevel@tonic-gate		    "\tprototype: aggregation\n\t argument: %s\n",
4537c478bdstevel@tonic-gate		    dnp->dn_ident->di_name,
4547c478bdstevel@tonic-gate		    dt_node_type_name(anp, n, sizeof (n)));
4557c478bdstevel@tonic-gate	}
4567c478bdstevel@tonic-gate
4577c478bdstevel@tonic-gate	if (argc == 2) {
4587c478bdstevel@tonic-gate		assert(trunc != NULL);
4597c478bdstevel@tonic-gate		if (!dt_node_is_scalar(trunc)) {
4607c478bdstevel@tonic-gate			dnerror(dnp, D_TRUNC_SCALAR,
4617c478bdstevel@tonic-gate			    "%s( ) argument #2 must be of scalar type\n",
4627c478bdstevel@tonic-gate			    dnp->dn_ident->di_name);
4637c478bdstevel@tonic-gate		}
4647c478bdstevel@tonic-gate	}
4657c478bdstevel@tonic-gate
4667c478bdstevel@tonic-gate	aid = anp->dn_ident;
4677c478bdstevel@tonic-gate
4687c478bdstevel@tonic-gate	if (aid->di_gen == dtp->dt_gen && !(aid->di_flags & DT_IDFLG_MOD)) {
4697c478bdstevel@tonic-gate		dnerror(dnp, D_TRUNC_AGGBAD,
4707c478bdstevel@tonic-gate		    "undefined aggregation: @%s\n", aid->di_name);
4717c478bdstevel@tonic-gate	}
4727c478bdstevel@tonic-gate
4737c478bdstevel@tonic-gate	ap = dt_stmt_action(dtp, sdp);
4747c478bdstevel@tonic-gate	dt_action_difconst(ap, anp->dn_ident->di_id, DTRACEACT_LIBACT);
4757c478bdstevel@tonic-gate	ap->dtad_arg = DT_ACT_TRUNC;
4767c478bdstevel@tonic-gate
4777c478bdstevel@tonic-gate	ap = dt_stmt_action(dtp, sdp);
4787c478bdstevel@tonic-gate
4797c478bdstevel@tonic-gate	if (argc == 1) {
4807c478bdstevel@tonic-gate		dt_action_difconst(ap, 0, DTRACEACT_LIBACT);
4817c478bdstevel@tonic-gate	} else {
4827c478bdstevel@tonic-gate		assert(trunc != NULL);
4837c478bdstevel@tonic-gate		dt_cg(yypcb, trunc);
4847c478bdstevel@tonic-gate		ap->dtad_difo = dt_as(yypcb);
4857c478bdstevel@tonic-gate		ap->dtad_kind = DTRACEACT_LIBACT;
4867c478bdstevel@tonic-gate	}
4877c478bdstevel@tonic-gate
4887c478bdstevel@tonic-gate	ap->dtad_arg = DT_ACT_TRUNC;
4897c478bdstevel@tonic-gate}
4907c478bdstevel@tonic-gate
4917c478bdstevel@tonic-gatestatic void
4927c478bdstevel@tonic-gatedt_action_printa(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
4937c478bdstevel@tonic-gate{
4947c478bdstevel@tonic-gate	dt_ident_t *aid, *fid;
4957c478bdstevel@tonic-gate	dtrace_actdesc_t *ap;
4967c478bdstevel@tonic-gate	const char *format;
49730ef842bmc	dt_node_t *anp, *proto = NULL;
4987c478bdstevel@tonic-gate
4997c478bdstevel@tonic-gate	char n[DT_TYPE_NAMELEN];
5007c478bdstevel@tonic-gate	int argc = 0, argr = 0;
5017c478bdstevel@tonic-gate
5027c478bdstevel@tonic-gate	for (anp = dnp->dn_args; anp != NULL; anp = anp->dn_list)
5037c478bdstevel@tonic-gate		argc++; /* count up arguments for error messages below */
5047c478bdstevel@tonic-gate
5057c478bdstevel@tonic-gate	switch (dnp->dn_args->dn_kind) {
5067c478bdstevel@tonic-gate	case DT_NODE_STRING:
5077c478bdstevel@tonic-gate		format = dnp->dn_args->dn_string;
5087c478bdstevel@tonic-gate		anp = dnp->dn_args->dn_list;
5097c478bdstevel@tonic-gate		argr = 2;
5107c478bdstevel@tonic-gate		break;
5117c478bdstevel@tonic-gate	case DT_NODE_AGG:
5127c478bdstevel@tonic-gate		format = NULL;
5137c478bdstevel@tonic-gate		anp = dnp->dn_args;
5147c478bdstevel@tonic-gate		argr = 1;
5157c478bdstevel@tonic-gate		break;
5167c478bdstevel@tonic-gate	default:
5177c478bdstevel@tonic-gate		format = NULL;
5187c478bdstevel@tonic-gate		anp = dnp->dn_args;
5197c478bdstevel@tonic-gate		argr = 1;
5207c478bdstevel@tonic-gate	}
5217c478bdstevel@tonic-gate
52230ef842bmc	if (argc < argr) {
5237c478bdstevel@tonic-gate		dnerror(dnp, D_PRINTA_PROTO,
5247c478bdstevel@tonic-gate		    "%s( ) prototype mismatch: %d args passed, %d expected\n",
5257c478bdstevel@tonic-gate		    dnp->dn_ident->di_name, argc, argr);
5267c478bdstevel@tonic-gate	}
5277c478bdstevel@tonic-gate
52830ef842bmc	assert(anp != NULL);
5297c478bdstevel@tonic-gate
53030ef842bmc	while (anp != NULL) {
53130ef842bmc		if (anp->dn_kind != DT_NODE_AGG) {
53230ef842bmc			dnerror(dnp, D_PRINTA_AGGARG,
53330ef842bmc			    "%s( ) argument #%d is incompatible with "
53430ef842bmc			    "prototype:\n\tprototype: aggregation\n"
53530ef842bmc			    "\t argument: %s\n", dnp->dn_ident->di_name, argr,
53630ef842bmc			    dt_node_type_name(anp, n, sizeof (n)));
53730ef842bmc		}
5387c478bdstevel@tonic-gate
53930ef842bmc		aid = anp->dn_ident;
54030ef842bmc		fid = aid->di_iarg;
5417c478bdstevel@tonic-gate
54230ef842bmc		if (aid->di_gen == dtp->dt_gen &&
54330ef842bmc		    !(aid->di_flags & DT_IDFLG_MOD)) {
54430ef842bmc			dnerror(dnp, D_PRINTA_AGGBAD,
54530ef842bmc			    "undefined aggregation: @%s\n", aid->di_name);
54630ef842bmc		}
5477c478bdstevel@tonic-gate
54830ef842bmc		/*
54930ef842bmc		 * If we have multiple aggregations, we must be sure that
55030ef842bmc		 * their key signatures match.
55130ef842bmc		 */
55230ef842bmc		if (proto != NULL) {
55330ef842bmc			dt_printa_validate(proto, anp);
55430ef842bmc		} else {
55530ef842bmc			proto = anp;
55630ef842bmc		}
5577c478bdstevel@tonic-gate
55830ef842bmc		if (format != NULL) {
55930ef842bmc			yylineno = dnp->dn_line;
56030ef842bmc
56130ef842bmc			sdp->dtsd_fmtdata =
56230ef842bmc			    dt_printf_create(yypcb->pcb_hdl, format);
56330ef842bmc			dt_printf_validate(sdp->dtsd_fmtdata,
56430ef842bmc			    DT_PRINTF_AGGREGATION, dnp->dn_ident, 1,
56530ef842bmc			    fid->di_id, ((dt_idsig_t *)aid->di_data)->dis_args);
56630ef842bmc			format = NULL;
56730ef842bmc		}
56830ef842bmc
56930ef842bmc		ap = dt_stmt_action(dtp, sdp);
57030ef842bmc		dt_action_difconst(ap, anp->dn_ident->di_id, DTRACEACT_PRINTA);
57130ef842bmc
57230ef842bmc		anp = anp->dn_list;
57330ef842bmc		argr++;
57430ef842bmc	}
5757c478bdstevel@tonic-gate}
5767c478bdstevel@tonic-gate
5777c478bdstevel@tonic-gatestatic void
5787c478bdstevel@tonic-gatedt_action_printflike(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp,
5797c478bdstevel@tonic-gate    dtrace_actkind_t kind)
5807c478bdstevel@tonic-gate{
5817c478bdstevel@tonic-gate	dt_node_t *anp, *arg1;
5827c478bdstevel@tonic-gate	dtrace_actdesc_t *ap = NULL;
5837c478bdstevel@tonic-gate	char n[DT_TYPE_NAMELEN], *str;
5847c478bdstevel@tonic-gate
5857c478bdstevel@tonic-gate	assert(DTRACEACT_ISPRINTFLIKE(kind));
5867c478bdstevel@tonic-gate
5877c478bdstevel@tonic-gate	if (dnp->dn_args->dn_kind != DT_NODE_STRING) {
5887c478bdstevel@tonic-gate		dnerror(dnp, D_PRINTF_ARG_FMT,
5897c478bdstevel@tonic-gate		    "%s( ) argument #1 is incompatible with prototype:\n"
5907c478bdstevel@tonic-gate		    "\tprototype: string constant\n\t argument: %s\n",
5917c478bdstevel@tonic-gate		    dnp->dn_ident->di_name,
5927c478bdstevel@tonic-gate		    dt_node_type_name(dnp->dn_args, n, sizeof (n)));
5937c478bdstevel@tonic-gate	}
5947c478bdstevel@tonic-gate
5957c478bdstevel@tonic-gate	arg1 = dnp->dn_args->dn_list;
5967c478bdstevel@tonic-gate	yylineno = dnp->dn_line;
5977c478bdstevel@tonic-gate	str = dnp->dn_args->dn_string;
5987c478bdstevel@tonic-gate
5997c478bdstevel@tonic-gate
6007c478bdstevel@tonic-gate	/*
6017c478bdstevel@tonic-gate	 * If this is an freopen(), we use an empty string to denote that
6027c478bdstevel@tonic-gate	 * stdout should be restored.  For other printf()-like actions, an
6037c478bdstevel@tonic-gate	 * empty format string is illegal:  an empty format string would
6047c478bdstevel@tonic-gate	 * result in malformed DOF, and the compiler thus flags an empty
6057c478bdstevel@tonic-gate	 * format string as a compile-time error.  To avoid propagating the
6067c478bdstevel@tonic-gate	 * freopen() special case throughout the system, we simply transpose
6077c478bdstevel@tonic-gate	 * an empty string into a sentinel string (DT_FREOPEN_RESTORE) that
6087c478bdstevel@tonic-gate	 * denotes that stdout should be restored.
6097c478bdstevel@tonic-gate	 */
6107c478bdstevel@tonic-gate	if (kind == DTRACEACT_FREOPEN) {
6117c478bdstevel@tonic-gate		if (strcmp(str, DT_FREOPEN_RESTORE) == 0) {
6127c478bdstevel@tonic-gate			/*
6137c478bdstevel@tonic-gate			 * Our sentinel is always an invalid argument to
6147c478bdstevel@tonic-gate			 * freopen(), but if it's been manually specified, we
6157c478bdstevel@tonic-gate			 * must fail now instead of when the freopen() is
6167c478bdstevel@tonic-gate			 * actually evaluated.
6177c478bdstevel@tonic-gate			 */
6187c478bdstevel@tonic-gate			dnerror(dnp, D_FREOPEN_INVALID,
6197c478bdstevel@tonic-gate			    "%s( ) argument #1 cannot be \"%s\"\n",
6207c478bdstevel@tonic-gate			    dnp->dn_ident->di_name, DT_FREOPEN_RESTORE);
6217c478bdstevel@tonic-gate		}
6227c478bdstevel@tonic-gate
6237c478bdstevel@tonic-gate		if (str[0] == '\0')
6247c478bdstevel@tonic-gate			str = DT_FREOPEN_RESTORE;
6257c478bdstevel@tonic-gate	}
6267c478bdstevel@tonic-gate
6271a7c1b7mws	sdp->dtsd_fmtdata = dt_printf_create(dtp, str);
6287c478bdstevel@tonic-gate
6297c478bdstevel@tonic-gate	dt_printf_validate(sdp->dtsd_fmtdata, DT_PRINTF_EXACTLEN,
6307c478bdstevel@tonic-gate	    dnp->dn_ident, 1, DTRACEACT_AGGREGATION, arg1);
6317c478bdstevel@tonic-gate
6327c478bdstevel@tonic-gate	if (arg1 == NULL) {
6337c478bdstevel@tonic-gate		dif_instr_t *dbuf;
6347c478bdstevel@tonic-gate		dtrace_difo_t *dp;
6357c478bdstevel@tonic-gate
6361a7c1b7mws		if ((dbuf = dt_alloc(dtp, sizeof (dif_instr_t))) == NULL ||
6371a7c1b7mws		    (dp = dt_zalloc(dtp, sizeof (dtrace_difo_t))) == NULL) {
6381a7c1b7mws			dt_free(dtp, dbuf);
6397c478bdstevel@tonic-gate			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
6407c478bdstevel@tonic-gate		}
6417c478bdstevel@tonic-gate
6427c478bdstevel@tonic-gate		dbuf[0] = DIF_INSTR_RET(DIF_REG_R0); /* ret %r0 */
6437c478bdstevel@tonic-gate
6447c478bdstevel@tonic-gate		dp->dtdo_buf = dbuf;
6457c478bdstevel@tonic-gate		dp->dtdo_len = 1;
6467c478bdstevel@tonic-gate		dp->dtdo_rtype = dt_int_rtype;
6477c478bdstevel@tonic-gate
6487c478bdstevel@tonic-gate		ap = dt_stmt_action(dtp, sdp);
6497c478bdstevel@tonic-gate		ap->dtad_difo = dp;
6507c478bdstevel@tonic-gate		ap->dtad_kind = kind;
6517c478bdstevel@tonic-gate		return;
6527c478bdstevel@tonic-gate	}
6537c478bdstevel@tonic-gate
6547c478bdstevel@tonic-gate	for (anp = arg1; anp != NULL; anp = anp->dn_list) {
6557c478bdstevel@tonic-gate		ap = dt_stmt_action(dtp, sdp);
6567c478bdstevel@tonic-gate		dt_cg(yypcb, anp);
6577c478bdstevel@tonic-gate		ap->dtad_difo = dt_as(yypcb);
6587c478bdstevel@tonic-gate		ap->dtad_kind = kind;
6597c478bdstevel@tonic-gate	}
6607c478bdstevel@tonic-gate}
6617c478bdstevel@tonic-gate
6627c478bdstevel@tonic-gatestatic void
6637c478bdstevel@tonic-gatedt_action_trace(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
6647c478bdstevel@tonic-gate{
665a386cc1Robert Mustacchi	int ctflib;
666a386cc1Robert Mustacchi
6677c478bdstevel@tonic-gate	dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
668e5803b7Adam H. Leventhal	boolean_t istrace = (dnp->dn_ident->di_id == DT_ACT_TRACE);
669e5803b7Adam H. Leventhal	const char *act = istrace ?  "trace" : "print";
6707c478bdstevel@tonic-gate
6717c478bdstevel@tonic-gate	if (dt_node_is_void(dnp->dn_args)) {
672e5803b7Adam H. Leventhal		dnerror(dnp->dn_args, istrace ? D_TRACE_VOID : D_PRINT_VOID,
673e5803b7Adam H. Leventhal		    "%s( ) may not be applied to a void expression\n", act);
6747c478bdstevel@tonic-gate	}
6757c478bdstevel@tonic-gate
676e5803b7Adam H. Leventhal	if (dt_node_resolve(dnp->dn_args, DT_IDENT_XLPTR) != NULL) {
677e5803b7Adam H. Leventhal		dnerror(dnp->dn_args, istrace ? D_TRACE_DYN : D_PRINT_DYN,
678e5803b7Adam H. Leventhal		    "%s( ) may not be applied to a translated pointer\n", act);
6797c478bdstevel@tonic-gate	}
6807c478bdstevel@tonic-gate
681e98f46cAdam Leventhal	if (dnp->dn_args->dn_kind == DT_NODE_AGG) {
682e98f46cAdam Leventhal		dnerror(dnp->dn_args, istrace ? D_TRACE_AGG : D_PRINT_AGG,
683e98f46cAdam Leventhal		    "%s( ) may not be applied to an aggregation%s\n", act,
684e98f46cAdam Leventhal		    istrace ? "" : " -- did you mean printa()?");
685e98f46cAdam Leventhal	}
686e98f46cAdam Leventhal
6877c478bdstevel@tonic-gate	dt_cg(yypcb, dnp->dn_args);
6887c478bdstevel@tonic-gate
689e5803b7Adam H. Leventhal	/*
690e5803b7Adam H. Leventhal	 * The print() action behaves identically to trace(), except that it
691e5803b7Adam H. Leventhal	 * stores the CTF type of the argument (if present) within the DOF for
692e5803b7Adam H. Leventhal	 * the DIFEXPR action.  To do this, we set the 'dtsd_strdata' to point
693e5803b7Adam H. Leventhal	 * to the fully-qualified CTF type ID for the result of the DIF
694e5803b7Adam H. Leventhal	 * action.  We use the ID instead of the name to handles complex types
695e5803b7Adam H. Leventhal	 * like arrays and function pointers that can't be resolved by
696e5803b7Adam H. Leventhal	 * ctf_type_lookup().  This is later processed by dtrace_dof_create()
697e5803b7Adam H. Leventhal	 * and turned into a reference into the string table so that we can
698a386cc1Robert Mustacchi	 * get the type information when we process the data after the fact.  In
699a386cc1Robert Mustacchi	 * the case where we are referring to userland CTF data, we also need to
700a386cc1Robert Mustacchi	 * to identify which ctf container in question we care about and encode
701a386cc1Robert Mustacchi	 * that within the name.
702e5803b7Adam H. Leventhal	 */
703e5803b7Adam H. Leventhal	if (dnp->dn_ident->di_id == DT_ACT_PRINT) {
704e5803b7Adam H. Leventhal		dt_node_t *dret;
705e5803b7Adam H. Leventhal		size_t n;
706e5803b7Adam H. Leventhal		dt_module_t *dmp;
707deef35fEric Schrock
708e5803b7Adam H. Leventhal		dret = yypcb->pcb_dret;
709e5803b7Adam H. Leventhal		dmp = dt_module_lookup_by_ctf(dtp, dret->dn_ctfp);
710deef35fEric Schrock
711a386cc1Robert Mustacchi		if (dmp->dm_pid != 0) {
712a386cc1Robert Mustacchi			ctflib = dt_module_getlibid(dtp, dmp, dret->dn_ctfp);
713a386cc1Robert Mustacchi			assert(ctflib >= 0);
714a386cc1Robert Mustacchi			n = snprintf(NULL, 0, "%s`%d`%d", dmp->dm_name,
715a386cc1Robert Mustacchi			    ctflib, dret->dn_type) + 1;
716a386cc1Robert Mustacchi		} else {
717a386cc1Robert Mustacchi			n = snprintf(NULL, 0, "%s`%d", dmp->dm_name,
718a386cc1Robert Mustacchi			    dret->dn_type) + 1;
719a386cc1Robert Mustacchi		}
720e5803b7Adam H. Leventhal		sdp->dtsd_strdata = dt_alloc(dtp, n);
721e5803b7Adam H. Leventhal		if (sdp->dtsd_strdata == NULL)
722e5803b7Adam H. Leventhal			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
723a386cc1Robert Mustacchi		if (dmp->dm_pid != 0) {
724a386cc1Robert Mustacchi			(void) snprintf(sdp->dtsd_strdata, n, "%s`%d`%d",
725a386cc1Robert Mustacchi			    dmp->dm_name, ctflib, dret->dn_type);
726a386cc1Robert Mustacchi		} else {
727a386cc1Robert Mustacchi			(void) snprintf(sdp->dtsd_strdata, n, "%s`%d",
728a386cc1Robert Mustacchi			    dmp->dm_name, dret->dn_type);
729a386cc1Robert Mustacchi		}
730deef35fEric Schrock	}
731deef35fEric Schrock
732deef35fEric Schrock	ap->dtad_difo = dt_as(yypcb);
733deef35fEric Schrock	ap->dtad_kind = DTRACEACT_DIFEXPR;
734deef35fEric Schrock}
735deef35fEric Schrock
7367c478bdstevel@tonic-gatestatic void
7377c478bdstevel@tonic-gatedt_action_tracemem(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
7387c478bdstevel@tonic-gate{
7397c478bdstevel@tonic-gate	dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
7407c478bdstevel@tonic-gate
7417c478bdstevel@tonic-gate	dt_node_t *addr = dnp->dn_args;
7421ea5f93Bryan Cantrill	dt_node_t *max = dnp->dn_args->dn_list;
7431ea5f93Bryan Cantrill	dt_node_t *size;
7447c478bdstevel@tonic-gate
7457c478bdstevel@tonic-gate	char n[DT_TYPE_NAMELEN];
7467c478bdstevel@tonic-gate
7477c478bdstevel@tonic-gate	if (dt_node_is_integer(addr) == 0 && dt_node_is_pointer(addr) == 0) {
7487c478bdstevel@tonic-gate		dnerror(addr, D_TRACEMEM_ADDR,
7497c478bdstevel@tonic-gate		    "tracemem( ) argument #1 is incompatible with "
7507c478bdstevel@tonic-gate		    "prototype:\n\tprototype: pointer or integer\n"
7517c478bdstevel@tonic-gate		    "\t argument: %s\n",
7527c478bdstevel@tonic-gate		    dt_node_type_name(addr, n, sizeof (n)));
7537c478bdstevel@tonic-gate	}
7547c478bdstevel@tonic-gate
7551ea5f93Bryan Cantrill	if (dt_node_is_posconst(max) == 0) {
7561ea5f93Bryan Cantrill		dnerror(max, D_TRACEMEM_SIZE, "tracemem( ) argument #2 must "
7577c478bdstevel@tonic-gate		    "be a non-zero positive integral constant expression\n");
7587c478bdstevel@tonic-gate	}
7597c478bdstevel@tonic-gate
7601ea5f93Bryan Cantrill	if ((size = max->dn_list) != NULL) {
7611ea5f93Bryan Cantrill		if (size->dn_list != NULL) {
7621ea5f93Bryan Cantrill			dnerror(size, D_TRACEMEM_ARGS, "tracemem ( ) prototype "
7631ea5f93Bryan Cantrill			    "mismatch: expected at most 3 args\n");
7641ea5f93Bryan Cantrill		}
7651ea5f93Bryan Cantrill
7661ea5f93Bryan Cantrill		if (!dt_node_is_scalar(size)) {
7671ea5f93Bryan Cantrill			dnerror(size, D_TRACEMEM_DYNSIZE, "tracemem ( ) "
7681ea5f93Bryan Cantrill			    "dynamic size (argument #3) must be of "
7691ea5f93Bryan Cantrill			    "scalar type\n");
7701ea5f93Bryan Cantrill		}
7711ea5f93Bryan Cantrill
7721ea5f93Bryan Cantrill		dt_cg(yypcb, size);
7731ea5f93Bryan Cantrill		ap->dtad_difo = dt_as(yypcb);
7741ea5f93Bryan Cantrill		ap->dtad_difo->dtdo_rtype = dt_int_rtype;
7751ea5f93Bryan Cantrill		ap->dtad_kind = DTRACEACT_TRACEMEM_DYNSIZE;
7761ea5f93Bryan Cantrill
7771ea5f93Bryan Cantrill		ap = dt_stmt_action(dtp, sdp);
7781ea5f93Bryan Cantrill	}
7791ea5f93Bryan Cantrill
7807c478bdstevel@tonic-gate	dt_cg(yypcb, addr);
7817c478bdstevel@tonic-gate	ap->dtad_difo = dt_as(yypcb);
7821ea5f93Bryan Cantrill	ap->dtad_kind = DTRACEACT_TRACEMEM;
7837c478bdstevel@tonic-gate
7847c478bdstevel@tonic-gate	ap->dtad_difo->dtdo_rtype.dtdt_flags |= DIF_TF_BYREF;
7851ea5f93Bryan Cantrill	ap->dtad_difo->dtdo_rtype.dtdt_size = max->dn_value;
7867c478bdstevel@tonic-gate}
7877c478bdstevel@tonic-gate
7887c478bdstevel@tonic-gatestatic void
7897c478bdstevel@tonic-gatedt_action_stack_args(dtrace_hdl_t *dtp, dtrace_actdesc_t *ap, dt_node_t *arg0)
7907c478bdstevel@tonic-gate{
7917c478bdstevel@tonic-gate	ap->dtad_kind = DTRACEACT_STACK;
7927c478bdstevel@tonic-gate
7937c478bdstevel@tonic-gate	if (dtp->dt_options[DTRACEOPT_STACKFRAMES] != DTRACEOPT_UNSET) {
7947c478bdstevel@tonic-gate		ap->dtad_arg = dtp->dt_options[DTRACEOPT_STACKFRAMES];
7957c478bdstevel@tonic-gate	} else {
7967c478bdstevel@tonic-gate		ap->dtad_arg = 0;
7977c478bdstevel@tonic-gate	}
7987c478bdstevel@tonic-gate
7997c478bdstevel@tonic-gate	if (arg0 != NULL) {
8007c478bdstevel@tonic-gate		if (arg0->dn_list != NULL) {
8017c478bdstevel@tonic-gate			dnerror(arg0, D_STACK_PROTO, "stack( ) prototype "
8027c478bdstevel@tonic-gate			    "mismatch: too many arguments\n");
8037c478bdstevel@tonic-gate		}
8047c478bdstevel@tonic-gate
8057c478bdstevel@tonic-gate		if (dt_node_is_posconst(arg0) == 0) {
8067c478bdstevel@tonic-gate			dnerror(arg0, D_STACK_SIZE, "stack( ) size must be a "
8077c478bdstevel@tonic-gate			    "non-zero positive integral constant expression\n");
8087c478bdstevel@tonic-gate		}
8097c478bdstevel@tonic-gate
8107c478bdstevel@tonic-gate		ap->dtad_arg = arg0->dn_value;
8117c478bdstevel@tonic-gate	}
8127c478bdstevel@tonic-gate}
8137c478bdstevel@tonic-gate
8147c478bdstevel@tonic-gatestatic void
8157c478bdstevel@tonic-gatedt_action_stack(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
8167c478bdstevel@tonic-gate{
8177c478bdstevel@tonic-gate	dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
8187c478bdstevel@tonic-gate	dt_action_stack_args(dtp, ap, dnp->dn_args);
8197c478bdstevel@tonic-gate}
8207c478bdstevel@tonic-gate
8217c478bdstevel@tonic-gatestatic void
8227c478bdstevel@tonic-gatedt_action_ustack_args(dtrace_hdl_t *dtp, dtrace_actdesc_t *ap, dt_node_t *dnp)
8237c478bdstevel@tonic-gate{
8247c478bdstevel@tonic-gate	uint32_t nframes = 0;
8257c478bdstevel@tonic-gate	uint32_t strsize = 0;	/* default string table size */
8267c478bdstevel@tonic-gate	dt_node_t *arg0 = dnp->dn_args;
8277c478bdstevel@tonic-gate	dt_node_t *arg1 = arg0 != NULL ? arg0->dn_list : NULL;
8287c478bdstevel@tonic-gate
8297c478bdstevel@tonic-gate	assert(dnp->dn_ident->di_id == DT_ACT_JSTACK ||
8307c478bdstevel@tonic-gate	    dnp->dn_ident->di_id == DT_ACT_USTACK);
8317c478bdstevel@tonic-gate
8327c478bdstevel@tonic-gate	if (dnp->dn_ident->di_id == DT_ACT_JSTACK) {
8337c478bdstevel@tonic-gate		if (dtp->dt_options[DTRACEOPT_JSTACKFRAMES] != DTRACEOPT_UNSET)
8347c478bdstevel@tonic-gate			nframes = dtp->dt_options[DTRACEOPT_JSTACKFRAMES];
8357c478bdstevel@tonic-gate
8367c478bdstevel@tonic-gate		if (dtp->dt_options[DTRACEOPT_JSTACKSTRSIZE] != DTRACEOPT_UNSET)
8377c478bdstevel@tonic-gate			strsize = dtp->dt_options[DTRACEOPT_JSTACKSTRSIZE];
8387c478bdstevel@tonic-gate
8397c478bdstevel@tonic-gate		ap->dtad_kind = DTRACEACT_JSTACK;
8407c478bdstevel@tonic-gate	} else {
8417c478bdstevel@tonic-gate		assert(dnp->dn_ident->di_id == DT_ACT_USTACK);
8427c478bdstevel@tonic-gate
8437c478bdstevel@tonic-gate		if (dtp->dt_options[DTRACEOPT_USTACKFRAMES] != DTRACEOPT_UNSET)
8447c478bdstevel@tonic-gate			nframes = dtp->dt_options[DTRACEOPT_USTACKFRAMES];
8457c478bdstevel@tonic-gate
8467c478bdstevel@tonic-gate		ap->dtad_kind = DTRACEACT_USTACK;
8477c478bdstevel@tonic-gate	}
8487c478bdstevel@tonic-gate
8497c478bdstevel@tonic-gate	if (arg0 != NULL) {
8507c478bdstevel@tonic-gate		if (!dt_node_is_posconst(arg0)) {
8517c478bdstevel@tonic-gate			dnerror(arg0, D_USTACK_FRAMES, "ustack( ) argument #1 "
8527c478bdstevel@tonic-gate			    "must be a non-zero positive integer constant\n");
8537c478bdstevel@tonic-gate		}
8547c478bdstevel@tonic-gate		nframes = (uint32_t)arg0->dn_value;
8557c478bdstevel@tonic-gate	}
8567c478bdstevel@tonic-gate
8577c478bdstevel@tonic-gate	if (arg1 != NULL) {
8587c478bdstevel@tonic-gate		if (arg1->dn_kind != DT_NODE_INT ||
8597c478bdstevel@tonic-gate		    ((arg1->dn_flags & DT_NF_SIGNED) &&
8607c478bdstevel@tonic-gate		    (int64_t)arg1->dn_value < 0)) {
8617c478bdstevel@tonic-gate			dnerror(arg1, D_USTACK_STRSIZE, "ustack( ) argument #2 "
8627c478bdstevel@tonic-gate			    "must be a positive integer constant\n");
8637c478bdstevel@tonic-gate		}
8647c478bdstevel@tonic-gate
8657c478bdstevel@tonic-gate		if (arg1->dn_list != NULL) {
8667c478bdstevel@tonic-gate			dnerror(arg1, D_USTACK_PROTO, "ustack( ) prototype "
8677c478bdstevel@tonic-gate			    "mismatch: too many arguments\n");
8687c478bdstevel@tonic-gate		}
8697c478bdstevel@tonic-gate
8707c478bdstevel@tonic-gate		strsize = (uint32_t)arg1->dn_value;
8717c478bdstevel@tonic-gate	}
8727c478bdstevel@tonic-gate
8737c478bdstevel@tonic-gate	ap->dtad_arg = DTRACE_USTACK_ARG(nframes, strsize);
8747c478bdstevel@tonic-gate}
8757c478bdstevel@tonic-gate
8767c478bdstevel@tonic-gatestatic void
8777c478bdstevel@tonic-gatedt_action_ustack(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
8787c478bdstevel@tonic-gate{
8797c478bdstevel@tonic-gate	dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
8807c478bdstevel@tonic-gate	dt_action_ustack_args(dtp, ap, dnp);
8817c478bdstevel@tonic-gate}
8827c478bdstevel@tonic-gate
883a1b5e53bmcstatic void
884a1b5e53bmcdt_action_setopt(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
885a1b5e53bmc{
886a1b5e53bmc	dtrace_actdesc_t *ap;
887a1b5e53bmc	dt_node_t *arg0, *arg1;
888a1b5e53bmc
889a1b5e53bmc	/*
890a1b5e53bmc	 * The prototype guarantees that we are called with either one or
891a1b5e53bmc	 * two arguments, and that any arguments that are present are strings.
892a1b5e53bmc	 */
893a1b5e53bmc	arg0 = dnp->dn_args;
894a1b5e53bmc	arg1 = arg0->dn_list;
895a1b5e53bmc
896a1b5e53bmc	ap = dt_stmt_action(dtp, sdp);
897a1b5e53bmc	dt_cg(yypcb, arg0);
898a1b5e53bmc	ap->dtad_difo = dt_as(yypcb);
899a1b5e53bmc	ap->dtad_kind = DTRACEACT_LIBACT;
900a1b5e53bmc	ap->dtad_arg = DT_ACT_SETOPT;
901a1b5e53bmc
902a1b5e53bmc	ap = dt_stmt_action(dtp, sdp);
903a1b5e53bmc
904a1b5e53bmc	if (arg1 == NULL) {
905a1b5e53bmc		dt_action_difconst(ap, 0, DTRACEACT_LIBACT);
906a1b5e53bmc	} else {
907a1b5e53bmc		dt_cg(yypcb, arg1);
908a1b5e53bmc		ap->dtad_difo = dt_as(yypcb);
909a1b5e53bmc		ap->dtad_kind = DTRACEACT_LIBACT;
910a1b5e53bmc	}
911a1b5e53bmc
912a1b5e53bmc	ap->dtad_arg = DT_ACT_SETOPT;
913a1b5e53bmc}
914a1b5e53bmc
915a1b5e53bmc/*ARGSUSED*/
916a1b5e53bmcstatic void
917a1b5e53bmcdt_action_symmod_args(dtrace_hdl_t *dtp, dtrace_actdesc_t *ap,
918a1b5e53bmc    dt_node_t *dnp, dtrace_actkind_t kind)
919a1b5e53bmc{
920a1b5e53bmc	assert(kind == DTRACEACT_SYM || kind == DTRACEACT_MOD ||
921a1b5e53bmc	    kind == DTRACEACT_USYM || kind == DTRACEACT_UMOD ||
922a1b5e53bmc	    kind == DTRACEACT_UADDR);
923a1b5e53bmc
924a1b5e53bmc	dt_cg(yypcb, dnp);
925a1b5e53bmc	ap->dtad_difo = dt_as(yypcb);
926a1b5e53bmc	ap->dtad_kind = kind;
927a1b5e53bmc	ap->dtad_difo->dtdo_rtype.dtdt_size = sizeof (uint64_t);
928a1b5e53bmc}
929a1b5e53bmc
930a1b5e53bmcstatic void
931a1b5e53bmcdt_action_symmod(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp,
932a1b5e53bmc    dtrace_actkind_t kind)
933a1b5e53bmc{
934a1b5e53bmc	dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
935a1b5e53bmc	dt_action_symmod_args(dtp, ap, dnp->dn_args, kind);
936a1b5e53bmc}
937a1b5e53bmc
9387c478bdstevel@tonic-gate/*ARGSUSED*/
9397c478bdstevel@tonic-gatestatic void
9407c478bdstevel@tonic-gatedt_action_ftruncate(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
9417c478bdstevel@tonic-gate{
9427c478bdstevel@tonic-gate	dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
9437c478bdstevel@tonic-gate
9447c478bdstevel@tonic-gate	/*
9457c478bdstevel@tonic-gate	 * Library actions need a DIFO that serves as an argument.  As
9467c478bdstevel@tonic-gate	 * ftruncate() doesn't take an argument, we generate the constant 0
9477c478bdstevel@tonic-gate	 * in a DIFO; this constant will be ignored when the ftruncate() is
9487c478bdstevel@tonic-gate	 * processed.
9497c478bdstevel@tonic-gate	 */
9507c478bdstevel@tonic-gate	dt_action_difconst(ap, 0, DTRACEACT_LIBACT);
9517c478bdstevel@tonic-gate	ap->dtad_arg = DT_ACT_FTRUNCATE;
9527c478bdstevel@tonic-gate}
9537c478bdstevel@tonic-gate
9547c478bdstevel@tonic-gate/*ARGSUSED*/
9557c478bdstevel@tonic-gatestatic void
9567c478bdstevel@tonic-gatedt_action_stop(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
9577c478bdstevel@tonic-gate{
9587c478bdstevel@tonic-gate	dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
9597c478bdstevel@tonic-gate
9607c478bdstevel@tonic-gate	ap->dtad_kind = DTRACEACT_STOP;
9617c478bdstevel@tonic-gate	ap->dtad_arg = 0;
9627c478bdstevel@tonic-gate}
9637c478bdstevel@tonic-gate
9647c478bdstevel@tonic-gate/*ARGSUSED*/
9657c478bdstevel@tonic-gatestatic void
9667c478bdstevel@tonic-gatedt_action_breakpoint(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
9677c478bdstevel@tonic-gate{
9687c478bdstevel@tonic-gate	dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
9697c478bdstevel@tonic-gate
9707c478bdstevel@tonic-gate	ap->dtad_kind = DTRACEACT_BREAKPOINT;
9717c478bdstevel@tonic-gate	ap->dtad_arg = 0;
9727c478bdstevel@tonic-gate}
9737c478bdstevel@tonic-gate
9747c478bdstevel@tonic-gate/*ARGSUSED*/
9757c478bdstevel@tonic-gatestatic void
9767c478bdstevel@tonic-gatedt_action_panic(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
9777c478bdstevel@tonic-gate{
9787c478bdstevel@tonic-gate	dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
9797c478bdstevel@tonic-gate
9807c478bdstevel@tonic-gate	ap->dtad_kind = DTRACEACT_PANIC;
9817c478bdstevel@tonic-gate	ap->dtad_arg = 0;
9827c478bdstevel@tonic-gate}
9837c478bdstevel@tonic-gate
9847c478bdstevel@tonic-gatestatic void
9857c478bdstevel@tonic-gatedt_action_chill(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
9867c478bdstevel@tonic-gate{
9877c478bdstevel@tonic-gate	dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
9887c478bdstevel@tonic-gate
9897c478bdstevel@tonic-gate	dt_cg(yypcb, dnp->dn_args);
9907c478bdstevel@tonic-gate	ap->dtad_difo = dt_as(yypcb);
9917c478bdstevel@tonic-gate	ap->dtad_kind = DTRACEACT_CHILL;
9927c478bdstevel@tonic-gate}
9937c478bdstevel@tonic-gate
9947c478bdstevel@tonic-gatestatic void
9957c478bdstevel@tonic-gatedt_action_raise(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
9967c478bdstevel@tonic-gate{
9977c478bdstevel@tonic-gate	dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
9987c478bdstevel@tonic-gate
9997c478bdstevel@tonic-gate	dt_cg(yypcb, dnp->dn_args);
10007c478bdstevel@tonic-gate	ap->dtad_difo = dt_as(yypcb);
10017c478bdstevel@tonic-gate	ap->dtad_kind = DTRACEACT_RAISE;
10027c478bdstevel@tonic-gate}
10037c478bdstevel@tonic-gate
10047c478bdstevel@tonic-gatestatic void
10057c478bdstevel@tonic-gatedt_action_exit(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
10067c478bdstevel@tonic-gate{
10077c478bdstevel@tonic-gate	dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
10087c478bdstevel@tonic-gate
10097c478bdstevel@tonic-gate	dt_cg(yypcb, dnp->dn_args);
10107c478bdstevel@tonic-gate	ap->dtad_difo = dt_as(yypcb);
10117c478bdstevel@tonic-gate	ap->dtad_kind = DTRACEACT_EXIT;
10127c478bdstevel@tonic-gate	ap->dtad_difo->dtdo_rtype.dtdt_size = sizeof (int);
10137c478bdstevel@tonic-gate}
10147c478bdstevel@tonic-gate
10157c478bdstevel@tonic-gatestatic void
10167c478bdstevel@tonic-gatedt_action_speculate(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
10177c478bdstevel@tonic-gate{
10187c478bdstevel@tonic-gate	dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
10197c478bdstevel@tonic-gate
10207c478bdstevel@tonic-gate	dt_cg(yypcb, dnp->dn_args);
10217c478bdstevel@tonic-gate	ap->dtad_difo = dt_as(yypcb);
10227c478bdstevel@tonic-gate	ap->dtad_kind = DTRACEACT_SPECULATE;
10237c478bdstevel@tonic-gate}
10247c478bdstevel@tonic-gate
10257c478bdstevel@tonic-gatestatic void
10267c478bdstevel@tonic-gatedt_action_commit(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
10277c478bdstevel@tonic-gate{
10287c478bdstevel@tonic-gate	dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
10297c478bdstevel@tonic-gate
10307c478bdstevel@tonic-gate	dt_cg(yypcb, dnp->dn_args);
10317c478bdstevel@tonic-gate	ap->dtad_difo = dt_as(yypcb);
10327c478bdstevel@tonic-gate	ap->dtad_kind = DTRACEACT_COMMIT;
10337c478bdstevel@tonic-gate}
10347c478bdstevel@tonic-gate
10357c478bdstevel@tonic-gatestatic void
10367c478bdstevel@tonic-gatedt_action_discard(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
10377c478bdstevel@tonic-gate{
10387c478bdstevel@tonic-gate	dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
10397c478bdstevel@tonic-gate
10407c478bdstevel@tonic-gate	dt_cg(yypcb, dnp->dn_args);
10417c478bdstevel@tonic-gate	ap->dtad_difo = dt_as(yypcb);
10427c478bdstevel@tonic-gate	ap->dtad_kind = DTRACEACT_DISCARD;
10437c478bdstevel@tonic-gate}
10447c478bdstevel@tonic-gate
10457c478bdstevel@tonic-gatestatic void
10467c478bdstevel@tonic-gatedt_compile_fun(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
10477c478bdstevel@tonic-gate{
10487c478bdstevel@tonic-gate	switch (dnp->dn_expr->dn_ident->di_id) {
10497c478bdstevel@tonic-gate	case DT_ACT_BREAKPOINT:
10507c478bdstevel@tonic-gate		dt_action_breakpoint(dtp, dnp->dn_expr, sdp);
10517c478bdstevel@tonic-gate		break;
10527c478bdstevel@tonic-gate	case DT_ACT_CHILL:
10537c478bdstevel@tonic-gate		dt_action_chill(dtp, dnp->dn_expr, sdp);
10547c478bdstevel@tonic-gate		break;
10557c478bdstevel@tonic-gate	case DT_ACT_CLEAR:
10567c478bdstevel@tonic-gate		dt_action_clear(dtp, dnp->dn_expr, sdp);
10577c478bdstevel@tonic-gate		break;
10587c478bdstevel@tonic-gate	case DT_ACT_COMMIT:
10597c478bdstevel@tonic-gate		dt_action_commit(dtp, dnp->dn_expr, sdp);
10607c478bdstevel@tonic-gate		break;
10617c478bdstevel@tonic-gate	case DT_ACT_DENORMALIZE:
10627c478bdstevel@tonic-gate		dt_action_normalize(dtp, dnp->dn_expr, sdp);
10637c478bdstevel@tonic-gate		break;
10647c478bdstevel@tonic-gate	case DT_ACT_DISCARD:
10657c478bdstevel@tonic-gate		dt_action_discard(dtp, dnp->dn_expr, sdp);
10667c478bdstevel@tonic-gate		break;
10677c478bdstevel@tonic-gate	case DT_ACT_EXIT:
10687c478bdstevel@tonic-gate		dt_action_exit(dtp, dnp->dn_expr, sdp);
10697c478bdstevel@tonic-gate		break;
10707c478bdstevel@tonic-gate	case DT_ACT_FREOPEN:
10717c478bdstevel@tonic-gate		dt_action_printflike(dtp, dnp->dn_expr, sdp, DTRACEACT_FREOPEN);
10727c478bdstevel@tonic-gate		break;
10737c478bdstevel@tonic-gate	case DT_ACT_FTRUNCATE:
10747c478bdstevel@tonic-gate		dt_action_ftruncate(dtp, dnp->dn_expr, sdp);
10757c478bdstevel@tonic-gate		break;
1076a1b5e53bmc	case DT_ACT_MOD:
1077a1b5e53bmc		dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_MOD);
1078a1b5e53bmc		break;
10797c478bdstevel@tonic-gate	case DT_ACT_NORMALIZE:
10807c478bdstevel@tonic-gate		dt_action_normalize(dtp, dnp->dn_expr, sdp);
10817c478bdstevel@tonic-gate		break;
10827c478bdstevel@tonic-gate	case DT_ACT_PANIC:
10837c478bdstevel@tonic-gate		dt_action_panic(dtp, dnp->dn_expr, sdp);
10847c478bdstevel@tonic-gate		break;
1085e5803b7Adam H. Leventhal	case DT_ACT_PRINT:
1086e5803b7Adam H. Leventhal		dt_action_trace(dtp, dnp->dn_expr, sdp);
1087e5803b7Adam H. Leventhal		break;
10887c478bdstevel@tonic-gate	case DT_ACT_PRINTA:
10897c478bdstevel@tonic-gate		dt_action_printa(dtp, dnp->dn_expr, sdp);
10907c478bdstevel@tonic-gate		break;
10917c478bdstevel@tonic-gate	case DT_ACT_PRINTF:
10927c478bdstevel@tonic-gate		dt_action_printflike(dtp, dnp->dn_expr, sdp, DTRACEACT_PRINTF);
10937c478bdstevel@tonic-gate		break;
10947c478bdstevel@tonic-gate	case DT_ACT_RAISE:
10957c478bdstevel@tonic-gate		dt_action_raise(dtp, dnp->dn_expr, sdp);
10967c478bdstevel@tonic-gate		break;
1097a1b5e53bmc	case DT_ACT_SETOPT:
1098a1b5e53bmc		dt_action_setopt(dtp, dnp->dn_expr, sdp);
1099a1b5e53bmc		break;
11007c478bdstevel@tonic-gate	case DT_ACT_SPECULATE:
11017c478bdstevel@tonic-gate		dt_action_speculate(dtp, dnp->dn_expr, sdp);
11027c478bdstevel@tonic-gate		break;
11037c478bdstevel@tonic-gate	case DT_ACT_STACK:
11047c478bdstevel@tonic-gate		dt_action_stack(dtp, dnp->dn_expr, sdp);
11057c478bdstevel@tonic-gate		break;
11067c478bdstevel@tonic-gate	case DT_ACT_STOP:
11077c478bdstevel@tonic-gate		dt_action_stop(dtp, dnp->dn_expr, sdp);
11087c478bdstevel@tonic-gate		break;
1109a1b5e53bmc	case DT_ACT_SYM:
1110a1b5e53bmc		dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_SYM);
1111a1b5e53bmc		break;
11127c478bdstevel@tonic-gate	case DT_ACT_SYSTEM:
11137c478bdstevel@tonic-gate		dt_action_printflike(dtp, dnp->dn_expr, sdp, DTRACEACT_SYSTEM);
11147c478bdstevel@tonic-gate		break;
11157c478bdstevel@tonic-gate	case DT_ACT_TRACE:
11167c478bdstevel@tonic-gate		dt_action_trace(dtp, dnp->dn_expr, sdp);
11177c478bdstevel@tonic-gate		break;
11187c478bdstevel@tonic-gate	case DT_ACT_TRACEMEM:
11197c478bdstevel@tonic-gate		dt_action_tracemem(dtp, dnp->dn_expr, sdp);
11207c478bdstevel@tonic-gate		break;
11217c478bdstevel@tonic-gate	case DT_ACT_TRUNC:
11227c478bdstevel@tonic-gate		dt_action_trunc(dtp, dnp->dn_expr, sdp);
11237c478bdstevel@tonic-gate		break;
1124a1b5e53bmc	case DT_ACT_UADDR:
1125a1b5e53bmc		dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_UADDR);
1126a1b5e53bmc		break;
1127a1b5e53bmc	case DT_ACT_UMOD:
1128a1b5e53bmc		dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_UMOD);
1129a1b5e53bmc		break;
1130a1b5e53bmc	case DT_ACT_USYM:
1131a1b5e53bmc		dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_USYM);
1132a1b5e53bmc		break;
11337c478bdstevel@tonic-gate	case DT_ACT_USTACK:
11347c478bdstevel@tonic-gate	case DT_ACT_JSTACK:
11357c478bdstevel@tonic-gate		dt_action_ustack(dtp, dnp->dn_expr, sdp);
11367c478bdstevel@tonic-gate		break;
11377c478bdstevel@tonic-gate	default:
11387c478bdstevel@tonic-gate		dnerror(dnp->dn_expr, D_UNKNOWN, "tracing function %s( ) is "
11397c478bdstevel@tonic-gate		    "not yet supported\n", dnp->dn_expr->dn_ident->di_name);
11407c478bdstevel@tonic-gate	}
11417c478bdstevel@tonic-gate}
11427c478bdstevel@tonic-gate
11437c478bdstevel@tonic-gatestatic void
11447c478bdstevel@tonic-gatedt_compile_exp(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
11457c478bdstevel@tonic-gate{
11467c478bdstevel@tonic-gate	dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
11477c478bdstevel@tonic-gate
11487c478bdstevel@tonic-gate	dt_cg(yypcb, dnp->dn_expr);
11497c478bdstevel@tonic-gate	ap->dtad_difo = dt_as(yypcb);
11507c478bdstevel@tonic-gate	ap->dtad_difo->dtdo_rtype = dt_void_rtype;
11517c478bdstevel@tonic-gate	ap->dtad_kind = DTRACEACT_DIFEXPR;
11527c478bdstevel@tonic-gate}
11537c478bdstevel@tonic-gate
11547c478bdstevel@tonic-gatestatic void
11557c478bdstevel@tonic-gatedt_compile_agg(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
11567c478bdstevel@tonic-gate{
11577c478bdstevel@tonic-gate	dt_ident_t *aid, *fid;
1158a1b5e53bmc	dt_node_t *anp, *incr = NULL;
11597c478bdstevel@tonic-gate	dtrace_actdesc_t *ap;
1160a1b5e53bmc	uint_t n = 1, argmax;
1161a1b5e53bmc	uint64_t arg = 0;
11627c478bdstevel@tonic-gate
11637c478bdstevel@tonic-gate	/*
11647c478bdstevel@tonic-gate	 * If the aggregation has no aggregating function applied to it, then
11657c478bdstevel@tonic-gate	 * this statement has no effect.  Flag this as a programming error.
11667c478bdstevel@tonic-gate	 */
11677c478bdstevel@tonic-gate	if (dnp->dn_aggfun == NULL) {
11687c478bdstevel@tonic-gate		dnerror(dnp, D_AGG_NULL, "expression has null effect: @%s\n",
11697c478bdstevel@tonic-gate		    dnp->dn_ident->di_name);
11707c478bdstevel@tonic-gate	}
11717c478bdstevel@tonic-gate
11727c478bdstevel@tonic-gate	aid = dnp->dn_ident;
11737c478bdstevel@tonic-gate	fid = dnp->dn_aggfun->dn_ident;
11747c478bdstevel@tonic-gate
11757c478bdstevel@tonic-gate	if (dnp->dn_aggfun->dn_args != NULL &&
11767c478bdstevel@tonic-gate	    dt_node_is_scalar(dnp->dn_aggfun->dn_args) == 0) {
11777c478bdstevel@tonic-gate		dnerror(dnp->dn_aggfun, D_AGG_SCALAR, "%s( ) argument #1 must "
11787c478bdstevel@tonic-gate		    "be of scalar type\n", fid->di_name);
11797c478bdstevel@tonic-gate	}
11807c478bdstevel@tonic-gate
11817c478bdstevel@tonic-gate	/*
11827c478bdstevel@tonic-gate	 * The ID of the aggregation itself is implicitly recorded as the first
11837c478bdstevel@tonic-gate	 * member of each aggregation tuple so we can distinguish them later.
11847c478bdstevel@tonic-gate	 */
11857c478bdstevel@tonic-gate	ap = dt_stmt_action(dtp, sdp);
11867c478bdstevel@tonic-gate	dt_action_difconst(ap, aid->di_id, DTRACEACT_DIFEXPR);
11877c478bdstevel@tonic-gate
11887c478bdstevel@tonic-gate	for (anp = dnp->dn_aggtup; anp != NULL; anp = anp->dn_list) {
11897c478bdstevel@tonic-gate		ap = dt_stmt_action(dtp, sdp);
11907c478bdstevel@tonic-gate		n++;
11917c478bdstevel@tonic-gate
11927c478bdstevel@tonic-gate		if (anp->dn_kind == DT_NODE_FUNC) {
11937c478bdstevel@tonic-gate			if (anp->dn_ident->di_id == DT_ACT_STACK) {
11947c478bdstevel@tonic-gate				dt_action_stack_args(dtp, ap, anp->dn_args);
11957c478bdstevel@tonic-gate				continue;
11967c478bdstevel@tonic-gate			}
11977c478bdstevel@tonic-gate
11987c478bdstevel@tonic-gate			if (anp->dn_ident->di_id == DT_ACT_USTACK ||
11997c478bdstevel@tonic-gate			    anp->dn_ident->di_id == DT_ACT_JSTACK) {
12007c478bdstevel@tonic-gate				dt_action_ustack_args(dtp, ap, anp);
12017c478bdstevel@tonic-gate				continue;
12027c478bdstevel@tonic-gate			}
12037c478bdstevel@tonic-gate
1204a1b5e53bmc			switch (anp->dn_ident->di_id) {
1205a1b5e53bmc			case DT_ACT_UADDR:
1206a1b5e53bmc				dt_action_symmod_args(dtp, ap,
1207a1b5e53bmc				    anp->dn_args, DTRACEACT_UADDR);
1208a1b5e53bmc				continue;
12097c478bdstevel@tonic-gate
1210a1b5e53bmc			case DT_ACT_USYM:
1211a1b5e53bmc				dt_action_symmod_args(dtp, ap,
1212a1b5e53bmc				    anp->dn_args, DTRACEACT_USYM);
1213a1b5e53bmc				continue;
12147c478bdstevel@tonic-gate
1215a1b5e53bmc			case DT_ACT_UMOD:
1216a1b5e53bmc				dt_action_symmod_args(dtp, ap,
1217a1b5e53bmc				    anp->dn_args, DTRACEACT_UMOD);
1218a1b5e53bmc				continue;
12197c478bdstevel@tonic-gate
1220a1b5e53bmc			case DT_ACT_SYM:
1221a1b5e53bmc				dt_action_symmod_args(dtp, ap,
1222a1b5e53bmc				    anp->dn_args, DTRACEACT_SYM);
1223a1b5e53bmc				continue;
1224a1b5e53bmc
1225a1b5e53bmc			case DT_ACT_MOD:
1226a1b5e53bmc				dt_action_symmod_args(dtp, ap,
1227a1b5e53bmc				    anp->dn_args, DTRACEACT_MOD);
1228a1b5e53bmc				continue;
1229a1b5e53bmc
1230a1b5e53bmc			default:
1231a1b5e53bmc				break;
1232a1b5e53bmc			}
1233a1b5e53bmc		}
1234a1b5e53bmc
1235a1b5e53bmc		dt_cg(yypcb, anp);
12367c478bdstevel@tonic-gate		ap->dtad_difo = dt_as(yypcb);
1237a1b5e53bmc		ap->dtad_kind = DTRACEACT_DIFEXPR;
12387c478bdstevel@tonic-gate	}
12397c478bdstevel@tonic-gate
12407c478bdstevel@tonic-gate	if (fid->di_id == DTRACEAGG_LQUANTIZE) {
12417c478bdstevel@tonic-gate		/*
1242a1b5e53bmc		 * For linear quantization, we have between two and four
1243a1b5e53bmc		 * arguments in addition to the expression:
12447c478bdstevel@tonic-gate		 *
12457c478bdstevel@tonic-gate		 *    arg1 => Base value
12467c478bdstevel@tonic-gate		 *    arg2 => Limit value
12477c478bdstevel@tonic-gate		 *    arg3 => Quantization level step size (defaults to 1)
1248a1b5e53bmc		 *    arg4 => Quantization increment value (defaults to 1)
12497c478bdstevel@tonic-gate		 */
12507c478bdstevel@tonic-gate		dt_node_t *arg1 = dnp->dn_aggfun->dn_args->dn_list;
12517c478bdstevel@tonic-gate		dt_node_t *arg2 = arg1->dn_list;
12527c478bdstevel@tonic-gate		dt_node_t *arg3 = arg2->dn_list;
125330ef842bmc		dt_idsig_t *isp;
125430ef842bmc		uint64_t nlevels, step = 1, oarg;
12557c478bdstevel@tonic-gate		int64_t baseval, limitval;
12567c478bdstevel@tonic-gate
12577c478bdstevel@tonic-gate		if (arg1->dn_kind != DT_NODE_INT) {
12587c478bdstevel@tonic-gate			dnerror(arg1, D_LQUANT_BASETYPE, "lquantize( ) "
12597c478bdstevel@tonic-gate			    "argument #1 must be an integer constant\n");
12607c478bdstevel@tonic-gate		}
12617c478bdstevel@tonic-gate
12627c478bdstevel@tonic-gate		baseval = (int64_t)arg1->dn_value;
12637c478bdstevel@tonic-gate
12647c478bdstevel@tonic-gate		if (baseval < INT32_MIN || baseval > INT32_MAX) {
12657c478bdstevel@tonic-gate			dnerror(arg1, D_LQUANT_BASEVAL, "lquantize( ) "
12667c478bdstevel@tonic-gate			    "argument #1 must be a 32-bit quantity\n");
12677c478bdstevel@tonic-gate		}
12687c478bdstevel@tonic-gate
12697c478bdstevel@tonic-gate		if (arg2->dn_kind != DT_NODE_INT) {
12707c478bdstevel@tonic-gate			dnerror(arg2, D_LQUANT_LIMTYPE, "lquantize( ) "
12717c478bdstevel@tonic-gate			    "argument #2 must be an integer constant\n");
12727c478bdstevel@tonic-gate		}
12737c478bdstevel@tonic-gate
12747c478bdstevel@tonic-gate		limitval = (int64_t)arg2->dn_value;
12757c478bdstevel@tonic-gate
12767c478bdstevel@tonic-gate		if (limitval < INT32_MIN || limitval > INT32_MAX) {
12777c478bdstevel@tonic-gate			dnerror(arg2, D_LQUANT_LIMVAL, "lquantize( ) "
12787c478bdstevel@tonic-gate			    "argument #2 must be a 32-bit quantity\n");
12797c478bdstevel@tonic-gate		}
12807c478bdstevel@tonic-gate
12817c478bdstevel@tonic-gate		if (limitval < baseval) {
12827c478bdstevel@tonic-gate			dnerror(dnp, D_LQUANT_MISMATCH,
12837c478bdstevel@tonic-gate			    "lquantize( ) base (argument #1) must be less "
12847c478bdstevel@tonic-gate			    "than limit (argument #2)\n");
12857c478bdstevel@tonic-gate		}
12867c478bdstevel@tonic-gate
12877c478bdstevel@tonic-gate		if (arg3 != NULL) {
12887c478bdstevel@tonic-gate			if (!dt_node_is_posconst(arg3)) {
12897c478bdstevel@tonic-gate				dnerror(arg3, D_LQUANT_STEPTYPE, "lquantize( ) "
12907c478bdstevel@tonic-gate				    "argument #3 must be a non-zero positive "
12917c478bdstevel@tonic-gate				    "integer constant\n");
12927c478bdstevel@tonic-gate			}
12937c478bdstevel@tonic-gate
12947c478bdstevel@tonic-gate			if ((step = arg3->dn_value) > UINT16_MAX) {
12957c478bdstevel@tonic-gate				dnerror(arg3, D_LQUANT_STEPVAL, "lquantize( ) "
12967c478bdstevel@tonic-gate				    "argument #3 must be a 16-bit quantity\n");
12977c478bdstevel@tonic-gate			}
12987c478bdstevel@tonic-gate		}
12997c478bdstevel@tonic-gate
13007c478bdstevel@tonic-gate		nlevels = (limitval - baseval) / step;
13017c478bdstevel@tonic-gate
13027c478bdstevel@tonic-gate		if (nlevels == 0) {
13037c478bdstevel@tonic-gate			dnerror(dnp, D_LQUANT_STEPLARGE,
13047c478bdstevel@tonic-gate			    "lquantize( ) step (argument #3) too large: must "
13057c478bdstevel@tonic-gate			    "have at least one quantization level\n");
13067c478bdstevel@tonic-gate		}
13077c478bdstevel@tonic-gate
13087c478bdstevel@tonic-gate		if (nlevels > UINT16_MAX) {
13097c478bdstevel@tonic-gate			dnerror(dnp, D_LQUANT_STEPSMALL, "lquantize( ) step "
13107c478bdstevel@tonic-gate			    "(argument #3) too small: number of quantization "
13117c478bdstevel@tonic-gate			    "levels must be a 16-bit quantity\n");
13127c478bdstevel@tonic-gate		}
13137c478bdstevel@tonic-gate
1314a1b5e53bmc		arg = (step << DTRACE_LQUANTIZE_STEPSHIFT) |
13157c478bdstevel@tonic-gate		    (nlevels << DTRACE_LQUANTIZE_LEVELSHIFT) |
13167c478bdstevel@tonic-gate		    ((baseval << DTRACE_LQUANTIZE_BASESHIFT) &
13177c478bdstevel@tonic-gate		    DTRACE_LQUANTIZE_BASEMASK);
1318