]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
perf libbfd: Ensure libbfd is initialized prior to use
authorIan Rogers <irogers@google.com>
Wed, 12 Nov 2025 07:43:11 +0000 (23:43 -0800)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 13 Nov 2025 20:55:19 +0000 (17:55 -0300)
Multiple threads may be creating and destroying BFD objects in
situations like `perf top`.

Without appropriate initialization crashes may occur during libbfd's
cache management.

BFD's locks require recursive mutexes, add support for these.

Committer testing:

This happens only when building with 'make BUILD_NONDISTRO=1' and having
the binutils-devel package (or equivalent) installed, i.e. linking with
binutils devel files, an opt-in perf build.

Before:

  root@x1:~# perf top
  perf: Segmentation fault
  -------- backtrace --------
  <SNIP multiple failed attempts at printing a backtrace>
  root@x1:~#

After this patch it works as before.

Closes: https://lore.kernel.org/lkml/aQt66zhfxSA80xwt@gentoo.org/
Fixes: 95931d9a594dd0b5 ("perf libbfd: Move libbfd functionality to its own file")
Reported-by: Guilherme Amadio <amadio@gentoo.org>
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.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: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/libbfd.c
tools/perf/util/mutex.c
tools/perf/util/mutex.h

index 01147fbf73b37638de32a4ed44b64a5dce99d051..6434c2dccd4a461b6ea89ff3bdd035563226797b 100644 (file)
@@ -38,6 +38,39 @@ struct a2l_data {
        asymbol **syms;
 };
 
+static bool perf_bfd_lock(void *bfd_mutex)
+{
+       mutex_lock(bfd_mutex);
+       return true;
+}
+
+static bool perf_bfd_unlock(void *bfd_mutex)
+{
+       mutex_unlock(bfd_mutex);
+       return true;
+}
+
+static void perf_bfd_init(void)
+{
+       static struct mutex bfd_mutex;
+
+       mutex_init_recursive(&bfd_mutex);
+
+       if (bfd_init() != BFD_INIT_MAGIC) {
+               pr_err("Error initializing libbfd\n");
+               return;
+       }
+       if (!bfd_thread_init(perf_bfd_lock, perf_bfd_unlock, &bfd_mutex))
+               pr_err("Error initializing libbfd threading\n");
+}
+
+static void ensure_bfd_init(void)
+{
+       static pthread_once_t bfd_init_once = PTHREAD_ONCE_INIT;
+
+       pthread_once(&bfd_init_once, perf_bfd_init);
+}
+
 static int bfd_error(const char *string)
 {
        const char *errmsg;
@@ -132,6 +165,7 @@ static struct a2l_data *addr2line_init(const char *path)
        bfd *abfd;
        struct a2l_data *a2l = NULL;
 
+       ensure_bfd_init();
        abfd = bfd_openr(path, NULL);
        if (abfd == NULL)
                return NULL;
@@ -288,6 +322,7 @@ int dso__load_bfd_symbols(struct dso *dso, const char *debugfile)
        bfd *abfd;
        u64 start, len;
 
+       ensure_bfd_init();
        abfd = bfd_openr(debugfile, NULL);
        if (!abfd)
                return -1;
@@ -393,6 +428,7 @@ int libbfd__read_build_id(const char *filename, struct build_id *bid, bool block
        if (fd < 0)
                return -1;
 
+       ensure_bfd_init();
        abfd = bfd_fdopenr(filename, /*target=*/NULL, fd);
        if (!abfd)
                return -1;
@@ -421,6 +457,7 @@ int libbfd_filename__read_debuglink(const char *filename, char *debuglink,
        asection *section;
        bfd *abfd;
 
+       ensure_bfd_init();
        abfd = bfd_openr(filename, NULL);
        if (!abfd)
                return -1;
@@ -480,6 +517,7 @@ int symbol__disassemble_bpf_libbfd(struct symbol *sym __maybe_unused,
        memset(tpath, 0, sizeof(tpath));
        perf_exe(tpath, sizeof(tpath));
 
+       ensure_bfd_init();
        bfdf = bfd_openr(tpath, NULL);
        if (bfdf == NULL)
                abort();
index bca7f0717f355e16ade273a16c2620a4254957c7..7aa1f3f55a7d4089e257472776b7c119c7c48aee 100644 (file)
@@ -17,7 +17,7 @@ static void check_err(const char *fn, int err)
 
 #define CHECK_ERR(err) check_err(__func__, err)
 
-static void __mutex_init(struct mutex *mtx, bool pshared)
+static void __mutex_init(struct mutex *mtx, bool pshared, bool recursive)
 {
        pthread_mutexattr_t attr;
 
@@ -27,21 +27,27 @@ static void __mutex_init(struct mutex *mtx, bool pshared)
        /* In normal builds enable error checking, such as recursive usage. */
        CHECK_ERR(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK));
 #endif
+       if (recursive)
+               CHECK_ERR(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE));
        if (pshared)
                CHECK_ERR(pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED));
-
        CHECK_ERR(pthread_mutex_init(&mtx->lock, &attr));
        CHECK_ERR(pthread_mutexattr_destroy(&attr));
 }
 
 void mutex_init(struct mutex *mtx)
 {
-       __mutex_init(mtx, /*pshared=*/false);
+       __mutex_init(mtx, /*pshared=*/false, /*recursive=*/false);
 }
 
 void mutex_init_pshared(struct mutex *mtx)
 {
-       __mutex_init(mtx, /*pshared=*/true);
+       __mutex_init(mtx, /*pshared=*/true, /*recursive=*/false);
+}
+
+void mutex_init_recursive(struct mutex *mtx)
+{
+       __mutex_init(mtx, /*pshared=*/false, /*recursive=*/true);
 }
 
 void mutex_destroy(struct mutex *mtx)
index 38458f00846fed45b8d00f371f54aadf91622c40..70232d8d094f8bfc8166c9e5c025c31ea76d36d2 100644 (file)
@@ -104,6 +104,8 @@ void mutex_init(struct mutex *mtx);
  * process-private attribute.
  */
 void mutex_init_pshared(struct mutex *mtx);
+/* Initializes a mutex that may be recursively held on the same thread. */
+void mutex_init_recursive(struct mutex *mtx);
 void mutex_destroy(struct mutex *mtx);
 
 void mutex_lock(struct mutex *mtx) EXCLUSIVE_LOCK_FUNCTION(*mtx);