mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
Currently, both libdw and libunwind define 'unwind__get_entries'. This
causes a duplicate symbol build failure when both are compiled into
perf.
This commit refactors the DWARF unwind post-processing to be
configurable at runtime via the .perfconfig file option
'unwind.style', or using the argument '--unwind-style' in the commands
'perf report', 'perf script' and 'perf inject', in a similar manner to
the addr2line or the disassembler style.
The file 'tools/perf/util/unwind.c' adds the top-level dispatch
function 'unwind__get_entries'. The backend implementations are
renamed to 'libdw__get_entries' and 'libunwind__get_entries'. Both are
attempted as fallbacks if not configured, or if the primary backend
fails.
Fixes: 2e9191573a ("perf build: Remove NO_LIBDW_DWARF_UNWIND option")
Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Albert Ou <aou@eecs.berkeley.edu>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexandre Ghiti <alex@ghiti.fr>
Cc: Andrew Jones <andrew.jones@oss.qualcomm.com>
Cc: Athira Rajeev <atrajeev@linux.ibm.com>
Cc: Dapeng Mi <dapeng1.mi@linux.intel.com>
Cc: Dmitrii Dolgov <9erthalion6@gmail.com>
Cc: Florian Fainelli <florian.fainelli@broadcom.com>
Cc: Howard Chu <howardchu95@gmail.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.g.garry@oracle.com>
Cc: Leo Yan <leo.yan@linux.dev>
Cc: libunwind-devel@nongnu.org
Cc: Li Guan <guanli.oerv@isrc.iscas.ac.cn>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Palmer Dabbelt <palmer@dabbelt.com>
Cc: Paul Walmsley <pjw@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Shimin Guo <shimin.guo@skydio.com>
Cc: Thomas Richter <tmricht@linux.ibm.com>
Cc: Tomas Glozar <tglozar@redhat.com>
Cc: Will Deacon <will@kernel.org>
[ Don't mix declarations and code, move 'entries' variable to the start of scope ]
[ Use pr_warning_once() instead of pr_err() in stubs for get_entries(), suggested by a local sashiko instance ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
105 lines
2.5 KiB
C
105 lines
2.5 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
#include "debug.h"
|
|
#include "symbol_conf.h"
|
|
#include "unwind.h"
|
|
#include <linux/string.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
int unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, void *arg __maybe_unused,
|
|
struct thread *thread __maybe_unused,
|
|
struct perf_sample *data __maybe_unused,
|
|
int max_stack __maybe_unused,
|
|
bool best_effort __maybe_unused)
|
|
{
|
|
int ret = 0;
|
|
|
|
#if defined(HAVE_LIBDW_SUPPORT) || defined(HAVE_LIBUNWIND_SUPPORT)
|
|
if (symbol_conf.unwind_style[0] == UNWIND_STYLE_UNKNOWN) {
|
|
int i = 0;
|
|
#ifdef HAVE_LIBDW_SUPPORT
|
|
symbol_conf.unwind_style[i++] = UNWIND_STYLE_LIBDW;
|
|
#endif
|
|
#ifdef HAVE_LIBUNWIND_SUPPORT
|
|
symbol_conf.unwind_style[i++] = UNWIND_STYLE_LIBUNWIND;
|
|
#endif
|
|
}
|
|
#endif //defined(HAVE_LIBDW_SUPPORT) || defined(HAVE_LIBUNWIND_SUPPORT)
|
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(symbol_conf.unwind_style); i++) {
|
|
switch (symbol_conf.unwind_style[i]) {
|
|
case UNWIND_STYLE_LIBDW:
|
|
ret = libdw__get_entries(cb, arg, thread, data, max_stack, best_effort);
|
|
break;
|
|
case UNWIND_STYLE_LIBUNWIND:
|
|
ret = libunwind__get_entries(cb, arg, thread, data, max_stack, best_effort);
|
|
break;
|
|
case UNWIND_STYLE_UNKNOWN:
|
|
default:
|
|
#if !defined(HAVE_LIBDW_SUPPORT) && !defined(HAVE_LIBUNWIND_SUPPORT)
|
|
pr_warning_once(
|
|
"Error: dwarf unwinding not supported, build perf with libdw or libunwind.\n");
|
|
#endif
|
|
ret = 0;
|
|
break;
|
|
}
|
|
if (ret > 0) {
|
|
ret = 0;
|
|
break;
|
|
}
|
|
if (ret < 0)
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int unwind__configure(const char *var, const char *value, void *cb __maybe_unused)
|
|
{
|
|
static const char * const unwind_style_names[] = {
|
|
[UNWIND_STYLE_LIBDW] = "libdw",
|
|
[UNWIND_STYLE_LIBUNWIND] = "libunwind",
|
|
NULL
|
|
};
|
|
char *s, *p, *saveptr;
|
|
size_t i = 0;
|
|
|
|
if (strcmp(var, "unwind.style"))
|
|
return 0;
|
|
|
|
if (!value)
|
|
return -1;
|
|
|
|
s = strdup(value);
|
|
if (!s)
|
|
return -1;
|
|
|
|
memset(symbol_conf.unwind_style, 0, sizeof(symbol_conf.unwind_style));
|
|
|
|
p = strtok_r(s, ",", &saveptr);
|
|
while (p && i < ARRAY_SIZE(symbol_conf.unwind_style)) {
|
|
bool found = false;
|
|
char *q = strim(p);
|
|
|
|
for (size_t j = UNWIND_STYLE_LIBDW; j < MAX_UNWIND_STYLE; j++) {
|
|
if (!strcasecmp(q, unwind_style_names[j])) {
|
|
symbol_conf.unwind_style[i++] = j;
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found)
|
|
pr_warning("Unknown unwind style: %s\n", q);
|
|
p = strtok_r(NULL, ",", &saveptr);
|
|
}
|
|
|
|
free(s);
|
|
return 0;
|
|
}
|
|
|
|
int unwind__option(const struct option *opt __maybe_unused,
|
|
const char *arg,
|
|
int unset __maybe_unused)
|
|
{
|
|
return unwind__configure("unwind.style", arg, NULL);
|
|
}
|