Path: blob/main/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c
39562 views
/*1* CDDL HEADER START2*3* The contents of this file are subject to the terms of the4* Common Development and Distribution License (the "License").5* You may not use this file except in compliance with the License.6*7* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE8* or http://www.opensolaris.org/os/licensing.9* See the License for the specific language governing permissions10* and limitations under the License.11*12* When distributing Covered Code, include this CDDL HEADER in each13* file and include the License file at usr/src/OPENSOLARIS.LICENSE.14* If applicable, add the following below this CDDL HEADER, with the15* fields enclosed by brackets "[]" replaced with your own identifying16* information: Portions Copyright [yyyy] [name of copyright owner]17*18* CDDL HEADER END19*/2021/*22* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.23* Copyright (c) 2011, 2016 by Delphix. All rights reserved.24* Copyright (c) 2013, Joyent Inc. All rights reserved.25* Copyright 2015 Gary Mills26*/2728/*29* DTrace D Language Compiler30*31* The code in this source file implements the main engine for the D language32* compiler. The driver routine for the compiler is dt_compile(), below. The33* compiler operates on either stdio FILEs or in-memory strings as its input34* and can produce either dtrace_prog_t structures from a D program or a single35* dtrace_difo_t structure from a D expression. Multiple entry points are36* provided as wrappers around dt_compile() for the various input/output pairs.37* The compiler itself is implemented across the following source files:38*39* dt_lex.l - lex scanner40* dt_grammar.y - yacc grammar41* dt_parser.c - parse tree creation and semantic checking42* dt_decl.c - declaration stack processing43* dt_xlator.c - D translator lookup and creation44* dt_ident.c - identifier and symbol table routines45* dt_pragma.c - #pragma processing and D pragmas46* dt_printf.c - D printf() and printa() argument checking and processing47* dt_cc.c - compiler driver and dtrace_prog_t construction48* dt_cg.c - DIF code generator49* dt_as.c - DIF assembler50* dt_dof.c - dtrace_prog_t -> DOF conversion51*52* Several other source files provide collections of utility routines used by53* these major files. The compiler itself is implemented in multiple passes:54*55* (1) The input program is scanned and parsed by dt_lex.l and dt_grammar.y56* and parse tree nodes are constructed using the routines in dt_parser.c.57* This node construction pass is described further in dt_parser.c.58*59* (2) The parse tree is "cooked" by assigning each clause a context (see the60* routine dt_setcontext(), below) based on its probe description and then61* recursively descending the tree performing semantic checking. The cook62* routines are also implemented in dt_parser.c and described there.63*64* (3) For actions that are DIF expression statements, the DIF code generator65* and assembler are invoked to create a finished DIFO for the statement.66*67* (4) The dtrace_prog_t data structures for the program clauses and actions68* are built, containing pointers to any DIFOs created in step (3).69*70* (5) The caller invokes a routine in dt_dof.c to convert the finished program71* into DOF format for use in anonymous tracing or enabling in the kernel.72*73* In the implementation, steps 2-4 are intertwined in that they are performed74* in order for each clause as part of a loop that executes over the clauses.75*76* The D compiler currently implements nearly no optimization. The compiler77* implements integer constant folding as part of pass (1), and a set of very78* simple peephole optimizations as part of pass (3). As with any C compiler,79* a large number of optimizations are possible on both the intermediate data80* structures and the generated DIF code. These possibilities should be81* investigated in the context of whether they will have any substantive effect82* on the overall DTrace probe effect before they are undertaken.83*/8485#include <sys/types.h>86#include <sys/wait.h>87#include <sys/sysmacros.h>8889#include <assert.h>90#include <string.h>91#include <strings.h>92#include <signal.h>93#include <unistd.h>94#include <stdlib.h>95#include <stdio.h>96#include <errno.h>97#include <ucontext.h>98#include <limits.h>99#include <ctype.h>100#include <dirent.h>101#include <dt_module.h>102#include <dt_program.h>103#include <dt_provider.h>104#include <dt_printf.h>105#include <dt_pid.h>106#include <dt_grammar.h>107#include <dt_ident.h>108#include <dt_string.h>109#include <dt_impl.h>110111static const dtrace_diftype_t dt_void_rtype = {112DIF_TYPE_CTF, CTF_K_INTEGER, 0, 0, 0113};114115static const dtrace_diftype_t dt_int_rtype = {116DIF_TYPE_CTF, CTF_K_INTEGER, 0, 0, sizeof (uint64_t)117};118119static void *dt_compile(dtrace_hdl_t *, int, dtrace_probespec_t, void *,120uint_t, int, char *const[], FILE *, const char *);121122/*ARGSUSED*/123static int124dt_idreset(dt_idhash_t *dhp, dt_ident_t *idp, void *ignored)125{126idp->di_flags &= ~(DT_IDFLG_REF | DT_IDFLG_MOD |127DT_IDFLG_DIFR | DT_IDFLG_DIFW);128return (0);129}130131/*ARGSUSED*/132static int133dt_idpragma(dt_idhash_t *dhp, dt_ident_t *idp, void *ignored)134{135yylineno = idp->di_lineno;136xyerror(D_PRAGMA_UNUSED, "unused #pragma %s\n", (char *)idp->di_iarg);137return (0);138}139140static dtrace_stmtdesc_t *141dt_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp,142dtrace_attribute_t descattr, dtrace_attribute_t stmtattr)143{144dtrace_stmtdesc_t *sdp = dtrace_stmt_create(dtp, edp);145146if (sdp == NULL)147longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);148149assert(yypcb->pcb_stmt == NULL);150yypcb->pcb_stmt = sdp;151152sdp->dtsd_descattr = descattr;153sdp->dtsd_stmtattr = stmtattr;154155return (sdp);156}157158static dtrace_actdesc_t *159dt_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)160{161dtrace_actdesc_t *new;162163if ((new = dtrace_stmt_action(dtp, sdp)) == NULL)164longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);165166return (new);167}168169/*170* Utility function to determine if a given action description is destructive.171* The dtdo_destructive bit is set for us by the DIF assembler (see dt_as.c).172*/173static int174dt_action_destructive(const dtrace_actdesc_t *ap)175{176return (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind) || (ap->dtad_kind ==177DTRACEACT_DIFEXPR && ap->dtad_difo->dtdo_destructive));178}179180static void181dt_stmt_append(dtrace_stmtdesc_t *sdp, const dt_node_t *dnp)182{183dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;184dtrace_actdesc_t *ap, *tap;185int commit = 0;186int speculate = 0;187int datarec = 0;188189/*190* Make sure that the new statement jibes with the rest of the ECB.191*/192for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {193if (ap->dtad_kind == DTRACEACT_COMMIT) {194if (commit) {195dnerror(dnp, D_COMM_COMM, "commit( ) may "196"not follow commit( )\n");197}198199if (datarec) {200dnerror(dnp, D_COMM_DREC, "commit( ) may "201"not follow data-recording action(s)\n");202}203204for (tap = ap; tap != NULL; tap = tap->dtad_next) {205if (!DTRACEACT_ISAGG(tap->dtad_kind))206continue;207208dnerror(dnp, D_AGG_COMM, "aggregating actions "209"may not follow commit( )\n");210}211212commit = 1;213continue;214}215216if (ap->dtad_kind == DTRACEACT_SPECULATE) {217if (speculate) {218dnerror(dnp, D_SPEC_SPEC, "speculate( ) may "219"not follow speculate( )\n");220}221222if (commit) {223dnerror(dnp, D_SPEC_COMM, "speculate( ) may "224"not follow commit( )\n");225}226227if (datarec) {228dnerror(dnp, D_SPEC_DREC, "speculate( ) may "229"not follow data-recording action(s)\n");230}231232speculate = 1;233continue;234}235236if (DTRACEACT_ISAGG(ap->dtad_kind)) {237if (speculate) {238dnerror(dnp, D_AGG_SPEC, "aggregating actions "239"may not follow speculate( )\n");240}241242datarec = 1;243continue;244}245246if (speculate) {247if (dt_action_destructive(ap)) {248dnerror(dnp, D_ACT_SPEC, "destructive actions "249"may not follow speculate( )\n");250}251252if (ap->dtad_kind == DTRACEACT_EXIT) {253dnerror(dnp, D_EXIT_SPEC, "exit( ) may not "254"follow speculate( )\n");255}256}257258/*259* Exclude all non data-recording actions.260*/261if (dt_action_destructive(ap) ||262ap->dtad_kind == DTRACEACT_DISCARD)263continue;264265if (ap->dtad_kind == DTRACEACT_DIFEXPR &&266ap->dtad_difo->dtdo_rtype.dtdt_kind == DIF_TYPE_CTF &&267ap->dtad_difo->dtdo_rtype.dtdt_size == 0)268continue;269270if (commit) {271dnerror(dnp, D_DREC_COMM, "data-recording actions "272"may not follow commit( )\n");273}274275if (!speculate)276datarec = 1;277}278279if (dtrace_stmt_add(yypcb->pcb_hdl, yypcb->pcb_prog, sdp) != 0)280longjmp(yypcb->pcb_jmpbuf, dtrace_errno(yypcb->pcb_hdl));281282if (yypcb->pcb_stmt == sdp)283yypcb->pcb_stmt = NULL;284}285286/*287* For the first element of an aggregation tuple or for printa(), we create a288* simple DIF program that simply returns the immediate value that is the ID289* of the aggregation itself. This could be optimized in the future by290* creating a new in-kernel dtad_kind that just returns an integer.291*/292static void293dt_action_difconst(dtrace_actdesc_t *ap, uint_t id, dtrace_actkind_t kind)294{295dtrace_hdl_t *dtp = yypcb->pcb_hdl;296dtrace_difo_t *dp = dt_zalloc(dtp, sizeof (dtrace_difo_t));297298if (dp == NULL)299longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);300301dp->dtdo_buf = dt_alloc(dtp, sizeof (dif_instr_t) * 2);302dp->dtdo_inttab = dt_alloc(dtp, sizeof (uint64_t));303304if (dp->dtdo_buf == NULL || dp->dtdo_inttab == NULL) {305dt_difo_free(dtp, dp);306longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);307}308309dp->dtdo_buf[0] = DIF_INSTR_SETX(0, 1); /* setx DIF_INTEGER[0], %r1 */310dp->dtdo_buf[1] = DIF_INSTR_RET(1); /* ret %r1 */311dp->dtdo_len = 2;312dp->dtdo_inttab[0] = id;313dp->dtdo_intlen = 1;314dp->dtdo_rtype = dt_int_rtype;315316ap->dtad_difo = dp;317ap->dtad_kind = kind;318}319320static void321dt_action_clear(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)322{323dt_ident_t *aid;324dtrace_actdesc_t *ap;325dt_node_t *anp;326327char n[DT_TYPE_NAMELEN];328int argc = 0;329330for (anp = dnp->dn_args; anp != NULL; anp = anp->dn_list)331argc++; /* count up arguments for error messages below */332333if (argc != 1) {334dnerror(dnp, D_CLEAR_PROTO,335"%s( ) prototype mismatch: %d args passed, 1 expected\n",336dnp->dn_ident->di_name, argc);337}338339anp = dnp->dn_args;340assert(anp != NULL);341342if (anp->dn_kind != DT_NODE_AGG) {343dnerror(dnp, D_CLEAR_AGGARG,344"%s( ) argument #1 is incompatible with prototype:\n"345"\tprototype: aggregation\n\t argument: %s\n",346dnp->dn_ident->di_name,347dt_node_type_name(anp, n, sizeof (n)));348}349350aid = anp->dn_ident;351352if (aid->di_gen == dtp->dt_gen && !(aid->di_flags & DT_IDFLG_MOD)) {353dnerror(dnp, D_CLEAR_AGGBAD,354"undefined aggregation: @%s\n", aid->di_name);355}356357ap = dt_stmt_action(dtp, sdp);358dt_action_difconst(ap, anp->dn_ident->di_id, DTRACEACT_LIBACT);359ap->dtad_arg = DT_ACT_CLEAR;360}361362static void363dt_action_normalize(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)364{365dt_ident_t *aid;366dtrace_actdesc_t *ap;367dt_node_t *anp, *normal;368int denormal = (strcmp(dnp->dn_ident->di_name, "denormalize") == 0);369370char n[DT_TYPE_NAMELEN];371int argc = 0;372373for (anp = dnp->dn_args; anp != NULL; anp = anp->dn_list)374argc++; /* count up arguments for error messages below */375376if ((denormal && argc != 1) || (!denormal && argc != 2)) {377dnerror(dnp, D_NORMALIZE_PROTO,378"%s( ) prototype mismatch: %d args passed, %d expected\n",379dnp->dn_ident->di_name, argc, denormal ? 1 : 2);380}381382anp = dnp->dn_args;383assert(anp != NULL);384385if (anp->dn_kind != DT_NODE_AGG) {386dnerror(dnp, D_NORMALIZE_AGGARG,387"%s( ) argument #1 is incompatible with prototype:\n"388"\tprototype: aggregation\n\t argument: %s\n",389dnp->dn_ident->di_name,390dt_node_type_name(anp, n, sizeof (n)));391}392393if ((normal = anp->dn_list) != NULL && !dt_node_is_scalar(normal)) {394dnerror(dnp, D_NORMALIZE_SCALAR,395"%s( ) argument #2 must be of scalar type\n",396dnp->dn_ident->di_name);397}398399aid = anp->dn_ident;400401if (aid->di_gen == dtp->dt_gen && !(aid->di_flags & DT_IDFLG_MOD)) {402dnerror(dnp, D_NORMALIZE_AGGBAD,403"undefined aggregation: @%s\n", aid->di_name);404}405406ap = dt_stmt_action(dtp, sdp);407dt_action_difconst(ap, anp->dn_ident->di_id, DTRACEACT_LIBACT);408409if (denormal) {410ap->dtad_arg = DT_ACT_DENORMALIZE;411return;412}413414ap->dtad_arg = DT_ACT_NORMALIZE;415416assert(normal != NULL);417ap = dt_stmt_action(dtp, sdp);418dt_cg(yypcb, normal);419420ap->dtad_difo = dt_as(yypcb);421ap->dtad_kind = DTRACEACT_LIBACT;422ap->dtad_arg = DT_ACT_NORMALIZE;423}424425static void426dt_action_trunc(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)427{428dt_ident_t *aid;429dtrace_actdesc_t *ap;430dt_node_t *anp, *trunc;431432char n[DT_TYPE_NAMELEN];433int argc = 0;434435for (anp = dnp->dn_args; anp != NULL; anp = anp->dn_list)436argc++; /* count up arguments for error messages below */437438if (argc > 2 || argc < 1) {439dnerror(dnp, D_TRUNC_PROTO,440"%s( ) prototype mismatch: %d args passed, %s expected\n",441dnp->dn_ident->di_name, argc,442argc < 1 ? "at least 1" : "no more than 2");443}444445anp = dnp->dn_args;446assert(anp != NULL);447trunc = anp->dn_list;448449if (anp->dn_kind != DT_NODE_AGG) {450dnerror(dnp, D_TRUNC_AGGARG,451"%s( ) argument #1 is incompatible with prototype:\n"452"\tprototype: aggregation\n\t argument: %s\n",453dnp->dn_ident->di_name,454dt_node_type_name(anp, n, sizeof (n)));455}456457if (argc == 2) {458assert(trunc != NULL);459if (!dt_node_is_scalar(trunc)) {460dnerror(dnp, D_TRUNC_SCALAR,461"%s( ) argument #2 must be of scalar type\n",462dnp->dn_ident->di_name);463}464}465466aid = anp->dn_ident;467468if (aid->di_gen == dtp->dt_gen && !(aid->di_flags & DT_IDFLG_MOD)) {469dnerror(dnp, D_TRUNC_AGGBAD,470"undefined aggregation: @%s\n", aid->di_name);471}472473ap = dt_stmt_action(dtp, sdp);474dt_action_difconst(ap, anp->dn_ident->di_id, DTRACEACT_LIBACT);475ap->dtad_arg = DT_ACT_TRUNC;476477ap = dt_stmt_action(dtp, sdp);478479if (argc == 1) {480dt_action_difconst(ap, 0, DTRACEACT_LIBACT);481} else {482assert(trunc != NULL);483dt_cg(yypcb, trunc);484ap->dtad_difo = dt_as(yypcb);485ap->dtad_kind = DTRACEACT_LIBACT;486}487488ap->dtad_arg = DT_ACT_TRUNC;489}490491static void492dt_action_printa(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)493{494dt_ident_t *aid, *fid;495dtrace_actdesc_t *ap;496const char *format;497dt_node_t *anp, *proto = NULL;498499char n[DT_TYPE_NAMELEN];500int argc = 0, argr = 0;501502for (anp = dnp->dn_args; anp != NULL; anp = anp->dn_list)503argc++; /* count up arguments for error messages below */504505switch (dnp->dn_args->dn_kind) {506case DT_NODE_STRING:507format = dnp->dn_args->dn_string;508anp = dnp->dn_args->dn_list;509argr = 2;510break;511case DT_NODE_AGG:512format = NULL;513anp = dnp->dn_args;514argr = 1;515break;516default:517format = NULL;518anp = dnp->dn_args;519argr = 1;520}521522if (argc < argr) {523dnerror(dnp, D_PRINTA_PROTO,524"%s( ) prototype mismatch: %d args passed, %d expected\n",525dnp->dn_ident->di_name, argc, argr);526}527528assert(anp != NULL);529530while (anp != NULL) {531if (anp->dn_kind != DT_NODE_AGG) {532dnerror(dnp, D_PRINTA_AGGARG,533"%s( ) argument #%d is incompatible with "534"prototype:\n\tprototype: aggregation\n"535"\t argument: %s\n", dnp->dn_ident->di_name, argr,536dt_node_type_name(anp, n, sizeof (n)));537}538539aid = anp->dn_ident;540fid = aid->di_iarg;541542if (aid->di_gen == dtp->dt_gen &&543!(aid->di_flags & DT_IDFLG_MOD)) {544dnerror(dnp, D_PRINTA_AGGBAD,545"undefined aggregation: @%s\n", aid->di_name);546}547548/*549* If we have multiple aggregations, we must be sure that550* their key signatures match.551*/552if (proto != NULL) {553dt_printa_validate(proto, anp);554} else {555proto = anp;556}557558if (format != NULL) {559yylineno = dnp->dn_line;560561sdp->dtsd_fmtdata =562dt_printf_create(yypcb->pcb_hdl, format);563dt_printf_validate(sdp->dtsd_fmtdata,564DT_PRINTF_AGGREGATION, dnp->dn_ident, 1,565fid->di_id, ((dt_idsig_t *)aid->di_data)->dis_args);566format = NULL;567}568569ap = dt_stmt_action(dtp, sdp);570dt_action_difconst(ap, anp->dn_ident->di_id, DTRACEACT_PRINTA);571572anp = anp->dn_list;573argr++;574}575}576577static void578dt_action_printflike(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp,579dtrace_actkind_t kind)580{581dt_node_t *anp, *arg1;582dtrace_actdesc_t *ap = NULL;583char n[DT_TYPE_NAMELEN], *str;584585assert(DTRACEACT_ISPRINTFLIKE(kind));586587if (dnp->dn_args->dn_kind != DT_NODE_STRING) {588dnerror(dnp, D_PRINTF_ARG_FMT,589"%s( ) argument #1 is incompatible with prototype:\n"590"\tprototype: string constant\n\t argument: %s\n",591dnp->dn_ident->di_name,592dt_node_type_name(dnp->dn_args, n, sizeof (n)));593}594595arg1 = dnp->dn_args->dn_list;596yylineno = dnp->dn_line;597str = dnp->dn_args->dn_string;598599600/*601* If this is an freopen(), we use an empty string to denote that602* stdout should be restored. For other printf()-like actions, an603* empty format string is illegal: an empty format string would604* result in malformed DOF, and the compiler thus flags an empty605* format string as a compile-time error. To avoid propagating the606* freopen() special case throughout the system, we simply transpose607* an empty string into a sentinel string (DT_FREOPEN_RESTORE) that608* denotes that stdout should be restored.609*/610if (kind == DTRACEACT_FREOPEN) {611if (strcmp(str, DT_FREOPEN_RESTORE) == 0) {612/*613* Our sentinel is always an invalid argument to614* freopen(), but if it's been manually specified, we615* must fail now instead of when the freopen() is616* actually evaluated.617*/618dnerror(dnp, D_FREOPEN_INVALID,619"%s( ) argument #1 cannot be \"%s\"\n",620dnp->dn_ident->di_name, DT_FREOPEN_RESTORE);621}622623if (str[0] == '\0')624str = DT_FREOPEN_RESTORE;625}626627sdp->dtsd_fmtdata = dt_printf_create(dtp, str);628629dt_printf_validate(sdp->dtsd_fmtdata, DT_PRINTF_EXACTLEN,630dnp->dn_ident, 1, DTRACEACT_AGGREGATION, arg1);631632if (arg1 == NULL) {633dif_instr_t *dbuf;634dtrace_difo_t *dp;635636if ((dbuf = dt_alloc(dtp, sizeof (dif_instr_t))) == NULL ||637(dp = dt_zalloc(dtp, sizeof (dtrace_difo_t))) == NULL) {638dt_free(dtp, dbuf);639longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);640}641642dbuf[0] = DIF_INSTR_RET(DIF_REG_R0); /* ret %r0 */643644dp->dtdo_buf = dbuf;645dp->dtdo_len = 1;646dp->dtdo_rtype = dt_int_rtype;647648ap = dt_stmt_action(dtp, sdp);649ap->dtad_difo = dp;650ap->dtad_kind = kind;651return;652}653654for (anp = arg1; anp != NULL; anp = anp->dn_list) {655ap = dt_stmt_action(dtp, sdp);656dt_cg(yypcb, anp);657ap->dtad_difo = dt_as(yypcb);658ap->dtad_kind = kind;659}660}661662static void663dt_action_trace(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)664{665int ctflib;666667dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);668boolean_t istrace = (dnp->dn_ident->di_id == DT_ACT_TRACE);669const char *act = istrace ? "trace" : "print";670671if (dt_node_is_void(dnp->dn_args)) {672dnerror(dnp->dn_args, istrace ? D_TRACE_VOID : D_PRINT_VOID,673"%s( ) may not be applied to a void expression\n", act);674}675676if (dt_node_resolve(dnp->dn_args, DT_IDENT_XLPTR) != NULL) {677dnerror(dnp->dn_args, istrace ? D_TRACE_DYN : D_PRINT_DYN,678"%s( ) may not be applied to a translated pointer\n", act);679}680681if (dnp->dn_args->dn_kind == DT_NODE_AGG) {682dnerror(dnp->dn_args, istrace ? D_TRACE_AGG : D_PRINT_AGG,683"%s( ) may not be applied to an aggregation%s\n", act,684istrace ? "" : " -- did you mean printa()?");685}686687dt_cg(yypcb, dnp->dn_args);688689/*690* The print() action behaves identically to trace(), except that it691* stores the CTF type of the argument (if present) within the DOF for692* the DIFEXPR action. To do this, we set the 'dtsd_strdata' to point693* to the fully-qualified CTF type ID for the result of the DIF694* action. We use the ID instead of the name to handles complex types695* like arrays and function pointers that can't be resolved by696* ctf_type_lookup(). This is later processed by dtrace_dof_create()697* and turned into a reference into the string table so that we can698* get the type information when we process the data after the fact. In699* the case where we are referring to userland CTF data, we also need to700* to identify which ctf container in question we care about and encode701* that within the name.702*/703if (dnp->dn_ident->di_id == DT_ACT_PRINT) {704dt_node_t *dret;705size_t n;706dt_module_t *dmp;707708dret = yypcb->pcb_dret;709dmp = dt_module_lookup_by_ctf(dtp, dret->dn_ctfp);710711n = snprintf(NULL, 0, "%s`%ld", dmp->dm_name, dret->dn_type) + 1;712if (dmp->dm_pid != 0) {713ctflib = dt_module_getlibid(dtp, dmp, dret->dn_ctfp);714assert(ctflib >= 0);715n = snprintf(NULL, 0, "%s`%d`%ld", dmp->dm_name,716ctflib, dret->dn_type) + 1;717} else {718n = snprintf(NULL, 0, "%s`%ld", dmp->dm_name,719dret->dn_type) + 1;720}721sdp->dtsd_strdata = dt_alloc(dtp, n);722if (sdp->dtsd_strdata == NULL)723longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);724(void) snprintf(sdp->dtsd_strdata, n, "%s`%ld", dmp->dm_name,725dret->dn_type);726if (dmp->dm_pid != 0) {727(void) snprintf(sdp->dtsd_strdata, n, "%s`%d`%ld",728dmp->dm_name, ctflib, dret->dn_type);729} else {730(void) snprintf(sdp->dtsd_strdata, n, "%s`%ld",731dmp->dm_name, dret->dn_type);732}733}734735ap->dtad_difo = dt_as(yypcb);736ap->dtad_kind = DTRACEACT_DIFEXPR;737}738739static void740dt_action_tracemem(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)741{742dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);743744dt_node_t *addr = dnp->dn_args;745dt_node_t *max = dnp->dn_args->dn_list;746dt_node_t *size;747748char n[DT_TYPE_NAMELEN];749750if (dt_node_is_integer(addr) == 0 && dt_node_is_pointer(addr) == 0) {751dnerror(addr, D_TRACEMEM_ADDR,752"tracemem( ) argument #1 is incompatible with "753"prototype:\n\tprototype: pointer or integer\n"754"\t argument: %s\n",755dt_node_type_name(addr, n, sizeof (n)));756}757758if (dt_node_is_posconst(max) == 0) {759dnerror(max, D_TRACEMEM_SIZE, "tracemem( ) argument #2 must "760"be a non-zero positive integral constant expression\n");761}762763if ((size = max->dn_list) != NULL) {764if (size->dn_list != NULL) {765dnerror(size, D_TRACEMEM_ARGS, "tracemem ( ) prototype "766"mismatch: expected at most 3 args\n");767}768769if (!dt_node_is_scalar(size)) {770dnerror(size, D_TRACEMEM_DYNSIZE, "tracemem ( ) "771"dynamic size (argument #3) must be of "772"scalar type\n");773}774775dt_cg(yypcb, size);776ap->dtad_difo = dt_as(yypcb);777ap->dtad_difo->dtdo_rtype = dt_int_rtype;778ap->dtad_kind = DTRACEACT_TRACEMEM_DYNSIZE;779780ap = dt_stmt_action(dtp, sdp);781}782783dt_cg(yypcb, addr);784ap->dtad_difo = dt_as(yypcb);785ap->dtad_kind = DTRACEACT_TRACEMEM;786787ap->dtad_difo->dtdo_rtype.dtdt_flags |= DIF_TF_BYREF;788ap->dtad_difo->dtdo_rtype.dtdt_size = max->dn_value;789}790791static void792dt_action_stack_args(dtrace_hdl_t *dtp, dtrace_actdesc_t *ap, dt_node_t *arg0)793{794ap->dtad_kind = DTRACEACT_STACK;795796if (dtp->dt_options[DTRACEOPT_STACKFRAMES] != DTRACEOPT_UNSET) {797ap->dtad_arg = dtp->dt_options[DTRACEOPT_STACKFRAMES];798} else {799ap->dtad_arg = 0;800}801802if (arg0 != NULL) {803if (arg0->dn_list != NULL) {804dnerror(arg0, D_STACK_PROTO, "stack( ) prototype "805"mismatch: too many arguments\n");806}807808if (dt_node_is_posconst(arg0) == 0) {809dnerror(arg0, D_STACK_SIZE, "stack( ) size must be a "810"non-zero positive integral constant expression\n");811}812813ap->dtad_arg = arg0->dn_value;814}815}816817static void818dt_action_stack(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)819{820dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);821dt_action_stack_args(dtp, ap, dnp->dn_args);822}823824static void825dt_action_ustack_args(dtrace_hdl_t *dtp, dtrace_actdesc_t *ap, dt_node_t *dnp)826{827uint32_t nframes = 0;828uint32_t strsize = 0; /* default string table size */829dt_node_t *arg0 = dnp->dn_args;830dt_node_t *arg1 = arg0 != NULL ? arg0->dn_list : NULL;831832assert(dnp->dn_ident->di_id == DT_ACT_JSTACK ||833dnp->dn_ident->di_id == DT_ACT_USTACK);834835if (dnp->dn_ident->di_id == DT_ACT_JSTACK) {836if (dtp->dt_options[DTRACEOPT_JSTACKFRAMES] != DTRACEOPT_UNSET)837nframes = dtp->dt_options[DTRACEOPT_JSTACKFRAMES];838839if (dtp->dt_options[DTRACEOPT_JSTACKSTRSIZE] != DTRACEOPT_UNSET)840strsize = dtp->dt_options[DTRACEOPT_JSTACKSTRSIZE];841842ap->dtad_kind = DTRACEACT_JSTACK;843} else {844assert(dnp->dn_ident->di_id == DT_ACT_USTACK);845846if (dtp->dt_options[DTRACEOPT_USTACKFRAMES] != DTRACEOPT_UNSET)847nframes = dtp->dt_options[DTRACEOPT_USTACKFRAMES];848849ap->dtad_kind = DTRACEACT_USTACK;850}851852if (arg0 != NULL) {853if (!dt_node_is_posconst(arg0)) {854dnerror(arg0, D_USTACK_FRAMES, "ustack( ) argument #1 "855"must be a non-zero positive integer constant\n");856}857nframes = (uint32_t)arg0->dn_value;858}859860if (arg1 != NULL) {861if (arg1->dn_kind != DT_NODE_INT ||862((arg1->dn_flags & DT_NF_SIGNED) &&863(int64_t)arg1->dn_value < 0)) {864dnerror(arg1, D_USTACK_STRSIZE, "ustack( ) argument #2 "865"must be a positive integer constant\n");866}867868if (arg1->dn_list != NULL) {869dnerror(arg1, D_USTACK_PROTO, "ustack( ) prototype "870"mismatch: too many arguments\n");871}872873strsize = (uint32_t)arg1->dn_value;874}875876ap->dtad_arg = DTRACE_USTACK_ARG(nframes, strsize);877}878879static void880dt_action_ustack(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)881{882dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);883dt_action_ustack_args(dtp, ap, dnp);884}885886static void887dt_action_setopt(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)888{889dtrace_actdesc_t *ap;890dt_node_t *arg0, *arg1;891892/*893* The prototype guarantees that we are called with either one or894* two arguments, and that any arguments that are present are strings.895*/896arg0 = dnp->dn_args;897arg1 = arg0->dn_list;898899ap = dt_stmt_action(dtp, sdp);900dt_cg(yypcb, arg0);901ap->dtad_difo = dt_as(yypcb);902ap->dtad_kind = DTRACEACT_LIBACT;903ap->dtad_arg = DT_ACT_SETOPT;904905ap = dt_stmt_action(dtp, sdp);906907if (arg1 == NULL) {908dt_action_difconst(ap, 0, DTRACEACT_LIBACT);909} else {910dt_cg(yypcb, arg1);911ap->dtad_difo = dt_as(yypcb);912ap->dtad_kind = DTRACEACT_LIBACT;913}914915ap->dtad_arg = DT_ACT_SETOPT;916}917918/*ARGSUSED*/919static void920dt_action_symmod_args(dtrace_hdl_t *dtp, dtrace_actdesc_t *ap,921dt_node_t *dnp, dtrace_actkind_t kind)922{923assert(kind == DTRACEACT_SYM || kind == DTRACEACT_MOD ||924kind == DTRACEACT_USYM || kind == DTRACEACT_UMOD ||925kind == DTRACEACT_UADDR);926927dt_cg(yypcb, dnp);928ap->dtad_difo = dt_as(yypcb);929ap->dtad_kind = kind;930ap->dtad_difo->dtdo_rtype.dtdt_size = sizeof (uint64_t);931}932933static void934dt_action_symmod(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp,935dtrace_actkind_t kind)936{937dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);938dt_action_symmod_args(dtp, ap, dnp->dn_args, kind);939}940941/*ARGSUSED*/942static void943dt_action_ftruncate(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)944{945dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);946947/*948* Library actions need a DIFO that serves as an argument. As949* ftruncate() doesn't take an argument, we generate the constant 0950* in a DIFO; this constant will be ignored when the ftruncate() is951* processed.952*/953dt_action_difconst(ap, 0, DTRACEACT_LIBACT);954ap->dtad_arg = DT_ACT_FTRUNCATE;955}956957/*ARGSUSED*/958static void959dt_action_stop(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)960{961dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);962963ap->dtad_kind = DTRACEACT_STOP;964ap->dtad_arg = 0;965}966967/*ARGSUSED*/968static void969dt_action_breakpoint(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)970{971dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);972973ap->dtad_kind = DTRACEACT_BREAKPOINT;974ap->dtad_arg = 0;975}976977/*ARGSUSED*/978static void979dt_action_panic(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)980{981dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);982983ap->dtad_kind = DTRACEACT_PANIC;984ap->dtad_arg = 0;985}986987static void988dt_action_chill(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)989{990dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);991992dt_cg(yypcb, dnp->dn_args);993ap->dtad_difo = dt_as(yypcb);994ap->dtad_kind = DTRACEACT_CHILL;995}996997static void998dt_action_raise(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)999{1000dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);10011002dt_cg(yypcb, dnp->dn_args);1003ap->dtad_difo = dt_as(yypcb);1004ap->dtad_kind = DTRACEACT_RAISE;1005}10061007static void1008dt_action_exit(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)1009{1010dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);10111012dt_cg(yypcb, dnp->dn_args);1013ap->dtad_difo = dt_as(yypcb);1014ap->dtad_kind = DTRACEACT_EXIT;1015ap->dtad_difo->dtdo_rtype.dtdt_size = sizeof (int);1016}10171018static void1019dt_action_speculate(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)1020{1021dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);10221023dt_cg(yypcb, dnp->dn_args);1024ap->dtad_difo = dt_as(yypcb);1025ap->dtad_kind = DTRACEACT_SPECULATE;1026}10271028static void1029dt_action_printm(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)1030{1031dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);10321033dt_node_t *size = dnp->dn_args;1034dt_node_t *addr = dnp->dn_args->dn_list;10351036char n[DT_TYPE_NAMELEN];10371038if (dt_node_is_posconst(size) == 0) {1039dnerror(size, D_PRINTM_SIZE, "printm( ) argument #1 must "1040"be a non-zero positive integral constant expression\n");1041}10421043if (dt_node_is_pointer(addr) == 0) {1044dnerror(addr, D_PRINTM_ADDR,1045"printm( ) argument #2 is incompatible with "1046"prototype:\n\tprototype: pointer\n"1047"\t argument: %s\n",1048dt_node_type_name(addr, n, sizeof (n)));1049}10501051dt_cg(yypcb, addr);1052ap->dtad_difo = dt_as(yypcb);1053ap->dtad_kind = DTRACEACT_PRINTM;10541055ap->dtad_difo->dtdo_rtype.dtdt_flags |= DIF_TF_BYREF;1056ap->dtad_difo->dtdo_rtype.dtdt_size = size->dn_value + sizeof(uintptr_t);1057}10581059static void1060dt_action_commit(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)1061{1062dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);10631064dt_cg(yypcb, dnp->dn_args);1065ap->dtad_difo = dt_as(yypcb);1066ap->dtad_kind = DTRACEACT_COMMIT;1067}10681069static void1070dt_action_discard(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)1071{1072dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);10731074dt_cg(yypcb, dnp->dn_args);1075ap->dtad_difo = dt_as(yypcb);1076ap->dtad_kind = DTRACEACT_DISCARD;1077}10781079static void1080dt_compile_fun(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)1081{1082switch (dnp->dn_expr->dn_ident->di_id) {1083case DT_ACT_BREAKPOINT:1084dt_action_breakpoint(dtp, dnp->dn_expr, sdp);1085break;1086case DT_ACT_CHILL:1087dt_action_chill(dtp, dnp->dn_expr, sdp);1088break;1089case DT_ACT_CLEAR:1090dt_action_clear(dtp, dnp->dn_expr, sdp);1091break;1092case DT_ACT_COMMIT:1093dt_action_commit(dtp, dnp->dn_expr, sdp);1094break;1095case DT_ACT_DENORMALIZE:1096dt_action_normalize(dtp, dnp->dn_expr, sdp);1097break;1098case DT_ACT_DISCARD:1099dt_action_discard(dtp, dnp->dn_expr, sdp);1100break;1101case DT_ACT_EXIT:1102dt_action_exit(dtp, dnp->dn_expr, sdp);1103break;1104case DT_ACT_FREOPEN:1105dt_action_printflike(dtp, dnp->dn_expr, sdp, DTRACEACT_FREOPEN);1106break;1107case DT_ACT_FTRUNCATE:1108dt_action_ftruncate(dtp, dnp->dn_expr, sdp);1109break;1110case DT_ACT_MOD:1111dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_MOD);1112break;1113case DT_ACT_NORMALIZE:1114dt_action_normalize(dtp, dnp->dn_expr, sdp);1115break;1116case DT_ACT_PANIC:1117dt_action_panic(dtp, dnp->dn_expr, sdp);1118break;1119case DT_ACT_PRINT:1120dt_action_trace(dtp, dnp->dn_expr, sdp);1121break;1122case DT_ACT_PRINTA:1123dt_action_printa(dtp, dnp->dn_expr, sdp);1124break;1125case DT_ACT_PRINTF:1126dt_action_printflike(dtp, dnp->dn_expr, sdp, DTRACEACT_PRINTF);1127break;1128case DT_ACT_PRINTM:1129dt_action_printm(dtp, dnp->dn_expr, sdp);1130break;1131case DT_ACT_RAISE:1132dt_action_raise(dtp, dnp->dn_expr, sdp);1133break;1134case DT_ACT_SETOPT:1135dt_action_setopt(dtp, dnp->dn_expr, sdp);1136break;1137case DT_ACT_SPECULATE:1138dt_action_speculate(dtp, dnp->dn_expr, sdp);1139break;1140case DT_ACT_STACK:1141dt_action_stack(dtp, dnp->dn_expr, sdp);1142break;1143case DT_ACT_STOP:1144dt_action_stop(dtp, dnp->dn_expr, sdp);1145break;1146case DT_ACT_SYM:1147dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_SYM);1148break;1149case DT_ACT_SYSTEM:1150dt_action_printflike(dtp, dnp->dn_expr, sdp, DTRACEACT_SYSTEM);1151break;1152case DT_ACT_TRACE:1153dt_action_trace(dtp, dnp->dn_expr, sdp);1154break;1155case DT_ACT_TRACEMEM:1156dt_action_tracemem(dtp, dnp->dn_expr, sdp);1157break;1158case DT_ACT_TRUNC:1159dt_action_trunc(dtp, dnp->dn_expr, sdp);1160break;1161case DT_ACT_UADDR:1162dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_UADDR);1163break;1164case DT_ACT_UMOD:1165dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_UMOD);1166break;1167case DT_ACT_USYM:1168dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_USYM);1169break;1170case DT_ACT_USTACK:1171case DT_ACT_JSTACK:1172dt_action_ustack(dtp, dnp->dn_expr, sdp);1173break;1174default:1175dnerror(dnp->dn_expr, D_UNKNOWN, "tracing function %s( ) is "1176"not yet supported\n", dnp->dn_expr->dn_ident->di_name);1177}1178}11791180static void1181dt_compile_exp(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)1182{1183dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);11841185dt_cg(yypcb, dnp->dn_expr);1186ap->dtad_difo = dt_as(yypcb);1187ap->dtad_difo->dtdo_rtype = dt_void_rtype;1188ap->dtad_kind = DTRACEACT_DIFEXPR;1189}11901191static void1192dt_compile_agg(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)1193{1194dt_ident_t *aid, *fid;1195dt_node_t *anp, *incr = NULL;1196dtrace_actdesc_t *ap;1197uint_t n = 1, argmax;1198uint64_t arg = 0;11991200/*1201* If the aggregation has no aggregating function applied to it, then1202* this statement has no effect. Flag this as a programming error.1203*/1204if (dnp->dn_aggfun == NULL) {1205dnerror(dnp, D_AGG_NULL, "expression has null effect: @%s\n",1206dnp->dn_ident->di_name);1207}12081209aid = dnp->dn_ident;1210fid = dnp->dn_aggfun->dn_ident;12111212if (dnp->dn_aggfun->dn_args != NULL &&1213dt_node_is_scalar(dnp->dn_aggfun->dn_args) == 0) {1214dnerror(dnp->dn_aggfun, D_AGG_SCALAR, "%s( ) argument #1 must "1215"be of scalar type\n", fid->di_name);1216}12171218/*1219* The ID of the aggregation itself is implicitly recorded as the first1220* member of each aggregation tuple so we can distinguish them later.1221*/1222ap = dt_stmt_action(dtp, sdp);1223dt_action_difconst(ap, aid->di_id, DTRACEACT_DIFEXPR);12241225for (anp = dnp->dn_aggtup; anp != NULL; anp = anp->dn_list) {1226ap = dt_stmt_action(dtp, sdp);1227n++;12281229if (anp->dn_kind == DT_NODE_FUNC) {1230if (anp->dn_ident->di_id == DT_ACT_STACK) {1231dt_action_stack_args(dtp, ap, anp->dn_args);1232continue;1233}12341235if (anp->dn_ident->di_id == DT_ACT_USTACK ||1236anp->dn_ident->di_id == DT_ACT_JSTACK) {1237dt_action_ustack_args(dtp, ap, anp);1238continue;1239}12401241switch (anp->dn_ident->di_id) {1242case DT_ACT_UADDR:1243dt_action_symmod_args(dtp, ap,1244anp->dn_args, DTRACEACT_UADDR);1245continue;12461247case DT_ACT_USYM:1248dt_action_symmod_args(dtp, ap,1249anp->dn_args, DTRACEACT_USYM);1250continue;12511252case DT_ACT_UMOD:1253dt_action_symmod_args(dtp, ap,1254anp->dn_args, DTRACEACT_UMOD);1255continue;12561257case DT_ACT_SYM:1258dt_action_symmod_args(dtp, ap,1259anp->dn_args, DTRACEACT_SYM);1260continue;12611262case DT_ACT_MOD:1263dt_action_symmod_args(dtp, ap,1264anp->dn_args, DTRACEACT_MOD);1265continue;12661267default:1268break;1269}1270}12711272dt_cg(yypcb, anp);1273ap->dtad_difo = dt_as(yypcb);1274ap->dtad_kind = DTRACEACT_DIFEXPR;1275}12761277if (fid->di_id == DTRACEAGG_LQUANTIZE) {1278/*1279* For linear quantization, we have between two and four1280* arguments in addition to the expression:1281*1282* arg1 => Base value1283* arg2 => Limit value1284* arg3 => Quantization level step size (defaults to 1)1285* arg4 => Quantization increment value (defaults to 1)1286*/1287dt_node_t *arg1 = dnp->dn_aggfun->dn_args->dn_list;1288dt_node_t *arg2 = arg1->dn_list;1289dt_node_t *arg3 = arg2->dn_list;1290dt_idsig_t *isp;1291uint64_t nlevels, step = 1, oarg;1292int64_t baseval, limitval;12931294if (arg1->dn_kind != DT_NODE_INT) {1295dnerror(arg1, D_LQUANT_BASETYPE, "lquantize( ) "1296"argument #1 must be an integer constant\n");1297}12981299baseval = (int64_t)arg1->dn_value;13001301if (baseval < INT32_MIN || baseval > INT32_MAX) {1302dnerror(arg1, D_LQUANT_BASEVAL, "lquantize( ) "1303"argument #1 must be a 32-bit quantity\n");1304}13051306if (arg2->dn_kind != DT_NODE_INT) {1307dnerror(arg2, D_LQUANT_LIMTYPE, "lquantize( ) "1308"argument #2 must be an integer constant\n");1309}13101311limitval = (int64_t)arg2->dn_value;13121313if (limitval < INT32_MIN || limitval > INT32_MAX) {1314dnerror(arg2, D_LQUANT_LIMVAL, "lquantize( ) "1315"argument #2 must be a 32-bit quantity\n");1316}13171318if (limitval < baseval) {1319dnerror(dnp, D_LQUANT_MISMATCH,1320"lquantize( ) base (argument #1) must be less "1321"than limit (argument #2)\n");1322}13231324if (arg3 != NULL) {1325if (!dt_node_is_posconst(arg3)) {1326dnerror(arg3, D_LQUANT_STEPTYPE, "lquantize( ) "1327"argument #3 must be a non-zero positive "1328"integer constant\n");1329}13301331if ((step = arg3->dn_value) > UINT16_MAX) {1332dnerror(arg3, D_LQUANT_STEPVAL, "lquantize( ) "1333"argument #3 must be a 16-bit quantity\n");1334}1335}13361337nlevels = (limitval - baseval) / step;13381339if (nlevels == 0) {1340dnerror(dnp, D_LQUANT_STEPLARGE,1341"lquantize( ) step (argument #3) too large: must "1342"have at least one quantization level\n");1343}13441345if (nlevels > UINT16_MAX) {1346dnerror(dnp, D_LQUANT_STEPSMALL, "lquantize( ) step "1347"(argument #3) too small: number of quantization "1348"levels must be a 16-bit quantity\n");1349}13501351arg = (step << DTRACE_LQUANTIZE_STEPSHIFT) |1352(nlevels << DTRACE_LQUANTIZE_LEVELSHIFT) |1353((baseval << DTRACE_LQUANTIZE_BASESHIFT) &1354DTRACE_LQUANTIZE_BASEMASK);13551356assert(arg != 0);13571358isp = (dt_idsig_t *)aid->di_data;13591360if (isp->dis_auxinfo == 0) {1361/*1362* This is the first time we've seen an lquantize()1363* for this aggregation; we'll store our argument1364* as the auxiliary signature information.1365*/1366isp->dis_auxinfo = arg;1367} else if ((oarg = isp->dis_auxinfo) != arg) {1368/*1369* If we have seen this lquantize() before and the1370* argument doesn't match the original argument, pick1371* the original argument apart to concisely report the1372* mismatch.1373*/1374int obaseval = DTRACE_LQUANTIZE_BASE(oarg);1375int onlevels = DTRACE_LQUANTIZE_LEVELS(oarg);1376int ostep = DTRACE_LQUANTIZE_STEP(oarg);13771378if (obaseval != baseval) {1379dnerror(dnp, D_LQUANT_MATCHBASE, "lquantize( ) "1380"base (argument #1) doesn't match previous "1381"declaration: expected %d, found %d\n",1382obaseval, (int)baseval);1383}13841385if (onlevels * ostep != nlevels * step) {1386dnerror(dnp, D_LQUANT_MATCHLIM, "lquantize( ) "1387"limit (argument #2) doesn't match previous"1388" declaration: expected %d, found %d\n",1389obaseval + onlevels * ostep,1390(int)baseval + (int)nlevels * (int)step);1391}13921393if (ostep != step) {1394dnerror(dnp, D_LQUANT_MATCHSTEP, "lquantize( ) "1395"step (argument #3) doesn't match previous "1396"declaration: expected %d, found %d\n",1397ostep, (int)step);1398}13991400/*1401* We shouldn't be able to get here -- one of the1402* parameters must be mismatched if the arguments1403* didn't match.1404*/1405assert(0);1406}14071408incr = arg3 != NULL ? arg3->dn_list : NULL;1409argmax = 5;1410}14111412if (fid->di_id == DTRACEAGG_LLQUANTIZE) {1413/*1414* For log/linear quantizations, we have between one and five1415* arguments in addition to the expression:1416*1417* arg1 => Factor1418* arg2 => Low magnitude1419* arg3 => High magnitude1420* arg4 => Number of steps per magnitude1421* arg5 => Quantization increment value (defaults to 1)1422*/1423dt_node_t *llarg = dnp->dn_aggfun->dn_args->dn_list;1424uint64_t oarg, order, v;1425dt_idsig_t *isp;1426int i;14271428struct {1429char *str; /* string identifier */1430int badtype; /* error on bad type */1431int badval; /* error on bad value */1432int mismatch; /* error on bad match */1433int shift; /* shift value */1434uint16_t value; /* value itself */1435} args[] = {1436{ "factor", D_LLQUANT_FACTORTYPE,1437D_LLQUANT_FACTORVAL, D_LLQUANT_FACTORMATCH,1438DTRACE_LLQUANTIZE_FACTORSHIFT },1439{ "low magnitude", D_LLQUANT_LOWTYPE,1440D_LLQUANT_LOWVAL, D_LLQUANT_LOWMATCH,1441DTRACE_LLQUANTIZE_LOWSHIFT },1442{ "high magnitude", D_LLQUANT_HIGHTYPE,1443D_LLQUANT_HIGHVAL, D_LLQUANT_HIGHMATCH,1444DTRACE_LLQUANTIZE_HIGHSHIFT },1445{ "linear steps per magnitude", D_LLQUANT_NSTEPTYPE,1446D_LLQUANT_NSTEPVAL, D_LLQUANT_NSTEPMATCH,1447DTRACE_LLQUANTIZE_NSTEPSHIFT },1448{ NULL }1449};14501451assert(arg == 0);14521453for (i = 0; args[i].str != NULL; i++) {1454if (llarg->dn_kind != DT_NODE_INT) {1455dnerror(llarg, args[i].badtype, "llquantize( ) "1456"argument #%d (%s) must be an "1457"integer constant\n", i + 1, args[i].str);1458}14591460if ((uint64_t)llarg->dn_value > UINT16_MAX) {1461dnerror(llarg, args[i].badval, "llquantize( ) "1462"argument #%d (%s) must be an unsigned "1463"16-bit quantity\n", i + 1, args[i].str);1464}14651466args[i].value = (uint16_t)llarg->dn_value;14671468assert(!(arg & ((uint64_t)UINT16_MAX <<1469args[i].shift)));1470arg |= ((uint64_t)args[i].value << args[i].shift);1471llarg = llarg->dn_list;1472}14731474assert(arg != 0);14751476if (args[0].value < 2) {1477dnerror(dnp, D_LLQUANT_FACTORSMALL, "llquantize( ) "1478"factor (argument #1) must be two or more\n");1479}14801481if (args[1].value >= args[2].value) {1482dnerror(dnp, D_LLQUANT_MAGRANGE, "llquantize( ) "1483"high magnitude (argument #3) must be greater "1484"than low magnitude (argument #2)\n");1485}14861487if (args[3].value < args[0].value) {1488dnerror(dnp, D_LLQUANT_FACTORNSTEPS, "llquantize( ) "1489"factor (argument #1) must be less than or "1490"equal to the number of linear steps per "1491"magnitude (argument #4)\n");1492}14931494for (v = args[0].value; v < args[3].value; v *= args[0].value)1495continue;14961497if ((args[3].value % args[0].value) || (v % args[3].value)) {1498dnerror(dnp, D_LLQUANT_FACTOREVEN, "llquantize( ) "1499"factor (argument #1) must evenly divide the "1500"number of steps per magnitude (argument #4), "1501"and the number of steps per magnitude must evenly "1502"divide a power of the factor\n");1503}15041505for (i = 0, order = 1; i <= args[2].value + 1; i++) {1506if (order * args[0].value > order) {1507order *= args[0].value;1508continue;1509}15101511dnerror(dnp, D_LLQUANT_MAGTOOBIG, "llquantize( ) "1512"factor (%d) raised to power of high magnitude "1513"(%d) plus 1 overflows 64-bits\n", args[0].value,1514args[2].value);1515}15161517isp = (dt_idsig_t *)aid->di_data;15181519if (isp->dis_auxinfo == 0) {1520/*1521* This is the first time we've seen an llquantize()1522* for this aggregation; we'll store our argument1523* as the auxiliary signature information.1524*/1525isp->dis_auxinfo = arg;1526} else if ((oarg = isp->dis_auxinfo) != arg) {1527/*1528* If we have seen this llquantize() before and the1529* argument doesn't match the original argument, pick1530* the original argument apart to concisely report the1531* mismatch.1532*/1533int expected = 0, found = 0;15341535for (i = 0; expected == found; i++) {1536assert(args[i].str != NULL);15371538expected = (oarg >> args[i].shift) & UINT16_MAX;1539found = (arg >> args[i].shift) & UINT16_MAX;1540}15411542dnerror(dnp, args[i - 1].mismatch, "llquantize( ) "1543"%s (argument #%d) doesn't match previous "1544"declaration: expected %d, found %d\n",1545args[i - 1].str, i, expected, found);1546}15471548incr = llarg;1549argmax = 6;1550}15511552if (fid->di_id == DTRACEAGG_QUANTIZE) {1553incr = dnp->dn_aggfun->dn_args->dn_list;1554argmax = 2;1555}15561557if (incr != NULL) {1558if (!dt_node_is_scalar(incr)) {1559dnerror(dnp, D_PROTO_ARG, "%s( ) increment value "1560"(argument #%d) must be of scalar type\n",1561fid->di_name, argmax);1562}15631564if ((anp = incr->dn_list) != NULL) {1565int argc = argmax;15661567for (; anp != NULL; anp = anp->dn_list)1568argc++;15691570dnerror(incr, D_PROTO_LEN, "%s( ) prototype "1571"mismatch: %d args passed, at most %d expected",1572fid->di_name, argc, argmax);1573}15741575ap = dt_stmt_action(dtp, sdp);1576n++;15771578dt_cg(yypcb, incr);1579ap->dtad_difo = dt_as(yypcb);1580ap->dtad_difo->dtdo_rtype = dt_void_rtype;1581ap->dtad_kind = DTRACEACT_DIFEXPR;1582}15831584assert(sdp->dtsd_aggdata == NULL);1585sdp->dtsd_aggdata = aid;15861587ap = dt_stmt_action(dtp, sdp);1588assert(fid->di_kind == DT_IDENT_AGGFUNC);1589assert(DTRACEACT_ISAGG(fid->di_id));1590ap->dtad_kind = fid->di_id;1591ap->dtad_ntuple = n;1592ap->dtad_arg = arg;15931594if (dnp->dn_aggfun->dn_args != NULL) {1595dt_cg(yypcb, dnp->dn_aggfun->dn_args);1596ap->dtad_difo = dt_as(yypcb);1597}1598}15991600static void1601dt_compile_one_clause(dtrace_hdl_t *dtp, dt_node_t *cnp, dt_node_t *pnp)1602{1603dtrace_ecbdesc_t *edp;1604dtrace_stmtdesc_t *sdp;1605dt_node_t *dnp;16061607yylineno = pnp->dn_line;1608dt_setcontext(dtp, pnp->dn_desc);1609(void) dt_node_cook(cnp, DT_IDFLG_REF);16101611if (DT_TREEDUMP_PASS(dtp, 2))1612dt_node_printr(cnp, stderr, 0);16131614if ((edp = dt_ecbdesc_create(dtp, pnp->dn_desc)) == NULL)1615longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);16161617assert(yypcb->pcb_ecbdesc == NULL);1618yypcb->pcb_ecbdesc = edp;16191620if (cnp->dn_pred != NULL) {1621dt_cg(yypcb, cnp->dn_pred);1622edp->dted_pred.dtpdd_difo = dt_as(yypcb);1623}16241625if (cnp->dn_acts == NULL) {1626dt_stmt_append(dt_stmt_create(dtp, edp,1627cnp->dn_ctxattr, _dtrace_defattr), cnp);1628}16291630for (dnp = cnp->dn_acts; dnp != NULL; dnp = dnp->dn_list) {1631assert(yypcb->pcb_stmt == NULL);1632sdp = dt_stmt_create(dtp, edp, cnp->dn_ctxattr, cnp->dn_attr);16331634switch (dnp->dn_kind) {1635case DT_NODE_DEXPR:1636if (dnp->dn_expr->dn_kind == DT_NODE_AGG)1637dt_compile_agg(dtp, dnp->dn_expr, sdp);1638else1639dt_compile_exp(dtp, dnp, sdp);1640break;1641case DT_NODE_DFUNC:1642dt_compile_fun(dtp, dnp, sdp);1643break;1644case DT_NODE_AGG:1645dt_compile_agg(dtp, dnp, sdp);1646break;1647default:1648dnerror(dnp, D_UNKNOWN, "internal error -- node kind "1649"%u is not a valid statement\n", dnp->dn_kind);1650}16511652assert(yypcb->pcb_stmt == sdp);1653dt_stmt_append(sdp, dnp);1654}16551656assert(yypcb->pcb_ecbdesc == edp);1657dt_ecbdesc_release(dtp, edp);1658dt_endcontext(dtp);1659yypcb->pcb_ecbdesc = NULL;1660}16611662static void1663dt_compile_clause(dtrace_hdl_t *dtp, dt_node_t *cnp)1664{1665dt_node_t *pnp;16661667for (pnp = cnp->dn_pdescs; pnp != NULL; pnp = pnp->dn_list)1668dt_compile_one_clause(dtp, cnp, pnp);1669}16701671static void1672dt_compile_xlator(dt_node_t *dnp)1673{1674dt_xlator_t *dxp = dnp->dn_xlator;1675dt_node_t *mnp;16761677for (mnp = dnp->dn_members; mnp != NULL; mnp = mnp->dn_list) {1678assert(dxp->dx_membdif[mnp->dn_membid] == NULL);1679dt_cg(yypcb, mnp);1680dxp->dx_membdif[mnp->dn_membid] = dt_as(yypcb);1681}1682}16831684void1685dt_setcontext(dtrace_hdl_t *dtp, dtrace_probedesc_t *pdp)1686{1687const dtrace_pattr_t *pap;1688dt_probe_t *prp;1689dt_provider_t *pvp;1690dt_ident_t *idp;1691char attrstr[8];1692int err;1693size_t prov_len;16941695/*1696* Both kernel and pid based providers are allowed to have names1697* ending with what could be interpreted as a number. We assume it's1698* a pid and that we may need to dynamically create probes for1699* that process if:1700*1701* (1) The provider doesn't exist, or,1702* (2) The provider exists and has DTRACE_PRIV_PROC privilege.1703*1704* On an error, dt_pid_create_probes() will set the error message1705* and tag -- we just have to longjmp() out of here.1706*/17071708prov_len = strlen(pdp->dtpd_provider);17091710if ((prov_len > 0 && isdigit(pdp->dtpd_provider[prov_len - 1])) &&1711((pvp = dt_provider_lookup(dtp, pdp->dtpd_provider)) == NULL ||1712pvp->pv_desc.dtvd_priv.dtpp_flags & DTRACE_PRIV_PROC) &&1713dt_pid_create_probes(pdp, dtp, yypcb) != 0) {1714longjmp(yypcb->pcb_jmpbuf, EDT_COMPILER);1715}17161717/*1718* Call dt_probe_info() to get the probe arguments and attributes. If1719* a representative probe is found, set 'pap' to the probe provider's1720* attributes. Otherwise set 'pap' to default Unstable attributes.1721*/1722if ((prp = dt_probe_info(dtp, pdp, &yypcb->pcb_pinfo)) == NULL) {1723pap = &_dtrace_prvdesc;1724err = dtrace_errno(dtp);1725bzero(&yypcb->pcb_pinfo, sizeof (dtrace_probeinfo_t));1726yypcb->pcb_pinfo.dtp_attr = pap->dtpa_provider;1727yypcb->pcb_pinfo.dtp_arga = pap->dtpa_args;1728} else {1729pap = &prp->pr_pvp->pv_desc.dtvd_attr;1730err = 0;1731}17321733if (err == EDT_NOPROBE && !(yypcb->pcb_cflags & DTRACE_C_ZDEFS)) {1734xyerror(D_PDESC_ZERO, "probe description %s:%s:%s:%s does not "1735"match any probes\n", pdp->dtpd_provider, pdp->dtpd_mod,1736pdp->dtpd_func, pdp->dtpd_name);1737}17381739if (err != EDT_NOPROBE && err != EDT_UNSTABLE && err != 0)1740xyerror(D_PDESC_INVAL, "%s\n", dtrace_errmsg(dtp, err));17411742dt_dprintf("set context to %s:%s:%s:%s [%u] prp=%p attr=%s argc=%d\n",1743pdp->dtpd_provider, pdp->dtpd_mod, pdp->dtpd_func, pdp->dtpd_name,1744pdp->dtpd_id, (void *)prp, dt_attr_str(yypcb->pcb_pinfo.dtp_attr,1745attrstr, sizeof (attrstr)), yypcb->pcb_pinfo.dtp_argc);17461747/*1748* Reset the stability attributes of D global variables that vary1749* based on the attributes of the provider and context itself.1750*/1751if ((idp = dt_idhash_lookup(dtp->dt_globals, "probeprov")) != NULL)1752idp->di_attr = pap->dtpa_provider;1753if ((idp = dt_idhash_lookup(dtp->dt_globals, "probemod")) != NULL)1754idp->di_attr = pap->dtpa_mod;1755if ((idp = dt_idhash_lookup(dtp->dt_globals, "probefunc")) != NULL)1756idp->di_attr = pap->dtpa_func;1757if ((idp = dt_idhash_lookup(dtp->dt_globals, "probename")) != NULL)1758idp->di_attr = pap->dtpa_name;1759if ((idp = dt_idhash_lookup(dtp->dt_globals, "args")) != NULL)1760idp->di_attr = pap->dtpa_args;17611762yypcb->pcb_pdesc = pdp;1763yypcb->pcb_probe = prp;1764}17651766/*1767* Reset context-dependent variables and state at the end of cooking a D probe1768* definition clause. This ensures that external declarations between clauses1769* do not reference any stale context-dependent data from the previous clause.1770*/1771void1772dt_endcontext(dtrace_hdl_t *dtp)1773{1774static const char *const cvars[] = {1775"probeprov", "probemod", "probefunc", "probename", "args", NULL1776};17771778dt_ident_t *idp;1779int i;17801781for (i = 0; cvars[i] != NULL; i++) {1782if ((idp = dt_idhash_lookup(dtp->dt_globals, cvars[i])) != NULL)1783idp->di_attr = _dtrace_defattr;1784}17851786yypcb->pcb_pdesc = NULL;1787yypcb->pcb_probe = NULL;1788}17891790static int1791dt_reduceid(dt_idhash_t *dhp, dt_ident_t *idp, dtrace_hdl_t *dtp)1792{1793if (idp->di_vers != 0 && idp->di_vers > dtp->dt_vmax)1794dt_idhash_delete(dhp, idp);17951796return (0);1797}17981799/*1800* When dtrace_setopt() is called for "version", it calls dt_reduce() to remove1801* any identifiers or translators that have been previously defined as bound to1802* a version greater than the specified version. Therefore, in our current1803* version implementation, establishing a binding is a one-way transformation.1804* In addition, no versioning is currently provided for types as our .d library1805* files do not define any types and we reserve prefixes DTRACE_ and dtrace_1806* for our exclusive use. If required, type versioning will require more work.1807*/1808int1809dt_reduce(dtrace_hdl_t *dtp, dt_version_t v)1810{1811char s[DT_VERSION_STRMAX];1812dt_xlator_t *dxp, *nxp;18131814if (v > dtp->dt_vmax)1815return (dt_set_errno(dtp, EDT_VERSREDUCED));1816else if (v == dtp->dt_vmax)1817return (0); /* no reduction necessary */18181819dt_dprintf("reducing api version to %s\n",1820dt_version_num2str(v, s, sizeof (s)));18211822dtp->dt_vmax = v;18231824for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL; dxp = nxp) {1825nxp = dt_list_next(dxp);1826if ((dxp->dx_souid.di_vers != 0 && dxp->dx_souid.di_vers > v) ||1827(dxp->dx_ptrid.di_vers != 0 && dxp->dx_ptrid.di_vers > v))1828dt_list_delete(&dtp->dt_xlators, dxp);1829}18301831(void) dt_idhash_iter(dtp->dt_macros, (dt_idhash_f *)dt_reduceid, dtp);1832(void) dt_idhash_iter(dtp->dt_aggs, (dt_idhash_f *)dt_reduceid, dtp);1833(void) dt_idhash_iter(dtp->dt_globals, (dt_idhash_f *)dt_reduceid, dtp);1834(void) dt_idhash_iter(dtp->dt_tls, (dt_idhash_f *)dt_reduceid, dtp);18351836return (0);1837}18381839/*1840* Fork and exec the cpp(1) preprocessor to run over the specified input file,1841* and return a FILE handle for the cpp output. We use the /dev/fd filesystem1842* here to simplify the code by leveraging file descriptor inheritance.1843*/1844static FILE *1845dt_preproc(dtrace_hdl_t *dtp, FILE *ifp)1846{1847int argc = dtp->dt_cpp_argc;1848char **argv = malloc(sizeof (char *) * (argc + 5));1849FILE *ofp = tmpfile();18501851#ifdef illumos1852char ipath[20], opath[20]; /* big enough for /dev/fd/ + INT_MAX + \0 */1853#endif1854char verdef[32]; /* big enough for -D__SUNW_D_VERSION=0x%08x + \0 */18551856struct sigaction act, oact;1857sigset_t mask, omask;18581859int wstat, estat;1860pid_t pid;1861#ifdef illumos1862off64_t off;1863#else1864off_t off = 0;1865#endif1866int c;18671868if (argv == NULL || ofp == NULL) {1869(void) dt_set_errno(dtp, errno);1870goto err;1871}18721873/*1874* If the input is a seekable file, see if it is an interpreter file.1875* If we see #!, seek past the first line because cpp will choke on it.1876* We start cpp just prior to the \n at the end of this line so that1877* it still sees the newline, ensuring that #line values are correct.1878*/1879if (isatty(fileno(ifp)) == 0 && (off = ftello64(ifp)) != -1) {1880if ((c = fgetc(ifp)) == '#' && (c = fgetc(ifp)) == '!') {1881for (off += 2; c != '\n'; off++) {1882if ((c = fgetc(ifp)) == EOF)1883break;1884}1885if (c == '\n')1886off--; /* start cpp just prior to \n */1887}1888(void) fflush(ifp);1889(void) fseeko64(ifp, off, SEEK_SET);1890}18911892#ifdef illumos1893(void) snprintf(ipath, sizeof (ipath), "/dev/fd/%d", fileno(ifp));1894(void) snprintf(opath, sizeof (opath), "/dev/fd/%d", fileno(ofp));1895#endif18961897bcopy(dtp->dt_cpp_argv, argv, sizeof (char *) * argc);18981899(void) snprintf(verdef, sizeof (verdef),1900"-D__SUNW_D_VERSION=0x%08x", dtp->dt_vmax);1901argv[argc++] = verdef;19021903#ifdef illumos1904switch (dtp->dt_stdcmode) {1905case DT_STDC_XA:1906case DT_STDC_XT:1907argv[argc++] = "-D__STDC__=0";1908break;1909case DT_STDC_XC:1910argv[argc++] = "-D__STDC__=1";1911break;1912}19131914argv[argc++] = ipath;1915argv[argc++] = opath;1916#else1917argv[argc++] = "-P";1918#endif1919argv[argc] = NULL;19201921/*1922* libdtrace must be able to be embedded in other programs that may1923* include application-specific signal handlers. Therefore, if we1924* need to fork to run cpp(1), we must avoid generating a SIGCHLD1925* that could confuse the containing application. To do this,1926* we block SIGCHLD and reset its disposition to SIG_DFL.1927* We restore our signal state once we are done.1928*/1929(void) sigemptyset(&mask);1930(void) sigaddset(&mask, SIGCHLD);1931(void) sigprocmask(SIG_BLOCK, &mask, &omask);19321933bzero(&act, sizeof (act));1934act.sa_handler = SIG_DFL;1935(void) sigaction(SIGCHLD, &act, &oact);19361937if ((pid = fork1()) == -1) {1938(void) sigaction(SIGCHLD, &oact, NULL);1939(void) sigprocmask(SIG_SETMASK, &omask, NULL);1940(void) dt_set_errno(dtp, EDT_CPPFORK);1941goto err;1942}19431944if (pid == 0) {1945#ifndef illumos1946if (isatty(fileno(ifp)) == 0)1947lseek(fileno(ifp), off, SEEK_SET);1948dup2(fileno(ifp), 0);1949dup2(fileno(ofp), 1);1950#endif1951(void) execvp(dtp->dt_cpp_path, argv);1952_exit(errno == ENOENT ? 127 : 126);1953}19541955do {1956dt_dprintf("waiting for %s (PID %d)\n", dtp->dt_cpp_path,1957(int)pid);1958} while (waitpid(pid, &wstat, 0) == -1 && errno == EINTR);19591960(void) sigaction(SIGCHLD, &oact, NULL);1961(void) sigprocmask(SIG_SETMASK, &omask, NULL);19621963dt_dprintf("%s returned exit status 0x%x\n", dtp->dt_cpp_path, wstat);1964estat = WIFEXITED(wstat) ? WEXITSTATUS(wstat) : -1;19651966if (estat != 0) {1967switch (estat) {1968case 126:1969(void) dt_set_errno(dtp, EDT_CPPEXEC);1970break;1971case 127:1972(void) dt_set_errno(dtp, EDT_CPPENT);1973break;1974default:1975(void) dt_set_errno(dtp, EDT_CPPERR);1976}1977goto err;1978}19791980free(argv);1981(void) fflush(ofp);1982(void) fseek(ofp, 0, SEEK_SET);1983return (ofp);19841985err:1986free(argv);1987(void) fclose(ofp);1988return (NULL);1989}19901991static void1992dt_lib_depend_error(dtrace_hdl_t *dtp, const char *format, ...)1993{1994va_list ap;19951996va_start(ap, format);1997dt_set_errmsg(dtp, NULL, NULL, NULL, 0, format, ap);1998va_end(ap);1999}20002001int2002dt_lib_depend_add(dtrace_hdl_t *dtp, dt_list_t *dlp, const char *arg)2003{2004dt_lib_depend_t *dld;2005const char *end;20062007assert(arg != NULL);20082009if ((end = strrchr(arg, '/')) == NULL)2010return (dt_set_errno(dtp, EINVAL));20112012if ((dld = dt_zalloc(dtp, sizeof (dt_lib_depend_t))) == NULL)2013return (-1);20142015if ((dld->dtld_libpath = dt_alloc(dtp, MAXPATHLEN)) == NULL) {2016dt_free(dtp, dld);2017return (-1);2018}20192020(void) strlcpy(dld->dtld_libpath, arg, end - arg + 2);2021if ((dld->dtld_library = strdup(arg)) == NULL) {2022dt_free(dtp, dld->dtld_libpath);2023dt_free(dtp, dld);2024return (dt_set_errno(dtp, EDT_NOMEM));2025}20262027dt_list_append(dlp, dld);2028return (0);2029}20302031dt_lib_depend_t *2032dt_lib_depend_lookup(dt_list_t *dld, const char *arg)2033{2034dt_lib_depend_t *dldn;20352036for (dldn = dt_list_next(dld); dldn != NULL;2037dldn = dt_list_next(dldn)) {2038if (strcmp(dldn->dtld_library, arg) == 0)2039return (dldn);2040}20412042return (NULL);2043}20442045/*2046* Go through all the library files, and, if any library dependencies exist for2047* that file, add it to that node's list of dependents. The result of this2048* will be a graph which can then be topologically sorted to produce a2049* compilation order.2050*/2051static int2052dt_lib_build_graph(dtrace_hdl_t *dtp)2053{2054dt_lib_depend_t *dld, *dpld;20552056for (dld = dt_list_next(&dtp->dt_lib_dep); dld != NULL;2057dld = dt_list_next(dld)) {2058char *library = dld->dtld_library;20592060for (dpld = dt_list_next(&dld->dtld_dependencies); dpld != NULL;2061dpld = dt_list_next(dpld)) {2062dt_lib_depend_t *dlda;20632064if ((dlda = dt_lib_depend_lookup(&dtp->dt_lib_dep,2065dpld->dtld_library)) == NULL) {2066dt_lib_depend_error(dtp,2067"Invalid library dependency in %s: %s\n",2068dld->dtld_library, dpld->dtld_library);20692070return (dt_set_errno(dtp, EDT_COMPILER));2071}20722073if ((dt_lib_depend_add(dtp, &dlda->dtld_dependents,2074library)) != 0) {2075return (-1); /* preserve dt_errno */2076}2077}2078}2079return (0);2080}20812082static int2083dt_topo_sort(dtrace_hdl_t *dtp, dt_lib_depend_t *dld, int *count)2084{2085dt_lib_depend_t *dpld, *dlda, *new;20862087dld->dtld_start = ++(*count);20882089for (dpld = dt_list_next(&dld->dtld_dependents); dpld != NULL;2090dpld = dt_list_next(dpld)) {2091dlda = dt_lib_depend_lookup(&dtp->dt_lib_dep,2092dpld->dtld_library);2093assert(dlda != NULL);20942095if (dlda->dtld_start == 0 &&2096dt_topo_sort(dtp, dlda, count) == -1)2097return (-1);2098}20992100if ((new = dt_zalloc(dtp, sizeof (dt_lib_depend_t))) == NULL)2101return (-1);21022103if ((new->dtld_library = strdup(dld->dtld_library)) == NULL) {2104dt_free(dtp, new);2105return (dt_set_errno(dtp, EDT_NOMEM));2106}21072108new->dtld_start = dld->dtld_start;2109new->dtld_finish = dld->dtld_finish = ++(*count);2110dt_list_prepend(&dtp->dt_lib_dep_sorted, new);21112112dt_dprintf("library %s sorted (%d/%d)\n", new->dtld_library,2113new->dtld_start, new->dtld_finish);21142115return (0);2116}21172118static int2119dt_lib_depend_sort(dtrace_hdl_t *dtp)2120{2121dt_lib_depend_t *dld, *dpld, *dlda;2122int count = 0;21232124if (dt_lib_build_graph(dtp) == -1)2125return (-1); /* preserve dt_errno */21262127/*2128* Perform a topological sort of the graph that hangs off2129* dtp->dt_lib_dep. The result of this process will be a2130* dependency ordered list located at dtp->dt_lib_dep_sorted.2131*/2132for (dld = dt_list_next(&dtp->dt_lib_dep); dld != NULL;2133dld = dt_list_next(dld)) {2134if (dld->dtld_start == 0 &&2135dt_topo_sort(dtp, dld, &count) == -1)2136return (-1); /* preserve dt_errno */;2137}21382139/*2140* Check the graph for cycles. If an ancestor's finishing time is2141* less than any of its dependent's finishing times then a back edge2142* exists in the graph and this is a cycle.2143*/2144for (dld = dt_list_next(&dtp->dt_lib_dep); dld != NULL;2145dld = dt_list_next(dld)) {2146for (dpld = dt_list_next(&dld->dtld_dependents); dpld != NULL;2147dpld = dt_list_next(dpld)) {2148dlda = dt_lib_depend_lookup(&dtp->dt_lib_dep_sorted,2149dpld->dtld_library);2150assert(dlda != NULL);21512152if (dlda->dtld_finish > dld->dtld_finish) {2153dt_lib_depend_error(dtp,2154"Cyclic dependency detected: %s => %s\n",2155dld->dtld_library, dpld->dtld_library);21562157return (dt_set_errno(dtp, EDT_COMPILER));2158}2159}2160}21612162return (0);2163}21642165static void2166dt_lib_depend_free(dtrace_hdl_t *dtp)2167{2168dt_lib_depend_t *dld, *dlda;21692170while ((dld = dt_list_next(&dtp->dt_lib_dep)) != NULL) {2171while ((dlda = dt_list_next(&dld->dtld_dependencies)) != NULL) {2172dt_list_delete(&dld->dtld_dependencies, dlda);2173dt_free(dtp, dlda->dtld_library);2174dt_free(dtp, dlda->dtld_libpath);2175dt_free(dtp, dlda);2176}2177while ((dlda = dt_list_next(&dld->dtld_dependents)) != NULL) {2178dt_list_delete(&dld->dtld_dependents, dlda);2179dt_free(dtp, dlda->dtld_library);2180dt_free(dtp, dlda->dtld_libpath);2181dt_free(dtp, dlda);2182}2183dt_list_delete(&dtp->dt_lib_dep, dld);2184dt_free(dtp, dld->dtld_library);2185dt_free(dtp, dld->dtld_libpath);2186dt_free(dtp, dld);2187}21882189while ((dld = dt_list_next(&dtp->dt_lib_dep_sorted)) != NULL) {2190dt_list_delete(&dtp->dt_lib_dep_sorted, dld);2191dt_free(dtp, dld->dtld_library);2192dt_free(dtp, dld);2193}2194}21952196/*2197* Open all the .d library files found in the specified directory and2198* compile each one of them. We silently ignore any missing directories and2199* other files found therein. We only fail (and thereby fail dt_load_libs()) if2200* we fail to compile a library and the error is something other than #pragma D2201* depends_on. Dependency errors are silently ignored to permit a library2202* directory to contain libraries which may not be accessible depending on our2203* privileges.2204*/2205static int2206dt_load_libs_dir(dtrace_hdl_t *dtp, const char *path)2207{2208struct dirent *dp;2209const char *p, *end;2210DIR *dirp;22112212char fname[PATH_MAX];2213FILE *fp;2214void *rv;2215dt_lib_depend_t *dld;22162217if ((dirp = opendir(path)) == NULL) {2218dt_dprintf("skipping lib dir %s: %s\n", path, strerror(errno));2219return (0);2220}22212222/* First, parse each file for library dependencies. */2223while ((dp = readdir(dirp)) != NULL) {2224if ((p = strrchr(dp->d_name, '.')) == NULL || strcmp(p, ".d"))2225continue; /* skip any filename not ending in .d */22262227(void) snprintf(fname, sizeof (fname),2228"%s/%s", path, dp->d_name);22292230if ((fp = fopen(fname, "r")) == NULL) {2231dt_dprintf("skipping library %s: %s\n",2232fname, strerror(errno));2233continue;2234}22352236/*2237* Skip files whose name match an already processed library2238*/2239for (dld = dt_list_next(&dtp->dt_lib_dep); dld != NULL;2240dld = dt_list_next(dld)) {2241end = strrchr(dld->dtld_library, '/');2242/* dt_lib_depend_add ensures this */2243assert(end != NULL);2244if (strcmp(end + 1, dp->d_name) == 0)2245break;2246}22472248if (dld != NULL) {2249dt_dprintf("skipping library %s, already processed "2250"library with the same name: %s", dp->d_name,2251dld->dtld_library);2252(void) fclose(fp);2253continue;2254}22552256dtp->dt_filetag = fname;2257if (dt_lib_depend_add(dtp, &dtp->dt_lib_dep, fname) != 0) {2258(void) fclose(fp);2259return (-1); /* preserve dt_errno */2260}22612262rv = dt_compile(dtp, DT_CTX_DPROG,2263DTRACE_PROBESPEC_NAME, NULL,2264DTRACE_C_EMPTY | DTRACE_C_CTL, 0, NULL, fp, NULL);22652266if (rv != NULL && dtp->dt_errno &&2267(dtp->dt_errno != EDT_COMPILER ||2268dtp->dt_errtag != dt_errtag(D_PRAGMA_DEPEND))) {2269(void) fclose(fp);2270return (-1); /* preserve dt_errno */2271}22722273if (dtp->dt_errno)2274dt_dprintf("error parsing library %s: %s\n",2275fname, dtrace_errmsg(dtp, dtrace_errno(dtp)));22762277(void) fclose(fp);2278dtp->dt_filetag = NULL;2279}22802281(void) closedir(dirp);22822283return (0);2284}22852286/*2287* Perform a topological sorting of all the libraries found across the entire2288* dt_lib_path. Once sorted, compile each one in topological order to cache its2289* inlines and translators, etc. We silently ignore any missing directories and2290* other files found therein. We only fail (and thereby fail dt_load_libs()) if2291* we fail to compile a library and the error is something other than #pragma D2292* depends_on. Dependency errors are silently ignored to permit a library2293* directory to contain libraries which may not be accessible depending on our2294* privileges.2295*/2296static int2297dt_load_libs_sort(dtrace_hdl_t *dtp)2298{2299dtrace_prog_t *pgp;2300FILE *fp;2301dt_lib_depend_t *dld;23022303/*2304* Finish building the graph containing the library dependencies2305* and perform a topological sort to generate an ordered list2306* for compilation.2307*/2308if (dt_lib_depend_sort(dtp) == -1)2309goto err;23102311for (dld = dt_list_next(&dtp->dt_lib_dep_sorted); dld != NULL;2312dld = dt_list_next(dld)) {23132314if ((fp = fopen(dld->dtld_library, "r")) == NULL) {2315dt_dprintf("skipping library %s: %s\n",2316dld->dtld_library, strerror(errno));2317continue;2318}23192320dtp->dt_filetag = dld->dtld_library;2321pgp = dtrace_program_fcompile(dtp, fp, DTRACE_C_EMPTY, 0, NULL);2322(void) fclose(fp);2323dtp->dt_filetag = NULL;23242325if (pgp == NULL && (dtp->dt_errno != EDT_COMPILER ||2326dtp->dt_errtag != dt_errtag(D_PRAGMA_DEPEND)))2327goto err;23282329if (pgp == NULL) {2330dt_dprintf("skipping library %s: %s\n",2331dld->dtld_library,2332dtrace_errmsg(dtp, dtrace_errno(dtp)));2333} else {2334dld->dtld_loaded = B_TRUE;2335dt_program_destroy(dtp, pgp);2336}2337}23382339dt_lib_depend_free(dtp);2340return (0);23412342err:2343dt_lib_depend_free(dtp);2344return (-1); /* preserve dt_errno */2345}23462347/*2348* Load the contents of any appropriate DTrace .d library files. These files2349* contain inlines and translators that will be cached by the compiler. We2350* defer this activity until the first compile to permit libdtrace clients to2351* add their own library directories and so that we can properly report errors.2352*/2353static int2354dt_load_libs(dtrace_hdl_t *dtp)2355{2356dt_dirpath_t *dirp;23572358if (dtp->dt_cflags & DTRACE_C_NOLIBS)2359return (0); /* libraries already processed */23602361dtp->dt_cflags |= DTRACE_C_NOLIBS;23622363/*2364* /usr/lib/dtrace is always at the head of the list. The rest of the2365* list is specified in the precedence order the user requested. Process2366* everything other than the head first. DTRACE_C_NOLIBS has already2367* been spcified so dt_vopen will ensure that there is always one entry2368* in dt_lib_path.2369*/2370for (dirp = dt_list_next(dt_list_next(&dtp->dt_lib_path));2371dirp != NULL; dirp = dt_list_next(dirp)) {2372if (dt_load_libs_dir(dtp, dirp->dir_path) != 0) {2373dtp->dt_cflags &= ~DTRACE_C_NOLIBS;2374return (-1); /* errno is set for us */2375}2376}23772378/* Handle /usr/lib/dtrace */2379dirp = dt_list_next(&dtp->dt_lib_path);2380if (dt_load_libs_dir(dtp, dirp->dir_path) != 0) {2381dtp->dt_cflags &= ~DTRACE_C_NOLIBS;2382return (-1); /* errno is set for us */2383}23842385if (dt_load_libs_sort(dtp) < 0)2386return (-1); /* errno is set for us */23872388return (0);2389}23902391static void *2392dt_compile(dtrace_hdl_t *dtp, int context, dtrace_probespec_t pspec, void *arg,2393uint_t cflags, int argc, char *const argv[], FILE *fp, const char *s)2394{2395dt_node_t *dnp;2396dt_decl_t *ddp;2397dt_pcb_t pcb;2398void *volatile rv;2399int err;24002401if ((fp == NULL && s == NULL) || (cflags & ~DTRACE_C_MASK) != 0) {2402(void) dt_set_errno(dtp, EINVAL);2403return (NULL);2404}24052406if (dt_list_next(&dtp->dt_lib_path) != NULL && dt_load_libs(dtp) != 0)2407return (NULL); /* errno is set for us */24082409if (dtp->dt_globals->dh_nelems != 0)2410(void) dt_idhash_iter(dtp->dt_globals, dt_idreset, NULL);24112412if (dtp->dt_tls->dh_nelems != 0)2413(void) dt_idhash_iter(dtp->dt_tls, dt_idreset, NULL);24142415if (fp && (cflags & DTRACE_C_CPP) && (fp = dt_preproc(dtp, fp)) == NULL)2416return (NULL); /* errno is set for us */24172418dt_pcb_push(dtp, &pcb);24192420pcb.pcb_fileptr = fp;2421pcb.pcb_string = s;2422pcb.pcb_strptr = s;2423pcb.pcb_strlen = s ? strlen(s) : 0;2424pcb.pcb_sargc = argc;2425pcb.pcb_sargv = argv;2426pcb.pcb_sflagv = argc ? calloc(argc, sizeof (ushort_t)) : NULL;2427pcb.pcb_pspec = pspec;2428pcb.pcb_cflags = dtp->dt_cflags | cflags;2429pcb.pcb_amin = dtp->dt_amin;2430pcb.pcb_yystate = -1;2431pcb.pcb_context = context;2432pcb.pcb_token = context;24332434if (context != DT_CTX_DPROG)2435yybegin(YYS_EXPR);2436else if (cflags & DTRACE_C_CTL)2437yybegin(YYS_CONTROL);2438else2439yybegin(YYS_CLAUSE);24402441if ((err = setjmp(yypcb->pcb_jmpbuf)) != 0)2442goto out;24432444if (yypcb->pcb_sargc != 0 && yypcb->pcb_sflagv == NULL)2445longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);24462447yypcb->pcb_idents = dt_idhash_create("ambiguous", NULL, 0, 0);2448yypcb->pcb_locals = dt_idhash_create("clause local", NULL,2449DIF_VAR_OTHER_UBASE, DIF_VAR_OTHER_MAX);24502451if (yypcb->pcb_idents == NULL || yypcb->pcb_locals == NULL)2452longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);24532454/*2455* Invoke the parser to evaluate the D source code. If any errors2456* occur during parsing, an error function will be called and we2457* will longjmp back to pcb_jmpbuf to abort. If parsing succeeds,2458* we optionally display the parse tree if debugging is enabled.2459*/2460if (yyparse() != 0 || yypcb->pcb_root == NULL)2461xyerror(D_EMPTY, "empty D program translation unit\n");24622463yybegin(YYS_DONE);24642465if (cflags & DTRACE_C_CTL)2466goto out;24672468if (context != DT_CTX_DTYPE && DT_TREEDUMP_PASS(dtp, 1))2469dt_node_printr(yypcb->pcb_root, stderr, 0);24702471if (yypcb->pcb_pragmas != NULL)2472(void) dt_idhash_iter(yypcb->pcb_pragmas, dt_idpragma, NULL);24732474if (argc > 1 && !(yypcb->pcb_cflags & DTRACE_C_ARGREF) &&2475!(yypcb->pcb_sflagv[argc - 1] & DT_IDFLG_REF)) {2476xyerror(D_MACRO_UNUSED, "extraneous argument '%s' ($%d is "2477"not referenced)\n", yypcb->pcb_sargv[argc - 1], argc - 1);2478}24792480/* Perform sugar transformations. */2481if (context == DT_CTX_DPROG) {2482dt_node_t *dnp, *next_dnp;2483dt_node_t *new_list = NULL;24842485for (dnp = yypcb->pcb_root->dn_list;2486dnp != NULL; dnp = next_dnp) {2487/* remove this node from the list */2488next_dnp = dnp->dn_list;2489dnp->dn_list = NULL;24902491if (dnp->dn_kind == DT_NODE_CLAUSE) {2492dnp = dt_compile_sugar(dtp, dnp);2493if (cflags & DTRACE_C_SUGAR) {2494dt_node_t *p;24952496dt_printd(dnp, stdout, 0);2497for (p = dnp->dn_list; p != NULL;2498p = p->dn_list)2499dt_printd(p, stdout, 0);2500}2501}2502/* append node to the new list */2503new_list = dt_node_link(new_list, dnp);2504}2505yypcb->pcb_root->dn_list = new_list;2506}25072508/*2509* If we have successfully created a parse tree for a D program, loop2510* over the clauses and actions and instantiate the corresponding2511* libdtrace program. If we are parsing a D expression, then we2512* simply run the code generator and assembler on the resulting tree.2513*/2514switch (context) {2515case DT_CTX_DPROG:2516assert(yypcb->pcb_root->dn_kind == DT_NODE_PROG);25172518if ((dnp = yypcb->pcb_root->dn_list) == NULL &&2519!(yypcb->pcb_cflags & DTRACE_C_EMPTY))2520xyerror(D_EMPTY, "empty D program translation unit\n");25212522if ((yypcb->pcb_prog = dt_program_create(dtp)) == NULL)2523longjmp(yypcb->pcb_jmpbuf, dtrace_errno(dtp));25242525for (; dnp != NULL; dnp = dnp->dn_list) {2526switch (dnp->dn_kind) {2527case DT_NODE_CLAUSE:2528if (DT_TREEDUMP_PASS(dtp, 4))2529dt_printd(dnp, stderr, 0);2530dt_compile_clause(dtp, dnp);2531break;2532case DT_NODE_XLATOR:2533if (dtp->dt_xlatemode == DT_XL_DYNAMIC)2534dt_compile_xlator(dnp);2535break;2536case DT_NODE_PROVIDER:2537(void) dt_node_cook(dnp, DT_IDFLG_REF);2538break;2539}2540}25412542yypcb->pcb_prog->dp_xrefs = yypcb->pcb_asxrefs;2543yypcb->pcb_prog->dp_xrefslen = yypcb->pcb_asxreflen;2544yypcb->pcb_asxrefs = NULL;2545yypcb->pcb_asxreflen = 0;25462547rv = yypcb->pcb_prog;2548break;25492550case DT_CTX_DEXPR:2551(void) dt_node_cook(yypcb->pcb_root, DT_IDFLG_REF);2552dt_cg(yypcb, yypcb->pcb_root);2553rv = dt_as(yypcb);2554break;25552556case DT_CTX_DTYPE:2557ddp = (dt_decl_t *)yypcb->pcb_root; /* root is really a decl */2558err = dt_decl_type(ddp, arg);2559dt_decl_free(ddp);25602561if (err != 0)2562longjmp(yypcb->pcb_jmpbuf, EDT_COMPILER);25632564rv = NULL;2565break;2566}25672568out:2569if (context != DT_CTX_DTYPE && yypcb->pcb_root != NULL &&2570DT_TREEDUMP_PASS(dtp, 3))2571dt_node_printr(yypcb->pcb_root, stderr, 0);25722573if (dtp->dt_cdefs_fd != -1 && (ftruncate64(dtp->dt_cdefs_fd, 0) == -1 ||2574lseek64(dtp->dt_cdefs_fd, 0, SEEK_SET) == -1 ||2575ctf_write(dtp->dt_cdefs->dm_ctfp, dtp->dt_cdefs_fd) == CTF_ERR))2576dt_dprintf("failed to update CTF cache: %s\n", strerror(errno));25772578if (dtp->dt_ddefs_fd != -1 && (ftruncate64(dtp->dt_ddefs_fd, 0) == -1 ||2579lseek64(dtp->dt_ddefs_fd, 0, SEEK_SET) == -1 ||2580ctf_write(dtp->dt_ddefs->dm_ctfp, dtp->dt_ddefs_fd) == CTF_ERR))2581dt_dprintf("failed to update CTF cache: %s\n", strerror(errno));25822583if (yypcb->pcb_fileptr && (cflags & DTRACE_C_CPP))2584(void) fclose(yypcb->pcb_fileptr); /* close dt_preproc() file */25852586dt_pcb_pop(dtp, err);2587(void) dt_set_errno(dtp, err);2588return (err ? NULL : rv);2589}25902591dtrace_prog_t *2592dtrace_program_strcompile(dtrace_hdl_t *dtp, const char *s,2593dtrace_probespec_t spec, uint_t cflags, int argc, char *const argv[])2594{2595return (dt_compile(dtp, DT_CTX_DPROG,2596spec, NULL, cflags, argc, argv, NULL, s));2597}25982599dtrace_prog_t *2600dtrace_program_fcompile(dtrace_hdl_t *dtp, FILE *fp,2601uint_t cflags, int argc, char *const argv[])2602{2603return (dt_compile(dtp, DT_CTX_DPROG,2604DTRACE_PROBESPEC_NAME, NULL, cflags, argc, argv, fp, NULL));2605}26062607int2608dtrace_type_strcompile(dtrace_hdl_t *dtp, const char *s, dtrace_typeinfo_t *dtt)2609{2610(void) dt_compile(dtp, DT_CTX_DTYPE,2611DTRACE_PROBESPEC_NONE, dtt, 0, 0, NULL, NULL, s);2612return (dtp->dt_errno ? -1 : 0);2613}26142615int2616dtrace_type_fcompile(dtrace_hdl_t *dtp, FILE *fp, dtrace_typeinfo_t *dtt)2617{2618(void) dt_compile(dtp, DT_CTX_DTYPE,2619DTRACE_PROBESPEC_NONE, dtt, 0, 0, NULL, fp, NULL);2620return (dtp->dt_errno ? -1 : 0);2621}262226232624