From 4cae8675ea798b141ccdeea0a5b3f46a1e4605eb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 3 Jun 2019 16:52:46 -0300 Subject: perf augmented_raw_syscalls: Tell which args are filenames and how many bytes to copy Since we know what args are strings from reading the syscall descriptions in tracefs and also already mark such args to be beautified using the syscall_arg__scnprintf_filename() helper, all we need is to fill in this info in the 'syscalls' BPF map we were using to state which syscalls the user is interested in, i.e. the syscall filter. Right now just set that with PATH_MAX and unroll the syscall arg in the BPF program, as the verifier isn't liking something clang generates when unrolling the loop. This also makes the augmented_raw_syscalls.c program support all arches, since we removed that set of defines with the hard coded syscall numbers, all should be automatically set for all arches, with the syscall id mapping done correcly. Doing baby steps here, i.e. just the first string arg for a syscall is printed, syscalls with more than one, say, the various rename* syscalls, need further work, but lets get first something that the BPF verifier accepts before increasing the complexity To test it, something like: # perf trace -e string -e /home/acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.c With: # cat ~/.perfconfig [llvm] dump-obj = true clang-opt = -g [trace] #add_events = /home/acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.c show_zeros = yes show_duration = no no_inherit = yes show_timestamp = no show_arg_names = no args_alignment = 40 show_prefix = yes # That commented add_events line is needed for developing this augmented_raw_syscalls.c BPF program, as if we add it via the 'add_events' mechanism so as to shorten the 'perf trace' command lines, then we end up not setting up the -v option which precludes us having access to the bpf verifier log :-\ Cc: Adrian Hunter Cc: Alexei Starovoitov Cc: Andrii Nakryiko Cc: Daniel Borkmann Cc: Jesper Dangaard Brouer Cc: Jiri Olsa Cc: Leo Yan Cc: Namhyung Kim Cc: Song Liu Cc: Yonghong Song Link: https://lkml.kernel.org/n/tip-dn863ya0cbsqycxuy0olvbt1@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'tools/perf/builtin-trace.c') diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 54b2d0fd0d02..19f22127f02e 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -972,8 +972,14 @@ struct syscall { struct syscall_arg_fmt *arg_fmt; }; +/* + * Must match what is in the BPF program: + * + * tools/perf/examples/bpf/augmented_raw_syscalls.c + */ struct bpf_map_syscall_entry { bool enabled; + u16 string_args_len[6]; }; /* @@ -2711,6 +2717,25 @@ out_enomem: } #ifdef HAVE_LIBBPF_SUPPORT +static void trace__init_bpf_map_syscall_args(struct trace *trace, int id, struct bpf_map_syscall_entry *entry) +{ + struct syscall *sc = trace__syscall_info(trace, NULL, id); + int arg = 0; + + if (sc == NULL) + goto out; + + for (; arg < sc->nr_args; ++arg) { + entry->string_args_len[arg] = 0; + if (sc->arg_fmt[arg].scnprintf == SCA_FILENAME) { + /* Should be set like strace -s strsize */ + entry->string_args_len[arg] = PATH_MAX; + } + } +out: + for (; arg < 6; ++arg) + entry->string_args_len[arg] = 0; +} static int trace__set_ev_qualifier_bpf_filter(struct trace *trace) { int fd = bpf_map__fd(trace->syscalls.map); @@ -2723,6 +2748,9 @@ static int trace__set_ev_qualifier_bpf_filter(struct trace *trace) for (i = 0; i < trace->ev_qualifier_ids.nr; ++i) { int key = trace->ev_qualifier_ids.entries[i]; + if (value.enabled) + trace__init_bpf_map_syscall_args(trace, key, &value); + err = bpf_map_update_elem(fd, &key, &value, BPF_EXIST); if (err) break; @@ -2740,6 +2768,9 @@ static int __trace__init_syscalls_bpf_map(struct trace *trace, bool enabled) int err = 0, key; for (key = 0; key < trace->sctbl->syscalls.nr_entries; ++key) { + if (enabled) + trace__init_bpf_map_syscall_args(trace, key, &value); + err = bpf_map_update_elem(fd, &key, &value, BPF_ANY); if (err) break; -- cgit v1.2.3 From 8195168e877948bb9a943ce11ad3e6ee71014bd5 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 5 Jun 2019 10:34:47 -0300 Subject: perf trace: Consume the augmented_raw_syscalls payload MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To support the SCA_FILENAME beautifier in more than one syscall arg, as needed for syscalls such as the rename* family, we need to, after processing one such arg, bump the augmented pointers so that the next augmented arg don't reuse data for the previous augmented arguments. Cc: Adrian Hunter Cc: Brendan Gregg Cc: Jiri Olsa Cc: Luis Cláudio Gonçalves Cc: Namhyung Kim Link: https://lkml.kernel.org/n/tip-4e4cmzyjxb3wkonfo1x9a27y@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'tools/perf/builtin-trace.c') diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 19f22127f02e..905e57c336b0 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -1233,8 +1233,17 @@ static void thread__set_filename_pos(struct thread *thread, const char *bf, static size_t syscall_arg__scnprintf_augmented_string(struct syscall_arg *arg, char *bf, size_t size) { struct augmented_arg *augmented_arg = arg->augmented.args; + size_t printed = scnprintf(bf, size, "\"%.*s\"", augmented_arg->size, augmented_arg->value); + /* + * So that the next arg with a payload can consume its augmented arg, i.e. for rename* syscalls + * we would have two strings, each prefixed by its size. + */ + int consumed = sizeof(*augmented_arg) + augmented_arg->size; - return scnprintf(bf, size, "\"%.*s\"", augmented_arg->size, augmented_arg->value); + arg->augmented.args += consumed; + arg->augmented.size -= consumed; + + return printed; } static size_t syscall_arg__scnprintf_filename(char *bf, size_t size, -- cgit v1.2.3 From dea87bfb7b280e8b14519eb6b5e8bafbbf4c66f2 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 5 Jun 2019 10:53:06 -0300 Subject: perf trace: Associate more argument names with the filename beautifier For instance, the rename* family uses "oldname", "newname", so check if "name" is at the end and treat it as a filename. Cc: Adrian Hunter Cc: Jiri Olsa Cc: Namhyung Kim Link: https://lkml.kernel.org/n/tip-wjy7j4bk06g7atzwoz1mid24@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'tools/perf/builtin-trace.c') diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 905e57c336b0..f7e4e50bddbd 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -1431,10 +1431,11 @@ static int syscall__set_arg_fmts(struct syscall *sc) if (sc->fmt && sc->fmt->arg[idx].scnprintf) continue; + len = strlen(field->name); + if (strcmp(field->type, "const char *") == 0 && - (strcmp(field->name, "filename") == 0 || - strcmp(field->name, "path") == 0 || - strcmp(field->name, "pathname") == 0)) + ((len >= 4 && strcmp(field->name + len - 4, "name") == 0) || + strstr(field->name, "path") != NULL)) sc->arg_fmt[idx].scnprintf = SCA_FILENAME; else if ((field->flags & TEP_FIELD_IS_POINTER) || strstr(field->name, "addr")) sc->arg_fmt[idx].scnprintf = SCA_PTR; @@ -1445,8 +1446,7 @@ static int syscall__set_arg_fmts(struct syscall *sc) else if ((strcmp(field->type, "int") == 0 || strcmp(field->type, "unsigned int") == 0 || strcmp(field->type, "long") == 0) && - (len = strlen(field->name)) >= 2 && - strcmp(field->name + len - 2, "fd") == 0) { + len >= 2 && strcmp(field->name + len - 2, "fd") == 0) { /* * /sys/kernel/tracing/events/syscalls/sys_enter* * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c -- cgit v1.2.3 From 012749caf9419f22636891259b664c6dd383e897 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Thu, 6 Jun 2019 10:38:59 -0300 Subject: perf trace: Exit when failing to build eBPF program On my Juno board with ARM64 CPUs, perf trace command reports the eBPF program building failure but the command will not exit and continue to run. If we define an eBPF event in config file, the event will be parsed with below flow: perf_config() `> trace__config() `> parse_events_option() `> parse_events__scanner() `-> parse_events_parse() `> parse_events_load_bpf() `> llvm__compile_bpf() Though the low level functions return back error values when detect eBPF building failure, but parse_events_option() returns 1 for this case and trace__config() passes 1 to perf_config(); perf_config() doesn't treat the returned value 1 as failure and it continues to parse other configurations. Thus the perf command continues to run even without enabling eBPF event successfully. This patch changes error handling in trace__config(), when it detects failure it will return -1 rather than directly pass error value (1); finally, perf_config() will directly bail out and perf will exit for this case. Committer notes: Simplified the patch to just check directly the return of parse_events_option() and it it is non-zero, change err from its initial zero value to -1. Signed-off-by: Leo Yan Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexei Starovoitov Cc: Daniel Borkmann Cc: Jiri Olsa Cc: Martin KaFai Lau Cc: Mathieu Poirier Cc: Mike Leach Cc: Namhyung Kim Cc: Song Liu Cc: Suzuki Poulouse Cc: Yonghong Song Fixes: ac96287cae08 ("perf trace: Allow specifying a set of events to add in perfconfig") Link: https://lkml.kernel.org/n/tip-x4i63f5kscykfok0hqim3zma@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'tools/perf/builtin-trace.c') diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index f7e4e50bddbd..1a2a605cf068 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -3703,7 +3703,12 @@ static int trace__config(const char *var, const char *value, void *arg) struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event", "event selector. use 'perf list' to list available events", parse_events_option); - err = parse_events_option(&o, value, 0); + /* + * We can't propagate parse_event_option() return, as it is 1 + * for failure while perf_config() expects -1. + */ + if (parse_events_option(&o, value, 0)) + err = -1; } else if (!strcmp(var, "trace.show_timestamp")) { trace->show_tstamp = perf_config_bool(var, value); } else if (!strcmp(var, "trace.show_duration")) { -- cgit v1.2.3 From 04c41bcb862bbec1fb225243ecf07a3219593f81 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 10 Jun 2019 15:37:45 -0300 Subject: perf trace: Skip unknown syscalls when expanding strace like syscall groups We have $INSTALL_DIR/share/perf-core/strace/groups/string files with syscalls that should be selected when 'string' is used, meaning, in this case, syscalls that receive as one of its arguments a string, like a pathname. But those were first selected and tested on x86_64, and end up failing in architectures where some of those syscalls are not available, like the 'access' syscall on arm64, which makes using 'perf trace -e string' in such archs to fail. Since this the routine doing the validation is used only when reading such files, do not fail when some syscall is not found in the syscalltbl, instead just use pr_debug() to register that in case people are suspicious of problems. Now using 'perf trace -e string' should work on arm64, selecting only the syscalls that have a string and are available on that architecture. Reported-by: Leo Yan Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Alexei Starovoitov Cc: Daniel Borkmann Cc: Jiri Olsa Cc: Martin KaFai Lau Cc: Mathieu Poirier Cc: Mike Leach Cc: Namhyung Kim Cc: Song Liu Cc: Suzuki K Poulose Cc: Yonghong Song Link: https://lkml.kernel.org/r/20190610184754.GU21245@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'tools/perf/builtin-trace.c') diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 1a2a605cf068..eb70a4b71755 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -1529,6 +1529,7 @@ static int trace__read_syscall_info(struct trace *trace, int id) static int trace__validate_ev_qualifier(struct trace *trace) { int err = 0, i; + bool printed_invalid_prefix = false; size_t nr_allocated; struct str_node *pos; @@ -1555,14 +1556,15 @@ static int trace__validate_ev_qualifier(struct trace *trace) if (id >= 0) goto matches; - if (err == 0) { - fputs("Error:\tInvalid syscall ", trace->output); - err = -EINVAL; + if (!printed_invalid_prefix) { + pr_debug("Skipping unknown syscalls: "); + printed_invalid_prefix = true; } else { - fputs(", ", trace->output); + pr_debug(", "); } - fputs(sc, trace->output); + pr_debug("%s", sc); + continue; } matches: trace->ev_qualifier_ids.entries[i++] = id; @@ -1591,15 +1593,14 @@ matches: } } - if (err < 0) { - fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'" - "\nHint:\tand: 'man syscalls'\n", trace->output); -out_free: - zfree(&trace->ev_qualifier_ids.entries); - trace->ev_qualifier_ids.nr = 0; - } out: + if (printed_invalid_prefix) + pr_debug("\n"); return err; +out_free: + zfree(&trace->ev_qualifier_ids.entries); + trace->ev_qualifier_ids.nr = 0; + goto out; } /* -- cgit v1.2.3