Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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/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>

authored by

Ian Rogers and committed by
Arnaldo Carvalho de Melo
b72b8132 3c723f44

+50 -4
+38
tools/perf/util/libbfd.c
··· 38 38 asymbol **syms; 39 39 }; 40 40 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 + 41 74 static int bfd_error(const char *string) 42 75 { 43 76 const char *errmsg; ··· 165 132 bfd *abfd; 166 133 struct a2l_data *a2l = NULL; 167 134 135 + ensure_bfd_init(); 168 136 abfd = bfd_openr(path, NULL); 169 137 if (abfd == NULL) 170 138 return NULL; ··· 322 288 bfd *abfd; 323 289 u64 start, len; 324 290 291 + ensure_bfd_init(); 325 292 abfd = bfd_openr(debugfile, NULL); 326 293 if (!abfd) 327 294 return -1; ··· 428 393 if (fd < 0) 429 394 return -1; 430 395 396 + ensure_bfd_init(); 431 397 abfd = bfd_fdopenr(filename, /*target=*/NULL, fd); 432 398 if (!abfd) 433 399 return -1; ··· 457 421 asection *section; 458 422 bfd *abfd; 459 423 424 + ensure_bfd_init(); 460 425 abfd = bfd_openr(filename, NULL); 461 426 if (!abfd) 462 427 return -1; ··· 517 480 memset(tpath, 0, sizeof(tpath)); 518 481 perf_exe(tpath, sizeof(tpath)); 519 482 483 + ensure_bfd_init(); 520 484 bfdf = bfd_openr(tpath, NULL); 521 485 if (bfdf == NULL) 522 486 abort();
+10 -4
tools/perf/util/mutex.c
··· 17 17 18 18 #define CHECK_ERR(err) check_err(__func__, err) 19 19 20 - static void __mutex_init(struct mutex *mtx, bool pshared) 20 + static void __mutex_init(struct mutex *mtx, bool pshared, bool recursive) 21 21 { 22 22 pthread_mutexattr_t attr; 23 23 ··· 27 27 /* In normal builds enable error checking, such as recursive usage. */ 28 28 CHECK_ERR(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK)); 29 29 #endif 30 + if (recursive) 31 + CHECK_ERR(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)); 30 32 if (pshared) 31 33 CHECK_ERR(pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)); 32 - 33 34 CHECK_ERR(pthread_mutex_init(&mtx->lock, &attr)); 34 35 CHECK_ERR(pthread_mutexattr_destroy(&attr)); 35 36 } 36 37 37 38 void mutex_init(struct mutex *mtx) 38 39 { 39 - __mutex_init(mtx, /*pshared=*/false); 40 + __mutex_init(mtx, /*pshared=*/false, /*recursive=*/false); 40 41 } 41 42 42 43 void mutex_init_pshared(struct mutex *mtx) 43 44 { 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); 45 51 } 46 52 47 53 void mutex_destroy(struct mutex *mtx)
+2
tools/perf/util/mutex.h
··· 104 104 * process-private attribute. 105 105 */ 106 106 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); 107 109 void mutex_destroy(struct mutex *mtx); 108 110 109 111 void mutex_lock(struct mutex *mtx) EXCLUSIVE_LOCK_FUNCTION(*mtx);