perf srcline: Add a timeout to reading from addr2line
authorIan Rogers <irogers@google.com>
Thu, 8 Jun 2023 06:18:12 +0000 (23:18 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Wed, 14 Jun 2023 21:19:06 +0000 (18:19 -0300)
addr2line may fail to send expected values causing perf to wait
indefinitely. Add a 1 second timeout (twice the timeout for reading from
/proc/pid/maps) so that such reads don't cause perf to appear to lock
up.

There are already checks that the file for addr2line contains a debug
section but this isn't always sufficient. The problem was observed when
a valid elf file would set the configuration for binutils addr2line,
then a later read of vmlinux with ELF debug sections would cause a
failing write/read which would block indefinitely.

As a service to future readers, if the io hits eof or an error, cleanup
the addr2line process.

Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Yang Jihong <yangjihong1@huawei.com>
Link: https://lore.kernel.org/r/20230608061812.3715566-2-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/config.c
tools/perf/util/srcline.c
tools/perf/util/srcline.h

index f340dc7..46f144c 100644 (file)
@@ -19,6 +19,7 @@
 #include "util/llvm-utils.h"   /* perf_llvm_config */
 #include "util/stat.h"  /* perf_stat__set_big_num */
 #include "util/evsel.h"  /* evsel__hw_names, evsel__use_bpf_counters */
+#include "util/srcline.h"  /* addr2line_timeout_ms */
 #include "build-id.h"
 #include "debug.h"
 #include "config.h"
@@ -434,12 +435,14 @@ static int perf_buildid_config(const char *var, const char *value)
        return 0;
 }
 
-static int perf_default_core_config(const char *var __maybe_unused,
-                                   const char *value __maybe_unused)
+static int perf_default_core_config(const char *var, const char *value)
 {
        if (!strcmp(var, "core.proc-map-timeout"))
                proc_map_timeout = strtoul(value, NULL, 10);
 
+       if (!strcmp(var, "core.addr2line-timeout"))
+               addr2line_timeout_ms = strtoul(value, NULL, 10);
+
        /* Add other config variables here. */
        return 0;
 }
index b27b4b3..c013bcb 100644 (file)
@@ -21,6 +21,8 @@
 #include "symbol.h"
 #include "subcmd/run-command.h"
 
+/* If addr2line doesn't return data for 1 second then timeout. */
+int addr2line_timeout_ms = 1 * 1000;
 bool srcline_full_filename;
 
 char *srcline__unknown = (char *)"??:0";
@@ -631,7 +633,7 @@ static int addr2line(const char *dso_name, u64 addr,
        int len;
        char buf[128];
        ssize_t written;
-       struct io io;
+       struct io io = { .eof = false };
        enum a2l_style a2l_style;
 
        if (!a2l) {
@@ -670,7 +672,7 @@ static int addr2line(const char *dso_name, u64 addr,
                goto out;
        }
        io__init(&io, a2l->out, buf, sizeof(buf));
-
+       io.timeout_ms = addr2line_timeout_ms;
        switch (read_addr2line_record(&io, a2l_style,
                                      &record_function, &record_filename, &record_line_nr)) {
        case -1:
@@ -741,6 +743,10 @@ static int addr2line(const char *dso_name, u64 addr,
 out:
        free(record_function);
        free(record_filename);
+       if (io.eof) {
+               dso->a2l = NULL;
+               addr2line_subprocess_cleanup(a2l);
+       }
        return ret;
 }
 
index 167645b..75010d3 100644 (file)
@@ -9,6 +9,7 @@
 struct dso;
 struct symbol;
 
+extern int addr2line_timeout_ms;
 extern bool srcline_full_filename;
 char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
                  bool show_sym, bool show_addr, u64 ip);