* [PATCH v2] perf libbfd: Ensure libbfd is initialized prior to use
@ 2025-11-12 7:43 Ian Rogers
2025-11-13 17:03 ` Ian Rogers
0 siblings, 1 reply; 6+ messages in thread
From: Ian Rogers @ 2025-11-12 7:43 UTC (permalink / raw)
To: Guilherme Amadio, Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Namhyung Kim, Alexander Shishkin,
Jiri Olsa, Ian Rogers, Adrian Hunter, linux-perf-users,
linux-kernel
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.
Reported-by: Guilherme Amadio <amadio@gentoo.org>
Closes: https://lore.kernel.org/lkml/aQt66zhfxSA80xwt@gentoo.org/
Fixes: 95931d9a594d ("perf libbfd: Move libbfd functionality to its own file")
Signed-off-by: Ian Rogers <irogers@google.com>
---
v2: Remove unneeded unistd.h include.
---
tools/perf/util/libbfd.c | 38 ++++++++++++++++++++++++++++++++++++++
tools/perf/util/mutex.c | 14 ++++++++++----
tools/perf/util/mutex.h | 2 ++
3 files changed, 50 insertions(+), 4 deletions(-)
diff --git a/tools/perf/util/libbfd.c b/tools/perf/util/libbfd.c
index 01147fbf73b3..6434c2dccd4a 100644
--- a/tools/perf/util/libbfd.c
+++ b/tools/perf/util/libbfd.c
@@ -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();
diff --git a/tools/perf/util/mutex.c b/tools/perf/util/mutex.c
index bca7f0717f35..7aa1f3f55a7d 100644
--- a/tools/perf/util/mutex.c
+++ b/tools/perf/util/mutex.c
@@ -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)
diff --git a/tools/perf/util/mutex.h b/tools/perf/util/mutex.h
index 38458f00846f..70232d8d094f 100644
--- a/tools/perf/util/mutex.h
+++ b/tools/perf/util/mutex.h
@@ -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);
--
2.51.2.1041.gc1ab5b90ca-goog
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH v2] perf libbfd: Ensure libbfd is initialized prior to use 2025-11-12 7:43 [PATCH v2] perf libbfd: Ensure libbfd is initialized prior to use Ian Rogers @ 2025-11-13 17:03 ` Ian Rogers 2025-11-13 20:25 ` Guilherme Amadio ` (2 more replies) 0 siblings, 3 replies; 6+ messages in thread From: Ian Rogers @ 2025-11-13 17:03 UTC (permalink / raw) To: Guilherme Amadio, Arnaldo Carvalho de Melo, Namhyung Kim Cc: Alexander Shishkin, Jiri Olsa, Adrian Hunter, linux-perf-users, Ingo Molnar, linux-kernel, Peter Zijlstra On Tue, Nov 11, 2025 at 11:43 PM Ian Rogers <irogers@google.com> wrote: > > 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. > > Reported-by: Guilherme Amadio <amadio@gentoo.org> > Closes: https://lore.kernel.org/lkml/aQt66zhfxSA80xwt@gentoo.org/ > Fixes: 95931d9a594d ("perf libbfd: Move libbfd functionality to its own file") > Signed-off-by: Ian Rogers <irogers@google.com> I'm hoping adding the missing initialization is just obviously correct, Guilherme if you could provide a Tested-by it would be great. Thanks, Ian > --- > v2: Remove unneeded unistd.h include. > --- > tools/perf/util/libbfd.c | 38 ++++++++++++++++++++++++++++++++++++++ > tools/perf/util/mutex.c | 14 ++++++++++---- > tools/perf/util/mutex.h | 2 ++ > 3 files changed, 50 insertions(+), 4 deletions(-) > > diff --git a/tools/perf/util/libbfd.c b/tools/perf/util/libbfd.c > index 01147fbf73b3..6434c2dccd4a 100644 > --- a/tools/perf/util/libbfd.c > +++ b/tools/perf/util/libbfd.c > @@ -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(); > diff --git a/tools/perf/util/mutex.c b/tools/perf/util/mutex.c > index bca7f0717f35..7aa1f3f55a7d 100644 > --- a/tools/perf/util/mutex.c > +++ b/tools/perf/util/mutex.c > @@ -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) > diff --git a/tools/perf/util/mutex.h b/tools/perf/util/mutex.h > index 38458f00846f..70232d8d094f 100644 > --- a/tools/perf/util/mutex.h > +++ b/tools/perf/util/mutex.h > @@ -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); > -- > 2.51.2.1041.gc1ab5b90ca-goog > ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] perf libbfd: Ensure libbfd is initialized prior to use 2025-11-13 17:03 ` Ian Rogers @ 2025-11-13 20:25 ` Guilherme Amadio 2025-11-13 20:42 ` Ian Rogers 2025-11-13 20:31 ` Arnaldo Carvalho de Melo 2025-11-13 20:42 ` Arnaldo Carvalho de Melo 2 siblings, 1 reply; 6+ messages in thread From: Guilherme Amadio @ 2025-11-13 20:25 UTC (permalink / raw) To: Ian Rogers Cc: Arnaldo Carvalho de Melo, Namhyung Kim, Alexander Shishkin, Jiri Olsa, Adrian Hunter, linux-perf-users, Ingo Molnar, linux-kernel, Peter Zijlstra Dear Ian, On Thu, Nov 13, 2025 at 09:03:42AM -0800, Ian Rogers wrote: > On Tue, Nov 11, 2025 at 11:43 PM Ian Rogers <irogers@google.com> wrote: > > > > 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. > > > > Reported-by: Guilherme Amadio <amadio@gentoo.org> > > Closes: https://lore.kernel.org/lkml/aQt66zhfxSA80xwt@gentoo.org/ > > Fixes: 95931d9a594d ("perf libbfd: Move libbfd functionality to its own file") > > Signed-off-by: Ian Rogers <irogers@google.com> > > I'm hoping adding the missing initialization is just obviously > correct, Guilherme if you could provide a Tested-by it would be great. Apologies for the hiatus, just been quite busy at work, but following the emails. Thank you very much for providing a fix, I tried to apply it on perf-tools-next, and perf-tools, but got the build error below (both before and after applying the patch): gentoo linux $ git describe && make -B -C tools/perf -f Makefile.perf BUILD_BPF_SKEL=1 BUILD_NONDISTRO=1 WERROR=0 NO_SHELLCHECK=1 NO_CAPSTONE=1 DEBUG=1 2>&1 | tail -n 20 v6.18-rc4-182-gda32d155f4a8 CC util/perf_event_attr_fprintf.o CC util/evswitch.o CC util/find_bit.o CC util/levenshtein.o CC util/libbfd.o In file included from /usr/include/bfd.h:10, from /usr/include/dis-asm.h:36, from /home/amadio/src/linux/tools/include/tools/dis-asm-compat.h:6, from util/libbfd.c:14: /usr/include/x86_64-pc-linux-gnu/bfd.h:35:2: error: #error config.h must be included before this header 35 | #error config.h must be included before this header | ^~~~~ make[3]: *** [/home/amadio/src/linux/tools/build/Makefile.build:86: util/libbfd.o] Error 1 make[3]: Leaving directory '/home/amadio/src/linux/tools/perf' make[2]: *** [/home/amadio/src/linux/tools/build/Makefile.build:142: util] Error 2 make[2]: Leaving directory '/home/amadio/src/linux/tools/perf' make[1]: *** [Makefile.perf:797: perf-util-in.o] Error 2 make[1]: Leaving directory '/home/amadio/src/linux/tools/perf' make: *** [Makefile.perf:289: sub-make] Error 2 make: Leaving directory '/home/amadio/src/linux/tools/perf' The header in /usr/include/x86_64-pc-linux-gnu/bfd.h:35 has this, right after the include guards: /* PR 14072: Ensure that config.h is included first. */ #if !defined PACKAGE && !defined PACKAGE_VERSION #error config.h must be included before this header #endif However, I did try a build with BUILD_NONDISTRO disabled and it works, so I'm tempted to change things in Gentoo to have it always disabled or offer libbfd support with a USE-flag but keep it off by default. I bisected the build failure to the same commit you added in the Fixes tag: 95931d9a594dd0b5f2191a6a6340549b8f3b031b is the first bad commit commit 95931d9a594dd0b5f2191a6a6340549b8f3b031b Author: Ian Rogers <irogers@google.com> Date: Mon Sep 29 12:07:54 2025 -0700 perf libbfd: Move libbfd functionality to its own file This is the version of binutils-libs I have, in case it's useful: gentoo linux $ qfile /usr/include/x86_64-pc-linux-gnu/bfd.h sys-libs/binutils-libs: /usr/include/x86_64-pc-linux-gnu/bfd.h gentoo linux $ equery l binutils-libs * Searching for binutils-libs ... [IP-] [ ] sys-libs/binutils-libs-2.45.1:0/2.45.1 gentoo linux $ eselect binutils list [1] x86_64-pc-linux-gnu-2.44 [2] x86_64-pc-linux-gnu-2.45.1 * Since I couldn't build with the patch, I instead checked out the parent of the commit above to check if "perf top" worked. However, it still crashed, so I bisected the crash to this commit: 53b00ff358dc75b12042b2b2aaf1d0e998fd0075 is the first bad commit commit 53b00ff358dc75b12042b2b2aaf1d0e998fd0075 Author: Ian Rogers <irogers@google.com> Date: Thu Jul 24 09:32:48 2025 -0700 perf record: Make --buildid-mmap the default (snip) Link: https://lore.kernel.org/r/20250724163302.596743-9-irogers@google.com I hope this is useful in getting the issue better understood. Best regards, -Guilherme > > Thanks, > Ian > > > --- > > v2: Remove unneeded unistd.h include. > > --- > > tools/perf/util/libbfd.c | 38 ++++++++++++++++++++++++++++++++++++++ > > tools/perf/util/mutex.c | 14 ++++++++++---- > > tools/perf/util/mutex.h | 2 ++ > > 3 files changed, 50 insertions(+), 4 deletions(-) > > > > diff --git a/tools/perf/util/libbfd.c b/tools/perf/util/libbfd.c > > index 01147fbf73b3..6434c2dccd4a 100644 > > --- a/tools/perf/util/libbfd.c > > +++ b/tools/perf/util/libbfd.c > > @@ -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(); > > diff --git a/tools/perf/util/mutex.c b/tools/perf/util/mutex.c > > index bca7f0717f35..7aa1f3f55a7d 100644 > > --- a/tools/perf/util/mutex.c > > +++ b/tools/perf/util/mutex.c > > @@ -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) > > diff --git a/tools/perf/util/mutex.h b/tools/perf/util/mutex.h > > index 38458f00846f..70232d8d094f 100644 > > --- a/tools/perf/util/mutex.h > > +++ b/tools/perf/util/mutex.h > > @@ -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); > > -- > > 2.51.2.1041.gc1ab5b90ca-goog > > ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] perf libbfd: Ensure libbfd is initialized prior to use 2025-11-13 20:25 ` Guilherme Amadio @ 2025-11-13 20:42 ` Ian Rogers 0 siblings, 0 replies; 6+ messages in thread From: Ian Rogers @ 2025-11-13 20:42 UTC (permalink / raw) To: Guilherme Amadio Cc: Arnaldo Carvalho de Melo, Namhyung Kim, Alexander Shishkin, Jiri Olsa, Adrian Hunter, linux-perf-users, Ingo Molnar, linux-kernel, Peter Zijlstra On Thu, Nov 13, 2025 at 12:25 PM Guilherme Amadio <amadio@gentoo.org> wrote: > > Dear Ian, > > On Thu, Nov 13, 2025 at 09:03:42AM -0800, Ian Rogers wrote: > > On Tue, Nov 11, 2025 at 11:43 PM Ian Rogers <irogers@google.com> wrote: > > > > > > 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. > > > > > > Reported-by: Guilherme Amadio <amadio@gentoo.org> > > > Closes: https://lore.kernel.org/lkml/aQt66zhfxSA80xwt@gentoo.org/ > > > Fixes: 95931d9a594d ("perf libbfd: Move libbfd functionality to its own file") > > > Signed-off-by: Ian Rogers <irogers@google.com> > > > > I'm hoping adding the missing initialization is just obviously > > correct, Guilherme if you could provide a Tested-by it would be great. > > Apologies for the hiatus, just been quite busy at work, but following > the emails. Thank you very much for providing a fix, I tried to apply > it on perf-tools-next, and perf-tools, but got the build error below > (both before and after applying the patch): > > gentoo linux $ git describe && make -B -C tools/perf -f Makefile.perf BUILD_BPF_SKEL=1 BUILD_NONDISTRO=1 WERROR=0 NO_SHELLCHECK=1 NO_CAPSTONE=1 DEBUG=1 2>&1 | tail -n 20 > v6.18-rc4-182-gda32d155f4a8 > CC util/perf_event_attr_fprintf.o > CC util/evswitch.o > CC util/find_bit.o > CC util/levenshtein.o > CC util/libbfd.o > In file included from /usr/include/bfd.h:10, > from /usr/include/dis-asm.h:36, > from /home/amadio/src/linux/tools/include/tools/dis-asm-compat.h:6, > from util/libbfd.c:14: > /usr/include/x86_64-pc-linux-gnu/bfd.h:35:2: error: #error config.h must be included before this header > 35 | #error config.h must be included before this header > | ^~~~~ > make[3]: *** [/home/amadio/src/linux/tools/build/Makefile.build:86: util/libbfd.o] Error 1 > make[3]: Leaving directory '/home/amadio/src/linux/tools/perf' > make[2]: *** [/home/amadio/src/linux/tools/build/Makefile.build:142: util] Error 2 > make[2]: Leaving directory '/home/amadio/src/linux/tools/perf' > make[1]: *** [Makefile.perf:797: perf-util-in.o] Error 2 > make[1]: Leaving directory '/home/amadio/src/linux/tools/perf' > make: *** [Makefile.perf:289: sub-make] Error 2 > make: Leaving directory '/home/amadio/src/linux/tools/perf' > > The header in /usr/include/x86_64-pc-linux-gnu/bfd.h:35 has this, right > after the include guards: > > /* PR 14072: Ensure that config.h is included first. */ > #if !defined PACKAGE && !defined PACKAGE_VERSION > #error config.h must be included before this header > #endif > > However, I did try a build with BUILD_NONDISTRO disabled and it works, so I'm > tempted to change things in Gentoo to have it always disabled or offer libbfd > support with a USE-flag but keep it off by default. > > I bisected the build failure to the same commit you added in the Fixes tag: > > 95931d9a594dd0b5f2191a6a6340549b8f3b031b is the first bad commit > commit 95931d9a594dd0b5f2191a6a6340549b8f3b031b > Author: Ian Rogers <irogers@google.com> > Date: Mon Sep 29 12:07:54 2025 -0700 > > perf libbfd: Move libbfd functionality to its own file > > > This is the version of binutils-libs I have, in case it's useful: > > gentoo linux $ qfile /usr/include/x86_64-pc-linux-gnu/bfd.h > sys-libs/binutils-libs: /usr/include/x86_64-pc-linux-gnu/bfd.h > gentoo linux $ equery l binutils-libs > * Searching for binutils-libs ... > [IP-] [ ] sys-libs/binutils-libs-2.45.1:0/2.45.1 > gentoo linux $ eselect binutils list > [1] x86_64-pc-linux-gnu-2.44 > [2] x86_64-pc-linux-gnu-2.45.1 * > > Since I couldn't build with the patch, I instead checked out the parent of the > commit above to check if "perf top" worked. However, it still crashed, so > I bisected the crash to this commit: > > 53b00ff358dc75b12042b2b2aaf1d0e998fd0075 is the first bad commit > commit 53b00ff358dc75b12042b2b2aaf1d0e998fd0075 > Author: Ian Rogers <irogers@google.com> > Date: Thu Jul 24 09:32:48 2025 -0700 > > perf record: Make --buildid-mmap the default > > (snip) > > Link: https://lore.kernel.org/r/20250724163302.596743-9-irogers@google.com > > I hope this is useful in getting the issue better understood. Thanks Guilherme, so I kind of figured this patch would be the problem. The issue is that we're using build-IDs by default now, we use the libbfd code to read build IDs, libbfd maintains a cache, because of a lack of proper initialization/locking by perf the cache crashes. The crashes would have been possible previously, say if you did a perf annotate and that loaded lots of things using libbfd, however, those things don't happen on threads, etc. we're just in a much more easy to crash situation that build IDs are the default. I couldn't repeat the config.h build failure. This looks like an issue in the actual bfd.h and not the perf code. I checked the git logs but didn't see anything that looked blame-able. Thanks, Ian > Best regards, > -Guilherme > > > > > Thanks, > > Ian > > > > > --- > > > v2: Remove unneeded unistd.h include. > > > --- > > > tools/perf/util/libbfd.c | 38 ++++++++++++++++++++++++++++++++++++++ > > > tools/perf/util/mutex.c | 14 ++++++++++---- > > > tools/perf/util/mutex.h | 2 ++ > > > 3 files changed, 50 insertions(+), 4 deletions(-) > > > > > > diff --git a/tools/perf/util/libbfd.c b/tools/perf/util/libbfd.c > > > index 01147fbf73b3..6434c2dccd4a 100644 > > > --- a/tools/perf/util/libbfd.c > > > +++ b/tools/perf/util/libbfd.c > > > @@ -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(); > > > diff --git a/tools/perf/util/mutex.c b/tools/perf/util/mutex.c > > > index bca7f0717f35..7aa1f3f55a7d 100644 > > > --- a/tools/perf/util/mutex.c > > > +++ b/tools/perf/util/mutex.c > > > @@ -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) > > > diff --git a/tools/perf/util/mutex.h b/tools/perf/util/mutex.h > > > index 38458f00846f..70232d8d094f 100644 > > > --- a/tools/perf/util/mutex.h > > > +++ b/tools/perf/util/mutex.h > > > @@ -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); > > > -- > > > 2.51.2.1041.gc1ab5b90ca-goog > > > ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] perf libbfd: Ensure libbfd is initialized prior to use 2025-11-13 17:03 ` Ian Rogers 2025-11-13 20:25 ` Guilherme Amadio @ 2025-11-13 20:31 ` Arnaldo Carvalho de Melo 2025-11-13 20:42 ` Arnaldo Carvalho de Melo 2 siblings, 0 replies; 6+ messages in thread From: Arnaldo Carvalho de Melo @ 2025-11-13 20:31 UTC (permalink / raw) To: Ian Rogers Cc: Guilherme Amadio, Namhyung Kim, Alexander Shishkin, Jiri Olsa, Adrian Hunter, linux-perf-users, Ingo Molnar, linux-kernel, Peter Zijlstra On Thu, Nov 13, 2025 at 09:03:42AM -0800, Ian Rogers wrote: > On Tue, Nov 11, 2025 at 11:43 PM Ian Rogers <irogers@google.com> wrote: > > > > 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. > > > > Reported-by: Guilherme Amadio <amadio@gentoo.org> > > Closes: https://lore.kernel.org/lkml/aQt66zhfxSA80xwt@gentoo.org/ > > Fixes: 95931d9a594d ("perf libbfd: Move libbfd functionality to its own file") > > Signed-off-by: Ian Rogers <irogers@google.com> > > I'm hoping adding the missing initialization is just obviously > correct, Guilherme if you could provide a Tested-by it would be great. Indeed, Guilherme? I'm now trying to reproduce the problem to then try with the patch, - Arnaldo ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] perf libbfd: Ensure libbfd is initialized prior to use 2025-11-13 17:03 ` Ian Rogers 2025-11-13 20:25 ` Guilherme Amadio 2025-11-13 20:31 ` Arnaldo Carvalho de Melo @ 2025-11-13 20:42 ` Arnaldo Carvalho de Melo 2 siblings, 0 replies; 6+ messages in thread From: Arnaldo Carvalho de Melo @ 2025-11-13 20:42 UTC (permalink / raw) To: Ian Rogers Cc: Guilherme Amadio, Namhyung Kim, Alexander Shishkin, Jiri Olsa, Adrian Hunter, linux-perf-users, Ingo Molnar, linux-kernel, Peter Zijlstra On Thu, Nov 13, 2025 at 09:03:42AM -0800, Ian Rogers wrote: > On Tue, Nov 11, 2025 at 11:43 PM Ian Rogers <irogers@google.com> wrote: > > > > 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. > > > > Reported-by: Guilherme Amadio <amadio@gentoo.org> > > Closes: https://lore.kernel.org/lkml/aQt66zhfxSA80xwt@gentoo.org/ > > Fixes: 95931d9a594d ("perf libbfd: Move libbfd functionality to its own file") > > Signed-off-by: Ian Rogers <irogers@google.com> > > I'm hoping adding the missing initialization is just obviously > correct, Guilherme if you could provide a Tested-by it would be great. I reproduced the problem by building with BUILD_NONDISTRO=1 + having binutils-devel installed, 'perf top' segfaults straight away. After applying this patch things gets back to normal. Thanks, applied. - Arnaldo > Thanks, > Ian > > > --- > > v2: Remove unneeded unistd.h include. > > --- > > tools/perf/util/libbfd.c | 38 ++++++++++++++++++++++++++++++++++++++ > > tools/perf/util/mutex.c | 14 ++++++++++---- > > tools/perf/util/mutex.h | 2 ++ > > 3 files changed, 50 insertions(+), 4 deletions(-) > > > > diff --git a/tools/perf/util/libbfd.c b/tools/perf/util/libbfd.c > > index 01147fbf73b3..6434c2dccd4a 100644 > > --- a/tools/perf/util/libbfd.c > > +++ b/tools/perf/util/libbfd.c > > @@ -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(); > > diff --git a/tools/perf/util/mutex.c b/tools/perf/util/mutex.c > > index bca7f0717f35..7aa1f3f55a7d 100644 > > --- a/tools/perf/util/mutex.c > > +++ b/tools/perf/util/mutex.c > > @@ -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) > > diff --git a/tools/perf/util/mutex.h b/tools/perf/util/mutex.h > > index 38458f00846f..70232d8d094f 100644 > > --- a/tools/perf/util/mutex.h > > +++ b/tools/perf/util/mutex.h > > @@ -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); > > -- > > 2.51.2.1041.gc1ab5b90ca-goog > > ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-11-13 20:43 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-11-12 7:43 [PATCH v2] perf libbfd: Ensure libbfd is initialized prior to use Ian Rogers 2025-11-13 17:03 ` Ian Rogers 2025-11-13 20:25 ` Guilherme Amadio 2025-11-13 20:42 ` Ian Rogers 2025-11-13 20:31 ` Arnaldo Carvalho de Melo 2025-11-13 20:42 ` Arnaldo Carvalho de Melo
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.