All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ian Rogers <irogers@google.com>
To: irogers@google.com
Cc: 9erthalion6@gmail.com, acme@kernel.org, adrian.hunter@intel.com,
	 alex@ghiti.fr, alexander.shishkin@linux.intel.com,
	 andrew.jones@oss.qualcomm.com, aou@eecs.berkeley.edu,
	atrajeev@linux.ibm.com,  blakejones@google.com,
	ctshao@google.com, dapeng1.mi@linux.intel.com,
	 howardchu95@gmail.com, james.clark@linaro.org,
	john.g.garry@oracle.com,  jolsa@kernel.org, leo.yan@linux.dev,
	libunwind-devel@nongnu.org,
	 linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org,  linux-perf-users@vger.kernel.org,
	linux-riscv@lists.infradead.org,  mingo@redhat.com,
	namhyung@kernel.org, palmer@dabbelt.com,  peterz@infradead.org,
	pjw@kernel.org, shimin.guo@skydio.com,  tglozar@redhat.com,
	tmricht@linux.ibm.com, will@kernel.org, yuzhuo@google.com
Subject: [PATCH v2 1/8] perf unwind: Refactor get_entries to allow dynamic libdw/libunwind selection
Date: Thu,  5 Mar 2026 14:19:20 -0800	[thread overview]
Message-ID: <20260305221927.3237145-2-irogers@google.com> (raw)
In-Reply-To: <20260305221927.3237145-1-irogers@google.com>

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: 2e9191573a69 ("perf build: Remove NO_LIBDW_DWARF_UNWIND option")
Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/builtin-inject.c        |   4 ++
 tools/perf/builtin-report.c        |   4 ++
 tools/perf/builtin-script.c        |   4 ++
 tools/perf/util/Build              |   1 +
 tools/perf/util/symbol_conf.h      |  15 +++++
 tools/perf/util/unwind-libdw.c     |   2 +-
 tools/perf/util/unwind-libunwind.c |   2 +-
 tools/perf/util/unwind.c           | 102 +++++++++++++++++++++++++++++
 tools/perf/util/unwind.h           |  40 +++++------
 9 files changed, 149 insertions(+), 25 deletions(-)
 create mode 100644 tools/perf/util/unwind.c

diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 5b29f4296861..9ad681b3c0dc 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -26,6 +26,7 @@
 #include "util/synthetic-events.h"
 #include "util/thread.h"
 #include "util/namespaces.h"
+#include "util/unwind.h"
 #include "util/util.h"
 #include "util/tsc.h"
 
@@ -2539,6 +2540,9 @@ int cmd_inject(int argc, const char **argv)
 		OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory",
 			   "guest mount directory under which every guest os"
 			   " instance has a subdir"),
+		OPT_CALLBACK(0, "unwind-style", NULL, "unwind style",
+			     "unwind styles (libdw,libunwind)",
+			     unwind__option),
 		OPT_BOOLEAN(0, "convert-callchain", &inject.convert_callchain,
 			    "Generate callchains using DWARF and drop register/stack data"),
 		OPT_END()
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 3b81f4b3dc49..ae20c0679990 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -48,6 +48,7 @@
 #include "util/time-utils.h"
 #include "util/auxtrace.h"
 #include "util/units.h"
+#include "util/unwind.h"
 #include "util/util.h" // perf_tip()
 #include "ui/ui.h"
 #include "ui/progress.h"
@@ -1455,6 +1456,9 @@ int cmd_report(int argc, const char **argv)
 	OPT_CALLBACK(0, "addr2line-style", NULL, "addr2line style",
 		     "addr2line styles (libdw,llvm,libbfd,addr2line)",
 		     report_parse_addr2line_config),
+	OPT_CALLBACK(0, "unwind-style", NULL, "unwind style",
+		     "unwind styles (libdw,libunwind)",
+		     unwind__option),
 	OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
 		    "Symbol demangling. Enabled by default, use --no-demangle to disable."),
 	OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 9f8b0fd27a0a..b6c7c164d02d 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -63,6 +63,7 @@
 #include <linux/err.h>
 #include "util/dlfilter.h"
 #include "util/record.h"
+#include "util/unwind.h"
 #include "util/util.h"
 #include "util/cgroup.h"
 #include "util/annotate.h"
@@ -4164,6 +4165,9 @@ int cmd_script(int argc, const char **argv)
 			"Enable symbol demangling"),
 	OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
 			"Enable kernel symbol demangling"),
+	OPT_CALLBACK(0, "unwind-style", NULL, "unwind style",
+		     "unwind styles (libdw,libunwind)",
+		     unwind__option),
 	OPT_STRING(0, "addr2line", &symbol_conf.addr2line_path, "path",
 			"addr2line binary to use for line numbers"),
 	OPT_STRING(0, "time", &script.time_str, "str",
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index bcccad7487a9..6190a8f5b0fa 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -218,6 +218,7 @@ ifndef CONFIG_SETNS
 perf-util-y += setns.o
 endif
 
+perf-util-y += unwind.o
 perf-util-$(CONFIG_LIBDW) += probe-finder.o
 perf-util-$(CONFIG_LIBDW) += dwarf-aux.o
 perf-util-$(CONFIG_LIBDW) += dwarf-regs.o
diff --git a/tools/perf/util/symbol_conf.h b/tools/perf/util/symbol_conf.h
index 71bb17372a6c..25d92bbbfee7 100644
--- a/tools/perf/util/symbol_conf.h
+++ b/tools/perf/util/symbol_conf.h
@@ -9,6 +9,19 @@
 struct strlist;
 struct intlist;
 
+enum unwind_style {
+
+	UNWIND_STYLE_UNKNOWN = 0,
+
+	UNWIND_STYLE_LIBDW,
+
+	UNWIND_STYLE_LIBUNWIND,
+
+};
+
+#define MAX_UNWIND_STYLE (UNWIND_STYLE_LIBUNWIND + 1)
+
+
 enum a2l_style {
 	A2L_STYLE_UNKNOWN = 0,
 	A2L_STYLE_LIBDW,
@@ -80,6 +93,7 @@ struct symbol_conf {
 			*bt_stop_list_str;
 	const char		*addr2line_path;
 	enum a2l_style	addr2line_style[MAX_A2L_STYLE];
+	enum unwind_style unwind_style[MAX_UNWIND_STYLE];
 	unsigned long	time_quantum;
        struct strlist	*dso_list,
 			*comm_list,
@@ -103,3 +117,4 @@ struct symbol_conf {
 extern struct symbol_conf symbol_conf;
 
 #endif // __PERF_SYMBOL_CONF
+
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 05e8e68bd49c..d8a5b7d54192 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -339,7 +339,7 @@ frame_callback(Dwfl_Frame *state, void *arg)
 	       DWARF_CB_ABORT : DWARF_CB_OK;
 }
 
-int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
+int libdw__get_entries(unwind_entry_cb_t cb, void *arg,
 			struct thread *thread,
 			struct perf_sample *data,
 			int max_stack,
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index cb8be6acfb6f..a0016b897dae 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -79,7 +79,7 @@ void unwind__finish_access(struct maps *maps)
 		ops->finish_access(maps);
 }
 
-int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
+int libunwind__get_entries(unwind_entry_cb_t cb, void *arg,
 			 struct thread *thread,
 			 struct perf_sample *data, int max_stack,
 			 bool best_effort)
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
new file mode 100644
index 000000000000..9ae7d5ad246d
--- /dev/null
+++ b/tools/perf/util/unwind.c
@@ -0,0 +1,102 @@
+// 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:
+#ifdef HAVE_LIBDW_SUPPORT
+			ret = libdw__get_entries(cb, arg, thread, data, max_stack, best_effort);
+#endif
+			break;
+		case UNWIND_STYLE_LIBUNWIND:
+#ifdef HAVE_LIBUNWIND_SUPPORT
+			ret = libunwind__get_entries(cb, arg, thread, data, max_stack, best_effort);
+#endif
+			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 = -1;
+			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;
+
+	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);
+}
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index 9f7164c6d9aa..581d042e170a 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -7,6 +7,7 @@
 #include "util/map_symbol.h"
 
 struct maps;
+struct option;
 struct perf_sample;
 struct thread;
 
@@ -26,7 +27,9 @@ struct unwind_libunwind_ops {
 			   struct perf_sample *data, int max_stack, bool best_effort);
 };
 
-#ifdef HAVE_DWARF_UNWIND_SUPPORT
+int unwind__configure(const char *var, const char *value, void *cb);
+int unwind__option(const struct option *opt, const char *arg, int unset);
+
 /*
  * When best_effort is set, don't report errors and fail silently. This could
  * be expanded in the future to be more permissive about things other than
@@ -36,8 +39,20 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
 			struct thread *thread,
 			struct perf_sample *data, int max_stack,
 			bool best_effort);
-/* libunwind specific */
+
+#ifdef HAVE_LIBDW_SUPPORT
+int libdw__get_entries(unwind_entry_cb_t cb, void *arg,
+		       struct thread *thread,
+		       struct perf_sample *data, int max_stack,
+		       bool best_effort);
+#endif
+
 #ifdef HAVE_LIBUNWIND_SUPPORT
+/* libunwind specific */
+int libunwind__get_entries(unwind_entry_cb_t cb, void *arg,
+			   struct thread *thread,
+			   struct perf_sample *data, int max_stack,
+			   bool best_effort);
 #ifndef LIBUNWIND__ARCH_REG_ID
 #define LIBUNWIND__ARCH_REG_ID(regnum) libunwind__arch_reg_id(regnum)
 #endif
@@ -57,26 +72,5 @@ static inline int unwind__prepare_access(struct maps *maps __maybe_unused,
 static inline void unwind__flush_access(struct maps *maps __maybe_unused) {}
 static inline void unwind__finish_access(struct maps *maps __maybe_unused) {}
 #endif
-#else
-static inline 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)
-{
-	return 0;
-}
-
-static inline int unwind__prepare_access(struct maps *maps __maybe_unused,
-					 struct map *map __maybe_unused,
-					 bool *initialized __maybe_unused)
-{
-	return 0;
-}
 
-static inline void unwind__flush_access(struct maps *maps __maybe_unused) {}
-static inline void unwind__finish_access(struct maps *maps __maybe_unused) {}
-#endif /* HAVE_DWARF_UNWIND_SUPPORT */
 #endif /* __UNWIND_H */
-- 
2.53.0.473.g4a7958ca14-goog



WARNING: multiple messages have this Message-ID (diff)
From: Ian Rogers <irogers@google.com>
To: irogers@google.com
Cc: 9erthalion6@gmail.com, acme@kernel.org, adrian.hunter@intel.com,
	 alex@ghiti.fr, alexander.shishkin@linux.intel.com,
	 andrew.jones@oss.qualcomm.com, aou@eecs.berkeley.edu,
	atrajeev@linux.ibm.com,  blakejones@google.com,
	ctshao@google.com, dapeng1.mi@linux.intel.com,
	 howardchu95@gmail.com, james.clark@linaro.org,
	john.g.garry@oracle.com,  jolsa@kernel.org, leo.yan@linux.dev,
	libunwind-devel@nongnu.org,
	 linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org,  linux-perf-users@vger.kernel.org,
	linux-riscv@lists.infradead.org,  mingo@redhat.com,
	namhyung@kernel.org, palmer@dabbelt.com,  peterz@infradead.org,
	pjw@kernel.org, shimin.guo@skydio.com,  tglozar@redhat.com,
	tmricht@linux.ibm.com, will@kernel.org, yuzhuo@google.com
Subject: [PATCH v2 1/8] perf unwind: Refactor get_entries to allow dynamic libdw/libunwind selection
Date: Thu,  5 Mar 2026 14:19:20 -0800	[thread overview]
Message-ID: <20260305221927.3237145-2-irogers@google.com> (raw)
In-Reply-To: <20260305221927.3237145-1-irogers@google.com>

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: 2e9191573a69 ("perf build: Remove NO_LIBDW_DWARF_UNWIND option")
Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/builtin-inject.c        |   4 ++
 tools/perf/builtin-report.c        |   4 ++
 tools/perf/builtin-script.c        |   4 ++
 tools/perf/util/Build              |   1 +
 tools/perf/util/symbol_conf.h      |  15 +++++
 tools/perf/util/unwind-libdw.c     |   2 +-
 tools/perf/util/unwind-libunwind.c |   2 +-
 tools/perf/util/unwind.c           | 102 +++++++++++++++++++++++++++++
 tools/perf/util/unwind.h           |  40 +++++------
 9 files changed, 149 insertions(+), 25 deletions(-)
 create mode 100644 tools/perf/util/unwind.c

diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 5b29f4296861..9ad681b3c0dc 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -26,6 +26,7 @@
 #include "util/synthetic-events.h"
 #include "util/thread.h"
 #include "util/namespaces.h"
+#include "util/unwind.h"
 #include "util/util.h"
 #include "util/tsc.h"
 
@@ -2539,6 +2540,9 @@ int cmd_inject(int argc, const char **argv)
 		OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory",
 			   "guest mount directory under which every guest os"
 			   " instance has a subdir"),
+		OPT_CALLBACK(0, "unwind-style", NULL, "unwind style",
+			     "unwind styles (libdw,libunwind)",
+			     unwind__option),
 		OPT_BOOLEAN(0, "convert-callchain", &inject.convert_callchain,
 			    "Generate callchains using DWARF and drop register/stack data"),
 		OPT_END()
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 3b81f4b3dc49..ae20c0679990 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -48,6 +48,7 @@
 #include "util/time-utils.h"
 #include "util/auxtrace.h"
 #include "util/units.h"
+#include "util/unwind.h"
 #include "util/util.h" // perf_tip()
 #include "ui/ui.h"
 #include "ui/progress.h"
@@ -1455,6 +1456,9 @@ int cmd_report(int argc, const char **argv)
 	OPT_CALLBACK(0, "addr2line-style", NULL, "addr2line style",
 		     "addr2line styles (libdw,llvm,libbfd,addr2line)",
 		     report_parse_addr2line_config),
+	OPT_CALLBACK(0, "unwind-style", NULL, "unwind style",
+		     "unwind styles (libdw,libunwind)",
+		     unwind__option),
 	OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
 		    "Symbol demangling. Enabled by default, use --no-demangle to disable."),
 	OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 9f8b0fd27a0a..b6c7c164d02d 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -63,6 +63,7 @@
 #include <linux/err.h>
 #include "util/dlfilter.h"
 #include "util/record.h"
+#include "util/unwind.h"
 #include "util/util.h"
 #include "util/cgroup.h"
 #include "util/annotate.h"
@@ -4164,6 +4165,9 @@ int cmd_script(int argc, const char **argv)
 			"Enable symbol demangling"),
 	OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
 			"Enable kernel symbol demangling"),
+	OPT_CALLBACK(0, "unwind-style", NULL, "unwind style",
+		     "unwind styles (libdw,libunwind)",
+		     unwind__option),
 	OPT_STRING(0, "addr2line", &symbol_conf.addr2line_path, "path",
 			"addr2line binary to use for line numbers"),
 	OPT_STRING(0, "time", &script.time_str, "str",
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index bcccad7487a9..6190a8f5b0fa 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -218,6 +218,7 @@ ifndef CONFIG_SETNS
 perf-util-y += setns.o
 endif
 
+perf-util-y += unwind.o
 perf-util-$(CONFIG_LIBDW) += probe-finder.o
 perf-util-$(CONFIG_LIBDW) += dwarf-aux.o
 perf-util-$(CONFIG_LIBDW) += dwarf-regs.o
diff --git a/tools/perf/util/symbol_conf.h b/tools/perf/util/symbol_conf.h
index 71bb17372a6c..25d92bbbfee7 100644
--- a/tools/perf/util/symbol_conf.h
+++ b/tools/perf/util/symbol_conf.h
@@ -9,6 +9,19 @@
 struct strlist;
 struct intlist;
 
+enum unwind_style {
+
+	UNWIND_STYLE_UNKNOWN = 0,
+
+	UNWIND_STYLE_LIBDW,
+
+	UNWIND_STYLE_LIBUNWIND,
+
+};
+
+#define MAX_UNWIND_STYLE (UNWIND_STYLE_LIBUNWIND + 1)
+
+
 enum a2l_style {
 	A2L_STYLE_UNKNOWN = 0,
 	A2L_STYLE_LIBDW,
@@ -80,6 +93,7 @@ struct symbol_conf {
 			*bt_stop_list_str;
 	const char		*addr2line_path;
 	enum a2l_style	addr2line_style[MAX_A2L_STYLE];
+	enum unwind_style unwind_style[MAX_UNWIND_STYLE];
 	unsigned long	time_quantum;
        struct strlist	*dso_list,
 			*comm_list,
@@ -103,3 +117,4 @@ struct symbol_conf {
 extern struct symbol_conf symbol_conf;
 
 #endif // __PERF_SYMBOL_CONF
+
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 05e8e68bd49c..d8a5b7d54192 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -339,7 +339,7 @@ frame_callback(Dwfl_Frame *state, void *arg)
 	       DWARF_CB_ABORT : DWARF_CB_OK;
 }
 
-int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
+int libdw__get_entries(unwind_entry_cb_t cb, void *arg,
 			struct thread *thread,
 			struct perf_sample *data,
 			int max_stack,
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index cb8be6acfb6f..a0016b897dae 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -79,7 +79,7 @@ void unwind__finish_access(struct maps *maps)
 		ops->finish_access(maps);
 }
 
-int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
+int libunwind__get_entries(unwind_entry_cb_t cb, void *arg,
 			 struct thread *thread,
 			 struct perf_sample *data, int max_stack,
 			 bool best_effort)
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
new file mode 100644
index 000000000000..9ae7d5ad246d
--- /dev/null
+++ b/tools/perf/util/unwind.c
@@ -0,0 +1,102 @@
+// 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:
+#ifdef HAVE_LIBDW_SUPPORT
+			ret = libdw__get_entries(cb, arg, thread, data, max_stack, best_effort);
+#endif
+			break;
+		case UNWIND_STYLE_LIBUNWIND:
+#ifdef HAVE_LIBUNWIND_SUPPORT
+			ret = libunwind__get_entries(cb, arg, thread, data, max_stack, best_effort);
+#endif
+			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 = -1;
+			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;
+
+	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);
+}
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index 9f7164c6d9aa..581d042e170a 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -7,6 +7,7 @@
 #include "util/map_symbol.h"
 
 struct maps;
+struct option;
 struct perf_sample;
 struct thread;
 
@@ -26,7 +27,9 @@ struct unwind_libunwind_ops {
 			   struct perf_sample *data, int max_stack, bool best_effort);
 };
 
-#ifdef HAVE_DWARF_UNWIND_SUPPORT
+int unwind__configure(const char *var, const char *value, void *cb);
+int unwind__option(const struct option *opt, const char *arg, int unset);
+
 /*
  * When best_effort is set, don't report errors and fail silently. This could
  * be expanded in the future to be more permissive about things other than
@@ -36,8 +39,20 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
 			struct thread *thread,
 			struct perf_sample *data, int max_stack,
 			bool best_effort);
-/* libunwind specific */
+
+#ifdef HAVE_LIBDW_SUPPORT
+int libdw__get_entries(unwind_entry_cb_t cb, void *arg,
+		       struct thread *thread,
+		       struct perf_sample *data, int max_stack,
+		       bool best_effort);
+#endif
+
 #ifdef HAVE_LIBUNWIND_SUPPORT
+/* libunwind specific */
+int libunwind__get_entries(unwind_entry_cb_t cb, void *arg,
+			   struct thread *thread,
+			   struct perf_sample *data, int max_stack,
+			   bool best_effort);
 #ifndef LIBUNWIND__ARCH_REG_ID
 #define LIBUNWIND__ARCH_REG_ID(regnum) libunwind__arch_reg_id(regnum)
 #endif
@@ -57,26 +72,5 @@ static inline int unwind__prepare_access(struct maps *maps __maybe_unused,
 static inline void unwind__flush_access(struct maps *maps __maybe_unused) {}
 static inline void unwind__finish_access(struct maps *maps __maybe_unused) {}
 #endif
-#else
-static inline 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)
-{
-	return 0;
-}
-
-static inline int unwind__prepare_access(struct maps *maps __maybe_unused,
-					 struct map *map __maybe_unused,
-					 bool *initialized __maybe_unused)
-{
-	return 0;
-}
 
-static inline void unwind__flush_access(struct maps *maps __maybe_unused) {}
-static inline void unwind__finish_access(struct maps *maps __maybe_unused) {}
-#endif /* HAVE_DWARF_UNWIND_SUPPORT */
 #endif /* __UNWIND_H */
-- 
2.53.0.473.g4a7958ca14-goog


_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

  reply	other threads:[~2026-03-05 22:19 UTC|newest]

Thread overview: 148+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-24 14:29 [RFC PATCH v1 0/7] perf libunwind multiple remote support Ian Rogers
2026-02-24 14:29 ` Ian Rogers
2026-02-24 14:29 ` [RFC PATCH v1 1/7] tools build: Deduplicate test-libunwind for different architectures Ian Rogers
2026-02-24 14:29   ` Ian Rogers
2026-02-24 14:29 ` [RFC PATCH v1 2/7] perf build: Be more programmatic when setting up libunwind variables Ian Rogers
2026-02-24 14:29   ` Ian Rogers
2026-02-24 14:29 ` [RFC PATCH v1 3/7] perf build loongarch: Remove reference to missing file Ian Rogers
2026-02-24 14:29   ` Ian Rogers
2026-02-24 14:29 ` [RFC PATCH v1 4/7] perf unwind-libunwind: Make libunwind register reading cross platform Ian Rogers
2026-02-24 14:29   ` Ian Rogers
2026-02-24 14:29 ` [RFC PATCH v1 5/7] perf unwind-libunwind: Move flush/finish access out of local Ian Rogers
2026-02-24 14:29   ` Ian Rogers
2026-02-24 14:29 ` [RFC PATCH v1 6/7] perf unwind-libunwind: Remove libunwind-local Ian Rogers
2026-02-24 14:29   ` Ian Rogers
2026-02-24 14:29 ` [RFC PATCH v1 7/7] perf unwind-libunwind: Add RISC-V libunwind support Ian Rogers
2026-02-24 14:29   ` Ian Rogers
2026-02-25 21:08   ` Andrew Jones
2026-02-25 21:08     ` Andrew Jones
2026-02-26  1:34     ` Ian Rogers
2026-02-26  1:34       ` Ian Rogers
2026-03-05 22:19       ` [PATCH v2 0/8] perf libunwind multiple remote support Ian Rogers
2026-03-05 22:19         ` Ian Rogers
2026-03-05 22:19         ` Ian Rogers [this message]
2026-03-05 22:19           ` [PATCH v2 1/8] perf unwind: Refactor get_entries to allow dynamic libdw/libunwind selection Ian Rogers
2026-03-31 20:38           ` Arnaldo Carvalho de Melo
2026-03-31 20:38             ` Arnaldo Carvalho de Melo
2026-03-31 20:42           ` Arnaldo Carvalho de Melo
2026-03-31 20:42             ` Arnaldo Carvalho de Melo
2026-03-31 21:21             ` Ian Rogers
2026-03-31 21:21               ` Ian Rogers
2026-03-05 22:19         ` [PATCH v2 2/8] perf build loongarch: Remove reference to missing file Ian Rogers
2026-03-05 22:19           ` Ian Rogers
2026-03-30 21:05           ` Arnaldo Carvalho de Melo
2026-03-30 21:05             ` Arnaldo Carvalho de Melo
2026-03-31 17:01             ` Ian Rogers
2026-03-31 17:01               ` Ian Rogers
2026-03-05 22:19         ` [PATCH v2 3/8] tools build: Deduplicate test-libunwind for different architectures Ian Rogers
2026-03-05 22:19           ` Ian Rogers
2026-03-30 21:08           ` Arnaldo Carvalho de Melo
2026-03-30 21:08             ` Arnaldo Carvalho de Melo
2026-03-05 22:19         ` [PATCH v2 4/8] perf build: Be more programmatic when setting up libunwind variables Ian Rogers
2026-03-05 22:19           ` Ian Rogers
2026-03-05 22:19         ` [PATCH v2 5/8] perf unwind-libunwind: Make libunwind register reading cross platform Ian Rogers
2026-03-05 22:19           ` Ian Rogers
2026-03-05 22:19         ` [PATCH v2 6/8] perf unwind-libunwind: Move flush/finish access out of local Ian Rogers
2026-03-05 22:19           ` Ian Rogers
2026-03-05 22:19         ` [PATCH v2 7/8] perf unwind-libunwind: Remove libunwind-local Ian Rogers
2026-03-05 22:19           ` Ian Rogers
2026-03-05 22:19         ` [PATCH v2 8/8] perf unwind-libunwind: Add RISC-V libunwind support Ian Rogers
2026-03-05 22:19           ` Ian Rogers
2026-03-19 21:39         ` [PATCH v2 0/8] perf libunwind multiple remote support Namhyung Kim
2026-03-19 21:39           ` Namhyung Kim
2026-03-21  3:06           ` Ian Rogers
2026-03-21  3:06             ` Ian Rogers
2026-03-21  8:20             ` Guilherme Amadio
2026-03-21  8:20               ` Guilherme Amadio
2026-03-21 23:42           ` [PATCH v1 0/2] perf build: Remove libunwind support Ian Rogers
2026-03-21 23:42             ` Ian Rogers
2026-03-21 23:42             ` [PATCH v1 1/2] " Ian Rogers
2026-03-21 23:42               ` Ian Rogers
2026-03-21 23:42             ` [PATCH v1 2/2] tools build: Remove libunwind feature tests Ian Rogers
2026-03-21 23:42               ` Ian Rogers
2026-03-26 22:51             ` [PATCH v1 0/2] perf build: Remove libunwind support Namhyung Kim
2026-03-26 22:51               ` Namhyung Kim
2026-03-26 23:14               ` Ian Rogers
2026-03-26 23:14                 ` Ian Rogers
2026-03-27 20:07               ` Arnaldo Carvalho de Melo
2026-03-27 20:07                 ` Arnaldo Carvalho de Melo
2026-03-27 20:37                 ` Ian Rogers
2026-03-27 20:37                   ` Ian Rogers
2026-03-27 20:41                   ` Ian Rogers
2026-03-27 20:41                     ` Ian Rogers
2026-03-27 21:08                   ` Arnaldo Carvalho de Melo
2026-03-27 21:08                     ` Arnaldo Carvalho de Melo
2026-03-30 18:49                     ` Arnaldo Carvalho de Melo
2026-03-30 18:49                       ` Arnaldo Carvalho de Melo
2026-04-04  5:40         ` [PATCH v3 0/8] perf libunwind multiple remote support Ian Rogers
2026-04-04  5:40           ` Ian Rogers
2026-04-04  5:40           ` [PATCH v3 1/8] perf unwind: Refactor get_entries to allow dynamic libdw/libunwind selection Ian Rogers
2026-04-04  5:40             ` Ian Rogers
2026-04-04  5:40           ` [PATCH v3 2/8] perf build loongarch: Remove reference to missing file Ian Rogers
2026-04-04  5:40             ` Ian Rogers
2026-04-04  5:40           ` [PATCH v3 3/8] tools build: Deduplicate test-libunwind for different architectures Ian Rogers
2026-04-04  5:40             ` Ian Rogers
2026-04-04  5:40           ` [PATCH v3 4/8] perf build: Be more programmatic when setting up libunwind variables Ian Rogers
2026-04-04  5:40             ` Ian Rogers
2026-04-04  5:40           ` [PATCH v3 5/8] perf unwind-libunwind: Make libunwind register reading cross platform Ian Rogers
2026-04-04  5:40             ` Ian Rogers
2026-04-04  5:40           ` [PATCH v3 6/8] perf unwind-libunwind: Move flush/finish access out of local Ian Rogers
2026-04-04  5:40             ` Ian Rogers
2026-04-04  5:40           ` [PATCH v3 7/8] perf unwind-libunwind: Remove libunwind-local Ian Rogers
2026-04-04  5:40             ` Ian Rogers
2026-04-04  5:40           ` [PATCH v3 8/8] perf unwind-libunwind: Add RISC-V libunwind support Ian Rogers
2026-04-04  5:40             ` Ian Rogers
2026-04-11  1:04           ` [PATCH v3 0/8] perf libunwind multiple remote support Ian Rogers
2026-04-11  1:04             ` Ian Rogers
2026-04-12 19:18             ` Arnaldo Carvalho de Melo
2026-04-12 19:18               ` Arnaldo Carvalho de Melo
2026-04-13  2:47               ` [PATCH v4 " Ian Rogers
2026-04-13  2:47                 ` Ian Rogers
2026-04-13  2:47                 ` [PATCH v4 1/8] perf unwind: Refactor get_entries to allow dynamic libdw/libunwind selection Ian Rogers
2026-04-13  2:47                   ` Ian Rogers
2026-04-30  3:25                   ` patchwork-bot+linux-riscv
2026-04-30  3:25                     ` patchwork-bot+linux-riscv
2026-05-01 13:40                     ` Ian Rogers
2026-05-01 13:40                       ` Ian Rogers
2026-05-05 20:42                       ` Ian Rogers
2026-05-05 20:42                         ` Ian Rogers
2026-04-13  2:47                 ` [PATCH v4 2/8] perf build loongarch: Remove reference to missing file Ian Rogers
2026-04-13  2:47                   ` Ian Rogers
2026-04-13  2:48                 ` [PATCH v4 3/8] tools build: Deduplicate test-libunwind for different architectures Ian Rogers
2026-04-13  2:48                   ` Ian Rogers
2026-04-13  2:48                 ` [PATCH v4 4/8] perf build: Be more programmatic when setting up libunwind variables Ian Rogers
2026-04-13  2:48                   ` Ian Rogers
2026-04-13  2:48                 ` [PATCH v4 5/8] perf unwind-libunwind: Make libunwind register reading cross platform Ian Rogers
2026-04-13  2:48                   ` Ian Rogers
2026-04-13  2:48                 ` [PATCH v4 6/8] perf unwind-libunwind: Move flush/finish access out of local Ian Rogers
2026-04-13  2:48                   ` Ian Rogers
2026-04-13  2:48                 ` [PATCH v4 7/8] perf unwind-libunwind: Remove libunwind-local Ian Rogers
2026-04-13  2:48                   ` Ian Rogers
2026-04-13  2:48                 ` [PATCH v4 8/8] perf unwind-libunwind: Add RISC-V libunwind support Ian Rogers
2026-04-13  2:48                   ` Ian Rogers
2026-04-13 21:01                 ` [PATCH v4 0/8] perf libunwind multiple remote support Ian Rogers
2026-04-13 21:01                   ` Ian Rogers
2026-05-13 23:31                 ` [PATCH v5 0/7] " Ian Rogers
2026-05-13 23:31                   ` Ian Rogers
2026-05-13 23:31                   ` [PATCH v5 1/7] perf unwind: Refactor get_entries to allow dynamic libdw/libunwind selection Ian Rogers
2026-05-13 23:31                     ` Ian Rogers
2026-05-15  0:12                     ` Arnaldo Carvalho de Melo
2026-05-15  0:12                       ` Arnaldo Carvalho de Melo
2026-05-13 23:31                   ` [PATCH v5 2/7] tools build: Deduplicate test-libunwind for different architectures Ian Rogers
2026-05-13 23:31                     ` Ian Rogers
2026-05-13 23:31                   ` [PATCH v5 3/7] perf build: Be more programmatic when setting up libunwind variables Ian Rogers
2026-05-13 23:31                     ` Ian Rogers
2026-05-13 23:31                   ` [PATCH v5 4/7] perf unwind-libunwind: Make libunwind register reading cross platform Ian Rogers
2026-05-13 23:31                     ` Ian Rogers
2026-05-13 23:31                   ` [PATCH v5 5/7] perf unwind-libunwind: Move flush/finish access out of local Ian Rogers
2026-05-13 23:31                     ` Ian Rogers
2026-05-13 23:31                   ` [PATCH v5 6/7] perf unwind-libunwind: Remove libunwind-local Ian Rogers
2026-05-13 23:31                     ` Ian Rogers
2026-05-13 23:31                   ` [PATCH v5 7/7] perf unwind-libunwind: Add RISC-V libunwind support Ian Rogers
2026-05-13 23:31                     ` Ian Rogers
2026-05-14 16:51                   ` [PATCH v5 0/7] perf libunwind multiple remote support Ian Rogers
2026-05-14 16:51                     ` Ian Rogers
2026-05-15  0:01                     ` Arnaldo Carvalho de Melo
2026-05-15  0:01                       ` Arnaldo Carvalho de Melo
2026-05-15  0:28                       ` Arnaldo Carvalho de Melo
2026-05-15  0:28                         ` Arnaldo Carvalho de Melo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260305221927.3237145-2-irogers@google.com \
    --to=irogers@google.com \
    --cc=9erthalion6@gmail.com \
    --cc=acme@kernel.org \
    --cc=adrian.hunter@intel.com \
    --cc=alex@ghiti.fr \
    --cc=alexander.shishkin@linux.intel.com \
    --cc=andrew.jones@oss.qualcomm.com \
    --cc=aou@eecs.berkeley.edu \
    --cc=atrajeev@linux.ibm.com \
    --cc=blakejones@google.com \
    --cc=ctshao@google.com \
    --cc=dapeng1.mi@linux.intel.com \
    --cc=howardchu95@gmail.com \
    --cc=james.clark@linaro.org \
    --cc=john.g.garry@oracle.com \
    --cc=jolsa@kernel.org \
    --cc=leo.yan@linux.dev \
    --cc=libunwind-devel@nongnu.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=linux-riscv@lists.infradead.org \
    --cc=mingo@redhat.com \
    --cc=namhyung@kernel.org \
    --cc=palmer@dabbelt.com \
    --cc=peterz@infradead.org \
    --cc=pjw@kernel.org \
    --cc=shimin.guo@skydio.com \
    --cc=tglozar@redhat.com \
    --cc=tmricht@linux.ibm.com \
    --cc=will@kernel.org \
    --cc=yuzhuo@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.