📄 dtrace.c
字号:
exec_prog(const dtrace_cmd_t *dcp){ dtrace_proginfo_t dpi; if (!g_exec) { dtrace_program_info(g_dtp, dcp->dc_prog, &dpi); } else if (dtrace_program_exec(g_dtp, dcp->dc_prog, &dpi) == -1) { dfatal("failed to enable '%s'", dcp->dc_name); } else { notice("%s '%s' matched %u probe%s\n", dcp->dc_desc, dcp->dc_name, dpi.dpi_matches, dpi.dpi_matches == 1 ? "" : "s"); } if (g_verbose) { oprintf("Stability data for %s %s:\n", dcp->dc_desc, dcp->dc_name); oprintf("\tMinimum probe description attributes\n"); oprintf("\t\tIdentifier Names: %s\n", dtrace_stability_name(dpi.dpi_descattr.dtat_name)); oprintf("\t\tData Semantics: %s\n", dtrace_stability_name(dpi.dpi_descattr.dtat_data)); oprintf("\t\tDependency Class: %s\n", dtrace_class_name(dpi.dpi_descattr.dtat_class)); oprintf("\tMinimum probe statement attributes\n"); oprintf("\t\tIdentifier Names: %s\n", dtrace_stability_name(dpi.dpi_stmtattr.dtat_name)); oprintf("\t\tData Semantics: %s\n", dtrace_stability_name(dpi.dpi_stmtattr.dtat_data)); oprintf("\t\tDependency Class: %s\n", dtrace_class_name(dpi.dpi_stmtattr.dtat_class)); } g_total += dpi.dpi_matches;}/* * Print out the specified DOF buffer as a set of ASCII bytes appropriate for * storing in a driver.conf(4) file associated with the dtrace driver. */static voidanon_prog(const dtrace_cmd_t *dcp, dof_hdr_t *dof, int n){ const uchar_t *p, *q; if (dof == NULL) dfatal("failed to create DOF image for '%s'", dcp->dc_name); p = (uchar_t *)dof; q = p + dof->dofh_loadsz; oprintf("dof-data-%d=0x%x", n, *p++); while (p < q) oprintf(",0x%x", *p++); oprintf(";\n"); dtrace_dof_destroy(dof);}/* * Link the specified D program in DOF form into an ELF file for use in either * helpers, userland provider definitions, or both. If -o was specified, that * path is used as the output file name. If -o wasn't specified and the input * program is from a script whose name is %.d, use basename(%.o) as the output * file name. Otherwise we use "d.out" as the default output file name. */static voidlink_prog(const dtrace_cmd_t *dcp){ char file[PATH_MAX], *p; if (g_ofile != NULL) { (void) snprintf(file, sizeof (file), g_cmdc > 1 ? "%s.%d" : "%s", g_ofile, (int)(dcp - g_cmdv)); } else if ((p = strrchr(dcp->dc_arg, '.')) != NULL && strcmp(p, ".d") == 0) { p[0] = '\0'; /* strip .d suffix */ (void) snprintf(file, sizeof (file), "%s.o", basename(dcp->dc_arg)); } else { (void) snprintf(file, sizeof (file), g_cmdc > 1 ? "%s.%d" : "%s", "d.out", (int)(dcp - g_cmdv)); } if (dtrace_program_link(g_dtp, dcp->dc_prog, 0, file, g_objc - 1, g_objv + 1) != 0) dfatal("failed to link %s %s", dcp->dc_desc, dcp->dc_name);}/*ARGSUSED*/static intlist_stmt(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *stp, dtrace_ecbdesc_t **last){ dtrace_ecbdesc_t *edp = stp->dtsd_ecbdesc; dtrace_probedesc_t probe; dtrace_id_t id = 0; if (edp == *last) return (0); for (;;) { bcopy(&edp->dted_probe, &probe, sizeof (dtrace_probedesc_t)); probe.dtpd_id = id; if (ioctl(g_fd, DTRACEIOC_PROBEMATCH, &probe) == -1) break; oprintf("%5d %10s %17s %33s %s\n", probe.dtpd_id, probe.dtpd_provider, probe.dtpd_mod, probe.dtpd_func, probe.dtpd_name); id = probe.dtpd_id + 1; } if (errno == EINVAL) { error("%s:%s:%s:%s contains too many glob meta-characters\n", edp->dted_probe.dtpd_provider, edp->dted_probe.dtpd_mod, edp->dted_probe.dtpd_func, edp->dted_probe.dtpd_name); } *last = edp; return (0);}/* * List the probes corresponding to the specified program by iterating over * each statement and then matching probes to the statement probe descriptions. */static voidlist_prog(const dtrace_cmd_t *dcp){ dtrace_ecbdesc_t *last = NULL; (void) dtrace_stmt_iter(g_dtp, dcp->dc_prog, (dtrace_stmt_f *)list_stmt, &last);}static voidcompile_file(dtrace_cmd_t *dcp){ char *arg0; FILE *fp; if ((fp = fopen(dcp->dc_arg, "r")) == NULL) fatal("failed to open %s", dcp->dc_arg); arg0 = g_argv[0]; g_argv[0] = dcp->dc_arg; if ((dcp->dc_prog = dtrace_program_fcompile(g_dtp, fp, g_cflags, g_argc, g_argv)) == NULL) dfatal("failed to compile script %s", dcp->dc_arg); g_argv[0] = arg0; (void) fclose(fp); dcp->dc_desc = "script"; dcp->dc_name = dcp->dc_arg;}static voidcompile_str(dtrace_cmd_t *dcp){ char *p; if ((dcp->dc_prog = dtrace_program_strcompile(g_dtp, dcp->dc_arg, dcp->dc_spec, g_cflags | DTRACE_C_PSPEC, g_argc, g_argv)) == NULL) dfatal("invalid probe specifier %s", dcp->dc_arg); if ((p = strpbrk(dcp->dc_arg, "{/;")) != NULL) *p = '\0'; /* crop name for reporting */ dcp->dc_desc = "description"; dcp->dc_name = dcp->dc_arg;}/*ARGSUSED*/static voidprochandler(struct ps_prochandle *P, void *arg){ const psinfo_t *prp = Ppsinfo(P); int pid = Pstatus(P)->pr_pid; char name[SIG2STR_MAX]; switch (Pstate(P)) { case PS_UNDEAD: /* * Ideally we would like to always report pr_wstat here, but it * isn't possible given current /proc semantics. If we grabbed * the process, Ppsinfo() will either fail or return a zeroed * psinfo_t depending on how far the parent is in reaping it. * When /proc provides a stable pr_wstat in the status file, * this code can be improved by examining this new pr_wstat. */ if (prp != NULL && WIFSIGNALED(prp->pr_wstat)) { notice("pid %d terminated by %s\n", pid, proc_signame(WTERMSIG(prp->pr_wstat), name, sizeof (name))); } else if (prp != NULL && WEXITSTATUS(prp->pr_wstat) != 0) { notice("pid %d exited with status %d\n", pid, WEXITSTATUS(prp->pr_wstat)); } else { notice("pid %d has exited\n", pid); } g_pslive--; break; case PS_LOST: notice("pid %d exec'd a set-id or unobservable program\n", pid); g_pslive--; break; }}/*ARGSUSED*/static interrhandler(dtrace_errdata_t *data, void *arg){ error(data->dteda_msg); return (DTRACE_HANDLE_OK);}/*ARGSUSED*/static intdrophandler(dtrace_dropdata_t *data, void *arg){ error(data->dtdda_msg); return (DTRACE_HANDLE_OK);}/*ARGSUSED*/static intchewrec(const dtrace_probedata_t *data, const dtrace_recdesc_t *rec, void *arg){ dtrace_actkind_t act; uintptr_t addr; if (rec == NULL) { /* * We have processed the final record; output the newline if * we're not in quiet mode. */ if (!g_quiet) oprintf("\n"); return (DTRACE_CONSUME_NEXT); } act = rec->dtrd_action; addr = (uintptr_t)data->dtpda_data; if (act == DTRACEACT_EXIT) { g_status = *((uint32_t *)addr); return (DTRACE_CONSUME_NEXT); } return (DTRACE_CONSUME_THIS);}/*ARGSUSED*/static intchew(const dtrace_probedata_t *data, void *arg){ dtrace_probedesc_t *pd = data->dtpda_pdesc; processorid_t cpu = data->dtpda_cpu; static int heading; if (g_impatient) { g_newline = 0; return (DTRACE_CONSUME_ABORT); } if (heading == 0) { if (!g_flowindent) { if (!g_quiet) { oprintf("%3s %6s %32s\n", "CPU", "ID", "FUNCTION:NAME"); } } else { oprintf("%3s %-41s\n", "CPU", "FUNCTION"); } heading = 1; } if (!g_flowindent) { if (!g_quiet) { char name[DTRACE_FUNCNAMELEN + DTRACE_NAMELEN + 2]; (void) snprintf(name, sizeof (name), "%s:%s", pd->dtpd_func, pd->dtpd_name); oprintf("%3d %6d %32s ", cpu, pd->dtpd_id, name); } } else { int indent = data->dtpda_indent; char *name; size_t len; if (data->dtpda_flow == DTRACEFLOW_NONE) { len = indent + DTRACE_FUNCNAMELEN + DTRACE_NAMELEN + 5; name = alloca(len); (void) snprintf(name, len, "%*s%s%s:%s", indent, "", data->dtpda_prefix, pd->dtpd_func, pd->dtpd_name); } else { len = indent + DTRACE_FUNCNAMELEN + 5; name = alloca(len); (void) snprintf(name, len, "%*s%s%s", indent, "", data->dtpda_prefix, pd->dtpd_func); } oprintf("%3d %-41s ", cpu, name); } return (DTRACE_CONSUME_THIS);}static voidgo(void){ int i; struct { char *name; char *optname; dtrace_optval_t val; } bufs[] = { { "buffer size", "bufsize" }, { "aggregation size", "aggsize" }, { "speculation size", "specsize" }, { "dynamic variable size", "dynvarsize" }, { NULL } }, rates[] = { { "cleaning rate", "cleanrate" }, { "status rate", "statusrate" }, { NULL } }; for (i = 0; bufs[i].name != NULL; i++) { if (dtrace_getopt(g_dtp, bufs[i].optname, &bufs[i].val) == -1) fatal("couldn't get option %s", bufs[i].optname); } for (i = 0; rates[i].name != NULL; i++) { if (dtrace_getopt(g_dtp, rates[i].optname, &rates[i].val) == -1) fatal("couldn't get option %s", rates[i].optname); } if (dtrace_go(g_dtp) == -1) dfatal("could not enable tracing"); for (i = 0; bufs[i].name != NULL; i++) { dtrace_optval_t j = 0, mul = 10; dtrace_optval_t nsize; if (bufs[i].val == DTRACEOPT_UNSET) continue; (void) dtrace_getopt(g_dtp, bufs[i].optname, &nsize); if (nsize == DTRACEOPT_UNSET || nsize == 0) continue; if (nsize >= bufs[i].val - sizeof (uint64_t)) continue; for (; (INT64_C(1) << mul) <= nsize; j++, mul += 10) continue; if (!(nsize & ((INT64_C(1) << (mul - 10)) - 1))) { error("%s lowered to %lld%c\n", bufs[i].name, (long long)nsize >> (mul - 10), " kmgtpe"[j]); } else { error("%s lowered to %lld bytes\n", bufs[i].name, (long long)nsize); } } for (i = 0; rates[i].name != NULL; i++) { dtrace_optval_t nval; char *dir; if (rates[i].val == DTRACEOPT_UNSET) continue; (void) dtrace_getopt(g_dtp, rates[i].optname, &nval); if (nval == DTRACEOPT_UNSET || nval == 0) continue; if (rates[i].val == nval) continue; dir = nval > rates[i].val ? "reduced" : "increased"; if (nval <= NANOSEC && (NANOSEC % nval) == 0) { error("%s %s to %lld hz\n", rates[i].name, dir, (long long)NANOSEC / (long long)nval); continue; } if ((nval % NANOSEC) == 0) { error("%s %s to once every %lld seconds\n", rates[i].name, dir, (long long)nval / (long long)NANOSEC); continue; } error("%s %s to once every %lld nanoseconds\n", rates[i].name, dir, (long long)nval); }}/*ARGSUSED*/static voidintr(int signo){ if (!g_intr) g_newline = 1; if (g_intr++) g_impatient = 1;}intmain(int argc, char *argv[]){ dtrace_bufdesc_t buf; struct sigaction act; dtrace_status_t status[2]; dtrace_optval_t opt; dtrace_cmd_t *dcp; int done = 0, mode = 0; int err, i; char c, *p, **v; struct ps_prochandle *P; pid_t pid; g_pname = basename(argv[0]); if (argc == 1) return (usage(stderr)); if ((g_argv = malloc(sizeof (char *) * argc)) == NULL || (g_cmdv = malloc(sizeof (dtrace_cmd_t) * argc)) == NULL || (g_psv = malloc(sizeof (struct ps_prochandle *) * argc)) == NULL) fatal("failed to allocate memory for arguments"); g_argv[g_argc++] = argv[0]; /* propagate argv[0] to D as $0/$$0 */ argv[0] = g_pname; /* rewrite argv[0] for getopt errors */ bzero(status, sizeof (status)); bzero(&buf, sizeof (buf)); /* * Make an initial pass through argv[] processing any arguments that * affect our behavior mode (g_mode) and flags used for dtrace_open(). * We also accumulate arguments that are not affiliated with getopt * options into g_argv[], and abort if any invalid options are found. */ for (optind = 1; optind < argc; optind++) { while ((c = getopt(argc, argv, DTRACE_OPTSTR)) != EOF) { switch (c) { case '3': if (strcmp(optarg, "2") != 0) { (void) fprintf(stderr, "%s: illegal option -- 3%s\n", argv[0], optarg); return (usage(stderr)); } g_oflags &= ~DTRACE_O_LP64; g_oflags |= DTRACE_O_ILP32; break; case '6':
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -