Skip to content

Commit b72b813

Browse files
captain5050acmel
authored andcommitted
perf libbfd: Ensure libbfd is initialized prior to use
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/[email protected]/ Fixes: 95931d9 ("perf libbfd: Move libbfd functionality to its own file") Reported-by: Guilherme Amadio <[email protected]> Signed-off-by: Ian Rogers <[email protected]> Tested-by: Arnaldo Carvalho de Melo <[email protected]> Cc: Adrian Hunter <[email protected]> Cc: Alexander Shishkin <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Peter Zijlstra <[email protected]> Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 3c723f4 commit b72b813

File tree

3 files changed

+50
-4
lines changed

3 files changed

+50
-4
lines changed

tools/perf/util/libbfd.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,39 @@ struct a2l_data {
3838
asymbol **syms;
3939
};
4040

41+
static bool perf_bfd_lock(void *bfd_mutex)
42+
{
43+
mutex_lock(bfd_mutex);
44+
return true;
45+
}
46+
47+
static bool perf_bfd_unlock(void *bfd_mutex)
48+
{
49+
mutex_unlock(bfd_mutex);
50+
return true;
51+
}
52+
53+
static void perf_bfd_init(void)
54+
{
55+
static struct mutex bfd_mutex;
56+
57+
mutex_init_recursive(&bfd_mutex);
58+
59+
if (bfd_init() != BFD_INIT_MAGIC) {
60+
pr_err("Error initializing libbfd\n");
61+
return;
62+
}
63+
if (!bfd_thread_init(perf_bfd_lock, perf_bfd_unlock, &bfd_mutex))
64+
pr_err("Error initializing libbfd threading\n");
65+
}
66+
67+
static void ensure_bfd_init(void)
68+
{
69+
static pthread_once_t bfd_init_once = PTHREAD_ONCE_INIT;
70+
71+
pthread_once(&bfd_init_once, perf_bfd_init);
72+
}
73+
4174
static int bfd_error(const char *string)
4275
{
4376
const char *errmsg;
@@ -132,6 +165,7 @@ static struct a2l_data *addr2line_init(const char *path)
132165
bfd *abfd;
133166
struct a2l_data *a2l = NULL;
134167

168+
ensure_bfd_init();
135169
abfd = bfd_openr(path, NULL);
136170
if (abfd == NULL)
137171
return NULL;
@@ -288,6 +322,7 @@ int dso__load_bfd_symbols(struct dso *dso, const char *debugfile)
288322
bfd *abfd;
289323
u64 start, len;
290324

325+
ensure_bfd_init();
291326
abfd = bfd_openr(debugfile, NULL);
292327
if (!abfd)
293328
return -1;
@@ -393,6 +428,7 @@ int libbfd__read_build_id(const char *filename, struct build_id *bid, bool block
393428
if (fd < 0)
394429
return -1;
395430

431+
ensure_bfd_init();
396432
abfd = bfd_fdopenr(filename, /*target=*/NULL, fd);
397433
if (!abfd)
398434
return -1;
@@ -421,6 +457,7 @@ int libbfd_filename__read_debuglink(const char *filename, char *debuglink,
421457
asection *section;
422458
bfd *abfd;
423459

460+
ensure_bfd_init();
424461
abfd = bfd_openr(filename, NULL);
425462
if (!abfd)
426463
return -1;
@@ -480,6 +517,7 @@ int symbol__disassemble_bpf_libbfd(struct symbol *sym __maybe_unused,
480517
memset(tpath, 0, sizeof(tpath));
481518
perf_exe(tpath, sizeof(tpath));
482519

520+
ensure_bfd_init();
483521
bfdf = bfd_openr(tpath, NULL);
484522
if (bfdf == NULL)
485523
abort();

tools/perf/util/mutex.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ static void check_err(const char *fn, int err)
1717

1818
#define CHECK_ERR(err) check_err(__func__, err)
1919

20-
static void __mutex_init(struct mutex *mtx, bool pshared)
20+
static void __mutex_init(struct mutex *mtx, bool pshared, bool recursive)
2121
{
2222
pthread_mutexattr_t attr;
2323

@@ -27,21 +27,27 @@ static void __mutex_init(struct mutex *mtx, bool pshared)
2727
/* In normal builds enable error checking, such as recursive usage. */
2828
CHECK_ERR(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK));
2929
#endif
30+
if (recursive)
31+
CHECK_ERR(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE));
3032
if (pshared)
3133
CHECK_ERR(pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED));
32-
3334
CHECK_ERR(pthread_mutex_init(&mtx->lock, &attr));
3435
CHECK_ERR(pthread_mutexattr_destroy(&attr));
3536
}
3637

3738
void mutex_init(struct mutex *mtx)
3839
{
39-
__mutex_init(mtx, /*pshared=*/false);
40+
__mutex_init(mtx, /*pshared=*/false, /*recursive=*/false);
4041
}
4142

4243
void mutex_init_pshared(struct mutex *mtx)
4344
{
44-
__mutex_init(mtx, /*pshared=*/true);
45+
__mutex_init(mtx, /*pshared=*/true, /*recursive=*/false);
46+
}
47+
48+
void mutex_init_recursive(struct mutex *mtx)
49+
{
50+
__mutex_init(mtx, /*pshared=*/false, /*recursive=*/true);
4551
}
4652

4753
void mutex_destroy(struct mutex *mtx)

tools/perf/util/mutex.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ void mutex_init(struct mutex *mtx);
104104
* process-private attribute.
105105
*/
106106
void mutex_init_pshared(struct mutex *mtx);
107+
/* Initializes a mutex that may be recursively held on the same thread. */
108+
void mutex_init_recursive(struct mutex *mtx);
107109
void mutex_destroy(struct mutex *mtx);
108110

109111
void mutex_lock(struct mutex *mtx) EXCLUSIVE_LOCK_FUNCTION(*mtx);

0 commit comments

Comments
 (0)