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 + -
显示快捷键?