/*PRINTFLIKE1*/ static void dfatal(const char *fmt, ...) { va_list ap; va_start(ap, fmt); (void) fprintf(stderr, "%s: ", g_pname); if (fmt != NULL) (void) vfprintf(stderr, fmt, ap); va_end(ap); if (fmt != NULL && fmt[strlen(fmt) - 1] != '\n') { (void) fprintf(stderr, ": %s\n", dtrace_errmsg(g_dtp, dtrace_errno(g_dtp))); } else if (fmt == NULL) { (void) fprintf(stderr, "%s\n", dtrace_errmsg(g_dtp, dtrace_errno(g_dtp))); } if (g_pr != NULL) { dtrace_proc_continue(g_dtp, g_pr); dtrace_proc_release(g_dtp, g_pr); } exit(E_ERROR); }
static void dt_pragma_option(const char *prname, dt_node_t *dnp) { dtrace_hdl_t *dtp = yypcb->pcb_hdl; char *opt, *val; if (dnp == NULL || dnp->dn_kind != DT_NODE_IDENT) { xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s <option>=<val>\n", prname); } if (dnp->dn_list != NULL) { xyerror(D_PRAGMA_MALFORM, "superfluous arguments specified for #pragma %s\n", prname); } opt = alloca(strlen(dnp->dn_string) + 1); (void) strcpy(opt, dnp->dn_string); if ((val = strchr(opt, '=')) != NULL) *val++ = '\0'; if (dtrace_setopt(dtp, opt, val) == -1) { if (val == NULL) { xyerror(D_PRAGMA_OPTSET, "failed to set option '%s': %s\n", opt, dtrace_errmsg(dtp, dtrace_errno(dtp))); } else { xyerror(D_PRAGMA_OPTSET, "failed to set option '%s' to '%s': %s\n", opt, val, dtrace_errmsg(dtp, dtrace_errno(dtp))); } } }
static VALUE load_ustack_helper(VALUE klass, VALUE path) { dtrace_hdl_t *dtp; dtrace_prog_t *helper; int err; void *dof; int argc = 1; char *argv[1] = { "ruby" }; printf("c land: I am trying to load %s", RSTRING_PTR(path)); puts(""); FILE *fp = fopen(RSTRING_PTR(path), "r"); if (fp == NULL) { rb_raise(rb_eFatal, "failed to open '%s', errno %d: %s", path, errno, strerror(errno)); } dtp = dtrace_open(DTRACE_VERSION, DTRACE_O_NODEV, &err); if (dtp == NULL) { dtrace_close(dtp); rb_raise(rb_eFatal, "dtrace_open failed: %s", dtrace_errmsg(dtp, err)); } (void) dtrace_setopt(dtp, "linkmode", "dynamic"); (void) dtrace_setopt(dtp, "unodefs", NULL); if ((helper = dtrace_program_fcompile(dtp, fp, DTRACE_C_ZDEFS, argc, argv)) == NULL) { dtrace_close(dtp); rb_raise(rb_eFatal, "compile failed: errno %d: %s", dtrace_errno(dtp), dtrace_errmsg(dtp, dtrace_errno(dtp))); } (void) fclose(fp); if ((dof = dtrace_dof_create(dtp, helper, 0)) == NULL) { dtrace_close(dtp); rb_raise(rb_eFatal, "DOF create failed: %s", dtrace_errmsg(dtp, dtrace_errno(dtp))); } if (load_dof(dof) != 0) { dtrace_close(dtp); rb_raise(rb_eFatal, "DOF load failed: %s", strerror(err)); } dtrace_close(dtp); return Qnil; }
static void dt_idcook_regs(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *ap) { dtrace_typeinfo_t dtt; dtrace_hdl_t *dtp = yypcb->pcb_hdl; char n[DT_TYPE_NAMELEN]; if (argc != 1) { xyerror(D_PROTO_LEN, "%s[ ] prototype mismatch: %d arg%s" "passed, 1 expected\n", idp->di_name, argc, argc == 1 ? " " : "s "); } if (ap->dn_kind != DT_NODE_INT) { xyerror(D_PROTO_ARG, "%s[ ] argument #1 is incompatible with " "prototype:\n\tprototype: %s\n\t argument: %s\n", idp->di_name, "integer constant", dt_type_name(ap->dn_ctfp, ap->dn_type, n, sizeof (n))); } if ((ap->dn_flags & DT_NF_SIGNED) && (int64_t)ap->dn_value < 0) { xyerror(D_REGS_IDX, "index %lld is out of range for array %s\n", (longlong_t)ap->dn_value, idp->di_name); } if (dt_type_lookup("uint64_t", &dtt) == -1) { xyerror(D_UNKNOWN, "failed to resolve type of %s: %s\n", idp->di_name, dtrace_errmsg(dtp, dtrace_errno(dtp))); } idp->di_ctfp = dtt.dtt_ctfp; idp->di_type = dtt.dtt_type; dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type); }
/* * The #pragma depends_on directive can be used to express a dependency on a * module, provider or library which if not present will cause processing to * abort. */ static void dt_pragma_depends(const char *prname, dt_node_t *cnp) { dtrace_hdl_t *dtp = yypcb->pcb_hdl; dt_node_t *nnp = cnp ? cnp->dn_list : NULL; int found; dt_lib_depend_t *dld; if (cnp == NULL || nnp == NULL || cnp->dn_kind != DT_NODE_IDENT || nnp->dn_kind != DT_NODE_IDENT) { xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s " "<class> <name>\n", prname); } if (strcmp(cnp->dn_string, "provider") == 0) found = dt_provider_lookup(dtp, nnp->dn_string) != NULL; else if (strcmp(cnp->dn_string, "module") == 0) { dt_module_t *mp = dt_module_lookup_by_name(dtp, nnp->dn_string); found = mp != NULL && dt_module_getctf(dtp, mp) != NULL; } else if (strcmp(cnp->dn_string, "library") == 0) { /* * We have the file we are working on in dtp->dt_filetag * so find that node and add the dependency in. */ if (yypcb->pcb_cflags & DTRACE_C_CTL) { char lib[MAXPATHLEN]; dld = dt_lib_depend_lookup(&dtp->dt_lib_dep, dtp->dt_filetag); assert(dld != NULL); (void) snprintf(lib, MAXPATHLEN, "%s%s", dld->dtld_libpath, nnp->dn_string); if ((dt_lib_depend_add(dtp, &dld->dtld_dependencies, lib)) != 0) { xyerror(D_PRAGMA_DEPEND, "failed to add dependency %s:%s\n", lib, dtrace_errmsg(dtp, dtrace_errno(dtp))); } } found = 1; } else { xyerror(D_PRAGMA_INVAL, "invalid class %s " "specified by #pragma %s\n", cnp->dn_string, prname); } if (!found) { xyerror(D_PRAGMA_DEPEND, "program requires %s %s\n", cnp->dn_string, nnp->dn_string); } }
/*PRINTFLIKE1*/ static void dfatal(const char *fmt, ...) { #if !defined(sun) && defined(NEED_ERRLOC) char *p_errfile = NULL; int errline = 0; #endif va_list ap; va_start(ap, fmt); (void) fprintf(stderr, "%s: ", g_pname); if (fmt != NULL) (void) vfprintf(stderr, fmt, ap); va_end(ap); if (fmt != NULL && fmt[strlen(fmt) - 1] != '\n') { (void) fprintf(stderr, ": %s\n", dtrace_errmsg(g_dtp, dtrace_errno(g_dtp))); } else if (fmt == NULL) { (void) fprintf(stderr, "%s\n", dtrace_errmsg(g_dtp, dtrace_errno(g_dtp))); } #if !defined(sun) && defined(NEED_ERRLOC) dt_get_errloc(g_dtp, &p_errfile, &errline); if (p_errfile != NULL) printf("File '%s', line %d\n", p_errfile, errline); #endif /* * Close the DTrace handle to ensure that any controlled processes are * correctly restored and continued. */ dtrace_close(g_dtp); exit(E_ERROR); }
void dt_buf_create(dtrace_hdl_t *dtp, dt_buf_t *bp, const char *name, size_t len) { if (len == 0) len = _dtrace_bufsize; bp->dbu_buf = bp->dbu_ptr = dt_zalloc(dtp, len); bp->dbu_len = len; if (bp->dbu_buf == NULL) bp->dbu_err = dtrace_errno(dtp); else bp->dbu_err = 0; bp->dbu_resizes = 0; bp->dbu_name = name; }
/*ARGSUSED*/ static int list_stmt(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *stp, dtrace_ecbdesc_t **last) { dtrace_ecbdesc_t *edp = stp->dtsd_ecbdesc; if (edp == *last) return (0); if (dtrace_probe_iter(g_dtp, &edp->dted_probe, list_probe, NULL) != 0) { error("failed to match %s:%s:%s:%s: %s\n", edp->dted_probe.dtpd_provider, edp->dted_probe.dtpd_mod, edp->dted_probe.dtpd_func, edp->dted_probe.dtpd_name, dtrace_errmsg(dtp, dtrace_errno(dtp))); } *last = edp; return (0); }
/*ARGSUSED*/ static void dt_idcook_type(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args) { if (idp->di_type == CTF_ERR) { dtrace_hdl_t *dtp = yypcb->pcb_hdl; dtrace_typeinfo_t dtt; if (dt_type_lookup(idp->di_iarg, &dtt) == -1) { xyerror(D_UNKNOWN, "failed to resolve type %s for identifier %s: %s\n", (const char *)idp->di_iarg, idp->di_name, dtrace_errmsg(dtp, dtrace_errno(dtp))); } idp->di_ctfp = dtt.dtt_ctfp; idp->di_type = dtt.dtt_type; } dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type); }
void dt_buf_write(dtrace_hdl_t *dtp, dt_buf_t *bp, const void *buf, size_t len, size_t align) { size_t off = (size_t)(bp->dbu_ptr - bp->dbu_buf); size_t adj = roundup(off, align) - off; if (bp->dbu_err != 0) { (void) dt_set_errno(dtp, bp->dbu_err); return; /* write silently fails */ } if (bp->dbu_ptr + adj + len > bp->dbu_buf + bp->dbu_len) { size_t new_len = bp->dbu_len * 2; uchar_t *new_buf; uint_t r = 1; while (bp->dbu_ptr + adj + len > bp->dbu_buf + new_len) { new_len *= 2; r++; } if ((new_buf = dt_zalloc(dtp, new_len)) == NULL) { bp->dbu_err = dtrace_errno(dtp); return; } bcopy(bp->dbu_buf, new_buf, off); dt_free(dtp, bp->dbu_buf); bp->dbu_buf = new_buf; bp->dbu_ptr = new_buf + off; bp->dbu_len = new_len; bp->dbu_resizes += r; } bp->dbu_ptr += adj; bcopy(buf, bp->dbu_ptr, len); bp->dbu_ptr += len; }
int dtrace_handle_err(dtrace_hdl_t *dtp, dtrace_handle_err_f *hdlr, void *arg) { dtrace_prog_t *pgp = NULL; dt_stmt_t *stp; dtrace_ecbdesc_t *edp; /* * We don't currently support multiple error handlers. */ if (dtp->dt_errhdlr != NULL) return (dt_set_errno(dtp, EALREADY)); /* * If the DTRACEOPT_GRABANON is enabled, the anonymous enabling will * already have a dtrace:::ERROR probe enabled; save 'hdlr' and 'arg' * but do not bother compiling and enabling _dt_errprog. */ if (dtp->dt_options[DTRACEOPT_GRABANON] != DTRACEOPT_UNSET) goto out; if ((pgp = dtrace_program_strcompile(dtp, _dt_errprog, DTRACE_PROBESPEC_NAME, DTRACE_C_ZDEFS, 0, NULL)) == NULL) return (dt_set_errno(dtp, dtrace_errno(dtp))); stp = dt_list_next(&pgp->dp_stmts); assert(stp != NULL); edp = stp->ds_desc->dtsd_ecbdesc; assert(edp != NULL); edp->dted_uarg = DT_ECB_ERROR; out: dtp->dt_errhdlr = hdlr; dtp->dt_errarg = arg; dtp->dt_errprog = pgp; return (0); }
int main(int argc, char *argv[]) { dtrace_probedesc_t pd, *pdp = NULL; dtrace_hdl_t *dtp; int err, c; char *p; g_progname = argv[0]; if ((dtp = dtrace_open(DTRACE_VERSION, 0, &err)) == NULL) { (void) fprintf(stderr, "%s: failed to open dtrace: %s\n", g_progname, dtrace_errmsg(dtp, err)); return (1); } while ((c = getopt(argc, argv, "evx:")) != -1) { switch (c) { case 'e': g_errexit++; break; case 'v': g_verbose++; break; case 'x': if ((p = strchr(optarg, '=')) != NULL) *p++ = '\0'; if (dtrace_setopt(dtp, optarg, p) != 0) { (void) fprintf(stderr, "%s: failed to set " "option -x %s: %s\n", g_progname, optarg, dtrace_errmsg(dtp, dtrace_errno(dtp))); return (2); } break; default: (void) fprintf(stderr, "Usage: %s [-ev] " "[-x opt[=arg]] [probedesc]\n", g_progname); return (2); } } argv += optind; argc -= optind; if (argc > 0) { if (dtrace_str2desc(dtp, DTRACE_PROBESPEC_NAME, argv[0], &pd)) { (void) fprintf(stderr, "%s: invalid probe description " "%s: %s\n", g_progname, argv[0], dtrace_errmsg(dtp, dtrace_errno(dtp))); return (2); } pdp = &pd; } g_fd = dtrace_ctlfd(dtp); (void) dtrace_probe_iter(dtp, pdp, probe, NULL); dtrace_close(dtp); (void) printf("\nTotal probes: %d\n", g_count); (void) printf("Total errors: %d\n\n", g_errs); return (g_errs != 0); }
/* * If a probe was discovered from the kernel, ask dtrace(7D) for a description * of each of its arguments, including native and translated types. */ static dt_probe_t * dt_probe_discover(dt_provider_t *pvp, const dtrace_probedesc_t *pdp) { dtrace_hdl_t *dtp = pvp->pv_hdl; char *name = dt_probe_key(pdp, alloca(dt_probe_keylen(pdp))); dt_node_t *xargs, *nargs; dt_ident_t *idp; dt_probe_t *prp; dtrace_typeinfo_t dtt; int i, nc, xc; int adc = _dtrace_argmax; dtrace_argdesc_t *adv = alloca(sizeof (dtrace_argdesc_t) * adc); dtrace_argdesc_t *adp = adv; assert(strcmp(pvp->pv_desc.dtvd_name, pdp->dtpd_provider) == 0); assert(pdp->dtpd_id != DTRACE_IDNONE); dt_dprintf("discovering probe %s:%s id=%d\n", pvp->pv_desc.dtvd_name, name, pdp->dtpd_id); for (nc = -1, i = 0; i < adc; i++, adp++) { bzero(adp, sizeof (dtrace_argdesc_t)); adp->dtargd_ndx = i; adp->dtargd_id = pdp->dtpd_id; if (dt_ioctl(dtp, DTRACEIOC_PROBEARG, adp) != 0) { (void) dt_set_errno(dtp, errno); return (NULL); } if (adp->dtargd_ndx == DTRACE_ARGNONE) break; /* all argument descs have been retrieved */ nc = MAX(nc, adp->dtargd_mapping); } xc = i; nc++; /* * The pid provider believes in giving the kernel a break. No reason to * give the kernel all the ctf containers that we're keeping ourselves * just to get it back from it. So if we're coming from a pid provider * probe and the kernel gave us no argument information we'll get some * here. If for some crazy reason the kernel knows about our userland * types then we just ignore this. */ if (xc == 0 && nc == 0 && strncmp(pvp->pv_desc.dtvd_name, "pid", 3) == 0) { nc = adc; dt_pid_get_types(dtp, pdp, adv, &nc); xc = nc; } /* * Now that we have discovered the number of native and translated * arguments from the argument descriptions, allocate a new probe ident * and corresponding dt_probe_t and hash it into the provider. */ xargs = dt_probe_alloc_args(pvp, xc); nargs = dt_probe_alloc_args(pvp, nc); if ((xc != 0 && xargs == NULL) || (nc != 0 && nargs == NULL)) return (NULL); /* dt_errno is set for us */ idp = dt_ident_create(name, DT_IDENT_PROBE, DT_IDFLG_ORPHAN, pdp->dtpd_id, _dtrace_defattr, 0, &dt_idops_probe, NULL, dtp->dt_gen); if (idp == NULL) { (void) dt_set_errno(dtp, EDT_NOMEM); return (NULL); } if ((prp = dt_probe_create(dtp, idp, 2, nargs, nc, xargs, xc)) == NULL) { dt_ident_destroy(idp); return (NULL); } dt_probe_declare(pvp, prp); /* * Once our new dt_probe_t is fully constructed, iterate over the * cached argument descriptions and assign types to prp->pr_nargv[] * and prp->pr_xargv[] and assign mappings to prp->pr_mapping[]. */ for (adp = adv, i = 0; i < xc; i++, adp++) { if (dtrace_type_strcompile(dtp, adp->dtargd_native, &dtt) != 0) { dt_dprintf("failed to resolve input type %s " "for %s:%s arg #%d: %s\n", adp->dtargd_native, pvp->pv_desc.dtvd_name, name, i + 1, dtrace_errmsg(dtp, dtrace_errno(dtp))); dtt.dtt_object = NULL; dtt.dtt_ctfp = NULL; dtt.dtt_type = CTF_ERR; } else { dt_node_type_assign(prp->pr_nargv[adp->dtargd_mapping], dtt.dtt_ctfp, dtt.dtt_type, dtt.dtt_flags & DTT_FL_USER ? B_TRUE : B_FALSE); } if (dtt.dtt_type != CTF_ERR && (adp->dtargd_xlate[0] == '\0' || strcmp(adp->dtargd_native, adp->dtargd_xlate) == 0)) { dt_node_type_propagate(prp->pr_nargv[ adp->dtargd_mapping], prp->pr_xargv[i]); } else if (dtrace_type_strcompile(dtp, adp->dtargd_xlate, &dtt) != 0) { dt_dprintf("failed to resolve output type %s " "for %s:%s arg #%d: %s\n", adp->dtargd_xlate, pvp->pv_desc.dtvd_name, name, i + 1, dtrace_errmsg(dtp, dtrace_errno(dtp))); dtt.dtt_object = NULL; dtt.dtt_ctfp = NULL; dtt.dtt_type = CTF_ERR; } else { dt_node_type_assign(prp->pr_xargv[i], dtt.dtt_ctfp, dtt.dtt_type, B_FALSE); } prp->pr_mapping[i] = adp->dtargd_mapping; prp->pr_argv[i] = dtt; } return (prp); }
/* * The #pragma depends_on directive can be used to express a dependency on a * module, provider or library which if not present will cause processing to * abort. */ static void dt_pragma_depends(const char *prname, dt_node_t *cnp) { dtrace_hdl_t *dtp = yypcb->pcb_hdl; dt_node_t *nnp = cnp ? cnp->dn_list : NULL; int found; dt_lib_depend_t *dld; char lib[MAXPATHLEN]; size_t plen; char *provs, *cpy, *tok; if (cnp == NULL || nnp == NULL || cnp->dn_kind != DT_NODE_IDENT || nnp->dn_kind != DT_NODE_IDENT) { xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s " "<class> <name>\n", prname); } if (strcmp(cnp->dn_string, "provider") == 0) { /* * First try to get the provider list using the * debug.dtrace.providers sysctl, since that'll work even if * we're not running as root. */ provs = NULL; if (sysctlbyname("debug.dtrace.providers", NULL, &plen, NULL, 0) || ((provs = dt_alloc(dtp, plen)) == NULL) || sysctlbyname("debug.dtrace.providers", provs, &plen, NULL, 0)) found = dt_provider_lookup(dtp, nnp->dn_string) != NULL; else { found = B_FALSE; for (cpy = provs; (tok = strsep(&cpy, " ")) != NULL; ) if (strcmp(tok, nnp->dn_string) == 0) { found = B_TRUE; break; } if (found == B_FALSE) found = dt_provider_lookup(dtp, nnp->dn_string) != NULL; } if (provs != NULL) dt_free(dtp, provs); } else if (strcmp(cnp->dn_string, "module") == 0) { dt_module_t *mp = dt_module_lookup_by_name(dtp, nnp->dn_string); found = mp != NULL && dt_module_getctf(dtp, mp) != NULL; } else if (strcmp(cnp->dn_string, "library") == 0) { if (yypcb->pcb_cflags & DTRACE_C_CTL) { assert(dtp->dt_filetag != NULL); dt_pragma_depends_finddep(dtp, nnp->dn_string, lib, sizeof (lib)); dld = dt_lib_depend_lookup(&dtp->dt_lib_dep, dtp->dt_filetag); assert(dld != NULL); if ((dt_lib_depend_add(dtp, &dld->dtld_dependencies, lib)) != 0) { xyerror(D_PRAGMA_DEPEND, "failed to add dependency %s:%s\n", lib, dtrace_errmsg(dtp, dtrace_errno(dtp))); } } else { /* * By this point we have already performed a topological * sort of the dependencies; we process this directive * as satisfied as long as the dependency was properly * loaded. */ if (dtp->dt_filetag == NULL) xyerror(D_PRAGMA_DEPEND, "main program may " "not explicitly depend on a library"); dld = dt_lib_depend_lookup(&dtp->dt_lib_dep, dtp->dt_filetag); assert(dld != NULL); dt_pragma_depends_finddep(dtp, nnp->dn_string, lib, sizeof (lib)); dld = dt_lib_depend_lookup(&dtp->dt_lib_dep_sorted, lib); assert(dld != NULL); if (!dld->dtld_loaded) xyerror(D_PRAGMA_DEPEND, "program requires " "library \"%s\" which failed to load", lib); } found = B_TRUE; } else { xyerror(D_PRAGMA_INVAL, "invalid class %s " "specified by #pragma %s\n", cnp->dn_string, prname); } if (!found) { xyerror(D_PRAGMA_DEPEND, "program requires %s %s\n", cnp->dn_string, nnp->dn_string); } }
static int dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func) { dtrace_hdl_t *dtp = pp->dpp_dtp; dt_pcb_t *pcb = pp->dpp_pcb; dt_proc_t *dpr = pp->dpp_dpr; fasttrap_probe_spec_t *ftp; uint64_t off; char *end; uint_t nmatches = 0; ulong_t sz; int glob, err; int isdash = strcmp("-", func) == 0; pid_t pid; #if defined(sun) pid = Pstatus(pp->dpp_pr)->pr_pid; #else pid = proc_getpid(pp->dpp_pr); #endif dt_dprintf("creating probe pid%d:%s:%s:%s\n", (int)pid, pp->dpp_obj, func, pp->dpp_name); sz = sizeof (fasttrap_probe_spec_t) + (isdash ? 4 : (symp->st_size - 1) * sizeof (ftp->ftps_offs[0])); if ((ftp = dt_alloc(dtp, sz)) == NULL) { dt_dprintf("proc_per_sym: dt_alloc(%lu) failed\n", sz); return (1); /* errno is set for us */ } ftp->ftps_pid = pid; (void) strncpy(ftp->ftps_func, func, sizeof (ftp->ftps_func)); dt_pid_objname(ftp->ftps_mod, sizeof (ftp->ftps_mod), pp->dpp_lmid, pp->dpp_obj); if (!isdash && gmatch("return", pp->dpp_name)) { if (dt_pid_create_return_probe(pp->dpp_pr, dtp, ftp, symp, pp->dpp_stret) < 0) { return (dt_pid_error(dtp, pcb, dpr, ftp, D_PROC_CREATEFAIL, "failed to create return probe " "for '%s': %s", func, dtrace_errmsg(dtp, dtrace_errno(dtp)))); } nmatches++; } if (!isdash && gmatch("entry", pp->dpp_name)) { if (dt_pid_create_entry_probe(pp->dpp_pr, dtp, ftp, symp) < 0) { return (dt_pid_error(dtp, pcb, dpr, ftp, D_PROC_CREATEFAIL, "failed to create entry probe " "for '%s': %s", func, dtrace_errmsg(dtp, dtrace_errno(dtp)))); } nmatches++; } glob = strisglob(pp->dpp_name); if (!glob && nmatches == 0) { off = strtoull(pp->dpp_name, &end, 16); if (*end != '\0') { return (dt_pid_error(dtp, pcb, dpr, ftp, D_PROC_NAME, "'%s' is an invalid probe name", pp->dpp_name)); } if (off >= symp->st_size) { return (dt_pid_error(dtp, pcb, dpr, ftp, D_PROC_OFF, "offset 0x%llx outside of function '%s'", (u_longlong_t)off, func)); } err = dt_pid_create_offset_probe(pp->dpp_pr, pp->dpp_dtp, ftp, symp, off); if (err == DT_PROC_ERR) { return (dt_pid_error(dtp, pcb, dpr, ftp, D_PROC_CREATEFAIL, "failed to create probe at " "'%s+0x%llx': %s", func, (u_longlong_t)off, dtrace_errmsg(dtp, dtrace_errno(dtp)))); } if (err == DT_PROC_ALIGN) { return (dt_pid_error(dtp, pcb, dpr, ftp, D_PROC_ALIGN, "offset 0x%llx is not aligned on an instruction", (u_longlong_t)off)); } nmatches++; } else if (glob && !isdash) { if (dt_pid_create_glob_offset_probes(pp->dpp_pr, pp->dpp_dtp, ftp, symp, pp->dpp_name) < 0) { return (dt_pid_error(dtp, pcb, dpr, ftp, D_PROC_CREATEFAIL, "failed to create offset probes in '%s': %s", func, dtrace_errmsg(dtp, dtrace_errno(dtp)))); } nmatches++; } pp->dpp_nmatches += nmatches; dt_free(dtp, ftp); return (0); }
/* * Cook a function call. If this is the first time we are cooking this * identifier, create its type signature based on predefined prototype stored * in di_iarg. We then validate the argument list against this signature. */ static void dt_idcook_func(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args) { if (idp->di_data == NULL) { dtrace_hdl_t *dtp = yypcb->pcb_hdl; dtrace_typeinfo_t dtt; dt_idsig_t *isp; char *s, *p1, *p2; int i = 0; assert(idp->di_iarg != NULL); s = alloca(strlen(idp->di_iarg) + 1); (void) strcpy(s, idp->di_iarg); if ((p2 = strrchr(s, ')')) != NULL) *p2 = '\0'; /* mark end of parameter list string */ if ((p1 = strchr(s, '(')) != NULL) *p1++ = '\0'; /* mark end of return type string */ if (p1 == NULL || p2 == NULL) { xyerror(D_UNKNOWN, "internal error: malformed entry " "for built-in function %s\n", idp->di_name); } for (p2 = p1; *p2 != '\0'; p2++) { if (!isspace(*p2)) { i++; break; } } for (p2 = strchr(p2, ','); p2++ != NULL; i++) p2 = strchr(p2, ','); /* * We first allocate a new ident signature structure with the * appropriate number of argument entries, and then look up * the return type and store its CTF data in di_ctfp/type. */ if ((isp = idp->di_data = malloc(sizeof (dt_idsig_t))) == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); isp->dis_varargs = -1; isp->dis_optargs = -1; isp->dis_argc = i; isp->dis_args = NULL; isp->dis_auxinfo = 0; if (i != 0 && (isp->dis_args = calloc(i, sizeof (dt_node_t))) == NULL) { idp->di_data = NULL; free(isp); longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); } if (dt_type_lookup(s, &dtt) == -1) { xyerror(D_UNKNOWN, "failed to resolve type of %s (%s):" " %s\n", idp->di_name, s, dtrace_errmsg(dtp, dtrace_errno(dtp))); } if (idp->di_kind == DT_IDENT_AGGFUNC) { idp->di_ctfp = DT_DYN_CTFP(dtp); idp->di_type = DT_DYN_TYPE(dtp); } else { idp->di_ctfp = dtt.dtt_ctfp; idp->di_type = dtt.dtt_type; } /* * For each comma-delimited parameter in the prototype string, * we look up the corresponding type and store its CTF data in * the corresponding location in dis_args[]. We also recognize * the special type string "@" to indicate that the specified * parameter may be a D expression of *any* type (represented * as a dis_args[] element with ctfp = NULL, type == CTF_ERR). * If a varargs "..." is present, we record the argument index * in dis_varargs for the benefit of dt_idcook_sign(), above. * If the type of an argument is enclosed in square brackets * (e.g. "[int]"), the argument is considered optional: the * argument may be absent, but if it is present, it must be of * the specified type. Note that varargs may not optional, * optional arguments may not follow varargs, and non-optional * arguments may not follow optional arguments. */ for (i = 0; i < isp->dis_argc; i++, p1 = p2) { while (isspace(*p1)) p1++; /* skip leading whitespace */ if ((p2 = strchr(p1, ',')) == NULL) p2 = p1 + strlen(p1); else *p2++ = '\0'; if (strcmp(p1, "@") == 0 || strcmp(p1, "...") == 0) { isp->dis_args[i].dn_ctfp = NULL; isp->dis_args[i].dn_type = CTF_ERR; if (*p1 == '.') isp->dis_varargs = i; continue; } if (*p1 == '[' && p1[strlen(p1) - 1] == ']') { if (isp->dis_varargs != -1) { xyerror(D_UNKNOWN, "optional arg#%d " "may not follow variable arg#%d\n", i + 1, isp->dis_varargs + 1); } if (isp->dis_optargs == -1) isp->dis_optargs = i; p1[strlen(p1) - 1] = '\0'; p1++; } else if (isp->dis_optargs != -1) { xyerror(D_UNKNOWN, "required arg#%d may not " "follow optional arg#%d\n", i + 1, isp->dis_optargs + 1); } if (dt_type_lookup(p1, &dtt) == -1) { xyerror(D_UNKNOWN, "failed to resolve type of " "%s arg#%d (%s): %s\n", idp->di_name, i + 1, p1, dtrace_errmsg(dtp, dtrace_errno(dtp))); } dt_node_type_assign(&isp->dis_args[i], dtt.dtt_ctfp, dtt.dtt_type); } } dt_idcook_sign(dnp, idp, argc, args, "", "( )"); }