diff options
Diffstat (limited to '')
-rw-r--r-- | tools/perf/util/probe-file.c | 148 |
1 files changed, 112 insertions, 36 deletions
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index 064b63a6a3f3..3d50de3217d5 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -22,6 +22,7 @@ #include "symbol.h" #include "strbuf.h" #include <api/fs/tracing_path.h> +#include <api/fs/fs.h> #include "probe-event.h" #include "probe-file.h" #include "session.h" @@ -31,44 +32,78 @@ /* 4096 - 2 ('\n' + '\0') */ #define MAX_CMDLEN 4094 -static void print_open_warning(int err, bool uprobe) +static bool print_common_warning(int err, bool readwrite) { - char sbuf[STRERR_BUFSIZE]; + if (err == -EACCES) + pr_warning("No permission to %s tracefs.\nPlease %s\n", + readwrite ? "write" : "read", + readwrite ? "run this command again with sudo." : + "try 'sudo mount -o remount,mode=755 /sys/kernel/tracing/'"); + else + return false; - if (err == -ENOENT) { - const char *config; + return true; +} - if (uprobe) - config = "CONFIG_UPROBE_EVENTS"; - else - config = "CONFIG_KPROBE_EVENTS"; +static bool print_configure_probe_event(int kerr, int uerr) +{ + const char *config, *file; + + if (kerr == -ENOENT && uerr == -ENOENT) { + file = "{k,u}probe_events"; + config = "CONFIG_KPROBE_EVENTS=y and CONFIG_UPROBE_EVENTS=y"; + } else if (kerr == -ENOENT) { + file = "kprobe_events"; + config = "CONFIG_KPROBE_EVENTS=y"; + } else if (uerr == -ENOENT) { + file = "uprobe_events"; + config = "CONFIG_UPROBE_EVENTS=y"; + } else + return false; - pr_warning("%cprobe_events file does not exist" - " - please rebuild kernel with %s.\n", - uprobe ? 'u' : 'k', config); - } else if (err == -ENOTSUP) - pr_warning("Tracefs or debugfs is not mounted.\n"); + 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("Failed to open %cprobe_events: %s\n", - uprobe ? 'u' : 'k', - str_error_r(-err, sbuf, sizeof(sbuf))); + pr_warning("%s/%s does not exist.\nPlease rebuild kernel with %s.\n", + tracing_path_mount(), file, config); + + return true; } -static void print_both_open_warning(int kerr, int uerr) +static void print_open_warning(int err, bool uprobe, bool readwrite) { - /* Both kprobes and uprobes are disabled, warn it. */ - if (kerr == -ENOTSUP && uerr == -ENOTSUP) - pr_warning("Tracefs or debugfs is not mounted.\n"); - else if (kerr == -ENOENT && uerr == -ENOENT) - pr_warning("Please rebuild kernel with CONFIG_KPROBE_EVENTS " - "or/and CONFIG_UPROBE_EVENTS.\n"); - else { - char sbuf[STRERR_BUFSIZE]; - pr_warning("Failed to open kprobe events: %s.\n", + char sbuf[STRERR_BUFSIZE]; + + if (print_common_warning(err, readwrite)) + return; + + if (print_configure_probe_event(uprobe ? 0 : err, uprobe ? err : 0)) + return; + + pr_warning("Failed to open %s/%cprobe_events: %s\n", + tracing_path_mount(), uprobe ? 'u' : 'k', + str_error_r(-err, sbuf, sizeof(sbuf))); +} + +static void 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))); - pr_warning("Failed to open uprobe events: %s.\n", + 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(const char *trace_file, bool readwrite) @@ -109,7 +144,7 @@ int probe_file__open(int flag) else fd = open_kprobe_events(flag & PF_FL_RW); if (fd < 0) - print_open_warning(fd, flag & PF_FL_UPROBE); + print_open_warning(fd, flag & PF_FL_UPROBE, flag & PF_FL_RW); return fd; } @@ -122,7 +157,7 @@ int probe_file__open_both(int *kfd, int *ufd, int flag) *kfd = open_kprobe_events(flag & PF_FL_RW); *ufd = open_uprobe_events(flag & PF_FL_RW); if (*kfd < 0 && *ufd < 0) { - print_both_open_warning(*kfd, *ufd); + print_both_open_warning(*kfd, *ufd, flag & PF_FL_RW); return *kfd; } @@ -342,11 +377,11 @@ int probe_file__del_events(int fd, struct strfilter *filter) ret = probe_file__get_events(fd, filter, namelist); if (ret < 0) - return ret; + goto out; ret = probe_file__del_strlist(fd, namelist); +out: strlist__delete(namelist); - return ret; } @@ -791,9 +826,11 @@ static char *synthesize_sdt_probe_command(struct sdt_note *note, const char *sdtgrp) { struct strbuf buf; - char *ret = NULL, **args; + char *ret = NULL; int i, args_count, err; unsigned long long ref_ctr_offset; + char *arg; + int arg_idx = 0; if (strbuf_init(&buf, 32) < 0) return NULL; @@ -813,12 +850,51 @@ static char *synthesize_sdt_probe_command(struct sdt_note *note, goto out; if (note->args) { - args = argv_split(note->args, &args_count); + char **args = argv_split(note->args, &args_count); - for (i = 0; i < args_count; ++i) { - if (synthesize_sdt_probe_arg(&buf, i, args[i]) < 0) + 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; + } + + if (synthesize_sdt_probe_arg(&buf, arg_idx, arg) < 0) { + free(arg); + argv_free(args); goto error; + } + + free(arg); + arg_idx++; } + + argv_free(args); } out: |