dt_cc.c

来自「Sun Solaris 10 中的 DTrace 组件的源代码。请参看: htt」· C语言 代码 · 共 2,025 行 · 第 1/4 页

C
2,025 行
字号
/* * Fork and exec the cpp(1) preprocessor to run over the specified input file, * and return a FILE handle for the cpp output.  We use the /dev/fd filesystem * here to simplify the code by leveraging file descriptor inheritance. */static FILE *dt_preproc(dtrace_hdl_t *dtp, FILE *ifp){	int argc = dtp->dt_cpp_argc;	char **argv = malloc(sizeof (char *) * (argc + 5));	FILE *ofp = tmpfile();	char ipath[20], opath[20]; /* big enough for /dev/fd/ + INT_MAX + \0 */	char verdef[32]; /* big enough for -D__SUNW_D_VERSION=0x%08x + \0 */	struct sigaction act, oact;	sigset_t mask, omask;	int wstat, estat;	pid_t pid;	off64_t off;	int c;	if (argv == NULL || ofp == NULL) {		(void) dt_set_errno(dtp, errno);		goto err;	}	/*	 * If the input is a seekable file, see if it is an interpreter file.	 * If we see #!, seek past the first line because cpp will choke on it.	 * We start cpp just prior to the \n at the end of this line so that	 * it still sees the newline, ensuring that #line values are correct.	 */	if (isatty(fileno(ifp)) == 0 && (off = ftello64(ifp)) != -1) {		if ((c = fgetc(ifp)) == '#' && (c = fgetc(ifp)) == '!') {			for (off += 2; c != '\n'; off++) {				if ((c = fgetc(ifp)) == EOF)					break;			}			if (c == '\n')				off--; /* start cpp just prior to \n */		}		(void) fflush(ifp);		(void) fseeko64(ifp, off, SEEK_SET);	}	(void) snprintf(ipath, sizeof (ipath), "/dev/fd/%d", fileno(ifp));	(void) snprintf(opath, sizeof (opath), "/dev/fd/%d", fileno(ofp));	bcopy(dtp->dt_cpp_argv, argv, sizeof (char *) * argc);	(void) snprintf(verdef, sizeof (verdef),	    "-D__SUNW_D_VERSION=0x%08x", dtp->dt_vmax);	argv[argc++] = verdef;	switch (dtp->dt_stdcmode) {	case DT_STDC_XA:	case DT_STDC_XT:		argv[argc++] = "-D__STDC__=0";		break;	case DT_STDC_XC:		argv[argc++] = "-D__STDC__=1";		break;	}	argv[argc++] = ipath;	argv[argc++] = opath;	argv[argc] = NULL;	/*	 * libdtrace must be able to be embedded in other programs that may	 * include application-specific signal handlers.  Therefore, if we	 * need to fork to run cpp(1), we must avoid generating a SIGCHLD	 * that could confuse the containing application.  To do this,	 * we block SIGCHLD and reset its disposition to SIG_DFL.	 * We restore our signal state once we are done.	 */	(void) sigemptyset(&mask);	(void) sigaddset(&mask, SIGCHLD);	(void) sigprocmask(SIG_BLOCK, &mask, &omask);	bzero(&act, sizeof (act));	act.sa_handler = SIG_DFL;	(void) sigaction(SIGCHLD, &act, &oact);	if ((pid = fork1()) == -1) {		(void) sigaction(SIGCHLD, &oact, NULL);		(void) sigprocmask(SIG_SETMASK, &omask, NULL);		(void) dt_set_errno(dtp, EDT_CPPFORK);		goto err;	}	if (pid == 0) {		(void) execvp(dtp->dt_cpp_path, argv);		_exit(errno == ENOENT ? 127 : 126);	}	do {		dt_dprintf("waiting for %s (PID %d)\n", dtp->dt_cpp_path,		    (int)pid);	} while (waitpid(pid, &wstat, 0) == -1 && errno == EINTR);	(void) sigaction(SIGCHLD, &oact, NULL);	(void) sigprocmask(SIG_SETMASK, &omask, NULL);	dt_dprintf("%s returned exit status 0x%x\n", dtp->dt_cpp_path, wstat);	estat = WIFEXITED(wstat) ? WEXITSTATUS(wstat) : -1;	if (estat != 0) {		switch (estat) {		case 126:			(void) dt_set_errno(dtp, EDT_CPPEXEC);			break;		case 127:			(void) dt_set_errno(dtp, EDT_CPPENT);			break;		default:			(void) dt_set_errno(dtp, EDT_CPPERR);		}		goto err;	}	free(argv);	(void) fflush(ofp);	(void) fseek(ofp, 0, SEEK_SET);	return (ofp);err:	free(argv);	(void) fclose(ofp);	return (NULL);}/* * Open all of the .d library files found in the specified directory and try to * compile each one in order to cache its inlines and translators, etc.  We * silently ignore any missing directories and other files found therein. * We only fail (and thereby fail dt_load_libs()) if we fail to compile a * library and the error is something other than #pragma D depends_on. * Dependency errors are silently ignored to permit a library directory to * contain libraries which may not be accessible depending on our privileges. * * Note that at present, no ordering is defined between library files found in * the same directory: if cross-library dependencies are eventually required, * we will need to extend the #pragma D depends_on directive with an additional * class for libraries, and this function will need to create a graph of the * various library pathnames and then perform a topological ordering using the * dependency information before we attempt to compile any of them. */static intdt_load_libs_dir(dtrace_hdl_t *dtp, const char *path){	struct dirent *dp, *ep;	const char *p;	DIR *dirp;	char fname[PATH_MAX];	dtrace_prog_t *pgp;	FILE *fp;	if ((dirp = opendir(path)) == NULL) {		dt_dprintf("skipping lib dir %s: %s\n", path, strerror(errno));		return (0);	}	ep = alloca(sizeof (struct dirent) + PATH_MAX + 1);	bzero(ep, sizeof (struct dirent) + PATH_MAX + 1);	while (readdir_r(dirp, ep, &dp) == 0 && dp != NULL) {		if ((p = strrchr(dp->d_name, '.')) == NULL || strcmp(p, ".d"))			continue; /* skip any filename not ending in .d */		(void) snprintf(fname, sizeof (fname),		    "%s/%s", path, dp->d_name);		if ((fp = fopen(fname, "r")) == NULL) {			dt_dprintf("skipping library %s: %s\n",			    fname, strerror(errno));			continue;		}		dtp->dt_filetag = fname;		pgp = dtrace_program_fcompile(dtp, fp, DTRACE_C_EMPTY, 0, NULL);		(void) fclose(fp);		dtp->dt_filetag = NULL;		if (pgp == NULL && (dtp->dt_errno != EDT_COMPILER ||		    dtp->dt_errtag != dt_errtag(D_PRAGMA_DEPEND))) {			(void) closedir(dirp);			return (-1); /* preserve dt_errno */		}		if (pgp == NULL) {			dt_dprintf("skipping library: %s\n",			    dtrace_errmsg(dtp, dtrace_errno(dtp)));		} else			dtrace_program_destroy(dtp, pgp);	}	(void) closedir(dirp);	return (0);}/* * Load the contents of any appropriate DTrace .d library files.  These files * contain inlines and translators that will be cached by the compiler.  We * defer this activity until the first compile to permit libdtrace clients to * add their own library directories and so that we can properly report errors. */static intdt_load_libs(dtrace_hdl_t *dtp){	dt_dirpath_t *dirp;	if (dtp->dt_cflags & DTRACE_C_NOLIBS)		return (0); /* libraries already processed */	dtp->dt_cflags |= DTRACE_C_NOLIBS;	for (dirp = dt_list_next(&dtp->dt_lib_path);	    dirp != NULL; dirp = dt_list_next(dirp)) {		if (dt_load_libs_dir(dtp, dirp->dir_path) != 0) {			dtp->dt_cflags &= ~DTRACE_C_NOLIBS;			return (-1); /* errno is set for us */		}	}	return (0);}static void *dt_compile(dtrace_hdl_t *dtp, int context, dtrace_probespec_t pspec,    dtrace_probedesc_t *pdp, uint_t cflags, int argc,    char *const argv[], FILE *fp, const char *s){	dt_node_t *dnp;	dtrace_difo_t *difo;	dt_pcb_t pcb;	int err;	if ((fp == NULL && s == NULL) || (cflags & ~DTRACE_C_MASK) != 0) {		(void) dt_set_errno(dtp, EINVAL);		return (NULL);	}	if (dt_list_next(&dtp->dt_lib_path) != NULL && dt_load_libs(dtp) != 0)		return (NULL); /* errno is set for us */	(void) ctf_discard(dtp->dt_cdefs->dm_ctfp);	(void) ctf_discard(dtp->dt_ddefs->dm_ctfp);	dt_idhash_iter(dtp->dt_globals, dt_idreset, NULL);	dt_idhash_iter(dtp->dt_tls, dt_idreset, NULL);	if (fp && (cflags & DTRACE_C_CPP) && (fp = dt_preproc(dtp, fp)) == NULL)		return (NULL); /* errno is set for us */	bzero(&pcb, sizeof (dt_pcb_t));	dt_scope_create(&pcb.pcb_dstack);	dt_irlist_create(&pcb.pcb_ir);	pcb.pcb_hdl = dtp;	pcb.pcb_fileptr = fp;	pcb.pcb_string = s;	pcb.pcb_strptr = s;	pcb.pcb_strlen = s ? strlen(s) : 0;	pcb.pcb_sargc = argc;	pcb.pcb_sargv = argv;	pcb.pcb_sflagv = argc ? calloc(argc, sizeof (ushort_t)) : NULL;	pcb.pcb_pspec = pspec;	pcb.pcb_cflags = dtp->dt_cflags | cflags;	pcb.pcb_amin = dtp->dt_amin;	pcb.pcb_yystate = -1;	pcb.pcb_context = context;	pcb.pcb_token = context;	dtp->dt_pcb = &pcb;	dtp->dt_gen++;	yyinit(&pcb);	if (context == DT_CTX_DPROG)		yybegin(YYS_CLAUSE);	else		yybegin(YYS_EXPR);	if ((err = setjmp(yypcb->pcb_jmpbuf)) != 0)		goto out;	if (yypcb->pcb_sargc != 0 && yypcb->pcb_sflagv == NULL)		longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);	yypcb->pcb_idents = dt_idhash_create("ambiguous", NULL, 0, 0);	yypcb->pcb_locals = dt_idhash_create("clause local", NULL,	    DIF_VAR_OTHER_UBASE, DIF_VAR_OTHER_MAX);	if (yypcb->pcb_idents == NULL || yypcb->pcb_locals == NULL)		longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);	if (pdp != NULL)		dt_setcontext(dtp, pdp);	/*	 * Invoke the parser to evaluate the D source code.  If any errors	 * occur during parsing, an error function will be called and we	 * will longjmp back to pcb_jmpbuf to abort.  If parsing succeeds,	 * we optionally display the parse tree if debugging is enabled.	 */	if (yyparse() != 0 || yypcb->pcb_root == NULL)		xyerror(D_EMPTY, "empty D program translation unit\n");	if (DT_TREEDUMP_PASS(dtp, 1))		dt_node_printr(yypcb->pcb_root, stderr, 0);	if (yypcb->pcb_pragmas != NULL)		dt_idhash_iter(yypcb->pcb_pragmas, dt_idpragma, NULL);	if (argc > 1 && !(yypcb->pcb_cflags & DTRACE_C_ARGREF) &&	    !(yypcb->pcb_sflagv[argc - 1] & DT_IDFLG_REF)) {		xyerror(D_MACRO_UNUSED, "extraneous argument '%s' ($%d is "		    "not referenced)\n", yypcb->pcb_sargv[argc - 1], argc - 1);	}	/*	 * If we have successfully created a parse tree for a D program, loop	 * over the clauses and actions and instantiate the corresponding	 * libdtrace program.  If we are parsing a D expression, then we	 * simply run the code generator and assembler on the resulting tree.	 */	if (context == DT_CTX_DPROG) {		assert(yypcb->pcb_root->dn_kind == DT_NODE_PROG);		if ((dnp = yypcb->pcb_root->dn_list) == NULL &&		    !(yypcb->pcb_cflags & DTRACE_C_EMPTY))			xyerror(D_EMPTY, "empty D program translation unit\n");		if ((yypcb->pcb_prog = dtrace_program_create(dtp)) == NULL)			longjmp(yypcb->pcb_jmpbuf, dtrace_errno(dtp));		for (; dnp != NULL; dnp = dnp->dn_list) {			if (dnp->dn_kind == DT_NODE_CLAUSE)				dt_compile_clause(dtp, dnp);		}	} else {		(void) dt_node_cook(yypcb->pcb_root, DT_IDFLG_REF);		dt_cg(yypcb, yypcb->pcb_root);		difo = dt_as(yypcb);	}out:	if (DT_TREEDUMP_PASS(dtp, 3))		dt_node_printr(yypcb->pcb_root, stderr, 0);	if (dtp->dt_cdefs_fd != -1 && (ftruncate64(dtp->dt_cdefs_fd, 0) == -1 ||	    lseek64(dtp->dt_cdefs_fd, 0, SEEK_SET) == -1 ||	    ctf_write(dtp->dt_cdefs->dm_ctfp, dtp->dt_cdefs_fd) == CTF_ERR))		dt_dprintf("failed to update CTF cache: %s\n", strerror(errno));	if (dtp->dt_ddefs_fd != -1 && (ftruncate64(dtp->dt_ddefs_fd, 0) == -1 ||	    lseek64(dtp->dt_ddefs_fd, 0, SEEK_SET) == -1 ||	    ctf_write(dtp->dt_ddefs->dm_ctfp, dtp->dt_ddefs_fd) == CTF_ERR))		dt_dprintf("failed to update CTF cache: %s\n", strerror(errno));	while (yypcb->pcb_dstack.ds_next != NULL)		(void) dt_scope_pop();	dt_scope_destroy(&yypcb->pcb_dstack);	dt_irlist_destroy(&yypcb->pcb_ir);	dt_node_link_free(&yypcb->pcb_list);	dt_node_link_free(&yypcb->pcb_hold);	if (yypcb->pcb_pragmas != NULL)		dt_idhash_destroy(yypcb->pcb_pragmas);	if (yypcb->pcb_locals != NULL)		dt_idhash_destroy(yypcb->pcb_locals);	if (yypcb->pcb_idents != NULL)		dt_idhash_destroy(yypcb->pcb_idents);	if (yypcb->pcb_inttab != NULL)		dt_inttab_destroy(yypcb->pcb_inttab);	if (yypcb->pcb_strtab != NULL)		dt_strtab_destroy(yypcb->pcb_strtab);	if (yypcb->pcb_regs != NULL)		dt_regset_destroy(yypcb->pcb_regs);	if (yypcb->pcb_difo != NULL)		dtrace_difo_release(yypcb->pcb_difo);	while (yypcb->pcb_pargs != NULL) {		dt_arg_t *old = yypcb->pcb_pargs;		yypcb->pcb_pargs = old->da_next;		free(old);	}	free(yypcb->pcb_filetag);	free(yypcb->pcb_sflagv);	if (yypcb->pcb_fileptr && (cflags & DTRACE_C_CPP))		(void) fclose(yypcb->pcb_fileptr); /* close dt_preproc() file */	if (err != 0) {		dt_xlator_t *dxp, *nxp;		dt_provider_t *pvp, *nvp;		if (yypcb->pcb_pred != NULL)			dtrace_difo_release(yypcb->pcb_pred);		if (yypcb->pcb_prog != NULL)			dtrace_program_destroy(dtp, yypcb->pcb_prog);		if (yypcb->pcb_stmt != NULL)			dtrace_stmt_destroy(yypcb->pcb_stmt);		if (yypcb->pcb_ecbdesc != NULL)			dtrace_ecbdesc_release(yypcb->pcb_ecbdesc);		for (dxp = dt_list_next(&dtp->dt_xlators); dxp; dxp = nxp) {			nxp = dt_list_next(dxp);			if (dxp->dx_gen == dtp->dt_gen)				dt_xlator_destroy(dtp, dxp);		}		for (pvp = dt_list_next(&dtp->dt_provlist); pvp; pvp = nvp) {			nvp = dt_list_next(pvp);			if (pvp->pv_gen == dtp->dt_gen)				dt_provider_destroy(dtp, pvp);		}		dt_idhash_iter(dtp->dt_aggs, dt_idkill, (void *)dtp->dt_gen);		dt_idhash_update(dtp->dt_aggs);		dt_idhash_iter(dtp->dt_globals, dt_idkill, (void *)dtp->dt_gen);		dt_idhash_update(dtp->dt_globals);		dt_idhash_iter(dtp->dt_tls, dt_idkill, (void *)dtp->dt_gen);		dt_idhash_update(dtp->dt_tls);		(void) ctf_discard(dtp->dt_cdefs->dm_ctfp);		(void) ctf_discard(dtp->dt_ddefs->dm_ctfp);		(void) dt_set_errno(dtp, err);		dtp->dt_pcb = NULL;		yypcb = NULL;		return (NULL);	}	(void) dt_set_errno(dtp, 0);	dtp->dt_pcb = NULL;	yypcb = NULL;	if (context == DT_CTX_DPROG)		return (pcb.pcb_prog);	else		return (difo);}dtrace_prog_t *dtrace_program_strcompile(dtrace_hdl_t *dtp, const char *s,    dtrace_probespec_t spec, uint_t cflags, int argc, char *const argv[]){	return (dt_compile(dtp, DT_CTX_DPROG,	    spec, NULL, cflags, argc, argv, NULL, s));}dtrace_prog_t *dtrace_program_fcompile(dtrace_hdl_t *dtp, FILE *fp,    uint_t cflags, int argc, char *const argv[]){	return (dt_compile(dtp, DT_CTX_DPROG,	    DTRACE_PROBESPEC_NAME, NULL, cflags, argc, argv, fp, NULL));}dtrace_difo_t *dtrace_difo_create(dtrace_hdl_t *dtp, const char *s, dtrace_probedesc_t *pdp){	return (dt_compile(dtp, DT_CTX_DEXPR,	    DTRACE_PROBESPEC_NONE, pdp, 0, 0, NULL, NULL, s));}voiddtrace_difo_hold(dtrace_difo_t *dp){	dp->dtdo_refcnt++;	assert(dp->dtdo_refcnt != 0);}voiddtrace_difo_release(dtrace_difo_t *dp){	assert(dp->dtdo_refcnt != 0);	if (--dp->dtdo_refcnt != 0)		return;	free(dp->dtdo_buf);	free(dp->dtdo_inttab);	free(dp->dtdo_strtab);	free(dp->dtdo_vartab);	free(dp->dtdo_kreltab);	free(dp->dtdo_ureltab);	free(dp);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?