if (!debugfs__configured() && !tracefs__configured())
pr_warning("Debugfs or tracefs is not mounted\n" "Please try 'sudo mount -t tracefs nodev /sys/kernel/tracing/'\n"); else
pr_warning("%s/%s does not exist.\nPlease rebuild kernel with %s.\n",
tracing_path_mount(), file, config);
pr_warning("Failed to open %s/%cprobe_events: %s\n",
tracing_path_mount(), uprobe ? 'u' : 'k',
str_error_r(-err, sbuf, sizeof(sbuf)));
}
staticvoid print_both_open_warning(int kerr, int uerr, bool readwrite)
{ char sbuf[STRERR_BUFSIZE];
if (kerr == uerr && print_common_warning(kerr, readwrite)) return;
if (print_configure_probe_event(kerr, uerr)) return;
if (kerr < 0)
pr_warning("Failed to open %s/kprobe_events: %s.\n",
tracing_path_mount(),
str_error_r(-kerr, sbuf, sizeof(sbuf))); if (uerr < 0)
pr_warning("Failed to open %s/uprobe_events: %s.\n",
tracing_path_mount(),
str_error_r(-uerr, sbuf, sizeof(sbuf)));
}
int open_trace_file(constchar *trace_file, bool readwrite)
{ char buf[PATH_MAX]; int ret;
ret = e_snprintf(buf, PATH_MAX, "%s/%s", tracing_path_mount(), trace_file); if (ret >= 0) {
pr_debug("Opening %s write=%d\n", buf, readwrite); if (readwrite && !probe_event_dry_run)
ret = open(buf, O_RDWR | O_APPEND, 0); else
ret = open(buf, O_RDONLY, 0);
/* Get raw string list of current kprobe_events or uprobe_events */ struct strlist *probe_file__get_rawlist(int fd)
{ int ret, idx, fddup;
FILE *fp; char buf[MAX_CMDLEN]; char *p; struct strlist *sl;
if (fd < 0) return NULL;
sl = strlist__new(NULL, NULL); if (sl == NULL) return NULL;
fddup = dup(fd); if (fddup < 0) goto out_free_sl;
fp = fdopen(fddup, "r"); if (!fp) goto out_close_fddup;
while (!feof(fp)) {
p = fgets(buf, MAX_CMDLEN, fp); if (!p) break;
idx = strlen(p) - 1; if (p[idx] == '\n')
p[idx] = '\0';
ret = strlist__add(sl, buf); if (ret < 0) {
pr_debug("strlist__add failed (%d)\n", ret); goto out_close_fp;
}
}
fclose(fp);
memset(&tev, 0, sizeof(tev));
rawlist = probe_file__get_rawlist(fd); if (!rawlist) return NULL;
sl = strlist__new(NULL, NULL);
strlist__for_each_entry(ent, rawlist) {
ret = parse_probe_trace_command(ent->s, &tev); if (ret < 0) break; if (include_group) {
ret = e_snprintf(buf, 128, "%s:%s", tev.group,
tev.event); if (ret >= 0)
ret = strlist__add(sl, buf);
} else
ret = strlist__add(sl, tev.event);
clear_probe_trace_event(&tev); /* Skip if there is same name multi-probe event in the list */ if (ret == -EEXIST)
ret = 0; if (ret < 0) break;
}
strlist__delete(rawlist);
int probe_file__get_events(int fd, struct strfilter *filter, struct strlist *plist)
{ struct strlist *namelist; struct str_node *ent; constchar *p; int ret = -ENOENT;
if (!plist) return -EINVAL;
namelist = __probe_file__get_namelist(fd, true); if (!namelist) return -ENOENT;
strlist__for_each_entry(ent, namelist) {
p = strchr(ent->s, ':'); if ((p && strfilter__compare(filter, p + 1)) ||
strfilter__compare(filter, ent->s)) {
ret = strlist__add(plist, ent->s); if (ret == -ENOMEM) {
pr_err("strlist__add failed with -ENOMEM\n"); goto out;
}
ret = 0;
}
}
out:
strlist__delete(namelist);
return ret;
}
int probe_file__del_strlist(int fd, struct strlist *namelist)
{ int ret = 0; struct str_node *ent;
strlist__for_each_entry(ent, namelist) {
ret = __del_trace_probe_event(fd, ent); if (ret < 0) break;
} return ret;
}
/* Caller must ensure to remove this entry from list */ staticvoid probe_cache_entry__delete(struct probe_cache_entry *entry)
{ if (entry) {
BUG_ON(!list_empty(&entry->node));
if (target && build_id_cache__cached(target)) { /* This is a cached buildid */
strlcpy(sbuildid, target, SBUILD_ID_SIZE);
dir_name = build_id_cache__linkname(sbuildid, NULL, 0); goto found;
}
if (!target || !strcmp(target, DSO__NAME_KALLSYMS)) {
target = DSO__NAME_KALLSYMS;
is_kallsyms = true;
ret = sysfs__snprintf_build_id("/", sbuildid, sizeof(sbuildid));
} else {
nsinfo__mountns_enter(nsi, &nsc);
ret = filename__snprintf_build_id(target, sbuildid, sizeof(sbuildid));
nsinfo__mountns_exit(&nsc);
}
if (ret < 0) {
pr_debug("Failed to get build-id from %s.\n", target); return ret;
}
/* If we have no buildid cache, make it */ if (!build_id_cache__cached(sbuildid)) {
ret = build_id_cache__add_s(sbuildid, target, nsi,
is_kallsyms, NULL); if (ret < 0) {
pr_debug("Failed to add build-id cache: %s\n", target); return ret;
}
}
dir_name = build_id_cache__cachedir(sbuildid, target, nsi, is_kallsyms, false);
found: if (!dir_name) {
pr_debug("Failed to get cache from %s\n", target); return -ENOMEM;
}
snprintf(cpath, PATH_MAX, "%s/probes", dir_name);
fd = open(cpath, O_CREAT | O_RDWR, 0644); if (fd < 0)
pr_debug("Failed to open cache(%d): %s\n", fd, cpath);
free(dir_name);
pcache->fd = fd;
return fd;
}
staticint probe_cache__load(struct probe_cache *pcache)
{ struct probe_cache_entry *entry = NULL; char buf[MAX_CMDLEN], *p; int ret = 0, fddup;
FILE *fp;
fddup = dup(pcache->fd); if (fddup < 0) return -errno;
fp = fdopen(fddup, "r"); if (!fp) {
close(fddup); return -EINVAL;
}
while (!feof(fp)) { if (!fgets(buf, MAX_CMDLEN, fp)) break;
p = strchr(buf, '\n'); if (p)
*p = '\0'; /* #perf_probe_event or %sdt_event */ if (buf[0] == '#' || buf[0] == '%') {
entry = probe_cache_entry__new(NULL); if (!entry) {
ret = -ENOMEM; goto out;
} if (buf[0] == '%')
entry->sdt = true;
entry->spev = strdup(buf + 1); if (entry->spev)
ret = parse_perf_probe_command(buf + 1,
&entry->pev); else
ret = -ENOMEM; if (ret < 0) {
probe_cache_entry__delete(entry); goto out;
}
list_add_tail(&entry->node, &pcache->entries);
} else { /* trace_probe_event */ if (!entry) {
ret = -EINVAL; goto out;
}
ret = strlist__add(entry->tevlist, buf); if (ret == -ENOMEM) {
pr_err("strlist__add failed with -ENOMEM\n"); goto out;
}
}
}
out:
fclose(fp); return ret;
}
for_each_probe_cache_entry(entry, pcache) { if (pev->sdt) { if (entry->pev.event &&
streql(entry->pev.event, pev->event) &&
(!pev->group ||
streql(entry->pev.group, pev->group))) goto found;
continue;
} /* Hit if same event name or same command-string */ if ((pev->event &&
(streql(entry->pev.group, pev->group) &&
streql(entry->pev.event, pev->event))) ||
(!strcmp(entry->spev, cmd))) goto found;
}
entry = NULL;
for_each_probe_cache_entry(entry, pcache) { /* Hit if same event name or same command-string */ if (streql(entry->pev.group, group) &&
streql(entry->pev.event, event)) goto found;
}
entry = NULL;
found: return entry;
}
int probe_cache__add_entry(struct probe_cache *pcache, struct perf_probe_event *pev, struct probe_trace_event *tevs, int ntevs)
{ struct probe_cache_entry *entry = NULL; char *command; int i, ret = 0;
if (!pcache || !pev || !tevs || ntevs <= 0) {
ret = -EINVAL; goto out_err;
}
/* Remove old cache entry */
entry = probe_cache__find(pcache, pev); if (entry) {
list_del_init(&entry->node);
probe_cache_entry__delete(entry);
}
ret = -ENOMEM;
entry = probe_cache_entry__new(pev); if (!entry) goto out_err;
for (i = 0; i < ntevs; i++) { if (!tevs[i].point.symbol) continue;
command = synthesize_probe_trace_command(&tevs[i]); if (!command) goto out_err;
ret = strlist__add(entry->tevlist, command); if (ret == -ENOMEM) {
pr_err("strlist__add failed with -ENOMEM\n"); goto out_err;
}
/* * Isolate the string number and convert it into a decimal value; * this will be an index to get suffix of the uprobe name (defining * the type)
*/ staticint sdt_arg_parse_size(char *n_ptr, constchar **suffix)
{ long type_idx;
type_idx = strtol(n_ptr, NULL, 10); if (type_idx < -8 || type_idx > 8) {
pr_debug4("Failed to get a valid sdt type\n"); return -1;
}
staticint synthesize_sdt_probe_arg(struct strbuf *buf, int i, constchar *arg)
{ char *op, *desc = strdup(arg), *new_op = NULL; constchar *suffix = ""; int ret = -1;
if (desc == NULL) {
pr_debug4("Allocation error\n"); return ret;
}
/* * Argument is in N@OP format. N is size of the argument and OP is * the actual assembly operand. N can be omitted; in that case * argument is just OP(without @).
*/
op = strchr(desc, '@'); if (op) {
op[0] = '\0';
op++;
if (sdt_arg_parse_size(desc, &suffix)) goto error;
} else {
op = desc;
}
ret = arch_sdt_arg_parse_op(op, &new_op);
if (ret < 0) goto error;
if (ret == SDT_ARG_VALID) {
ret = strbuf_addf(buf, " arg%d=%s%s", i + 1, new_op, suffix); if (ret < 0) goto error;
}
ret = 0;
error:
free(desc);
free(new_op); return ret;
}
staticchar *synthesize_sdt_probe_command(struct sdt_note *note, constchar *pathname, constchar *sdtgrp)
{ struct strbuf buf; char *ret = NULL; int i, args_count, err; unsignedlonglong ref_ctr_offset; char *arg; int arg_idx = 0;
if (note->args) { char **args = argv_split(note->args, &args_count);
if (args == NULL) goto error;
for (i = 0; i < args_count; ) { /* * FIXUP: Arm64 ELF section '.note.stapsdt' uses string * format "-4@[sp, NUM]" if a probe is to access data in * the stack, e.g. below is an example for the SDT * Arguments: * * Arguments: -4@[sp, 12] -4@[sp, 8] -4@[sp, 4] * * Since the string introduces an extra space character * in the middle of square brackets, the argument is * divided into two items. Fixup for this case, if an * item contains sub string "[sp,", need to concatenate * the two items.
*/ if (strstr(args[i], "[sp,") && (i+1) < args_count) {
err = asprintf(&arg, "%s %s", args[i], args[i+1]);
i += 2;
} else {
err = asprintf(&arg, "%s", args[i]);
i += 1;
}
/* Failed to allocate memory */ if (err < 0) {
argv_free(args); goto error;
}
while (getline(&buf, &len, fp) > 0) for (enum ftrace_readme i = 0; i < FTRACE_README_END; i++) if (!ftrace_readme_table[i].avail)
ftrace_readme_table[i].avail =
strglobmatch(buf, ftrace_readme_table[i].pattern);
scanned = true;
fclose(fp);
free(buf);
result: if (type >= FTRACE_README_END) returnfalse;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.