dt_cc.c
来自「Sun Solaris 10 中的 DTrace 组件的源代码。请参看: htt」· C语言 代码 · 共 2,025 行 · 第 1/4 页
C
2,025 行
/* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only. * See the file usr/src/LICENSING.NOTICE in this distribution or * http://www.opensolaris.org/license/ for details. */#pragma ident "@(#)dt_cc.c 1.14 04/12/18 SMI"/* * DTrace D Language Compiler * * The code in this source file implements the main engine for the D language * compiler. The driver routine for the compiler is dt_compile(), below. The * compiler operates on either stdio FILEs or in-memory strings as its input * and can produce either dtrace_prog_t structures from a D program or a single * dtrace_difo_t structure from a D expression. Multiple entry points are * provided as wrappers around dt_compile() for the various input/output pairs. * The compiler itself is implemented across the following source files: * * dt_lex.l - lex scanner * dt_grammar.y - yacc grammar * dt_parser.c - parse tree creation and semantic checking * dt_decl.c - declaration stack processing * dt_xlator.c - D translator lookup and creation * dt_ident.c - identifier and symbol table routines * dt_pragma.c - #pragma processing and D pragmas * dt_printf.c - D printf() and printa() argument checking and processing * dt_cc.c - compiler driver and dtrace_prog_t construction * dt_cg.c - DIF code generator * dt_as.c - DIF assembler * dt_dof.c - dtrace_prog_t -> DOF conversion * * Several other source files provide collections of utility routines used by * these major files. The compiler itself is implemented in multiple passes: * * (1) The input program is scanned and parsed by dt_lex.l and dt_grammar.y * and parse tree nodes are constructed using the routines in dt_parser.c. * This node construction pass is described further in dt_parser.c. * * (2) The parse tree is "cooked" by assigning each clause a context (see the * routine dt_setcontext(), below) based on its probe description and then * recursively descending the tree performing semantic checking. The cook * routines are also implemented in dt_parser.c and described there. * * (3) For actions that are DIF expression statements, the DIF code generator * and assembler are invoked to create a finished DIFO for the statement. * * (4) The dtrace_prog_t data structures for the program clauses and actions * are built, containing pointers to any DIFOs created in step (3). * * (5) The caller invokes a routine in dt_dof.c to convert the finished program * into DOF format for use in anonymous tracing or enabling in the kernel. * * In the implementation, steps 2-4 are intertwined in that they are performed * in order for each clause as part of a loop that executes over the clauses. * * The D compiler currently implements nearly no optimization. The compiler * implements integer constant folding as part of pass (1), and a set of very * simple peephole optimizations as part of pass (3). As with any C compiler, * a large number of optimizations are possible on both the intermediate data * structures and the generated DIF code. These possibilities should be * investigated in the context of whether they will have any substantive effect * on the overall DTrace probe effect before they are undertaken. */#include <sys/types.h>#include <sys/wait.h>#include <assert.h>#include <strings.h>#include <signal.h>#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <ucontext.h>#include <limits.h>#include <alloca.h>#include <ctype.h>#define _POSIX_PTHREAD_SEMANTICS#include <dirent.h>#undef _POSIX_PTHREAD_SEMANTICS#include <dt_module.h>#include <dt_provider.h>#include <dt_printf.h>#include <dt_pid.h>#include <dt_grammar.h>#include <dt_ident.h>#include <dt_string.h>#include <dt_impl.h>static const dtrace_pattr_t dt_def_pattr = {{ DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_COMMON },{ DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_COMMON },{ DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_COMMON },{ DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_COMMON },{ DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_COMMON },};static const dtrace_diftype_t dt_void_rtype = { DIF_TYPE_CTF, CTF_K_INTEGER, 0, 0, 0};static const dtrace_diftype_t dt_int_rtype = { DIF_TYPE_CTF, CTF_K_INTEGER, 0, 0, sizeof (uint64_t)};/*ARGSUSED*/static voiddt_idreset(dt_idhash_t *dhp, dt_ident_t *idp, void *ignored){ idp->di_flags &= ~(DT_IDFLG_REF | DT_IDFLG_MOD | DT_IDFLG_DIFR | DT_IDFLG_DIFW);}static voiddt_idkill(dt_idhash_t *dhp, dt_ident_t *idp, void *gen){ if (idp->di_gen == (ulong_t)gen) dt_idhash_delete(dhp, idp);}/*ARGSUSED*/static voiddt_idpragma(dt_idhash_t *dhp, dt_ident_t *idp, void *ignored){ yylineno = idp->di_lineno; xyerror(D_PRAGMA_UNUSED, "unused #pragma %s\n", (char *)idp->di_iarg);}static dtrace_stmtdesc_t *dt_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp, dtrace_attribute_t descattr, dtrace_attribute_t stmtattr){ dtrace_stmtdesc_t *sdp = dtrace_stmt_create(dtp, edp); if (sdp == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); assert(yypcb->pcb_stmt == NULL); yypcb->pcb_stmt = sdp; sdp->dtsd_descattr = descattr; sdp->dtsd_stmtattr = stmtattr; return (sdp);}static dtrace_actdesc_t *dt_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp){ dtrace_actdesc_t *new; if ((new = dtrace_stmt_action(dtp, sdp)) == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); return (new);}/* * Utility function to determine if a given action description is destructive. * The dtdo_destructive bit is set for us by the DIF assembler (see dt_as.c). */static intdt_action_destructive(const dtrace_actdesc_t *ap){ return (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind) || (ap->dtad_kind == DTRACEACT_DIFEXPR && ap->dtad_difo->dtdo_destructive));}static voiddt_stmt_append(dtrace_stmtdesc_t *sdp, const dt_node_t *dnp){ dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc; dtrace_actdesc_t *ap, *tap; int commit = 0; int speculate = 0; int datarec = 0; /* * Make sure that the new statement jibes with the rest of the ECB. */ for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) { if (ap->dtad_kind == DTRACEACT_COMMIT) { if (commit) { dnerror(dnp, D_COMM_COMM, "commit( ) may " "not follow commit( )\n"); } if (datarec) { dnerror(dnp, D_COMM_DREC, "commit( ) may " "not follow data-recording action(s)\n"); } for (tap = ap; tap != NULL; tap = tap->dtad_next) { if (!DTRACEACT_ISAGG(tap->dtad_kind)) continue; dnerror(dnp, D_AGG_COMM, "aggregating actions " "may not follow commit( )\n"); } commit = 1; continue; } if (ap->dtad_kind == DTRACEACT_SPECULATE) { if (speculate) { dnerror(dnp, D_SPEC_SPEC, "speculate( ) may " "not follow speculate( )\n"); } if (commit) { dnerror(dnp, D_SPEC_COMM, "speculate( ) may " "not follow commit( )\n"); } if (datarec) { dnerror(dnp, D_SPEC_DREC, "speculate( ) may " "not follow data-recording action(s)\n"); } speculate = 1; continue; } if (DTRACEACT_ISAGG(ap->dtad_kind)) { if (speculate) { dnerror(dnp, D_AGG_SPEC, "aggregating actions " "may not follow speculate( )\n"); } datarec = 1; continue; } if (speculate) { if (dt_action_destructive(ap)) { dnerror(dnp, D_ACT_SPEC, "destructive actions " "may not follow speculate( )\n"); } if (ap->dtad_kind == DTRACEACT_EXIT) { dnerror(dnp, D_EXIT_SPEC, "exit( ) may not " "follow speculate( )\n"); } } /* * Exclude all non data-recording actions. */ if (dt_action_destructive(ap) || ap->dtad_kind == DTRACEACT_DISCARD) continue; if (ap->dtad_kind == DTRACEACT_DIFEXPR && ap->dtad_difo->dtdo_rtype.dtdt_kind == DIF_TYPE_CTF && ap->dtad_difo->dtdo_rtype.dtdt_size == 0) continue; if (commit) { dnerror(dnp, D_DREC_COMM, "data-recording actions " "may not follow commit( )\n"); } if (!speculate) datarec = 1; } if (dtrace_stmt_add(yypcb->pcb_hdl, yypcb->pcb_prog, sdp) != 0) longjmp(yypcb->pcb_jmpbuf, dtrace_errno(yypcb->pcb_hdl)); if (yypcb->pcb_stmt == sdp) yypcb->pcb_stmt = NULL;}/* * For the first element of an aggregation tuple or for printa(), we create a * simple DIF program that simply returns the immediate value that is the ID * of the aggregation itself. This could be optimized in the future by * creating a new in-kernel dtad_kind that just returns an integer. */static voiddt_action_difconst(dtrace_actdesc_t *ap, uint_t id, dtrace_actkind_t kind){ dtrace_difo_t *dp = malloc(sizeof (dtrace_difo_t)); if (dp == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); bzero(dp, sizeof (dtrace_difo_t)); dtrace_difo_hold(dp); dp->dtdo_buf = malloc(sizeof (dif_instr_t) * 2); dp->dtdo_inttab = malloc(sizeof (uint64_t)); if (dp->dtdo_buf == NULL || dp->dtdo_inttab == NULL) { dtrace_difo_release(dp); longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); } dp->dtdo_buf[0] = DIF_INSTR_SETX(0, 1); /* setx DIF_INTEGER[0], %r1 */ dp->dtdo_buf[1] = DIF_INSTR_RET(1); /* ret %r1 */ dp->dtdo_len = 2; dp->dtdo_inttab[0] = id; dp->dtdo_intlen = 1; dp->dtdo_rtype = dt_int_rtype; ap->dtad_difo = dp; ap->dtad_kind = kind;}static voiddt_action_clear(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp){ dt_ident_t *aid; dtrace_actdesc_t *ap; dt_node_t *anp; char n[DT_TYPE_NAMELEN]; int argc = 0; for (anp = dnp->dn_args; anp != NULL; anp = anp->dn_list) argc++; /* count up arguments for error messages below */ if (argc != 1) { dnerror(dnp, D_CLEAR_PROTO, "%s( ) prototype mismatch: %d args passed, 1 expected\n", dnp->dn_ident->di_name, argc); } anp = dnp->dn_args; assert(anp != NULL); if (anp->dn_kind != DT_NODE_AGG) { dnerror(dnp, D_CLEAR_AGGARG, "%s( ) argument #1 is incompatible with prototype:\n" "\tprototype: aggregation\n\t argument: %s\n", dnp->dn_ident->di_name, dt_node_type_name(anp, n, sizeof (n))); } aid = anp->dn_ident; if (aid->di_gen == dtp->dt_gen && !(aid->di_flags & DT_IDFLG_MOD)) { dnerror(dnp, D_CLEAR_AGGBAD, "undefined aggregation: @%s\n", aid->di_name); } ap = dt_stmt_action(dtp, sdp); dt_action_difconst(ap, anp->dn_ident->di_id, DTRACEACT_LIBACT); ap->dtad_arg = DT_ACT_CLEAR;}static voiddt_action_normalize(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp){ dt_ident_t *aid; dtrace_actdesc_t *ap; dt_node_t *anp, *normal; int denormal = (strcmp(dnp->dn_ident->di_name, "denormalize") == 0); char n[DT_TYPE_NAMELEN]; int argc = 0; for (anp = dnp->dn_args; anp != NULL; anp = anp->dn_list) argc++; /* count up arguments for error messages below */ if ((denormal && argc != 1) || (!denormal && argc != 2)) { dnerror(dnp, D_NORMALIZE_PROTO, "%s( ) prototype mismatch: %d args passed, %d expected\n", dnp->dn_ident->di_name, argc, denormal ? 1 : 2); } anp = dnp->dn_args; assert(anp != NULL); if (anp->dn_kind != DT_NODE_AGG) { dnerror(dnp, D_NORMALIZE_AGGARG, "%s( ) argument #1 is incompatible with prototype:\n" "\tprototype: aggregation\n\t argument: %s\n", dnp->dn_ident->di_name, dt_node_type_name(anp, n, sizeof (n))); } if ((normal = anp->dn_list) != NULL && !dt_node_is_scalar(normal)) { dnerror(dnp, D_NORMALIZE_SCALAR, "%s( ) argument #2 must be of scalar type\n", dnp->dn_ident->di_name); } aid = anp->dn_ident; if (aid->di_gen == dtp->dt_gen && !(aid->di_flags & DT_IDFLG_MOD)) { dnerror(dnp, D_NORMALIZE_AGGBAD, "undefined aggregation: @%s\n", aid->di_name); } ap = dt_stmt_action(dtp, sdp); dt_action_difconst(ap, anp->dn_ident->di_id, DTRACEACT_LIBACT); if (denormal) { ap->dtad_arg = DT_ACT_DENORMALIZE; return; } ap->dtad_arg = DT_ACT_NORMALIZE; assert(normal != NULL); ap = dt_stmt_action(dtp, sdp); dt_cg(yypcb, normal); ap->dtad_difo = dt_as(yypcb); ap->dtad_kind = DTRACEACT_LIBACT; ap->dtad_arg = DT_ACT_NORMALIZE;}static voiddt_action_trunc(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp){ dt_ident_t *aid; dtrace_actdesc_t *ap; dt_node_t *anp, *trunc; char n[DT_TYPE_NAMELEN]; int argc = 0; for (anp = dnp->dn_args; anp != NULL; anp = anp->dn_list) argc++; /* count up arguments for error messages below */ if (argc > 2 || argc < 1) { dnerror(dnp, D_TRUNC_PROTO, "%s( ) prototype mismatch: %d args passed, %s expected\n", dnp->dn_ident->di_name, argc, argc < 1 ? "at least 1" : "no more than 2"); } anp = dnp->dn_args; assert(anp != NULL); trunc = anp->dn_list; if (anp->dn_kind != DT_NODE_AGG) { dnerror(dnp, D_TRUNC_AGGARG, "%s( ) argument #1 is incompatible with prototype:\n" "\tprototype: aggregation\n\t argument: %s\n", dnp->dn_ident->di_name, dt_node_type_name(anp, n, sizeof (n))); } if (argc == 2) { assert(trunc != NULL); if (!dt_node_is_scalar(trunc)) { dnerror(dnp, D_TRUNC_SCALAR, "%s( ) argument #2 must be of scalar type\n", dnp->dn_ident->di_name); } } aid = anp->dn_ident; if (aid->di_gen == dtp->dt_gen && !(aid->di_flags & DT_IDFLG_MOD)) { dnerror(dnp, D_TRUNC_AGGBAD, "undefined aggregation: @%s\n", aid->di_name); } ap = dt_stmt_action(dtp, sdp); dt_action_difconst(ap, anp->dn_ident->di_id, DTRACEACT_LIBACT); ap->dtad_arg = DT_ACT_TRUNC; ap = dt_stmt_action(dtp, sdp); if (argc == 1) { dt_action_difconst(ap, 0, DTRACEACT_LIBACT); } else { assert(trunc != NULL); dt_cg(yypcb, trunc); ap->dtad_difo = dt_as(yypcb); ap->dtad_kind = DTRACEACT_LIBACT; } ap->dtad_arg = DT_ACT_TRUNC;}static voiddt_action_printa(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp){ dt_ident_t *aid, *fid; dtrace_actdesc_t *ap; const char *format; dt_node_t *anp; char n[DT_TYPE_NAMELEN]; int argc = 0, argr = 0; for (anp = dnp->dn_args; anp != NULL; anp = anp->dn_list) argc++; /* count up arguments for error messages below */ switch (dnp->dn_args->dn_kind) { case DT_NODE_STRING: format = dnp->dn_args->dn_string; anp = dnp->dn_args->dn_list; argr = 2;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?