mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 04:44:45 +01:00
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: 95931d9a59 ("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>
This commit is contained in:
parent
3c723f4497
commit
b72b8132d8
3 changed files with 50 additions and 4 deletions
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue