diff options
Diffstat (limited to 'tools/perf/builtin-trace.c')
-rw-r--r-- | tools/perf/builtin-trace.c | 84 |
1 files changed, 65 insertions, 19 deletions
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index ff17c4a1b7f8f..12f5ad98f8c1c 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -971,8 +971,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]; }; /* @@ -1226,8 +1232,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; + + arg->augmented.args += consumed; + arg->augmented.size -= consumed; - return scnprintf(bf, size, "\"%.*s\"", augmented_arg->size, augmented_arg->value); + return printed; } static size_t syscall_arg__scnprintf_filename(char *bf, size_t size, @@ -1415,10 +1430,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; @@ -1429,8 +1445,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 @@ -1513,6 +1528,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; @@ -1539,14 +1555,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; @@ -1575,15 +1592,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; } /* @@ -2710,6 +2726,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); @@ -2722,6 +2757,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; @@ -2739,6 +2777,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; @@ -3662,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")) { |