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