Commit b72b8132 authored by Ian Rogers's avatar Ian Rogers Committed by Arnaldo Carvalho de Melo
Browse files

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: 95931d9a ("perf libbfd: Move libbfd functionality to its own file")
Reported-by: default avatarGuilherme Amadio <amadio@gentoo.org>
Signed-off-by: default avatarIan Rogers <irogers@google.com>
Tested-by: default avatarArnaldo 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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 3c723f44
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -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();
+10 −4
Original line number Diff line number Diff line
@@ -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)
+2 −0
Original line number Diff line number Diff line
@@ -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);