perf trace: Expand strings in filters to integers
So that one can try things like: # perf trace -e msr:* --filter="msr!=FS_BASE && msr != IA32_TSC_DEADLINE && msr != 0x830 && msr != 0x83f && msr !=IA32_SPEC_CTRL" --filter-pids 3750 That, at this point in the patchset, without any strtoul in place for tracepoint arguments, will result in: No resolver (strtoul) for "msr" in "msr:read_msr", can't set filter "(msr!=FS_BASE && msr != IA32_TSC_DEADLINE && msr != 0x830 && msr != 0x83f && msr !=IA32_SPEC_CTRL) && (common_pid != 25407 && common_pid != 3750)" # See you in the next cset! Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Brendan Gregg <brendan.d.gregg@gmail.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Luis Cláudio Gonçalves <lclaudio@redhat.com> Cc: Namhyung Kim <namhyung@kernel.org> Link: https://lkml.kernel.org/n/tip-dx5j70fv2rgkeezd1cb3hv2p@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
d0a3a10410
commit
90df0249c2
@ -3484,6 +3484,133 @@ static int ordered_events__deliver_event(struct ordered_events *oe,
|
||||
return __trace__deliver_event(trace, event->event);
|
||||
}
|
||||
|
||||
static struct syscall_arg_fmt *perf_evsel__syscall_arg_fmt(struct evsel *evsel, char *arg)
|
||||
{
|
||||
struct tep_format_field *field;
|
||||
struct syscall_arg_fmt *fmt = evsel->priv;
|
||||
|
||||
if (evsel->tp_format == NULL || fmt == NULL)
|
||||
return NULL;
|
||||
|
||||
for (field = evsel->tp_format->format.fields; field; field = field->next, ++fmt)
|
||||
if (strcmp(field->name, arg) == 0)
|
||||
return fmt;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int trace__expand_filter(struct trace *trace __maybe_unused, struct evsel *evsel)
|
||||
{
|
||||
char *tok, *left = evsel->filter, *new_filter = evsel->filter;
|
||||
|
||||
while ((tok = strpbrk(left, "=<>!")) != NULL) {
|
||||
char *right = tok + 1, *right_end;
|
||||
|
||||
if (*right == '=')
|
||||
++right;
|
||||
|
||||
while (isspace(*right))
|
||||
++right;
|
||||
|
||||
if (*right == '\0')
|
||||
break;
|
||||
|
||||
while (!isalpha(*left))
|
||||
if (++left == tok) {
|
||||
/*
|
||||
* Bail out, can't find the name of the argument that is being
|
||||
* used in the filter, let it try to set this filter, will fail later.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
right_end = right + 1;
|
||||
while (isalnum(*right_end) || *right_end == '_')
|
||||
++right_end;
|
||||
|
||||
if (isalpha(*right)) {
|
||||
struct syscall_arg_fmt *fmt;
|
||||
int left_size = tok - left,
|
||||
right_size = right_end - right;
|
||||
char arg[128];
|
||||
|
||||
while (isspace(left[left_size - 1]))
|
||||
--left_size;
|
||||
|
||||
scnprintf(arg, sizeof(arg), "%.*s", left_size, left);
|
||||
|
||||
fmt = perf_evsel__syscall_arg_fmt(evsel, arg);
|
||||
if (fmt == NULL) {
|
||||
pr_debug("\"%s\" not found in \"%s\", can't set filter \"%s\"\n",
|
||||
arg, evsel->name, evsel->filter);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pr_debug2("trying to expand \"%s\" \"%.*s\" \"%.*s\" -> ",
|
||||
arg, (int)(right - tok), tok, right_size, right);
|
||||
|
||||
if (fmt->strtoul) {
|
||||
u64 val;
|
||||
if (fmt->strtoul(right, right_size, NULL, &val)) {
|
||||
char *n, expansion[19];
|
||||
int expansion_lenght = scnprintf(expansion, sizeof(expansion), "%#" PRIx64, val);
|
||||
int expansion_offset = right - new_filter;
|
||||
|
||||
pr_debug("%s", expansion);
|
||||
|
||||
if (asprintf(&n, "%.*s%s%s", expansion_offset, new_filter, expansion, right_end) < 0) {
|
||||
pr_debug(" out of memory!\n");
|
||||
free(new_filter);
|
||||
return -1;
|
||||
}
|
||||
if (new_filter != evsel->filter)
|
||||
free(new_filter);
|
||||
left = n + expansion_offset + expansion_lenght;
|
||||
new_filter = n;
|
||||
} else {
|
||||
pr_err("\"%.*s\" not found for \"%s\" in \"%s\", can't set filter \"%s\"\n",
|
||||
right_size, right, arg, evsel->name, evsel->filter);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
pr_err("No resolver (strtoul) for \"%s\" in \"%s\", can't set filter \"%s\"\n",
|
||||
arg, evsel->name, evsel->filter);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pr_debug("\n");
|
||||
} else {
|
||||
left = right_end;
|
||||
}
|
||||
}
|
||||
|
||||
if (new_filter != evsel->filter) {
|
||||
pr_debug("New filter for %s: %s\n", evsel->name, new_filter);
|
||||
perf_evsel__set_filter(evsel, new_filter);
|
||||
free(new_filter);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int trace__expand_filters(struct trace *trace, struct evsel **err_evsel)
|
||||
{
|
||||
struct evlist *evlist = trace->evlist;
|
||||
struct evsel *evsel;
|
||||
|
||||
evlist__for_each_entry(evlist, evsel) {
|
||||
if (evsel->filter == NULL)
|
||||
continue;
|
||||
|
||||
if (trace__expand_filter(trace, evsel)) {
|
||||
*err_evsel = evsel;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int trace__run(struct trace *trace, int argc, const char **argv)
|
||||
{
|
||||
struct evlist *evlist = trace->evlist;
|
||||
@ -3625,6 +3752,9 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
|
||||
*/
|
||||
trace->fd_path_disabled = !trace__syscall_enabled(trace, syscalltbl__id(trace->sctbl, "close"));
|
||||
|
||||
err = trace__expand_filters(trace, &evsel);
|
||||
if (err)
|
||||
goto out_delete_evlist;
|
||||
err = perf_evlist__apply_filters(evlist, &evsel);
|
||||
if (err < 0)
|
||||
goto out_error_apply_filters;
|
||||
|
Loading…
Reference in New Issue
Block a user