static int dt_pid_mod_filt(void *arg, const prmap_t *pmp, const char *obj) { char name[DTRACE_MODNAMELEN]; dt_pid_probe_t *pp = arg; if (gmatch(obj, pp->dpp_mod)) return (dt_pid_per_mod(pp, pmp, obj)); #if defined(sun) (void) Plmid(pp->dpp_pr, pmp->pr_vaddr, &pp->dpp_lmid); #else pp->dpp_lmid = 0; #endif if ((pp->dpp_obj = strrchr(obj, '/')) == NULL) pp->dpp_obj = obj; else pp->dpp_obj++; if (gmatch(pp->dpp_obj, pp->dpp_mod)) return (dt_pid_per_mod(pp, pmp, obj)); #if defined(sun) (void) Plmid(pp->dpp_pr, pmp->pr_vaddr, &pp->dpp_lmid); #endif dt_pid_objname(name, sizeof (name), pp->dpp_lmid, pp->dpp_obj); if (gmatch(name, pp->dpp_mod)) return (dt_pid_per_mod(pp, pmp, obj)); return (0); }
/* * patMatch: Return 1 if name matches any of the comma separated patterns * in pat. Patterns are shell filename matching patterns (composed * of ?, [...], *, and literal characters). If deselect is non-zero, * reverse the return value (0 becomes 1, 1 becomes 0). A NULL pattern * list matches everything. */ int patMatch(const char *pat, const char *name, int deselect) { const char *pStart; const char *pEnd; int match; int flip; if (deselect) { flip = 1; /* must be 1, not other non-zero */ } else { flip = 0; } if (pat == NULL) { return 1 ^ flip; } pStart = pat; for (pEnd = pStart; *pEnd; ++pEnd) { if (*pEnd == ',') { match = gmatch(name, pStart, pEnd); if (match) { return 1 ^ flip; } pStart = pEnd + 1; } } match = gmatch(name, pStart, pStart + strlen(pStart)); /* returns 1 or 0 */ return match ^ flip; }
/* Check if name passes matching rules */ int prof_name_matched(char *name, struct sdev_node *dir) { int type, match = 0; char *expr; nvlist_t *nvl; nvpair_t *nvp = NULL; int rv; /* check against nvlist for leaf include/exclude */ nvl = dir->sdev_prof.dev_name; while (nvp = nvlist_next_nvpair(nvl, nvp)) { expr = nvpair_name(nvp); rv = nvpair_value_int32(nvp, &type); if (rv != 0) { cmn_err(CE_WARN, sdev_nvp_val_err, rv, nvpair_name(nvp)); break; } if (type == PROFILE_TYPE_EXCLUDE) { if (gmatch(name, expr)) return (0); /* excluded */ } else if (!match) { match = gmatch(name, expr); } } if (match) { sdcmn_err10(("prof_name_matched: %s\n", name)); return (match); } /* check for match against directory globbing pattern */ nvl = dir->sdev_prof.dev_glob_incdir; while (nvp = nvlist_next_nvpair(nvl, nvp)) { char *pathleft; expr = nvpair_name(nvp); if (gmatch(name, expr) == 0) continue; rv = nvpair_value_string(nvp, &pathleft); if (rv != 0) { cmn_err(CE_WARN, sdev_nvp_val_err, rv, nvpair_name(nvp)); break; } if (is_nonempty_dir(name, pathleft, dir)) { sdcmn_err10(("prof_name_matched: dir %s\n", name)); return (1); } } return (0); }
/* * Match a string against a shell glob or extended regular expression. */ static boolean_t ks_match(ks_returner_t *ret, const char *str, ks_pattern_t *pattern) { int regcode; char *regstr; char *errbuf; size_t bufsz; if (ret->ready == B_TRUE) { return B_FALSE; } if (pattern->pstr != NULL && gmatch(pattern->pstr, "/*/") != 0) { /* All regex patterns are strdup'd copies */ regstr = pattern->pstr + 1; *(strrchr(regstr, '/')) = '\0'; regcode = regcomp(&pattern->preg, regstr, REG_EXTENDED | REG_NOSUB); if (regcode != 0) { bufsz = regerror(regcode, NULL, NULL, 0); if (bufsz != 0) { errbuf = malloc(bufsz); if (errbuf == NULL) { ret->term = EKSTAT_ERROR("regex buffer malloc"); ret->ready = B_TRUE; free(pattern->pstr); pattern->pstr = NULL; return B_FALSE; } (void) regerror(regcode, NULL, errbuf, bufsz); ret->term = EKSTAT_ERROR(errbuf); ret->ready = B_TRUE; free(errbuf); } free(pattern->pstr); pattern->pstr = NULL; return B_FALSE; } free(pattern->pstr); pattern->pstr = NULL; } if (pattern->pstr == NULL) { return (regexec(&pattern->preg, str, 0, NULL, 0) == 0); } return ((gmatch(str, pattern->pstr) != 0)); }
/* apply include/exclude pattern to existing directory content */ static void apply_dir_pattern(struct sdev_node *dir, char *expr, char *pathleft, int type) { struct sdev_node *dv; /* leaf pattern */ if (pathleft == NULL) { if (type == PROFILE_TYPE_INCLUDE) return; /* nothing to do for include */ (void) sdev_cleandir(dir, expr, SDEV_ENFORCE); return; } /* directory pattern */ rw_enter(&dir->sdev_contents, RW_WRITER); for (dv = SDEV_FIRST_ENTRY(dir); dv; dv = SDEV_NEXT_ENTRY(dir, dv)) { if (gmatch(dv->sdev_name, expr) == 0 || SDEVTOV(dv)->v_type != VDIR) continue; process_rule(dv, dv->sdev_origin, pathleft, NULL, type); } rw_exit(&dir->sdev_contents); }
/* * Check if exec name matches cfgname found in madv cfg file. */ static int fnmatch(const char *execname, char *cfgname, char *cwd) { const char *ename; int rc; /* cfgname should not have a '/' unless it begins with one */ if (cfgname[0] == '/') { /* * if execname does not begin with a '/', prepend the * current directory. */ if (execname[0] != '/') { ename = (const char *)strcat(cwd, execname); } else ename = execname; } else { /* simple cfg name */ if (ename = strrchr(execname, '/')) /* execname is a path name - get the base name */ ename++; else ename = execname; } rc = gmatch(ename, cfgname); MADVPRINT(2, (stderr, "gmatch: %s %s %s %d\n", cfgname, ename, execname, rc)); return (rc); }
static void apply_glob_pattern(struct sdev_node *pdir, struct sdev_node *cdir) { char *name; nvpair_t *nvp = NULL; nvlist_t *nvl; struct vnode *vp = SDEVTOV(cdir); int rv = 0; if (vp->v_type != VDIR) return; name = cdir->sdev_name; nvl = pdir->sdev_prof.dev_glob_incdir; while (nvp = nvlist_next_nvpair(nvl, nvp)) { char *pathleft; char *expr = nvpair_name(nvp); if (!gmatch(name, expr)) continue; rv = nvpair_value_string(nvp, &pathleft); if (rv != 0) { cmn_err(CE_WARN, sdev_nvp_val_err, rv, nvpair_name(nvp)); break; } process_rule(cdir, cdir->sdev_origin, pathleft, NULL, PROFILE_TYPE_INCLUDE); } }
static int dt_pid_sym_filt(void *arg, const GElf_Sym *symp, const char *func) { dt_pid_probe_t *pp = arg; if (symp->st_shndx == SHN_UNDEF) return (0); if (symp->st_size == 0) { dt_dprintf("st_size of %s is zero\n", func); return (0); } if (pp->dpp_last_taken == 0 || symp->st_value != pp->dpp_last.st_value || symp->st_size != pp->dpp_last.st_size) { /* * Due to 4524008, _init and _fini may have a bloated st_size. * While this bug has been fixed for a while, old binaries * may exist that still exhibit this problem. As a result, we * don't match _init and _fini though we allow users to * specify them explicitly. */ if (strcmp(func, "_init") == 0 || strcmp(func, "_fini") == 0) return (0); if ((pp->dpp_last_taken = gmatch(func, pp->dpp_func)) != 0) { pp->dpp_last = *symp; return (dt_pid_per_sym(pp, symp, func)); } } return (0); }
bool pattern_match(const char *pat,const char *str) { #ifdef _SGI_SOURCE return (gmatch(str,pat) != 0); #else return (fnmatch(pat,str,0) == 0); #endif }
static int match_name(char *name, void *arg) { struct match_arg *margp = (struct match_arg *)arg; if (gmatch(name, margp->expr)) { margp->match = 1; return (WALK_DIR_TERMINATE); } return (WALK_DIR_CONTINUE); }
/* * Apply pattern matching to a table: all table entries that match a pattern * are added to wp. */ static void glob_table(const char *pat, XPtrV *wp, struct table *tp) { struct tstate ts; struct tbl *te; for (ktwalk(&ts, tp); (te = ktnext(&ts)); ) { if (gmatch(te->name, pat, false)) XPput(*wp, str_save(te->name, ATEMP)); } }
int dt_pid_create_probes_module(dtrace_hdl_t *dtp, dt_proc_t *dpr) { dtrace_prog_t *pgp; dt_stmt_t *stp; dtrace_probedesc_t *pdp, pd; pid_t pid; int ret = 0, found = B_FALSE; char provname[DTRACE_PROVNAMELEN]; (void) snprintf(provname, sizeof (provname), "pid%d", (int)dpr->dpr_pid); for (pgp = dt_list_next(&dtp->dt_programs); pgp != NULL; pgp = dt_list_next(pgp)) { for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = dt_list_next(stp)) { pdp = &stp->ds_desc->dtsd_ecbdesc->dted_probe; pid = dt_pid_get_pid(pdp, dtp, NULL, dpr); if (pid != dpr->dpr_pid) continue; found = B_TRUE; pd = *pdp; if (gmatch(provname, pdp->dtpd_provider) != 0 && dt_pid_create_pid_probes(&pd, dtp, NULL, dpr) != 0) ret = 1; /* * If it's not strictly a pid provider, we might match * a USDT provider. */ if (strcmp(provname, pdp->dtpd_provider) != 0 && dt_pid_create_usdt_probes(&pd, dtp, NULL, dpr) != 0) ret = 1; } } if (found) { /* * Give DTrace a shot to the ribs to get it to check * out the newly created probes. */ (void) dt_ioctl(dtp, DTRACEIOC_ENABLE, NULL); } return (ret); }
/* * Match a string against a shell glob or extended regular expression. */ static boolean_t ks_match(const char *str, ks_pattern_t *pattern) { int regcode; char *regstr; char *errbuf; size_t bufsz; if (pattern->pstr != NULL && gmatch(pattern->pstr, "/*/") != 0) { /* All regex patterns are strdup'd copies */ regstr = pattern->pstr + 1; *(strrchr(regstr, '/')) = '\0'; regcode = regcomp(&pattern->preg, regstr, REG_EXTENDED | REG_NOSUB); if (regcode != 0) { bufsz = regerror(regcode, NULL, NULL, 0); if (bufsz != 0) { errbuf = malloc(bufsz); if (errbuf == NULL) { perror("malloc"); exit(3); } (void) regerror(regcode, NULL, errbuf, bufsz); (void) fprintf(stderr, "kstat: %s\n", errbuf); } usage(); exit(2); } pattern->pstr = NULL; } if (pattern->pstr == NULL) { return (regexec(&pattern->preg, str, 0, NULL, 0) == 0); } return ((gmatch(str, pattern->pstr) != 0)); }
/*ARGSUSED*/ int dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp, fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern) { ulong_t i; ftp->ftps_type = DTFTP_OFFSETS; ftp->ftps_pc = (uintptr_t)symp->st_value; ftp->ftps_size = (size_t)symp->st_size; ftp->ftps_noffs = 0; /* * If we're matching against everything, just iterate through each * instruction in the function, otherwise look for matching offset * names by constructing the string and comparing it against the * pattern. */ if (strcmp("*", pattern) == 0) { for (i = 0; i < symp->st_size; i += 4) { ftp->ftps_offs[ftp->ftps_noffs++] = i; } } else { char name[sizeof (i) * 2 + 1]; for (i = 0; i < symp->st_size; i += 4) { (void) snprintf(name, sizeof(name), "%lx", i); if (gmatch(name, pattern)) ftp->ftps_offs[ftp->ftps_noffs++] = i; } } if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { dt_dprintf("fasttrap probe creation ioctl failed: %s\n", strerror(errno)); return (dt_set_errno(dtp, errno)); } return (ftp->ftps_noffs); }
/* * Check if string matches any of exec arguments. */ static int argmatch(char *str) { int fd; psinfo_t pi; int rc = 0; int arg; char **argv; fd = open("/proc/self/psinfo", O_RDONLY); if (fd >= 0) { if (read(fd, &pi, sizeof (pi)) == sizeof (pi)) { argv = (char **)pi.pr_argv; argv++; MADVPRINT(2, (stderr, "argmatch: %s ", str)); for (arg = 1; arg < pi.pr_argc; arg++, argv++) { if (rc = gmatch(*argv, str)) { MADVPRINT(2, (stderr, "%s ", *argv)); break; } } MADVPRINT(2, (stderr, "%d\n", rc)); } else { madverr(errfp, dgettext(TEXT_DOMAIN, "%s: /proc/self/psinfo read failed [%s]\n"), madvident, strerror(errno)); } (void) close(fd); } else { madverr(errfp, dgettext(TEXT_DOMAIN, "%s: /proc/self/psinfo open failed [%s]\n"), madvident, strerror(errno)); } return (rc); }
int expand(unsigned char *as, int rcnt) { int count; DIR *dirf; BOOL dir = 0; unsigned char *rescan = 0; unsigned char *slashsav = 0; register unsigned char *s, *cs; unsigned char *s2 = 0; struct argnod *schain = gchain; BOOL slash; int len; wchar_t wc; if (trapnote & SIGSET) return (0); s = cs = as; /* * check for meta chars */ { register BOOL open; slash = 0; open = 0; do { if ((len = nextc(&wc, (char *)cs)) <= 0) { len = 1; wc = (unsigned char)*cs; } cs += len; switch (wc) { case 0: if (rcnt && slash) break; else return (0); case '/': slash++; open = 0; continue; case '[': open++; continue; case ']': if (open == 0) continue; case '?': case '*': if (rcnt > slash) continue; else cs--; break; case '\\': cs++; default: continue; } break; } while (TRUE); } for (;;) { if (cs == s) { s = (unsigned char *)nullstr; break; } else if (*--cs == '/') { *cs = 0; if (s == cs) s = (unsigned char *)"/"; else { /* * push trimmed copy of directory prefix * onto stack */ s2 = cpystak(s); trim(s2); s = s2; } break; } } if ((dirf = opendir(*s ? (char *)s : (char *)".")) != 0) dir++; /* Let s point to original string because it will be trimmed later */ if (s2) s = as; count = 0; if (*cs == 0) slashsav = cs++; /* remember where first slash in as is */ /* check for rescan */ if (dir) { register unsigned char *rs; struct dirent *e; rs = cs; do /* find next / in as */ { if (*rs == '/') { rescan = rs; *rs = 0; gchain = 0; } } while (*rs++); while ((e = readdir(dirf)) && (trapnote & SIGSET) == 0) { if (e->d_name[0] == '.' && *cs != '.') continue; if (gmatch(e->d_name, cs)) { addg(s, e->d_name, rescan, slashsav); count++; } } closedir(dirf); if (rescan) { register struct argnod *rchain; rchain = gchain; gchain = schain; if (count) { count = 0; while (rchain) { count += expand(rchain->argval, slash + 1); rchain = rchain->argnxt; } } *rescan = '/'; } } if (slashsav) *slashsav = '/'; return (count); }
int test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2, int do_eval) { int res; int not; struct stat b1, b2; if (!do_eval) return 0; switch ((int) op) { /* * Unary Operators */ case TO_STNZE: /* -n */ return *opnd1 != '\0'; case TO_STZER: /* -z */ return *opnd1 == '\0'; case TO_OPTION: /* -o */ if ((not = *opnd1 == '!')) opnd1++; if ((res = option(opnd1)) < 0) res = 0; else { res = Flag(res); if (not) res = !res; } return res; case TO_FILRD: /* -r */ return test_eaccess(opnd1, R_OK) == 0; case TO_FILWR: /* -w */ return test_eaccess(opnd1, W_OK) == 0; case TO_FILEX: /* -x */ return test_eaccess(opnd1, X_OK) == 0; case TO_FILAXST: /* -a */ return test_stat(opnd1, &b1) == 0; case TO_FILEXST: /* -e */ /* at&t ksh does not appear to do the /dev/fd/ thing for * this (unless the os itself handles it) */ return stat(opnd1, &b1) == 0; case TO_FILREG: /* -r */ return test_stat(opnd1, &b1) == 0 && S_ISREG(b1.st_mode); case TO_FILID: /* -d */ return test_stat(opnd1, &b1) == 0 && S_ISDIR(b1.st_mode); case TO_FILCDEV: /* -c */ return test_stat(opnd1, &b1) == 0 && S_ISCHR(b1.st_mode); case TO_FILBDEV: /* -b */ return test_stat(opnd1, &b1) == 0 && S_ISBLK(b1.st_mode); case TO_FILFIFO: /* -p */ return test_stat(opnd1, &b1) == 0 && S_ISFIFO(b1.st_mode); case TO_FILSYM: /* -h -L */ return lstat(opnd1, &b1) == 0 && S_ISLNK(b1.st_mode); case TO_FILSOCK: /* -S */ return test_stat(opnd1, &b1) == 0 && S_ISSOCK(b1.st_mode); case TO_FILCDF:/* -H HP context dependent files (directories) */ return 0; case TO_FILSETU: /* -u */ return test_stat(opnd1, &b1) == 0 && (b1.st_mode & S_ISUID) == S_ISUID; case TO_FILSETG: /* -g */ return test_stat(opnd1, &b1) == 0 && (b1.st_mode & S_ISGID) == S_ISGID; case TO_FILSTCK: /* -k */ return test_stat(opnd1, &b1) == 0 && (b1.st_mode & S_ISVTX) == S_ISVTX; case TO_FILGZ: /* -s */ return test_stat(opnd1, &b1) == 0 && b1.st_size > 0L; case TO_FILTT: /* -t */ if (opnd1 && !bi_getn(opnd1, &res)) { te->flags |= TEF_ERROR; res = 0; } else { /* generate error if in FPOSIX mode? */ res = isatty(opnd1 ? res : 0); } return res; case TO_FILUID: /* -O */ return test_stat(opnd1, &b1) == 0 && b1.st_uid == ksheuid; case TO_FILGID: /* -G */ return test_stat(opnd1, &b1) == 0 && b1.st_gid == getegid(); /* * Binary Operators */ case TO_STEQL: /* = */ if (te->flags & TEF_DBRACKET) return gmatch(opnd1, opnd2, false); return strcmp(opnd1, opnd2) == 0; case TO_STNEQ: /* != */ if (te->flags & TEF_DBRACKET) return !gmatch(opnd1, opnd2, false); return strcmp(opnd1, opnd2) != 0; case TO_STLT: /* < */ return strcmp(opnd1, opnd2) < 0; case TO_STGT: /* > */ return strcmp(opnd1, opnd2) > 0; case TO_INTEQ: /* -eq */ case TO_INTNE: /* -ne */ case TO_INTGE: /* -ge */ case TO_INTGT: /* -gt */ case TO_INTLE: /* -le */ case TO_INTLT: /* -lt */ { long v1, v2; if (!evaluate(opnd1, &v1, KSH_RETURN_ERROR, false) || !evaluate(opnd2, &v2, KSH_RETURN_ERROR, false)) { /* error already printed.. */ te->flags |= TEF_ERROR; return 1; } switch ((int) op) { case TO_INTEQ: return v1 == v2; case TO_INTNE: return v1 != v2; case TO_INTGE: return v1 >= v2; case TO_INTGT: return v1 > v2; case TO_INTLE: return v1 <= v2; case TO_INTLT: return v1 < v2; } } case TO_FILNT: /* -nt */ { int s2; /* ksh88/ksh93 succeed if file2 can't be stated * (subtly different from `does not exist'). */ return stat(opnd1, &b1) == 0 && (((s2 = stat(opnd2, &b2)) == 0 && b1.st_mtime > b2.st_mtime) || s2 < 0); } case TO_FILOT: /* -ot */ { int s1; /* ksh88/ksh93 succeed if file1 can't be stated * (subtly different from `does not exist'). */ return stat(opnd2, &b2) == 0 && (((s1 = stat(opnd1, &b1)) == 0 && b1.st_mtime < b2.st_mtime) || s1 < 0); } case TO_FILEQ: /* -ef */ return stat (opnd1, &b1) == 0 && stat (opnd2, &b2) == 0 && b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino; } (*te->error)(te, 0, "internal error: unknown op"); return 1; }
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); }
/*ARGSUSED*/ int dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp, fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern) { uint8_t *text; ulong_t i, end; int size; pid_t pid = Pstatus(P)->pr_pid; char dmodel = Pstatus(P)->pr_dmodel; if ((text = malloc(symp->st_size)) == NULL) { dt_dprintf("mr sparkle: malloc() failed\n"); return (DT_PROC_ERR); } if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) { dt_dprintf("mr sparkle: Pread() failed\n"); free(text); return (DT_PROC_ERR); } /* * We can't instrument offsets in functions with jump tables as * we might interpret a jump table offset as an instruction. */ if (dt_pid_has_jump_table(P, dtp, text, ftp, symp)) { free(text); return (0); } ftp->ftps_probe_type = DTFTP_OFFSETS; ftp->ftps_pc = symp->st_value; ftp->ftps_size = (size_t)symp->st_size; ftp->ftps_noffs = 0; end = ftp->ftps_size; if (strcmp("*", pattern) == 0) { for (i = 0; i < end; i += size) { ftp->ftps_offs[ftp->ftps_noffs++] = i; size = dt_instr_size(&text[i], dtp, pid, symp->st_value + i, dmodel); /* bail if we hit an invalid opcode */ if (size <= 0) break; } } else { char name[sizeof (i) * 2 + 1]; for (i = 0; i < end; i += size) { (void) snprintf(name, sizeof (name), "%lx", i); if (gmatch(name, pattern)) ftp->ftps_offs[ftp->ftps_noffs++] = i; size = dt_instr_size(&text[i], dtp, pid, symp->st_value + i, dmodel); /* bail if we hit an invalid opcode */ if (size <= 0) break; } } free(text); if (ftp->ftps_noffs > 0) { if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { dt_dprintf("fasttrap probe creation ioctl failed: %s\n", strerror(errno)); return (dt_set_errno(dtp, errno)); } } return (ftp->ftps_noffs); }
int execute(TREPTR argt, int execflg, int *pf1, int *pf2) { /* `stakbot' is preserved by this routine */ register TREPTR t; STKPTR sav = savstak(); sigchk(); if ((t = argt) && execbrk == 0) { register int treeflgs; int oldexit, type; register char **com; treeflgs = t->tretyp; type = treeflgs & COMMSK; oldexit = exitval; exitval = 0; switch (type) { case TCOM: { STRING a1; int argn, internal; ARGPTR schain = gchain; IOPTR io = t->treio; gchain = 0; argn = getarg((void *)t);/*FIXME*/ com = scan(argn); a1 = com[1]; gchain = schain; if ((internal = syslook(com[0], commands)) || argn == 0) setlist(((COMPTR) t)->comset, 0); if (argn && (flags & noexec) == 0) { /* print command if execpr */ if (flags & execpr) { argn = 0; prs(execpmsg); while (com[argn] != ENDARGS) { prs(com[argn++]); blank(); } newline(); } switch (internal) { case SYSDOT: if (a1) { register int f; if ((f = pathopen(getpath(a1), a1)) < 0) failed(a1, notfound); else execexp(0, f); } break; case SYSTIMES: { struct tms t; times(&t); prt(t.tms_cutime); blank(); prt(t.tms_cstime); newline(); } break; case SYSEXIT: exitsh(a1 ? stoi(a1) : oldexit); case SYSNULL: io = 0; break; case SYSCONT: execbrk = -loopcnt; break; case SYSBREAK: if ((execbrk = loopcnt) && a1) breakcnt = stoi(a1); break; case SYSTRAP: if (a1) { BOOL clear; if ((clear = digit(*a1)) == 0) ++com; while (*++com) { int i; if ((i = stoi(*com)) >= MAXTRAP || i < MINTRAP) failed(*com, badtrap); else if (clear) clrsig(i); else { replace(&trapcom[i], a1); if (*a1) getsig(i); else ignsig(i); } } } else { /* print out current traps */ int i; for (i = 0; i < MAXTRAP; i++) { if (trapcom[i]) { prn(i); prs(colon); prs(trapcom[i]); newline(); } } } break; case SYSEXEC: com++; initio(io); ioset = 0; io = 0; if (a1 == 0) break; case SYSLOGIN: flags |= forked; oldsigs(); execa((const char **)com); done(); case SYSCD: if (flags & rshflg) failed(com[0], restricted); else if ((a1 == 0 && (a1 = (char *)homenod.namval) == 0) || chdir(a1) < 0) /* FIXME */ failed(a1, baddir); break; case SYSSHFT: if (dolc < 1) error(badshift); else { dolv++; dolc--; } assnum(&dolladr, dolc); break; case SYSWAIT: await(-1); break; case SYSREAD: exitval = readvar(&com[1]); break; /* case SYSTST: exitval=testcmd(com); break; */ case SYSSET: if (a1) { int argc; argc = options(argn, (const char **)com); if (argc > 1) setargs((const char **)com + argn - argc); } else if (((COMPTR) t)->comset == 0) /* Scan name chain and print */ namscan(printnam); break; case SYSRDONLY: exitval = N_RDONLY; case SYSXPORT: if (exitval == 0) exitval = N_EXPORT;; if (a1) { while (*++com) attrib(lookup(*com), exitval); } else { namscan(printflg); } exitval = 0; break; case SYSEVAL: if (a1) execexp(a1, (UFD)&com[2]); /* FIXME */ break; case SYSUMASK: if (a1) { int c, i; i = 0; while ((c = *a1++) >= '0' && c <= '7') i = (i << 3) + c - '0'; umask(i); } else { int i, j; umask(i = umask(0)); prc('0'); for (j = 6; j >= 0; j -= 3) prc(((i >> j) & 07) + '0'); newline(); } break; default: internal = builtin(argn, com); } if (internal) { if (io) error(illegal); chktrap(); break; } } else if (t->treio == 0) break; } case TFORK: if (execflg && (treeflgs & (FAMP | FPOU)) == 0) parent = 0; else { while ((parent = fork()) == -1) { sigchk(); alarm(10); pause(); } } if (parent) { /* This is the parent branch of fork; */ /* it may or may not wait for the child. */ if (treeflgs & FPRS && flags & ttyflg) { prn(parent); newline(); } if (treeflgs & FPCL) closepipe(pf1); if ((treeflgs & (FAMP | FPOU)) == 0) await(parent); else if ((treeflgs & FAMP) == 0) post(parent); else assnum(&pcsadr, parent); chktrap(); break; } else { /* this is the forked branch (child) of execute */ flags |= forked; iotemp = 0; postclr(); settmp(); /* Turn off INTR and QUIT if `FINT' */ /* Reset ramaining signals to parent */ /* except for those `lost' by trap */ oldsigs(); if (treeflgs & FINT) { signal(INTR, SIG_IGN); signal(QUIT, SIG_IGN); } /* pipe in or out */ if (treeflgs & FPIN) { sh_rename(pf1[INPIPE], 0); close(pf1[OTPIPE]); } if (treeflgs & FPOU) { sh_rename(pf2[OTPIPE], 1); close(pf2[INPIPE]); } /* default std input for & */ if (treeflgs & FINT && ioset == 0) sh_rename(chkopen(devnull), 0); /* io redirection */ initio(t->treio); if (type != TCOM) execute(((FORKPTR) t)->forktre, 1, NULL, NULL); else if (com[0] != ENDARGS) { setlist(((COMPTR) t)->comset, N_EXPORT); execa((const char **)com); } done(); } case TPAR: sh_rename(dup(2), output); execute(((PARPTR) t)->partre, execflg, NULL, NULL); done(); case TFIL: { int pv[2]; chkpipe(pv); if (execute(((LSTPTR) t)->lstlef, 0, pf1, pv) == 0) execute(((LSTPTR) t)->lstrit, execflg, pv, pf2); else closepipe(pv); break; } case TLST: execute(((LSTPTR) t)->lstlef, 0, NULL, NULL); execute(((LSTPTR) t)->lstrit, execflg, NULL, NULL); break; case TAND: if (execute(((LSTPTR) t)->lstlef, 0, NULL, NULL) == 0) execute(((LSTPTR) t)->lstrit, execflg, NULL, NULL); break; case TORF: if (execute(((LSTPTR) t)->lstlef, 0, NULL, NULL) != 0) execute(((LSTPTR) t)->lstrit, execflg, NULL, NULL); break; case TFOR: { NAMPTR n = lookup(((FORPTR) t)->fornam); char **args; DOLPTR argsav = 0; if (((FORPTR) t)->forlst == 0) { args = (char **)dolv + 1; argsav = useargs(); } else { ARGPTR schain = gchain; gchain = 0; trim((args = scan(getarg(((FORPTR) t)->forlst)))[0]); gchain = schain; } loopcnt++; while (*args != ENDARGS && execbrk == 0) { assign(n, *args++); execute(((FORPTR) t)->fortre, 0, NULL, NULL); if (execbrk < 0) { execbrk = 0; } } if (breakcnt) breakcnt--; execbrk = breakcnt; loopcnt--; argfor = freeargs(argsav); break; } case TWH: case TUN: { int i = 0; loopcnt++; while (execbrk == 0 && (execute(((WHPTR) t)->whtre, 0, NULL, NULL) == 0) == (type == TWH)) { i = execute(((WHPTR) t)->dotre, 0, NULL, NULL); if (execbrk < 0) execbrk = 0; } if (breakcnt) breakcnt--; execbrk = breakcnt; loopcnt--; exitval = i; break; } case TIF: if (execute(((IFPTR) t)->iftre, 0, NULL, NULL) == 0) execute(((IFPTR) t)->thtre, execflg, NULL, NULL); else execute(((IFPTR) t)->eltre, execflg, NULL, NULL); break; case TSW: { register char *r = mactrim(((SWPTR) t)->swarg); t = (TREPTR) ((SWPTR) t)->swlst; while (t) { ARGPTR rex = ((REGPTR) t)->regptr; while (rex) { register char *s; if (gmatch(r, s = macro(rex->argval)) || (trim(s), eq(r, s))) { execute(((REGPTR)t)->regcom, 0, NULL, NULL); t = 0; break; } else rex = ((ARGPTR)rex)->argnxt; } if (t) t = (TREPTR) ((REGPTR) t)->regnxt; } } break; } exitset(); }
int gmatch(const char *s, const char *p) { const char *bs = s; int mb_cur_max = MB_CUR_MAX; wint_t c, scc; int n; if (fetch(scc, s, n) == WEOF) return (0); switch (fetch(c, p, n)) { case '[': { int ok = 0, excl; unsigned long lc = ULONG_MAX; const char *bp; if (*p == '!') { p++; excl = 1; } else excl = 0; fetch(c, p, n); bp = p; while (c != '\0') { if (c == ']' && p > bp) return (ok ^ excl ? gmatch(s, p) : 0); else if (c == '-' && p > bp && *p != ']') { if (*p == '\\') p++; if (fetch(c, p, n) == '\0') break; if (lc <= scc && scc <= c) ok = 1; } else { if (c == '\\') { if (fetch(c, p, n) == '\0') break; } if (scc == (lc = c)) ok = 1; } fetch(c, p, n); } return (0); } case '\\': fetch(c, p, n); if (c == '\0') return (0); /*FALLTHRU*/ default: if (c != scc) return (0); /*FALLTHRU*/ case '?': return (scc ? gmatch(s, p) : 0); case '*': if (*p == '\0') return (1); s = bs; while (*s) { if (gmatch(s, p)) return (1); fetch(scc, s, n); } return (0); case '\0': return (scc == '\0'); case WEOF: return (0); } }
int gmatch(const char *s, const char *p) { const char *olds; wchar_t scc, c; int n; wchar_t cl; olds = s; n = mbtowc(&cl, s, MB_LEN_MAX); if (n <= 0) { s++; scc = n; } else { scc = cl; s += n; } n = mbtowc(&cl, p, MB_LEN_MAX); if (n < 0) return (0); if (n == 0) return (scc == 0); p += n; c = cl; switch (c) { case '[': if (scc <= 0) return (0); { int ok; wchar_t lc = 0; int notflag = 0; ok = 0; if (*p == '!') { notflag = 1; p++; } Popwchar(p, c); do { if (c == '-' && lc && *p != ']') { Popwchar(p, c); if (c == '\\') { Popwchar(p, c); } if (notflag) { if (!multibyte || valid_range(lc, c)) { if (scc < lc || scc > c) ok++; else return (0); } } else { if (!multibyte || valid_range(lc, c)) if (lc <= scc && scc <= c) ok++; } } else if (c == '\\') { /* skip to quoted character */ Popwchar(p, c); } lc = c; if (notflag) { if (scc != lc) ok++; else return (0); } else { if (scc == lc) ok++; } Popwchar(p, c); } while (c != ']'); return (ok ? gmatch(s, p) : 0); } case '\\': /* skip to quoted character and see if it matches */ Popwchar(p, c); default: if (c != scc) return (0); /*FALLTHRU*/ case '?': return (scc > 0 ? gmatch(s, p) : 0); case '*': while (*p == '*') p++; if (*p == 0) return (1); s = olds; while (*s) { if (gmatch(s, p)) return (1); n = mbtowc(&cl, s, MB_LEN_MAX); if (n < 0) /* skip past illegal byte sequence */ s++; else s += n; } return (0); } }
int dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb) { char provname[DTRACE_PROVNAMELEN]; struct ps_prochandle *P; dt_proc_t *dpr; pid_t pid; int err = 0; assert(pcb != NULL); if ((pid = dt_pid_get_pid(pdp, dtp, pcb, NULL)) == -1) return (-1); if (dtp->dt_ftfd == -1) { if (dtp->dt_fterr == ENOENT) { (void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_NODEV, "pid provider is not installed on this system"); } else { (void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_NODEV, "pid provider is not available: %s", strerror(dtp->dt_fterr)); } return (-1); } (void) snprintf(provname, sizeof (provname), "pid%d", (int)pid); if (gmatch(provname, pdp->dtpd_provider) != 0) { if ((P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0)) == NULL) { (void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_GRAB, "failed to grab process %d", (int)pid); return (-1); } dpr = dt_proc_lookup(dtp, P, 0); assert(dpr != NULL); (void) pthread_mutex_lock(&dpr->dpr_lock); if ((err = dt_pid_create_pid_probes(pdp, dtp, pcb, dpr)) == 0) { /* * Alert other retained enablings which may match * against the newly created probes. */ (void) dt_ioctl(dtp, DTRACEIOC_ENABLE, NULL); } (void) pthread_mutex_unlock(&dpr->dpr_lock); dt_proc_release(dtp, P); } /* * If it's not strictly a pid provider, we might match a USDT provider. */ if (strcmp(provname, pdp->dtpd_provider) != 0) { if ((P = dt_proc_grab(dtp, pid, 0, 1)) == NULL) { (void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_GRAB, "failed to grab process %d", (int)pid); return (-1); } dpr = dt_proc_lookup(dtp, P, 0); assert(dpr != NULL); (void) pthread_mutex_lock(&dpr->dpr_lock); if (!dpr->dpr_usdt) { err = dt_pid_create_usdt_probes(pdp, dtp, pcb, dpr); dpr->dpr_usdt = B_TRUE; } (void) pthread_mutex_unlock(&dpr->dpr_lock); dt_proc_release(dtp, P); } return (err ? -1 : 0); }