From 9955d0be161a9baa241ae7b98426a4c705cb21cb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 15 Jun 2016 15:48:08 -0300 Subject: perf annotate: Use pipe + fork instead of popen We will need to redirect the stderr as well, so open code popen as a starting point. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-k0zt9svg4bswiglem7ornts4@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index e9825fe825fd..2dd396a1f64b 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1134,8 +1134,10 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) char symfs_filename[PATH_MAX]; struct kcore_extract kce; bool delete_extract = false; + int stdout_fd[2]; int lineno = 0; int nline; + pid_t pid; if (filename) symbol__join_symfs(symfs_filename, filename); @@ -1258,9 +1260,32 @@ fallback: pr_debug("Executing: %s\n", command); - file = popen(command, "r"); + err = -1; + if (pipe(stdout_fd) < 0) { + pr_err("Failure creating the pipe to run %s\n", command); + goto out_remove_tmp; + } + + pid = fork(); + if (pid < 0) { + pr_err("Failure forking to run %s\n", command); + goto out_close_stdout; + } + + if (pid == 0) { + close(stdout_fd[0]); + dup2(stdout_fd[1], 1); + close(stdout_fd[1]); + execl("/bin/sh", "sh", "-c", command, NULL); + perror(command); + exit(-1); + } + + close(stdout_fd[1]); + + file = fdopen(stdout_fd[0], "r"); if (!file) { - pr_err("Failure running %s\n", command); + pr_err("Failure creating FILE stream for %s\n", command); /* * If we were using debug info should retry with * original binary. @@ -1286,9 +1311,11 @@ fallback: if (dso__is_kcore(dso)) delete_last_nop(sym); - pclose(file); - + fclose(file); + err = 0; out_remove_tmp: + close(stdout_fd[0]); + if (dso__needs_decompress(dso)) unlink(symfs_filename); out_free_filename: @@ -1297,6 +1324,10 @@ out_free_filename: if (free_filename) free(filename); return err; + +out_close_stdout: + close(stdout_fd[1]); + goto out_remove_tmp; } static void insert_source_line(struct rb_root *root, struct source_line *src_line) -- cgit v1.2.3 From 5cb725a9723aebb248106ff7f8c6c7253b24bbb1 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 29 Jul 2016 16:44:56 -0300 Subject: perf annotate: Rename symbol__annotate() to symbol__disassemble() This function will not annotate anything, it will just disassembly the given map->dso and symbol. It currently does this by parsing the output of 'objdump --disassemble', but this could conceivably be done using a library or an offshot of the kernel's instruction decoder (arch/x86/lib/inat.c), etc. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-2xpfl4bfnrd6x584b390qok7@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 2 +- tools/perf/ui/browsers/annotate.c | 2 +- tools/perf/ui/gtk/annotate.c | 2 +- tools/perf/util/annotate.c | 4 ++-- tools/perf/util/annotate.h | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index bd108683fcb8..823dbbbf82a9 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -128,7 +128,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) return err; } - err = symbol__annotate(sym, map, 0); + err = symbol__disassemble(sym, map, 0); if (err == 0) { out_assign: top->sym_filter_entry = he; diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 29dc6d20364e..f4d6a8a962af 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -1050,7 +1050,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, (nr_pcnt - 1); } - if (symbol__annotate(sym, map, sizeof_bdl) < 0) { + if (symbol__disassemble(sym, map, sizeof_bdl) < 0) { ui__error("%s", ui_helpline__last_msg); goto out_free_offsets; } diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c index 9c7ff8d31b27..35e4b9e28c8d 100644 --- a/tools/perf/ui/gtk/annotate.c +++ b/tools/perf/ui/gtk/annotate.c @@ -166,7 +166,7 @@ static int symbol__gtk_annotate(struct symbol *sym, struct map *map, if (map->dso->annotate_warned) return -1; - if (symbol__annotate(sym, map, 0) < 0) { + if (symbol__disassemble(sym, map, 0) < 0) { ui__error("%s", ui_helpline__current); return -1; } diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 2dd396a1f64b..4f47b6069197 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1123,7 +1123,7 @@ static void delete_last_nop(struct symbol *sym) } } -int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) +int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize) { struct dso *dso = map->dso; char *filename = dso__build_id_filename(dso, NULL, 0); @@ -1694,7 +1694,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, struct rb_root source_line = RB_ROOT; u64 len; - if (symbol__annotate(sym, map, 0) < 0) + if (symbol__disassemble(sym, map, 0) < 0) return -1; len = symbol__size(sym); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index a23084f54128..b0750d8bee1f 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -155,7 +155,7 @@ int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 addr); int symbol__alloc_hist(struct symbol *sym); void symbol__annotate_zero_histograms(struct symbol *sym); -int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); +int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize); int symbol__annotate_init(struct map *map, struct symbol *sym); int symbol__annotate_printf(struct symbol *sym, struct map *map, -- cgit v1.2.3 From ee51d851392e1fe3e8be30b3c5847f34da343424 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 29 Jul 2016 16:27:18 -0300 Subject: perf annotate: Introduce strerror for handling symbol__disassemble() errors We were just using pr_error() which makes it difficult for non stdio UIs to provide errors using its widgets, as they need to somehow catch what was passed to pr_error(). Fix it by introducing a __strerror() interface like the ones used elsewhere, for instance target__strerror(). This is just the initial step, more work will be done, but first some error handling bugs noticed while working on this need to be dealt with. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-dgd22zl2xg7x4vcnoa83jxfb@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 4 +++ tools/perf/ui/browsers/annotate.c | 9 ++++-- tools/perf/ui/gtk/annotate.c | 8 +++-- tools/perf/util/annotate.c | 68 ++++++++++++++++++++++++--------------- tools/perf/util/annotate.h | 20 ++++++++++++ 5 files changed, 78 insertions(+), 31 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 823dbbbf82a9..418ed94756d3 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -132,6 +132,10 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) if (err == 0) { out_assign: top->sym_filter_entry = he; + } else { + char msg[BUFSIZ]; + symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); + pr_err("Couldn't annotate %s: %s\n", sym->name, msg); } pthread_mutex_unlock(¬es->lock); diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index f4d6a8a962af..2e2d10022355 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -1026,7 +1026,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, .use_navkeypressed = true, }, }; - int ret = -1; + int ret = -1, err; int nr_pcnt = 1; size_t sizeof_bdl = sizeof(struct browser_disasm_line); @@ -1050,8 +1050,11 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, (nr_pcnt - 1); } - if (symbol__disassemble(sym, map, sizeof_bdl) < 0) { - ui__error("%s", ui_helpline__last_msg); + err = symbol__disassemble(sym, map, sizeof_bdl); + if (err) { + char msg[BUFSIZ]; + symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); + ui__error("Couldn't annotate %s:\n%s", sym->name, msg); goto out_free_offsets; } diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c index 35e4b9e28c8d..42d319927762 100644 --- a/tools/perf/ui/gtk/annotate.c +++ b/tools/perf/ui/gtk/annotate.c @@ -162,12 +162,16 @@ static int symbol__gtk_annotate(struct symbol *sym, struct map *map, GtkWidget *notebook; GtkWidget *scrolled_window; GtkWidget *tab_label; + int err; if (map->dso->annotate_warned) return -1; - if (symbol__disassemble(sym, map, 0) < 0) { - ui__error("%s", ui_helpline__current); + err = symbol__disassemble(sym, map, 0); + if (err) { + char msg[BUFSIZ]; + symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); + ui__error("Couldn't annotate %s: %s\n", sym->name, msg); return -1; } diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 4f47b6069197..4982ed487e96 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1123,6 +1123,45 @@ static void delete_last_nop(struct symbol *sym) } } +int symbol__strerror_disassemble(struct symbol *sym __maybe_unused, struct map *map, + int errnum, char *buf, size_t buflen) +{ + struct dso *dso = map->dso; + + BUG_ON(buflen == 0); + + if (errnum >= 0) { + str_error_r(errnum, buf, buflen); + return 0; + } + + switch (errnum) { + case SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX: { + char bf[SBUILD_ID_SIZE + 15] = " with build id "; + char *build_id_msg = NULL; + + if (dso->has_build_id) { + build_id__sprintf(dso->build_id, + sizeof(dso->build_id), bf + 15); + build_id_msg = bf; + } + scnprintf(buf, buflen, + "No vmlinux file%s\nwas found in the path.\n\n" + "Note that annotation using /proc/kcore requires CAP_SYS_RAWIO capability.\n\n" + "Please use:\n\n" + " perf buildid-cache -vu vmlinux\n\n" + "or:\n\n" + " --vmlinux vmlinux\n", build_id_msg ?: ""); + } + break; + default: + scnprintf(buf, buflen, "Internal error: Invalid %d error code\n", errnum); + break; + } + + return 0; +} + int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize) { struct dso *dso = map->dso; @@ -1143,11 +1182,8 @@ int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize) symbol__join_symfs(symfs_filename, filename); if (filename == NULL) { - if (dso->has_build_id) { - pr_err("Can't annotate %s: not enough memory\n", - sym->name); - return -ENOMEM; - } + if (dso->has_build_id) + return ENOMEM; goto fallback; } else if (dso__is_kcore(dso)) { goto fallback; @@ -1168,27 +1204,7 @@ fallback: if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && !dso__is_kcore(dso)) { - char bf[SBUILD_ID_SIZE + 15] = " with build id "; - char *build_id_msg = NULL; - - if (dso->annotate_warned) - goto out_free_filename; - - if (dso->has_build_id) { - build_id__sprintf(dso->build_id, - sizeof(dso->build_id), bf + 15); - build_id_msg = bf; - } - err = -ENOENT; - dso->annotate_warned = 1; - pr_err("Can't annotate %s:\n\n" - "No vmlinux file%s\nwas found in the path.\n\n" - "Note that annotation using /proc/kcore requires CAP_SYS_RAWIO capability.\n\n" - "Please use:\n\n" - " perf buildid-cache -vu vmlinux\n\n" - "or:\n\n" - " --vmlinux vmlinux\n", - sym->name, build_id_msg ?: ""); + err = SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX; goto out_free_filename; } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index b0750d8bee1f..f67ccb027561 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -157,6 +157,26 @@ void symbol__annotate_zero_histograms(struct symbol *sym); int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize); +enum symbol_disassemble_errno { + SYMBOL_ANNOTATE_ERRNO__SUCCESS = 0, + + /* + * Choose an arbitrary negative big number not to clash with standard + * errno since SUS requires the errno has distinct positive values. + * See 'Issue 6' in the link below. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html + */ + __SYMBOL_ANNOTATE_ERRNO__START = -10000, + + SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX = __SYMBOL_ANNOTATE_ERRNO__START, + + __SYMBOL_ANNOTATE_ERRNO__END, +}; + +int symbol__strerror_disassemble(struct symbol *sym, struct map *map, + int errnum, char *buf, size_t buflen); + int symbol__annotate_init(struct map *map, struct symbol *sym); int symbol__annotate_printf(struct symbol *sym, struct map *map, struct perf_evsel *evsel, bool full_paths, -- cgit v1.2.3 From c17c17e8c26a5d44b3a8a6ef8c55233d72eed6c0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 1 Aug 2016 18:49:13 -0300 Subject: perf annotate: Plug filename string leak If dso__build_id_filename(..., NULL, ...) returns !NULL its because it allocated it, so, when reaching the 'if (dso__is_kcore()) test, we already checked that and were just "fallbacking" to using dso->long_name, but without freeing filename, thus leaking it. Fix it by adding the dso__is_kcore() test to the 'or' group just after it, the one containing the full fallback code, including freeing the filename. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Fixes: ee205503f233 ("perf tools: Fix annotation with kcore") Link: http://lkml.kernel.org/n/tip-qi4rpjq8yo6myvg99kkgt0xz@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 4982ed487e96..4024d309bb00 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1185,9 +1185,8 @@ int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize) if (dso->has_build_id) return ENOMEM; goto fallback; - } else if (dso__is_kcore(dso)) { - goto fallback; - } else if (readlink(symfs_filename, command, sizeof(command)) < 0 || + } else if (dso__is_kcore(dso) || + readlink(symfs_filename, command, sizeof(command)) < 0 || strstr(command, DSO__NAME_KALLSYMS) || access(symfs_filename, R_OK)) { free(filename); -- cgit v1.2.3