From nobody Thu Apr 9 20:26:03 2026 Received: from mail-dl1-f74.google.com (mail-dl1-f74.google.com [74.125.82.74]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 66D573624C3 for ; Thu, 5 Mar 2026 22:19:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772749183; cv=none; b=DSvVJe9cXUsSF3CvquWERui+ZCjRLb98VOq8+guosQJisV3m6jkeqvXiOKg6XTwRY3/XZBaQnobEjeH9sFb6AZ74TnRvQ0jvR7hadVvjEVpaVij3FDHIJ52Acd6Km6WKPZ4BY8dshQ52QssM2qQYkKSBfLhoba6q00JtiWoJNwM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772749183; c=relaxed/simple; bh=JyAAez58X4D2TUjK+ofESbbInKX6QnXCuE///zO5y+s=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=mKM/Hrc6IWvwl1pqezrg2AnP8Km0KdU9YF4e+SeemQkElvI4ARiA0wVw9MjHKJgLTyfg+FcQlkXividDSKeMwlocWvC1qnQ0L0Ni0CtH+GRhQU8rkxU2dyt720M2luD2rhelbijr0uUTbAcMoFc2qIl7l87m2h8hIS3shOuPbPE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Jm4zsSJE; arc=none smtp.client-ip=74.125.82.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Jm4zsSJE" Received: by mail-dl1-f74.google.com with SMTP id a92af1059eb24-128ba70cc99so1962741c88.0 for ; Thu, 05 Mar 2026 14:19:42 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1772749181; x=1773353981; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=V/5FsEHMS6n6PE3kEHPdT1dcIRmDeXw08dhLTo8bgaQ=; b=Jm4zsSJEAqnCMPUzkr0mwjTkUKqZty93EDZOJFJiRnzl0LDUPFLtzcNZJBtXwjFlf/ TGBZhbYiPm8Ah8qKTXgPKQuExihjfz3KstOPuymddOqgAX0YsqVC1neZsIKsH40mVt2L kRIFMP4D5xmbOKjLcuV2qnJA7brt6bLjLDVKi30F41xAFFOUkcr7GYMZtIgloksQk2TR Ts07pOvIvJFAEwQLG0Efguzwfh1B1NsnBlAerdhHIglhk//AvT64kEk9g8+uV7vNg+72 iQCLQ/rXtwziOrdUvOVWu1aAy4xQfsYslB4oAHfaYC7D4fa1yPAQ1bUBAbsi7yX4l0VP EJCQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772749181; x=1773353981; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=V/5FsEHMS6n6PE3kEHPdT1dcIRmDeXw08dhLTo8bgaQ=; b=pHfTl4XZ5pHGrSF18fOL8KCsFkzxxx+2N5SBzFghUWvGvw4uruemdDDbhvaeuEQWaM ScQup8XKX+j+Svj3g91gz5QmxnhPDeumNXHj3zooTII4ebNfTsRYU4hdEJ3lBnYEIk+f LTmz7lFxlpmp4lTU50ioUYj8iVfZYh6ECt30CIdkoakUTBTUzTXoHSGGGXkfjK5PmRsP i/mH6Rcf/USB/Gx97JWwFuE/a3AhTeItkwW37R6/1Xj15vXAhPVqCnTH7xnKrXzuvcZP eD/PPr3zDt/+jSlnuvzI0rC7fAa9/Vox6pN2dp5noIeX4dwPb0/G9OI4UQYT5sEklN7M qwTQ== X-Forwarded-Encrypted: i=1; AJvYcCUE6ytJZTjsNcrFdB3A95Le9D/TRInriJHjz6HJC9XPZhiMUl505B1bqLaoHYl91b9OfkO99c8A0s0JpN4=@vger.kernel.org X-Gm-Message-State: AOJu0YyNsACdDq43t9wDULgBPnQPaT819lNWw0cjTyEAdajTfup1Qc8+ I5XRgHu8bM20YVUZtngTG+JDjAYXYFH9bHKGWTN/OfOZjbjd2MZ5wfcd5+Er9vH1BuVZ56czwEH T43oxOCjbvw== X-Received: from dlbvv5.prod.google.com ([2002:a05:7022:5f05:b0:128:bb47:9b7]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7022:518:b0:127:5c54:a124 with SMTP id a92af1059eb24-128c2e8efdbmr5925c88.31.1772749181224; Thu, 05 Mar 2026 14:19:41 -0800 (PST) Date: Thu, 5 Mar 2026 14:19:20 -0800 In-Reply-To: <20260305221927.3237145-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260305221927.3237145-1-irogers@google.com> X-Mailer: git-send-email 2.53.0.473.g4a7958ca14-goog Message-ID: <20260305221927.3237145-2-irogers@google.com> Subject: [PATCH v2 1/8] perf unwind: Refactor get_entries to allow dynamic libdw/libunwind selection From: Ian Rogers 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 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 --- 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" =20 @@ -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 #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 +=3D setns.o endif =20 +perf-util-y +=3D unwind.o perf-util-$(CONFIG_LIBDW) +=3D probe-finder.o perf-util-$(CONFIG_LIBDW) +=3D dwarf-aux.o perf-util-$(CONFIG_LIBDW) +=3D 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; =20 +enum unwind_style { + + UNWIND_STYLE_UNKNOWN =3D 0, + + UNWIND_STYLE_LIBDW, + + UNWIND_STYLE_LIBUNWIND, + +}; + +#define MAX_UNWIND_STYLE (UNWIND_STYLE_LIBUNWIND + 1) + + enum a2l_style { A2L_STYLE_UNKNOWN =3D 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; =20 #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; } =20 -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-li= bunwind.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); } =20 -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 +#include +#include + +int unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, void *arg __m= aybe_unused, + struct thread *thread __maybe_unused, + struct perf_sample *data __maybe_unused, + int max_stack __maybe_unused, + bool best_effort __maybe_unused) +{ + int ret =3D 0; + +#if defined(HAVE_LIBDW_SUPPORT) || defined(HAVE_LIBUNWIND_SUPPORT) + if (symbol_conf.unwind_style[0] =3D=3D UNWIND_STYLE_UNKNOWN) { + int i =3D 0; +#ifdef HAVE_LIBDW_SUPPORT + symbol_conf.unwind_style[i++] =3D UNWIND_STYLE_LIBDW; +#endif +#ifdef HAVE_LIBUNWIND_SUPPORT + symbol_conf.unwind_style[i++] =3D UNWIND_STYLE_LIBUNWIND; +#endif + } +#endif //defined(HAVE_LIBDW_SUPPORT) || defined(HAVE_LIBUNWIND_SUPPORT) + + for (size_t i =3D 0; i < ARRAY_SIZE(symbol_conf.unwind_style); i++) { + switch (symbol_conf.unwind_style[i]) { + case UNWIND_STYLE_LIBDW: +#ifdef HAVE_LIBDW_SUPPORT + ret =3D libdw__get_entries(cb, arg, thread, data, max_stack, best_effor= t); +#endif + break; + case UNWIND_STYLE_LIBUNWIND: +#ifdef HAVE_LIBUNWIND_SUPPORT + ret =3D libunwind__get_entries(cb, arg, thread, data, max_stack, best_e= ffort); +#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 libunw= ind.\n"); +#endif + ret =3D -1; + break; + } + if (ret =3D=3D 0) + break; + } + return ret; +} + +int unwind__configure(const char *var, const char *value, void *cb __maybe= _unused) +{ + static const char * const unwind_style_names[] =3D { + [UNWIND_STYLE_LIBDW] =3D "libdw", + [UNWIND_STYLE_LIBUNWIND] =3D "libunwind", + NULL + }; + char *s, *p, *saveptr; + size_t i =3D 0; + + if (strcmp(var, "unwind.style")) + return 0; + + if (!value) + return -1; + + s =3D strdup(value); + if (!s) + return -1; + + p =3D strtok_r(s, ",", &saveptr); + while (p && i < ARRAY_SIZE(symbol_conf.unwind_style)) { + bool found =3D false; + char *q =3D strim(p); + + for (size_t j =3D UNWIND_STYLE_LIBDW; j < MAX_UNWIND_STYLE; j++) { + if (!strcasecmp(q, unwind_style_names[j])) { + symbol_conf.unwind_style[i++] =3D j; + found =3D true; + break; + } + } + if (!found) + pr_warning("Unknown unwind style: %s\n", q); + p =3D 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" =20 struct maps; +struct option; struct perf_sample; struct thread; =20 @@ -26,7 +27,9 @@ struct unwind_libunwind_ops { struct perf_sample *data, int max_stack, bool best_effort); }; =20 -#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 co= uld * 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 *ma= ps __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; -} =20 -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 */ --=20 2.53.0.473.g4a7958ca14-goog From nobody Thu Apr 9 20:26:03 2026 Received: from mail-dl1-f74.google.com (mail-dl1-f74.google.com [74.125.82.74]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6E6863630B1 for ; Thu, 5 Mar 2026 22:19:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772749185; cv=none; b=Ngyn+HOFNc/ezjWP6zwDqj1EYAC6VH0UV6C95ABy/4nJQM1OR/wFxpYGpTVAuzFhxrpS0MNsggNMZfCDhiX/OdmfdRoZ+eqspjLcwY7pVnBX6VKA+JeheQBF9+j8WWUjLRZ/Qk7JW2vABIbuqx6nOurkCXG16Dtkv/smKPgXWmI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772749185; c=relaxed/simple; bh=VmqlhdFQu366zPLEzAbt56XCnrXcl+tJEHsljQ6/V14=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=euRCb9jcD0EXsgRLCcIl30Wl5ia0JM1Y78+6SjP29v+BhkO+azttQcdnyxRm7yOmcMzqu+64bo0JsW9B2CyukKCZMvSOW2VO5zrgA/5qxnjnDm5823cq8iPbgPbciD18njbead/RSIznh/CdUPwrPC0o7jJ+NmsDv0rKX+8Y6oY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=nFoZLsGF; arc=none smtp.client-ip=74.125.82.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="nFoZLsGF" Received: by mail-dl1-f74.google.com with SMTP id a92af1059eb24-127133794b6so12436952c88.1 for ; Thu, 05 Mar 2026 14:19:44 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1772749184; x=1773353984; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=539R4WcAWVflmqEMddxOg3bYov+MI6a6nT4NY7eQniQ=; b=nFoZLsGFYB7uREj3LmZK52LhAl5ngtYAk7SjKs5zp5cBk8PlPeFC7SgZFaOhe7Nae9 fDkBDilpo7+IVWREnyKFwFkfwlFGAx9P1Le3p4XD31Xy9CcdS4HmmwUpEpjp6LCJ/5S2 6cKTf2H27qpkzgTKtJ3Z9Wyn114D4TPAVhHCGHlXAPFgvHk7exKsv+GuZcBZNush+5WA G3dPyWmZ6Z6cI4NB+t0ooOGda/ir9u4/g1FpmA+1V+ib0L1i+q67bnGWvkDbQoRUfriS KEWoxPDpsStldnCJnQhOMyNAdBA3EEzigqFm0+LIl9hTh2W1I1bvV19MfmA3lr+DAeSi D1Lg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772749184; x=1773353984; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=539R4WcAWVflmqEMddxOg3bYov+MI6a6nT4NY7eQniQ=; b=HuGlXT3fxF5AdH5CfCw56UaObNjG/wsxYsC6vfARulsYsxK84wgW4e2CEkFQ3CWvvO LfihXeJyLrDDU2H3Jxl6RT33tpG92asSQznryWCnzNIjew9hyAN8EXqHzfNUPzrcxBDi nx3VJXzzORpT4is39ANA/TH3uZvp8Ct6YV7uSGH72SGV4Trbl5NWAK8fFoeFLz19Plvc 4uTAiEbqZGNGFxFcZaTEp1+FmtsSZd3SVZehQq7xjusQJNnWyY99DQ8iAzLg8jpQKvWS LEgKObnBoz8mYC1BiXiFaWOP8I1Tqd9TJBiOF8wuLvk3jhvXrhEs/FBXxb9VNq10pEl4 Czqg== X-Forwarded-Encrypted: i=1; AJvYcCW7S2xXtc8ESGfhFlx/6b1gqYVQTjOfORivpX/XQ786yMCRa7MzyCW1G3jvRQTdyp9EnMibYYwBJhCux18=@vger.kernel.org X-Gm-Message-State: AOJu0YwPPawBGEuNstb2jyEOtvCyA64k7ID1guB83queVHQvhi6apESG g69jyARyJyhnKt4XLrOGhUILEVEwVRrVMsEa1GciTrWoN7RSOBoSErN99f4M3sLy/syqPdtX6zr YkrS7yGtCcA== X-Received: from dlbvv18.prod.google.com ([2002:a05:7022:5f12:b0:127:fa:7498]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7022:518:b0:127:5c54:a124 with SMTP id a92af1059eb24-128c2e8efdbmr5966c88.31.1772749183172; Thu, 05 Mar 2026 14:19:43 -0800 (PST) Date: Thu, 5 Mar 2026 14:19:21 -0800 In-Reply-To: <20260305221927.3237145-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260305221927.3237145-1-irogers@google.com> X-Mailer: git-send-email 2.53.0.473.g4a7958ca14-goog Message-ID: <20260305221927.3237145-3-irogers@google.com> Subject: [PATCH v2 2/8] perf build loongarch: Remove reference to missing file From: Ian Rogers 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 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The file was removed in commit e62fae9d9e85 ("perf unwind-libdw: Fix a cross-arch unwinding bug") but the Build file not updated. Fixes: commit e62fae9d9e85 ("perf unwind-libdw: Fix a cross-arch unwinding = bug") Signed-off-by: Ian Rogers --- tools/perf/arch/loongarch/util/Build | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/perf/arch/loongarch/util/Build b/tools/perf/arch/loongar= ch/util/Build index 3ad73d0289f3..8d91e78d31c9 100644 --- a/tools/perf/arch/loongarch/util/Build +++ b/tools/perf/arch/loongarch/util/Build @@ -1,4 +1,3 @@ perf-util-y +=3D header.o =20 perf-util-$(CONFIG_LOCAL_LIBUNWIND) +=3D unwind-libunwind.o -perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) +=3D unwind-libdw.o --=20 2.53.0.473.g4a7958ca14-goog From nobody Thu Apr 9 20:26:03 2026 Received: from mail-dy1-f202.google.com (mail-dy1-f202.google.com [74.125.82.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6E00B364042 for ; Thu, 5 Mar 2026 22:19:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772749187; cv=none; b=dUjvHdVTjNi3FCEH0jF5Cl2myhCAsNfq+TCJK2vI/7xjVfVFASRQV4S56JoG5DxpGmsmSc0gv8HUwPT0/Ik4ytMtNVpZBf/V28Qx95EH55lBxtrJqX8z4Jq/uR1VPkc3LW29aXNxXOJigNAMDgq3jj1R9XdzUZSj0DkvxchYVAo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772749187; c=relaxed/simple; bh=WxZb1kNqws9cW/YcMqcFf/DyHK/I3FltpaQ7tA28Nww=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=YFbuyY8iEUHDRuv3GMkBT1nUURr1xkDCc1gaZNkic3ffvJ8oZdfueUBXlJ2sQSkuaUgZ2TiV+ecH3mCdKHKBuYvPjquIj0shfUGN9ai7ePTVP+Ek9i4J4rYG7TXC1TfNPBltbpk8nfgPT4eKL23wPLRmmci2ucLtSPv6JTKeUck= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=1QOqinUr; arc=none smtp.client-ip=74.125.82.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="1QOqinUr" Received: by mail-dy1-f202.google.com with SMTP id 5a478bee46e88-2ba8013a9e3so8410297eec.0 for ; Thu, 05 Mar 2026 14:19:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1772749186; x=1773353986; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=koMggD1S7O2t84HzXzhkoa+xwVt/Yu03GNBlSsAh+a4=; b=1QOqinUrRLzU/ekTNE/p1jT8LEiM5fN24KZ3ugQHDN7MlTC0n+2ADW3+8tbE2vYTsh nEyArO4Tl9YHDNjO7t0m91xWOp5pvvsbP8INgNZdCZq4YIOrUBM5IwRDeOq2eZAHbTNh 6sE5oJVIIsfPPVQViA7s/RfX18ROUcqpvxvHlJ5VX5ZAsvs4JXNBSi6UVsWpz3n7K+hR 1acQd6G3uwnRX3sSxDizkPDk7N9nIe727Xnu5RFsa6/zgel1R5SMjut3n5yDoMotDhr7 ybUonDb0paHKOo2WiYaZQaH6v+ZJpEU95ISKrBSjySNRAN5pA7twR0dMgo72YvFTmA+r /F4w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772749186; x=1773353986; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=koMggD1S7O2t84HzXzhkoa+xwVt/Yu03GNBlSsAh+a4=; b=aM8nUdjuEoEEixYB3OQh2IGQdTcXlHG8RGrKmjjipVCwjH6huqf5Vqvr+Jel/M3WlS EwlcShSQOUaK4xMHcnnp9zJNzz2nVPKuq+B4FewaZV01J+pSv2cKZp7zdi5SJ/zWj87G bsgrzRqbRFKgQWdkZ8qoM4QARMOcUx3JzHBJNvXrlfH9HlKOVSUg6VAoI9NJmKIN6bGn S7IbfLpESQpPJdcpAoM1cxIRELpA3azRtS63dhczHJyjV4yWz3VisXEV5460UzESG7iH o/wk7e8bEQ3V20ZsJwnX6kCjknLZtx5C5Q9PKnwKsZQOy36jHq4kwQAtc05mJJoxNcdc 4awA== X-Forwarded-Encrypted: i=1; AJvYcCVI57erGdZJV7IAy94w6VBARmV6kRX/CtB8d089EkN+Ak2Watff4CUnouBk5IeIVohC3c02vkA7r4PAiTM=@vger.kernel.org X-Gm-Message-State: AOJu0YxY1yMJkJs2E0HAf2nu7FKvNuuvDTY3y7jlqyoHJMyk6seTn3p3 BDqozwD+jiduLckGD/rkoJJcGcgbyka06yQCyBaftvx/ZQxDzUrnJR+glETKPF43jkhdboVNHTl eNPqmgLHUCQ== X-Received: from dyaf18-n1.prod.google.com ([2002:a05:693c:8392:10b0:2be:48a1:a0fb]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7301:4094:b0:2b8:4a34:6c39 with SMTP id 5a478bee46e88-2be4deabf41mr22043eec.16.1772749185413; Thu, 05 Mar 2026 14:19:45 -0800 (PST) Date: Thu, 5 Mar 2026 14:19:22 -0800 In-Reply-To: <20260305221927.3237145-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260305221927.3237145-1-irogers@google.com> X-Mailer: git-send-email 2.53.0.473.g4a7958ca14-goog Message-ID: <20260305221927.3237145-4-irogers@google.com> Subject: [PATCH v2 3/8] tools build: Deduplicate test-libunwind for different architectures From: Ian Rogers 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 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The separate test files only exist to pass a different #include, instead have a single source file and pass -include to $(CC) to include the relevant header file for the architecture being tested. Generate the rules using a foreach loop. Include tests for all current libunwind architectures. Signed-off-by: Ian Rogers --- tools/build/feature/Makefile | 38 +++++++++---------- tools/build/feature/test-libunwind-aarch64.c | 27 ------------- tools/build/feature/test-libunwind-arm.c | 28 -------------- .../test-libunwind-debug-frame-aarch64.c | 17 --------- .../feature/test-libunwind-debug-frame-arm.c | 17 --------- .../feature/test-libunwind-debug-frame.c | 1 - tools/build/feature/test-libunwind-x86.c | 28 -------------- tools/build/feature/test-libunwind-x86_64.c | 28 -------------- tools/build/feature/test-libunwind.c | 1 - 9 files changed, 19 insertions(+), 166 deletions(-) delete mode 100644 tools/build/feature/test-libunwind-aarch64.c delete mode 100644 tools/build/feature/test-libunwind-arm.c delete mode 100644 tools/build/feature/test-libunwind-debug-frame-aarch64.c delete mode 100644 tools/build/feature/test-libunwind-debug-frame-arm.c delete mode 100644 tools/build/feature/test-libunwind-x86.c delete mode 100644 tools/build/feature/test-libunwind-x86_64.c diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile index 1fbcb3ce74d2..a0b40e826688 100644 --- a/tools/build/feature/Makefile +++ b/tools/build/feature/Makefile @@ -204,27 +204,27 @@ $(OUTPUT)test-numa_num_possible_cpus.bin: $(BUILD) -lnuma =20 $(OUTPUT)test-libunwind.bin: - $(BUILD) -lelf -llzma + $(BUILD) -include libunwind.h -lelf -llzma -lunwind =20 $(OUTPUT)test-libunwind-debug-frame.bin: - $(BUILD) -lelf -llzma -$(OUTPUT)test-libunwind-x86.bin: - $(BUILD) -lelf -llzma -lunwind-x86 - -$(OUTPUT)test-libunwind-x86_64.bin: - $(BUILD) -lelf -llzma -lunwind-x86_64 - -$(OUTPUT)test-libunwind-arm.bin: - $(BUILD) -lelf -llzma -lunwind-arm - -$(OUTPUT)test-libunwind-aarch64.bin: - $(BUILD) -lelf -llzma -lunwind-aarch64 - -$(OUTPUT)test-libunwind-debug-frame-arm.bin: - $(BUILD) -lelf -llzma -lunwind-arm - -$(OUTPUT)test-libunwind-debug-frame-aarch64.bin: - $(BUILD) -lelf -llzma -lunwind-aarch64 + $(BUILD) -include libunwind.h -lelf -llzma -lunwind + +LIBUNWIND_ARCHS:=3Daarch64 arm loongarch64 mips ppc32 ppc64 riscv s390x x8= 6 x86_64 +define LIBUNWIND_RULE +$$(OUTPUT)test-libunwind-$(1).bin: + $$(CC) $$(CFLAGS) -MD -Wall -Werror -include libunwind-$(1).h -o $$@ \ + test-libunwind.c $$(LDFLAGS) -lelf -llzma -lunwind-$(1) \ + > $$(@:.bin=3D.make.output) 2>&1 + +$$(OUTPUT)test-libunwind-debug-frame-$(1).bin: + $$(CC) $$(CFLAGS) -MD -Wall -Werror -include libunwind-$(1).h -o $$@ \ + test-libunwind-debug-frame.c $$(LDFLAGS) -lelf -llzma -lunwind-$(1) \ + > $$(@:.bin=3D.make.output) 2>&1 + +endef +$(foreach arch,$(LIBUNWIND_ARCHS), \ + $(eval $(call LIBUNWIND_RULE,$(arch))) \ +) =20 $(OUTPUT)test-libslang.bin: $(BUILD) -lslang diff --git a/tools/build/feature/test-libunwind-aarch64.c b/tools/build/fea= ture/test-libunwind-aarch64.c deleted file mode 100644 index 323803f49212..000000000000 --- a/tools/build/feature/test-libunwind-aarch64.c +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include - -extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, - unw_word_t ip, - unw_dyn_info_t *di, - unw_proc_info_t *pi, - int need_unwind_info, void *arg); - -#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) - -static unw_accessors_t accessors; - -int main(void) -{ - unw_addr_space_t addr_space; - - addr_space =3D unw_create_addr_space(&accessors, 0); - if (addr_space) - return 0; - - unw_init_remote(NULL, addr_space, NULL); - dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL); - - return 0; -} diff --git a/tools/build/feature/test-libunwind-arm.c b/tools/build/feature= /test-libunwind-arm.c deleted file mode 100644 index cb378b7d6866..000000000000 --- a/tools/build/feature/test-libunwind-arm.c +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include - -extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, - unw_word_t ip, - unw_dyn_info_t *di, - unw_proc_info_t *pi, - int need_unwind_info, void *arg); - - -#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) - -static unw_accessors_t accessors; - -int main(void) -{ - unw_addr_space_t addr_space; - - addr_space =3D unw_create_addr_space(&accessors, 0); - if (addr_space) - return 0; - - unw_init_remote(NULL, addr_space, NULL); - dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL); - - return 0; -} diff --git a/tools/build/feature/test-libunwind-debug-frame-aarch64.c b/too= ls/build/feature/test-libunwind-debug-frame-aarch64.c deleted file mode 100644 index 36d6646c185e..000000000000 --- a/tools/build/feature/test-libunwind-debug-frame-aarch64.c +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include - -extern int -UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug, - unw_word_t ip, unw_word_t segbase, - const char *obj_name, unw_word_t start, - unw_word_t end); - -#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) - -int main(void) -{ - dwarf_find_debug_frame(0, NULL, 0, 0, NULL, 0, 0); - return 0; -} diff --git a/tools/build/feature/test-libunwind-debug-frame-arm.c b/tools/b= uild/feature/test-libunwind-debug-frame-arm.c deleted file mode 100644 index 8696e48e1268..000000000000 --- a/tools/build/feature/test-libunwind-debug-frame-arm.c +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include - -extern int -UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug, - unw_word_t ip, unw_word_t segbase, - const char *obj_name, unw_word_t start, - unw_word_t end); - -#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) - -int main(void) -{ - dwarf_find_debug_frame(0, NULL, 0, 0, NULL, 0, 0); - return 0; -} diff --git a/tools/build/feature/test-libunwind-debug-frame.c b/tools/build= /feature/test-libunwind-debug-frame.c index efb55cdd8d01..4c57e37004b3 100644 --- a/tools/build/feature/test-libunwind-debug-frame.c +++ b/tools/build/feature/test-libunwind-debug-frame.c @@ -1,5 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#include #include =20 extern int diff --git a/tools/build/feature/test-libunwind-x86.c b/tools/build/feature= /test-libunwind-x86.c deleted file mode 100644 index e5e0f6c89637..000000000000 --- a/tools/build/feature/test-libunwind-x86.c +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include - -extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, - unw_word_t ip, - unw_dyn_info_t *di, - unw_proc_info_t *pi, - int need_unwind_info, void *arg); - - -#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) - -static unw_accessors_t accessors; - -int main(void) -{ - unw_addr_space_t addr_space; - - addr_space =3D unw_create_addr_space(&accessors, 0); - if (addr_space) - return 0; - - unw_init_remote(NULL, addr_space, NULL); - dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL); - - return 0; -} diff --git a/tools/build/feature/test-libunwind-x86_64.c b/tools/build/feat= ure/test-libunwind-x86_64.c deleted file mode 100644 index 62ae4db597dc..000000000000 --- a/tools/build/feature/test-libunwind-x86_64.c +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include - -extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, - unw_word_t ip, - unw_dyn_info_t *di, - unw_proc_info_t *pi, - int need_unwind_info, void *arg); - - -#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) - -static unw_accessors_t accessors; - -int main(void) -{ - unw_addr_space_t addr_space; - - addr_space =3D unw_create_addr_space(&accessors, 0); - if (addr_space) - return 0; - - unw_init_remote(NULL, addr_space, NULL); - dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL); - - return 0; -} diff --git a/tools/build/feature/test-libunwind.c b/tools/build/feature/tes= t-libunwind.c index 53fd26614ff0..5af5dc3a73d4 100644 --- a/tools/build/feature/test-libunwind.c +++ b/tools/build/feature/test-libunwind.c @@ -1,5 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#include #include =20 extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, --=20 2.53.0.473.g4a7958ca14-goog From nobody Thu Apr 9 20:26:03 2026 Received: from mail-dl1-f74.google.com (mail-dl1-f74.google.com [74.125.82.74]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 75EF1364044 for ; Thu, 5 Mar 2026 22:19:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772749190; cv=none; b=a/ctCRPYlS2vSpF5Ml+X5A3RDSAfn5fRtWJz5Nw5J+Pw8Jped28TXB6swq9t/yrdESEPwkwV7S01Aqm0/Yi/b5IYyrMYPeC927oL5ZAk1ACVxV09ZGQqCOq+hpOWztNHQ/htNF0vTjXjMlA9W/e5T48stmjaRgluXG3pPe27HBI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772749190; c=relaxed/simple; bh=aByzoR2ts9ih+0N9j5NApfRYrIS0PYqQcc/wzIPCpCk=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Wh3/mNWqWWfYuB6y9SMg92+peKyD5eYNkQbc1siqegOQN/ub/s9dlf9fQUaFX337lG+l1h/zgRuNa+3aHfUbvIXAMShygBRWApLe1aXot7jApmNbvfNBJQ1HEEIlMssJMHA5NW/X2Z9J8eQVCGuBms/qGW4h7j0hiFkah4tTJIE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=T9sWieM3; arc=none smtp.client-ip=74.125.82.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="T9sWieM3" Received: by mail-dl1-f74.google.com with SMTP id a92af1059eb24-12711ec96fbso5201742c88.0 for ; Thu, 05 Mar 2026 14:19:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1772749188; x=1773353988; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=enTjN37d4hARcTHIjUjR8jWWNgPDrM7ZrLy1xVh8f7c=; b=T9sWieM3Gso9RZYXUa6epDafQyBwPFLCY/uc3k4t5mExYCkI8fRy33HvebLs0+1m1S R4ebxtUKrP0Xf0Lj5inOfX3n1Zmc0q325ftjI4kupGhbKTEksj653KPCVWzoYMwOgoY9 dWEEPtYabfsmXnS7zhuepx3A+/gsUuQ0c4WVVAB9ua/482FG90PC/9jmj5yDDUi+/EL3 24TS3T93MLmhcuil5fqVauM6zDbOITBvSVNDDkVUPpV80ywPDNar9/Nyp4qGW1KnWbPr dFkgyExaYgMsaBoN298R6ydSnVYSWzL6UwlK/ReZFaS7sW1QFrOG/sgh54u//AaXBzML cHOg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772749188; x=1773353988; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=enTjN37d4hARcTHIjUjR8jWWNgPDrM7ZrLy1xVh8f7c=; b=YtBte0H/wmCjSA7FnLM0PEcQFmSyrFniTyfKAVFfXOa93y+/brM33p6jISbBCfhkKY 7/dudYHH9URnNuwjUwl1QBYkNTr0qc62/u1c1UZA+KOfjl8aewy/BaQn6Ww/Z4uRJfjl ymstuERbS2o3i5Y/4Mtt4VzO1SG8p4atNW053GxICa2CLwmaZlfkur/LoYcIAhBHKKhg GK6bao8zBltdHJwhXDTh1R21Cl9OTnM/p+UluaD5zZm9FyIC8pCcaVI35KalIbpuVKBF 9gk3/XDiKuDYZMnEmGvx+1Ft7NxHNbJlhS5UOA9N3e7Khc9Hpib45DVeP7Xh9OT9ywXF J32g== X-Forwarded-Encrypted: i=1; AJvYcCX0bJHl7f82HLHvluMaLBjX2fDUP/DU6JHSPF+DX6PcK7gQf33e+tB/G6h2Chn7jpSerPG+rKTRL9HY9HA=@vger.kernel.org X-Gm-Message-State: AOJu0YyPQKOWfeJFSW7cm+HHPdpEEthxHRGqrkFU5DpNAsfDCKvn+7Gt rC6wmghwqJDOSt+GK/ouf1gNkJoTuMcj1pEC7EOhHXcyGDbgEwn6zBksvnf+TMyPBjFAgeC2o0e PBG5XzlWk6Q== X-Received: from dyx5.prod.google.com ([2002:a05:693c:8205:b0:2bd:f73f:2b3]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7022:427:b0:124:9ae7:b2df with SMTP id a92af1059eb24-128c2ecce39mr3060c88.44.1772749187504; Thu, 05 Mar 2026 14:19:47 -0800 (PST) Date: Thu, 5 Mar 2026 14:19:23 -0800 In-Reply-To: <20260305221927.3237145-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260305221927.3237145-1-irogers@google.com> X-Mailer: git-send-email 2.53.0.473.g4a7958ca14-goog Message-ID: <20260305221927.3237145-5-irogers@google.com> Subject: [PATCH v2 4/8] perf build: Be more programmatic when setting up libunwind variables From: Ian Rogers 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 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Iterate LIBUNWIND_ARCHS when setting up CONFIG_ and HAVE_ definitions rather than treating each architecture individually. This sets up the libunwind build variables and C definitions beyond x86 and arm/aarch64. The existing naming convention is followed for compatibility. Signed-off-by: Ian Rogers --- tools/perf/Makefile.config | 215 +++++++++++++++---------------------- 1 file changed, 89 insertions(+), 126 deletions(-) diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index a8dc72cfe48e..f38213ecce08 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -65,95 +65,83 @@ $(call detected_var,SRCARCH) =20 CFLAGS +=3D -I$(OUTPUT)arch/$(SRCARCH)/include/generated =20 -# Additional ARCH settings for ppc -ifeq ($(SRCARCH),powerpc) - ifndef NO_LIBUNWIND - LIBUNWIND_LIBS :=3D -lunwind -lunwind-ppc64 - endif -endif - # Additional ARCH settings for x86 ifeq ($(SRCARCH),x86) $(call detected,CONFIG_X86) ifeq (${IS_64_BIT}, 1) CFLAGS +=3D -DHAVE_ARCH_X86_64_SUPPORT ARCH_INCLUDE =3D ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/mem= set_64.S - ifndef NO_LIBUNWIND - LIBUNWIND_LIBS =3D -lunwind-x86_64 -lunwind -llzma - endif $(call detected,CONFIG_X86_64) - else - ifndef NO_LIBUNWIND - LIBUNWIND_LIBS =3D -lunwind-x86 -llzma -lunwind - endif endif endif =20 -ifeq ($(SRCARCH),arm) - ifndef NO_LIBUNWIND - LIBUNWIND_LIBS =3D -lunwind -lunwind-arm - endif +ifeq ($(ARCH),s390) + CFLAGS +=3D -fPIC endif =20 -ifeq ($(SRCARCH),arm64) - ifndef NO_LIBUNWIND - LIBUNWIND_LIBS =3D -lunwind -lunwind-aarch64 - endif +ifneq ($(LIBUNWIND),1) + NO_LIBUNWIND :=3D 1 endif =20 -ifeq ($(SRCARCH),loongarch) - ifndef NO_LIBUNWIND +ifndef NO_LIBUNWIND + ifeq ($(SRCARCH),arm) + LIBUNWIND_LIBS =3D -lunwind -lunwind-arm + endif + ifeq ($(SRCARCH),arm64) + LIBUNWIND_LIBS =3D -lunwind -lunwind-aarch64 + endif + ifeq ($(SRCARCH),loongarch) LIBUNWIND_LIBS =3D -lunwind -lunwind-loongarch64 endif -endif - -ifeq ($(ARCH),s390) - CFLAGS +=3D -fPIC -endif - -ifeq ($(ARCH),mips) - ifndef NO_LIBUNWIND + ifeq ($(ARCH),mips) LIBUNWIND_LIBS =3D -lunwind -lunwind-mips endif + ifeq ($(SRCARCH),powerpc) + LIBUNWIND_LIBS :=3D -lunwind -lunwind-ppc64 + endif + ifeq ($(SRCARCH),riscv) + LIBUNWIND_LIBS :=3D -lunwind -lunwind-riscv + endif + ifeq ($(SRCARCH),s390) + LIBUNWIND_LIBS :=3D -lunwind -lunwind-s390x + endif + ifeq ($(SRCARCH),x86) + ifeq (${IS_64_BIT}, 1) + LIBUNWIND_LIBS =3D -lunwind-x86_64 -lunwind -llzma + else + LIBUNWIND_LIBS =3D -lunwind-x86 -lunwind -llzma + endif + endif + ifeq ($(LIBUNWIND_LIBS),) + NO_LIBUNWIND :=3D 1 + endif endif =20 -ifneq ($(LIBUNWIND),1) - NO_LIBUNWIND :=3D 1 -endif - -ifeq ($(LIBUNWIND_LIBS),) - NO_LIBUNWIND :=3D 1 -endif # # For linking with debug library, run like: # # make DEBUG=3D1 LIBUNWIND_DIR=3D/opt/libunwind/ # - -libunwind_arch_set_flags =3D $(eval $(libunwind_arch_set_flags_code)) -define libunwind_arch_set_flags_code - FEATURE_CHECK_CFLAGS-libunwind-$(1) =3D -I$(LIBUNWIND_DIR)/include - FEATURE_CHECK_LDFLAGS-libunwind-$(1) =3D -L$(LIBUNWIND_DIR)/lib -endef - -ifdef LIBUNWIND_DIR - LIBUNWIND_CFLAGS =3D -I$(LIBUNWIND_DIR)/include - LIBUNWIND_LDFLAGS =3D -L$(LIBUNWIND_DIR)/lib - LIBUNWIND_ARCHS =3D x86 x86_64 arm aarch64 debug-frame-arm debug-frame-a= arch64 loongarch - $(foreach libunwind_arch,$(LIBUNWIND_ARCHS),$(call libunwind_arch_set_fl= ags,$(libunwind_arch))) -endif +LIBUNWIND_ARCHS:=3Daarch64 arm loongarch64 mips ppc32 ppc64 riscv s390x x8= 6 x86_64 =20 ifndef NO_LIBUNWIND - # Set per-feature check compilation flags FEATURE_CHECK_CFLAGS-libunwind =3D $(LIBUNWIND_CFLAGS) FEATURE_CHECK_LDFLAGS-libunwind =3D $(LIBUNWIND_LDFLAGS) $(LIBUNWIND_LIB= S) FEATURE_CHECK_CFLAGS-libunwind-debug-frame =3D $(LIBUNWIND_CFLAGS) FEATURE_CHECK_LDFLAGS-libunwind-debug-frame =3D $(LIBUNWIND_LDFLAGS) $(L= IBUNWIND_LIBS) - =20 - FEATURE_CHECK_LDFLAGS-libunwind-arm +=3D -lunwind -lunwind-arm - FEATURE_CHECK_LDFLAGS-libunwind-aarch64 +=3D -lunwind -lunwind-aarch64 - FEATURE_CHECK_LDFLAGS-libunwind-x86 +=3D -lunwind -llzma -lunwind-x86 - FEATURE_CHECK_LDFLAGS-libunwind-x86_64 +=3D -lunwind -llzma -lunwind-x86= _64 + + ifdef LIBUNWIND_DIR + LIBUNWIND_CFLAGS =3D -I$(LIBUNWIND_DIR)/include + LIBUNWIND_LDFLAGS =3D -L$(LIBUNWIND_DIR)/lib + + define libunwind_arch_set_flags + FEATURE_CHECK_CFLAGS-libunwind-$(1) =3D -I$(LIBUNWIND_DIR)/include + FEATURE_CHECK_LDFLAGS-libunwind-$(1) =3D -L$(LIBUNWIND_DIR)/lib + endef + $(foreach arch,$(LIBUNWIND_ARCHS), \ + $(eval $(call libunwind_arch_set_flags,$(arch))) \ + ) + endif endif =20 ifdef CSINCLUDES @@ -637,49 +625,6 @@ ifeq ($(SRCARCH),powerpc) endif endif =20 -ifndef NO_LIBUNWIND - have_libunwind :=3D - - $(call feature_check,libunwind) - - $(call feature_check,libunwind-x86) - ifeq ($(feature-libunwind-x86), 1) - $(call detected,CONFIG_LIBUNWIND_X86) - CFLAGS +=3D -DHAVE_LIBUNWIND_X86_SUPPORT - LDFLAGS +=3D -lunwind-x86 - EXTLIBS_LIBUNWIND +=3D -lunwind-x86 - have_libunwind =3D 1 - endif - - $(call feature_check,libunwind-aarch64) - ifeq ($(feature-libunwind-aarch64), 1) - $(call detected,CONFIG_LIBUNWIND_AARCH64) - CFLAGS +=3D -DHAVE_LIBUNWIND_AARCH64_SUPPORT - LDFLAGS +=3D -lunwind-aarch64 - EXTLIBS_LIBUNWIND +=3D -lunwind-aarch64 - have_libunwind =3D 1 - $(call feature_check,libunwind-debug-frame-aarch64) - ifneq ($(feature-libunwind-debug-frame-aarch64), 1) - $(warning No debug_frame support found in libunwind-aarch64) - CFLAGS +=3D -DNO_LIBUNWIND_DEBUG_FRAME_AARCH64 - endif - endif - - ifneq ($(feature-libunwind), 1) - $(warning No libunwind found. Please install libunwind-dev[el] >=3D 1.= 1 and/or set LIBUNWIND_DIR and set LIBUNWIND=3D1 in the make command line a= s it is opt-in now) - NO_LOCAL_LIBUNWIND :=3D 1 - else - have_libunwind :=3D 1 - $(call detected,CONFIG_LOCAL_LIBUNWIND) - endif - - ifneq ($(have_libunwind), 1) - NO_LIBUNWIND :=3D 1 - endif -else - NO_LOCAL_LIBUNWIND :=3D 1 -endif - ifndef NO_LIBBPF ifneq ($(feature-bpf), 1) $(warning BPF API too old. Please install recent kernel headers. BPF s= upport in 'perf record' is disabled.) @@ -738,6 +683,49 @@ ifndef GEN_VMLINUX_H VMLINUX_H=3D$(src-perf)/util/bpf_skel/vmlinux/vmlinux.h endif =20 +ifndef NO_LIBUNWIND + have_libunwind :=3D + + $(call feature_check,libunwind) + ifneq ($(feature-libunwind), 1) + $(warning No libunwind found. Please install libunwind-dev[el] >=3D 1.= 1 and/or set LIBUNWIND_DIR and set LIBUNWIND=3D1 in the make command line a= s it is opt-in now) + NO_LOCAL_LIBUNWIND :=3D 1 + else + have_libunwind :=3D 1 + $(call detected,CONFIG_LOCAL_LIBUNWIND) + CFLAGS +=3D -DHAVE_LIBUNWIND_SUPPORT + CFLAGS +=3D $(LIBUNWIND_CFLAGS) + LDFLAGS +=3D $(LIBUNWIND_LDFLAGS) + EXTLIBS +=3D $(EXTLIBS_LIBUNWIND) + $(call feature_check,libunwind-debug-frame) + ifneq ($(feature-libunwind-debug-frame), 1) + CFLAGS +=3D -DNO_LIBUNWIND_DEBUG_FRAME + endif + endif + + define PROCESS_REMOTE_LIBUNWIND_ARCH + $(call feature_check,libunwind-$(1)) + + ifeq ($$(feature-libunwind-$(1)), 1) + upper_arch :=3D $$(shell echo $(1) | tr '[:lower:]' '[:upper:]') + $$(call detected,CONFIG_LIBUNWIND_$$(upper_arch)) + + CFLAGS +=3D -DHAVE_LIBUNWIND_$$(upper_arch)_SUPPORT + LDFLAGS +=3D -lunwind-$(1) + EXTLIBS_LIBUNWIND +=3D -lunwind-$(1) + have_libunwind :=3D 1 + + $$(call feature_check,libunwind-debug-frame-$(1)) + ifneq ($$(feature-libunwind-debug-frame-$(1)), 1) + CFLAGS +=3D -DNO_LIBUNWIND_DEBUG_FRAME_$$(upper_arch) + endif + endif + endef + $(foreach arch,$(LIBUNWIND_ARCHS), \ + $(eval $(call PROCESS_REMOTE_LIBUNWIND_ARCH,$(arch))) \ + ) +endif + dwarf-post-unwind :=3D 1 dwarf-post-unwind-text :=3D BUG =20 @@ -760,31 +748,6 @@ ifeq ($(dwarf-post-unwind),1) $(call detected,CONFIG_DWARF_UNWIND) endif =20 -ifndef NO_LIBUNWIND - ifndef NO_LOCAL_LIBUNWIND - ifeq ($(SRCARCH),$(filter $(SRCARCH),arm arm64)) - $(call feature_check,libunwind-debug-frame) - ifneq ($(feature-libunwind-debug-frame), 1) - $(warning No debug_frame support found in libunwind) - CFLAGS +=3D -DNO_LIBUNWIND_DEBUG_FRAME - endif - else - # non-ARM has no dwarf_find_debug_frame() function: - CFLAGS +=3D -DNO_LIBUNWIND_DEBUG_FRAME - endif - EXTLIBS +=3D $(LIBUNWIND_LIBS) - LDFLAGS +=3D $(LIBUNWIND_LIBS) - endif - ifeq ($(findstring -static,${LDFLAGS}),-static) - # gcc -static links libgcc_eh which contans piece of libunwind - LIBUNWIND_LDFLAGS +=3D -Wl,--allow-multiple-definition - endif - CFLAGS +=3D -DHAVE_LIBUNWIND_SUPPORT - CFLAGS +=3D $(LIBUNWIND_CFLAGS) - LDFLAGS +=3D $(LIBUNWIND_LDFLAGS) - EXTLIBS +=3D $(EXTLIBS_LIBUNWIND) -endif - ifneq ($(NO_LIBTRACEEVENT),1) $(call detected,CONFIG_TRACE) endif --=20 2.53.0.473.g4a7958ca14-goog From nobody Thu Apr 9 20:26:03 2026 Received: from mail-dl1-f74.google.com (mail-dl1-f74.google.com [74.125.82.74]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 955EE361665 for ; Thu, 5 Mar 2026 22:19:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772749193; cv=none; b=VI7vFUk4XBwgpXluhXFVJSiHlcn3MOh809pEj1Ey8ILhAHzT0/Ut2zKZEZfkKIME3vdCIgEYVPOIczWEtwtLAXARuE7aonj2khU1wi2KCNj/Vl6WjRLFV4/E7nFqD215qNEPeOqPIEy3TUuagzcafNCLgVpwiR6J9H4C4tglbUY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772749193; c=relaxed/simple; bh=OOjFVkrI/fOHnOf04LL6t4OugB24FJrxvR8edC/o/mY=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=o/270MthQchvmk8XX19JdAJjkDnKDgPfIPn00UzpukEruUEGphBavU1ceNWEnWoUg5MSKn6hOiMGd0HoP9X0BGlz1/QqvVvQPRmtM/kA1xFxTKThtRA75DL7m0VCQ5YrAm03vh5UbUk8ZJVl8qS1MkAJxyQSyJ7NNZbzOWicM3g= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=TYR7x5BC; arc=none smtp.client-ip=74.125.82.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="TYR7x5BC" Received: by mail-dl1-f74.google.com with SMTP id a92af1059eb24-1270dcd11c1so11541031c88.0 for ; Thu, 05 Mar 2026 14:19:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1772749190; x=1773353990; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=MvLOjcuvObtYy4srf5ve0JpIVK/JZL2gNx7DyGOF3u0=; b=TYR7x5BC9caZuoKrguuwp6Mqd1cZtOBMf7ROhArKC3rx18rv7Y7Rrp0mwGwQMhX6Hx vcTLjRfaqUFLTKqJ376aLQanYWAVk2/RjENDNUjPH/5rroRVC6bcqzOla72rGioYVkCw tVoa+b7pvMAxAA+20KhGwf7+xDHQl29MqBkIWzrCgW7jCZkbmEXGR6ps+VHtVug2uZnH 4sxpqDAtwQNH1AnG+KvMUnT9v/p15ivepr9TTwV8tMx+5x2UIQ3G8ITvzX/wcYxl5jmn p2hJ0xrkL73Ef8D52/E763VcBDVF/YbLv7Jy0YSbOnEc6XOIoA25S79yZejY6r5YlW28 5FQw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772749190; x=1773353990; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=MvLOjcuvObtYy4srf5ve0JpIVK/JZL2gNx7DyGOF3u0=; b=N5mqSz9qhQfNuFmhJ/tlvWOf0GK76mnJglaOO4stLq+LUWz1tUe8UsNWrpqkUBgxgr h9JYduDPrgOBpSNTnwTKLeCNY3jZMgbXuZ7pvwIMPQFnZ9MHez0bcsI/HPRYbQA/ys3G lZOAvKyDY57stocyDy/T9f0SziTe6h75c/R9LAd/JtxDMkPPlKv5FeHSYivqM641xFLD UDz2ynp6DsoS5KA5XTJZOhW0cIZEqH4LnSvUdBheukW8F8uKkyBKAT3xiAxUDX0zaHb8 WV3gYrDWGGw7DDkl0nZaA/js94Bmt72T5TvAuqiJphm1j7oF2r/X5+WIWJyMcHeo/Fwa cd6g== X-Forwarded-Encrypted: i=1; AJvYcCXK1Jr0PbEFsVHqKVKPzjR+/i/w91+ZXT4tN7ZTIPLneNb/3Vbc4wAiEN33JFFbWvvhut6Y4A71/iWPvok=@vger.kernel.org X-Gm-Message-State: AOJu0YxvBOQSscbamAlcj2B68bPa6mSLEKSAC2pXD6++XJP5KBjCkcyC R7rzGQMyBMaupLgbeWGa9nFA6R7q3VKBH8ecQR+VCAYRkOKFwbLJaMc215nCrDLHA3JVCw6ZtEL 8K7eP2IKfAg== X-Received: from dlbur22-n1.prod.google.com ([2002:a05:7022:ea56:10b0:127:8b1c:2126]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7022:6283:b0:119:e56b:98ab with SMTP id a92af1059eb24-128c2e22452mr10605c88.18.1772749189740; Thu, 05 Mar 2026 14:19:49 -0800 (PST) Date: Thu, 5 Mar 2026 14:19:24 -0800 In-Reply-To: <20260305221927.3237145-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260305221927.3237145-1-irogers@google.com> X-Mailer: git-send-email 2.53.0.473.g4a7958ca14-goog Message-ID: <20260305221927.3237145-6-irogers@google.com> Subject: [PATCH v2 5/8] perf unwind-libunwind: Make libunwind register reading cross platform From: Ian Rogers 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 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Move the libunwind register to perf register mapping functions in arch/../util/unwind-libunwind.c into a new libunwind-arch directory. Rename the functions to __get_perf_regnum_for_unw_regnum_. Add untested ppc32 and s390 functions. Add a get_perf_regnum_for_unw_regnum function that takes an ELF machine as well as a register number and chooses the appropriate architecture implementation. Split the x86 and powerpc 32 and 64-bit implementations apart so that a single libunwind-.h header is included. Move the e_machine into the unwind_info struct to make it easier to pass. Signed-off-by: Ian Rogers --- tools/perf/arch/arm/util/Build | 2 - tools/perf/arch/arm/util/unwind-libunwind.c | 50 -------- tools/perf/arch/arm64/util/Build | 1 - tools/perf/arch/arm64/util/unwind-libunwind.c | 17 --- tools/perf/arch/loongarch/util/Build | 2 - .../arch/loongarch/util/unwind-libunwind.c | 82 ------------- tools/perf/arch/mips/Build | 1 - tools/perf/arch/mips/util/Build | 1 - tools/perf/arch/mips/util/unwind-libunwind.c | 22 ---- tools/perf/arch/powerpc/util/Build | 1 - .../perf/arch/powerpc/util/unwind-libunwind.c | 92 -------------- tools/perf/arch/x86/util/Build | 3 - tools/perf/arch/x86/util/unwind-libunwind.c | 115 ------------------ tools/perf/util/Build | 1 + tools/perf/util/libunwind-arch/Build | 10 ++ .../perf/util/libunwind-arch/libunwind-arch.c | 32 +++++ .../perf/util/libunwind-arch/libunwind-arch.h | 16 +++ .../perf/util/libunwind-arch/libunwind-arm.c | 15 +++ .../util/libunwind-arch/libunwind-arm64.c | 14 +++ .../perf/util/libunwind-arch/libunwind-i386.c | 43 +++++++ .../util/libunwind-arch/libunwind-loongarch.c | 27 ++++ .../perf/util/libunwind-arch/libunwind-mips.c | 29 +++++ .../util/libunwind-arch/libunwind-ppc32.c | 31 +++++ .../util/libunwind-arch/libunwind-ppc64.c | 33 +++++ .../perf/util/libunwind-arch/libunwind-s390.c | 29 +++++ .../util/libunwind-arch/libunwind-x86_64.c | 52 ++++++++ tools/perf/util/libunwind/arm64.c | 5 - tools/perf/util/libunwind/x86_32.c | 12 -- tools/perf/util/unwind-libunwind-local.c | 12 +- tools/perf/util/unwind.h | 5 - 30 files changed, 338 insertions(+), 417 deletions(-) delete mode 100644 tools/perf/arch/arm/util/unwind-libunwind.c delete mode 100644 tools/perf/arch/arm64/util/unwind-libunwind.c delete mode 100644 tools/perf/arch/loongarch/util/unwind-libunwind.c delete mode 100644 tools/perf/arch/mips/Build delete mode 100644 tools/perf/arch/mips/util/Build delete mode 100644 tools/perf/arch/mips/util/unwind-libunwind.c delete mode 100644 tools/perf/arch/powerpc/util/unwind-libunwind.c delete mode 100644 tools/perf/arch/x86/util/unwind-libunwind.c create mode 100644 tools/perf/util/libunwind-arch/Build create mode 100644 tools/perf/util/libunwind-arch/libunwind-arch.c create mode 100644 tools/perf/util/libunwind-arch/libunwind-arch.h create mode 100644 tools/perf/util/libunwind-arch/libunwind-arm.c create mode 100644 tools/perf/util/libunwind-arch/libunwind-arm64.c create mode 100644 tools/perf/util/libunwind-arch/libunwind-i386.c create mode 100644 tools/perf/util/libunwind-arch/libunwind-loongarch.c create mode 100644 tools/perf/util/libunwind-arch/libunwind-mips.c create mode 100644 tools/perf/util/libunwind-arch/libunwind-ppc32.c create mode 100644 tools/perf/util/libunwind-arch/libunwind-ppc64.c create mode 100644 tools/perf/util/libunwind-arch/libunwind-s390.c create mode 100644 tools/perf/util/libunwind-arch/libunwind-x86_64.c diff --git a/tools/perf/arch/arm/util/Build b/tools/perf/arch/arm/util/Build index b94bf3c5279a..768ae5d16553 100644 --- a/tools/perf/arch/arm/util/Build +++ b/tools/perf/arch/arm/util/Build @@ -1,3 +1 @@ -perf-util-$(CONFIG_LOCAL_LIBUNWIND) +=3D unwind-libunwind.o - perf-util-y +=3D pmu.o auxtrace.o cs-etm.o diff --git a/tools/perf/arch/arm/util/unwind-libunwind.c b/tools/perf/arch/= arm/util/unwind-libunwind.c deleted file mode 100644 index 438906bf0014..000000000000 --- a/tools/perf/arch/arm/util/unwind-libunwind.c +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include -#include -#include "perf_regs.h" -#include "../../../util/unwind.h" -#include "../../../util/debug.h" - -int libunwind__arch_reg_id(int regnum) -{ - switch (regnum) { - case UNW_ARM_R0: - return PERF_REG_ARM_R0; - case UNW_ARM_R1: - return PERF_REG_ARM_R1; - case UNW_ARM_R2: - return PERF_REG_ARM_R2; - case UNW_ARM_R3: - return PERF_REG_ARM_R3; - case UNW_ARM_R4: - return PERF_REG_ARM_R4; - case UNW_ARM_R5: - return PERF_REG_ARM_R5; - case UNW_ARM_R6: - return PERF_REG_ARM_R6; - case UNW_ARM_R7: - return PERF_REG_ARM_R7; - case UNW_ARM_R8: - return PERF_REG_ARM_R8; - case UNW_ARM_R9: - return PERF_REG_ARM_R9; - case UNW_ARM_R10: - return PERF_REG_ARM_R10; - case UNW_ARM_R11: - return PERF_REG_ARM_FP; - case UNW_ARM_R12: - return PERF_REG_ARM_IP; - case UNW_ARM_R13: - return PERF_REG_ARM_SP; - case UNW_ARM_R14: - return PERF_REG_ARM_LR; - case UNW_ARM_R15: - return PERF_REG_ARM_PC; - default: - pr_err("unwind: invalid reg id %d\n", regnum); - return -EINVAL; - } - - return -EINVAL; -} diff --git a/tools/perf/arch/arm64/util/Build b/tools/perf/arch/arm64/util/= Build index 4e06a08d281a..4b70c4788c80 100644 --- a/tools/perf/arch/arm64/util/Build +++ b/tools/perf/arch/arm64/util/Build @@ -1,4 +1,3 @@ -perf-util-$(CONFIG_LOCAL_LIBUNWIND) +=3D unwind-libunwind.o perf-util-y +=3D ../../arm/util/auxtrace.o perf-util-y +=3D ../../arm/util/cs-etm.o perf-util-y +=3D ../../arm/util/pmu.o diff --git a/tools/perf/arch/arm64/util/unwind-libunwind.c b/tools/perf/arc= h/arm64/util/unwind-libunwind.c deleted file mode 100644 index 871af5992298..000000000000 --- a/tools/perf/arch/arm64/util/unwind-libunwind.c +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include - -#ifndef REMOTE_UNWIND_LIBUNWIND -#include -#include "perf_regs.h" -#include "../../../util/unwind.h" -#endif -#include "../../../util/debug.h" - -int LIBUNWIND__ARCH_REG_ID(int regnum) -{ - if (regnum < 0 || regnum >=3D PERF_REG_ARM64_EXTENDED_MAX) - return -EINVAL; - - return regnum; -} diff --git a/tools/perf/arch/loongarch/util/Build b/tools/perf/arch/loongar= ch/util/Build index 8d91e78d31c9..2328fb9a30a3 100644 --- a/tools/perf/arch/loongarch/util/Build +++ b/tools/perf/arch/loongarch/util/Build @@ -1,3 +1 @@ perf-util-y +=3D header.o - -perf-util-$(CONFIG_LOCAL_LIBUNWIND) +=3D unwind-libunwind.o diff --git a/tools/perf/arch/loongarch/util/unwind-libunwind.c b/tools/perf= /arch/loongarch/util/unwind-libunwind.c deleted file mode 100644 index f693167b86ef..000000000000 --- a/tools/perf/arch/loongarch/util/unwind-libunwind.c +++ /dev/null @@ -1,82 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include -#include -#include "perf_regs.h" -#include "../../util/unwind.h" -#include "util/debug.h" - -int libunwind__arch_reg_id(int regnum) -{ - switch (regnum) { - case UNW_LOONGARCH64_R1: - return PERF_REG_LOONGARCH_R1; - case UNW_LOONGARCH64_R2: - return PERF_REG_LOONGARCH_R2; - case UNW_LOONGARCH64_R3: - return PERF_REG_LOONGARCH_R3; - case UNW_LOONGARCH64_R4: - return PERF_REG_LOONGARCH_R4; - case UNW_LOONGARCH64_R5: - return PERF_REG_LOONGARCH_R5; - case UNW_LOONGARCH64_R6: - return PERF_REG_LOONGARCH_R6; - case UNW_LOONGARCH64_R7: - return PERF_REG_LOONGARCH_R7; - case UNW_LOONGARCH64_R8: - return PERF_REG_LOONGARCH_R8; - case UNW_LOONGARCH64_R9: - return PERF_REG_LOONGARCH_R9; - case UNW_LOONGARCH64_R10: - return PERF_REG_LOONGARCH_R10; - case UNW_LOONGARCH64_R11: - return PERF_REG_LOONGARCH_R11; - case UNW_LOONGARCH64_R12: - return PERF_REG_LOONGARCH_R12; - case UNW_LOONGARCH64_R13: - return PERF_REG_LOONGARCH_R13; - case UNW_LOONGARCH64_R14: - return PERF_REG_LOONGARCH_R14; - case UNW_LOONGARCH64_R15: - return PERF_REG_LOONGARCH_R15; - case UNW_LOONGARCH64_R16: - return PERF_REG_LOONGARCH_R16; - case UNW_LOONGARCH64_R17: - return PERF_REG_LOONGARCH_R17; - case UNW_LOONGARCH64_R18: - return PERF_REG_LOONGARCH_R18; - case UNW_LOONGARCH64_R19: - return PERF_REG_LOONGARCH_R19; - case UNW_LOONGARCH64_R20: - return PERF_REG_LOONGARCH_R20; - case UNW_LOONGARCH64_R21: - return PERF_REG_LOONGARCH_R21; - case UNW_LOONGARCH64_R22: - return PERF_REG_LOONGARCH_R22; - case UNW_LOONGARCH64_R23: - return PERF_REG_LOONGARCH_R23; - case UNW_LOONGARCH64_R24: - return PERF_REG_LOONGARCH_R24; - case UNW_LOONGARCH64_R25: - return PERF_REG_LOONGARCH_R25; - case UNW_LOONGARCH64_R26: - return PERF_REG_LOONGARCH_R26; - case UNW_LOONGARCH64_R27: - return PERF_REG_LOONGARCH_R27; - case UNW_LOONGARCH64_R28: - return PERF_REG_LOONGARCH_R28; - case UNW_LOONGARCH64_R29: - return PERF_REG_LOONGARCH_R29; - case UNW_LOONGARCH64_R30: - return PERF_REG_LOONGARCH_R30; - case UNW_LOONGARCH64_R31: - return PERF_REG_LOONGARCH_R31; - case UNW_LOONGARCH64_PC: - return PERF_REG_LOONGARCH_PC; - default: - pr_err("unwind: invalid reg id %d\n", regnum); - return -EINVAL; - } - - return -EINVAL; -} diff --git a/tools/perf/arch/mips/Build b/tools/perf/arch/mips/Build deleted file mode 100644 index e63eabc2c8f4..000000000000 --- a/tools/perf/arch/mips/Build +++ /dev/null @@ -1 +0,0 @@ -perf-util-y +=3D util/ diff --git a/tools/perf/arch/mips/util/Build b/tools/perf/arch/mips/util/Bu= ild deleted file mode 100644 index 818b808a8247..000000000000 --- a/tools/perf/arch/mips/util/Build +++ /dev/null @@ -1 +0,0 @@ -perf-util-$(CONFIG_LOCAL_LIBUNWIND) +=3D unwind-libunwind.o diff --git a/tools/perf/arch/mips/util/unwind-libunwind.c b/tools/perf/arch= /mips/util/unwind-libunwind.c deleted file mode 100644 index 0d8c99c29da6..000000000000 --- a/tools/perf/arch/mips/util/unwind-libunwind.c +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include -#include -#include "perf_regs.h" -#include "../../util/unwind.h" -#include "util/debug.h" - -int libunwind__arch_reg_id(int regnum) -{ - switch (regnum) { - case UNW_MIPS_R1 ... UNW_MIPS_R25: - return regnum - UNW_MIPS_R1 + PERF_REG_MIPS_R1; - case UNW_MIPS_R28 ... UNW_MIPS_R31: - return regnum - UNW_MIPS_R28 + PERF_REG_MIPS_R28; - case UNW_MIPS_PC: - return PERF_REG_MIPS_PC; - default: - pr_err("unwind: invalid reg id %d\n", regnum); - return -EINVAL; - } -} diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/u= til/Build index d66574cbb9a9..ae928050e07a 100644 --- a/tools/perf/arch/powerpc/util/Build +++ b/tools/perf/arch/powerpc/util/Build @@ -6,5 +6,4 @@ perf-util-y +=3D evsel.o =20 perf-util-$(CONFIG_LIBDW) +=3D skip-callchain-idx.o =20 -perf-util-$(CONFIG_LIBUNWIND) +=3D unwind-libunwind.o perf-util-y +=3D auxtrace.o diff --git a/tools/perf/arch/powerpc/util/unwind-libunwind.c b/tools/perf/a= rch/powerpc/util/unwind-libunwind.c deleted file mode 100644 index 90a6beda20de..000000000000 --- a/tools/perf/arch/powerpc/util/unwind-libunwind.c +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright 2016 Chandan Kumar, IBM Corporation. - */ - -#include -#include -#include -#include "../../util/unwind.h" -#include "../../util/debug.h" - -int libunwind__arch_reg_id(int regnum) -{ - switch (regnum) { - case UNW_PPC64_R0: - return PERF_REG_POWERPC_R0; - case UNW_PPC64_R1: - return PERF_REG_POWERPC_R1; - case UNW_PPC64_R2: - return PERF_REG_POWERPC_R2; - case UNW_PPC64_R3: - return PERF_REG_POWERPC_R3; - case UNW_PPC64_R4: - return PERF_REG_POWERPC_R4; - case UNW_PPC64_R5: - return PERF_REG_POWERPC_R5; - case UNW_PPC64_R6: - return PERF_REG_POWERPC_R6; - case UNW_PPC64_R7: - return PERF_REG_POWERPC_R7; - case UNW_PPC64_R8: - return PERF_REG_POWERPC_R8; - case UNW_PPC64_R9: - return PERF_REG_POWERPC_R9; - case UNW_PPC64_R10: - return PERF_REG_POWERPC_R10; - case UNW_PPC64_R11: - return PERF_REG_POWERPC_R11; - case UNW_PPC64_R12: - return PERF_REG_POWERPC_R12; - case UNW_PPC64_R13: - return PERF_REG_POWERPC_R13; - case UNW_PPC64_R14: - return PERF_REG_POWERPC_R14; - case UNW_PPC64_R15: - return PERF_REG_POWERPC_R15; - case UNW_PPC64_R16: - return PERF_REG_POWERPC_R16; - case UNW_PPC64_R17: - return PERF_REG_POWERPC_R17; - case UNW_PPC64_R18: - return PERF_REG_POWERPC_R18; - case UNW_PPC64_R19: - return PERF_REG_POWERPC_R19; - case UNW_PPC64_R20: - return PERF_REG_POWERPC_R20; - case UNW_PPC64_R21: - return PERF_REG_POWERPC_R21; - case UNW_PPC64_R22: - return PERF_REG_POWERPC_R22; - case UNW_PPC64_R23: - return PERF_REG_POWERPC_R23; - case UNW_PPC64_R24: - return PERF_REG_POWERPC_R24; - case UNW_PPC64_R25: - return PERF_REG_POWERPC_R25; - case UNW_PPC64_R26: - return PERF_REG_POWERPC_R26; - case UNW_PPC64_R27: - return PERF_REG_POWERPC_R27; - case UNW_PPC64_R28: - return PERF_REG_POWERPC_R28; - case UNW_PPC64_R29: - return PERF_REG_POWERPC_R29; - case UNW_PPC64_R30: - return PERF_REG_POWERPC_R30; - case UNW_PPC64_R31: - return PERF_REG_POWERPC_R31; - case UNW_PPC64_LR: - return PERF_REG_POWERPC_LINK; - case UNW_PPC64_CTR: - return PERF_REG_POWERPC_CTR; - case UNW_PPC64_XER: - return PERF_REG_POWERPC_XER; - case UNW_PPC64_NIP: - return PERF_REG_POWERPC_NIP; - default: - pr_err("unwind: invalid reg id %d\n", regnum); - return -EINVAL; - } - return -EINVAL; -} diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build index b94c91984c66..7f89fffe4615 100644 --- a/tools/perf/arch/x86/util/Build +++ b/tools/perf/arch/x86/util/Build @@ -8,9 +8,6 @@ perf-util-y +=3D evlist.o perf-util-y +=3D mem-events.o perf-util-y +=3D evsel.o perf-util-y +=3D iostat.o - -perf-util-$(CONFIG_LOCAL_LIBUNWIND) +=3D unwind-libunwind.o - perf-util-y +=3D auxtrace.o perf-util-y +=3D intel-pt.o perf-util-y +=3D intel-bts.o diff --git a/tools/perf/arch/x86/util/unwind-libunwind.c b/tools/perf/arch/= x86/util/unwind-libunwind.c deleted file mode 100644 index 47357973b55b..000000000000 --- a/tools/perf/arch/x86/util/unwind-libunwind.c +++ /dev/null @@ -1,115 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include -#include "../../util/debug.h" -#ifndef REMOTE_UNWIND_LIBUNWIND -#include -#include "perf_regs.h" -#include "../../util/unwind.h" -#endif - -#ifdef HAVE_ARCH_X86_64_SUPPORT -int LIBUNWIND__ARCH_REG_ID(int regnum) -{ - int id; - - switch (regnum) { - case UNW_X86_64_RAX: - id =3D PERF_REG_X86_AX; - break; - case UNW_X86_64_RDX: - id =3D PERF_REG_X86_DX; - break; - case UNW_X86_64_RCX: - id =3D PERF_REG_X86_CX; - break; - case UNW_X86_64_RBX: - id =3D PERF_REG_X86_BX; - break; - case UNW_X86_64_RSI: - id =3D PERF_REG_X86_SI; - break; - case UNW_X86_64_RDI: - id =3D PERF_REG_X86_DI; - break; - case UNW_X86_64_RBP: - id =3D PERF_REG_X86_BP; - break; - case UNW_X86_64_RSP: - id =3D PERF_REG_X86_SP; - break; - case UNW_X86_64_R8: - id =3D PERF_REG_X86_R8; - break; - case UNW_X86_64_R9: - id =3D PERF_REG_X86_R9; - break; - case UNW_X86_64_R10: - id =3D PERF_REG_X86_R10; - break; - case UNW_X86_64_R11: - id =3D PERF_REG_X86_R11; - break; - case UNW_X86_64_R12: - id =3D PERF_REG_X86_R12; - break; - case UNW_X86_64_R13: - id =3D PERF_REG_X86_R13; - break; - case UNW_X86_64_R14: - id =3D PERF_REG_X86_R14; - break; - case UNW_X86_64_R15: - id =3D PERF_REG_X86_R15; - break; - case UNW_X86_64_RIP: - id =3D PERF_REG_X86_IP; - break; - default: - pr_err("unwind: invalid reg id %d\n", regnum); - return -EINVAL; - } - - return id; -} -#else -int LIBUNWIND__ARCH_REG_ID(int regnum) -{ - int id; - - switch (regnum) { - case UNW_X86_EAX: - id =3D PERF_REG_X86_AX; - break; - case UNW_X86_EDX: - id =3D PERF_REG_X86_DX; - break; - case UNW_X86_ECX: - id =3D PERF_REG_X86_CX; - break; - case UNW_X86_EBX: - id =3D PERF_REG_X86_BX; - break; - case UNW_X86_ESI: - id =3D PERF_REG_X86_SI; - break; - case UNW_X86_EDI: - id =3D PERF_REG_X86_DI; - break; - case UNW_X86_EBP: - id =3D PERF_REG_X86_BP; - break; - case UNW_X86_ESP: - id =3D PERF_REG_X86_SP; - break; - case UNW_X86_EIP: - id =3D PERF_REG_X86_IP; - break; - default: - pr_err("unwind: invalid reg id %d\n", regnum); - return -EINVAL; - } - - return id; -} -#endif /* HAVE_ARCH_X86_64_SUPPORT */ diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 6190a8f5b0fa..434dc6716a75 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -230,6 +230,7 @@ perf-util-$(CONFIG_LIBDW) +=3D unwind-libdw.o =20 perf-util-$(CONFIG_LOCAL_LIBUNWIND) +=3D unwind-libunwind-local.o perf-util-$(CONFIG_LIBUNWIND) +=3D unwind-libunwind.o +perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-arch/ perf-util-$(CONFIG_LIBUNWIND_X86) +=3D libunwind/x86_32.o perf-util-$(CONFIG_LIBUNWIND_AARCH64) +=3D libunwind/arm64.o =20 diff --git a/tools/perf/util/libunwind-arch/Build b/tools/perf/util/libunwi= nd-arch/Build new file mode 100644 index 000000000000..87fd657a3248 --- /dev/null +++ b/tools/perf/util/libunwind-arch/Build @@ -0,0 +1,10 @@ +perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-arch.o +perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-arm64.o +perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-arm.o +perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-loongarch.o +perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-mips.o +perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-ppc32.o +perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-ppc64.o +perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-s390.o +perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-i386.o +perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-x86_64.o diff --git a/tools/perf/util/libunwind-arch/libunwind-arch.c b/tools/perf/u= til/libunwind-arch/libunwind-arch.c new file mode 100644 index 000000000000..5439bf90d161 --- /dev/null +++ b/tools/perf/util/libunwind-arch/libunwind-arch.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "libunwind-arch.h" +#include "../debug.h" +#include +#include + +int get_perf_regnum_for_unw_regnum(unsigned int e_machine, int unw_regnum) +{ + switch (e_machine) { + case EM_ARM: + return __get_perf_regnum_for_unw_regnum_arm(unw_regnum); + case EM_AARCH64: + return __get_perf_regnum_for_unw_regnum_arm64(unw_regnum); + case EM_LOONGARCH: + return __get_perf_regnum_for_unw_regnum_loongarch(unw_regnum); + case EM_MIPS: + return __get_perf_regnum_for_unw_regnum_mips(unw_regnum); + case EM_PPC: + return __get_perf_regnum_for_unw_regnum_ppc32(unw_regnum); + case EM_PPC64: + return __get_perf_regnum_for_unw_regnum_ppc64(unw_regnum); + case EM_S390: + return __get_perf_regnum_for_unw_regnum_s390(unw_regnum); + case EM_386: + return __get_perf_regnum_for_unw_regnum_i386(unw_regnum); + case EM_X86_64: + return __get_perf_regnum_for_unw_regnum_x86_64(unw_regnum); + default: + pr_err("ELF MACHINE %x is not supported.\n", e_machine); + return -EINVAL; + } +} diff --git a/tools/perf/util/libunwind-arch/libunwind-arch.h b/tools/perf/u= til/libunwind-arch/libunwind-arch.h new file mode 100644 index 000000000000..e1009c6cb965 --- /dev/null +++ b/tools/perf/util/libunwind-arch/libunwind-arch.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LIBUNWIND_ARCH_H +#define __LIBUNWIND_ARCH_H + +int __get_perf_regnum_for_unw_regnum_arm(int unw_regnum); +int __get_perf_regnum_for_unw_regnum_arm64(int unw_regnum); +int __get_perf_regnum_for_unw_regnum_loongarch(int unw_regnum); +int __get_perf_regnum_for_unw_regnum_mips(int unw_regnum); +int __get_perf_regnum_for_unw_regnum_ppc32(int unw_regnum); +int __get_perf_regnum_for_unw_regnum_ppc64(int unw_regnum); +int __get_perf_regnum_for_unw_regnum_s390(int unw_regnum); +int __get_perf_regnum_for_unw_regnum_i386(int unw_regnum); +int __get_perf_regnum_for_unw_regnum_x86_64(int unw_regnum); +int get_perf_regnum_for_unw_regnum(unsigned int e_machine, int unw_regnum); + +#endif /* __LIBUNWIND_ARCH_H */ diff --git a/tools/perf/util/libunwind-arch/libunwind-arm.c b/tools/perf/ut= il/libunwind-arch/libunwind-arm.c new file mode 100644 index 000000000000..6740ee55b043 --- /dev/null +++ b/tools/perf/util/libunwind-arch/libunwind-arm.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "libunwind-arch.h" +#include "../debug.h" +#include "../../../arch/arm/include/uapi/asm/perf_regs.h" +#include +#include + +int __get_perf_regnum_for_unw_regnum_arm(int unw_regnum) +{ + if (unw_regnum < 0 || unw_regnum >=3D PERF_REG_ARM_MAX) { + pr_err("unwind: invalid reg id %d\n", unw_regnum); + return -EINVAL; + } + return unw_regnum; +} diff --git a/tools/perf/util/libunwind-arch/libunwind-arm64.c b/tools/perf/= util/libunwind-arch/libunwind-arm64.c new file mode 100644 index 000000000000..53b1877dfa04 --- /dev/null +++ b/tools/perf/util/libunwind-arch/libunwind-arm64.c @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "libunwind-arch.h" +#include "../debug.h" +#include "../../../arch/arm64/include/uapi/asm/perf_regs.h" +#include + +int __get_perf_regnum_for_unw_regnum_arm64(int unw_regnum) +{ + if (unw_regnum < 0 || unw_regnum >=3D PERF_REG_ARM64_EXTENDED_MAX) { + pr_err("unwind: invalid reg id %d\n", unw_regnum); + return -EINVAL; + } + return unw_regnum; +} diff --git a/tools/perf/util/libunwind-arch/libunwind-i386.c b/tools/perf/u= til/libunwind-arch/libunwind-i386.c new file mode 100644 index 000000000000..9eaf4ebff0c2 --- /dev/null +++ b/tools/perf/util/libunwind-arch/libunwind-i386.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "libunwind-arch.h" +#include "../debug.h" +#include "../../../arch/x86/include/uapi/asm/perf_regs.h" +#include +#include +#include + +#ifdef HAVE_LIBUNWIND_X86_SUPPORT +#include +#endif + +int __get_perf_regnum_for_unw_regnum_i386(int unw_regnum __maybe_unused) +{ +#ifndef HAVE_LIBUNWIND_X86_SUPPORT + return -EINVAL; +#else + static const int perf_i386_regnums[] =3D { +#define REGNUM(reg) [UNW_X86_E ## reg] =3D PERF_REG_X86_ ## reg + REGNUM(AX), + REGNUM(DX), + REGNUM(CX), + REGNUM(BX), + REGNUM(SI), + REGNUM(DI), + REGNUM(BP), + REGNUM(SP), + REGNUM(IP), +#undef REGNUM + }; + + if (unw_regnum =3D=3D UNW_X86_EAX) + return PERF_REG_X86_AX; + + if (unw_regnum < 0 || unw_regnum > (int)ARRAY_SIZE(perf_i386_regnums) || + perf_i386_regnums[unw_regnum] =3D=3D 0) { + pr_err("unwind: invalid reg id %d\n", unw_regnum); + return -EINVAL; + } + + return perf_i386_regnums[unw_regnum]; +#endif // HAVE_LIBUNWIND_X86_SUPPORT +} diff --git a/tools/perf/util/libunwind-arch/libunwind-loongarch.c b/tools/p= erf/util/libunwind-arch/libunwind-loongarch.c new file mode 100644 index 000000000000..7009410989bc --- /dev/null +++ b/tools/perf/util/libunwind-arch/libunwind-loongarch.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "libunwind-arch.h" +#include "../debug.h" +#include "../../../arch/loongarch/include/uapi/asm/perf_regs.h" +#include +#include + +#ifdef HAVE_LIBUNWIND_LOONGARCH64_SUPPORT +#include +#endif + +int __get_perf_regnum_for_unw_regnum_loongarch(int unw_regnum __maybe_unus= ed) +{ +#ifndef HAVE_LIBUNWIND_LOONGARCH64_SUPPORT + return -EINVAL; +#else + switch (unw_regnum) { + case UNW_LOONGARCH64_R1 ... UNW_LOONGARCH64_31: + return unw_regnum - UNW_LOONGARCH64_R1 + PERF_REG_LOONGARCH_R1; + case UNW_LOONGARCH64_PC: + return PERF_REG_LOONGARCH_PC; + default: + pr_err("unwind: invalid reg id %d\n", unw_regnum); + return -EINVAL; + } +#endif // HAVE_LIBUNWIND_LOONGARCH64_SUPPORT +} diff --git a/tools/perf/util/libunwind-arch/libunwind-mips.c b/tools/perf/u= til/libunwind-arch/libunwind-mips.c new file mode 100644 index 000000000000..01a506c8079c --- /dev/null +++ b/tools/perf/util/libunwind-arch/libunwind-mips.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "libunwind-arch.h" +#include "../debug.h" +#include "../../../arch/mips/include/uapi/asm/perf_regs.h" +#include +#include + +#ifdef HAVE_LIBUNWIND_MIPS_SUPPORT +#include +#endif + +int __get_perf_regnum_for_unw_regnum_mips(int unw_regnum __maybe_unused) +{ +#ifndef HAVE_LIBUNWIND_MIPS_SUPPORT + return -EINVAL; +#else + switch (unw_regnum) { + case UNW_MIPS_R1 ... UNW_MIPS_R25: + return unw_regnum - UNW_MIPS_R1 + PERF_REG_MIPS_R1; + case UNW_MIPS_R28 ... UNW_MIPS_R31: + return unw_regnum - UNW_MIPS_R28 + PERF_REG_MIPS_R28; + case UNW_MIPS_PC: + return PERF_REG_MIPS_PC; + default: + pr_err("unwind: invalid reg id %d\n", unw_regnum); + return -EINVAL; + } +#endif // HAVE_LIBUNWIND_MIPS_SUPPORT +} diff --git a/tools/perf/util/libunwind-arch/libunwind-ppc32.c b/tools/perf/= util/libunwind-arch/libunwind-ppc32.c new file mode 100644 index 000000000000..edcb0ec95dd7 --- /dev/null +++ b/tools/perf/util/libunwind-arch/libunwind-ppc32.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include "libunwind-arch.h" +#include "../debug.h" +#include "../../../arch/powerpc/include/uapi/asm/perf_regs.h" +#include +#include + +#ifdef HAVE_LIBUNWIND_PPC32_SUPPORT +#include +#endif + +int __get_perf_regnum_for_unw_regnum_ppc32(int unw_regnum __maybe_unused) +{ +#ifndef HAVE_LIBUNWIND_PPC32_SUPPORT + return -EINVAL; +#else + switch (unw_regnum) { + case UNW_PPC32_R0 ... UNW_PPC32_31: + return unw_regnum - UNW_PPC32_R0 + PERF_REG_POWERPC_R0; + case UNW_PPC32_LR: + return PERF_REG_POWERPC_LINK; + case UNW_PPC32_CTR: + return PERF_REG_POWERPC_CTR; + case UNW_PPC32_XER: + return PERF_REG_POWERPC_XER; + default: + pr_err("unwind: invalid reg id %d\n", unw_regnum); + return -EINVAL; + } +#endif // HAVE_LIBUNWIND_PPC32_SUPPORT +} diff --git a/tools/perf/util/libunwind-arch/libunwind-ppc64.c b/tools/perf/= util/libunwind-arch/libunwind-ppc64.c new file mode 100644 index 000000000000..9f57a049600b --- /dev/null +++ b/tools/perf/util/libunwind-arch/libunwind-ppc64.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include "libunwind-arch.h" +#include "../debug.h" +#include "../../../arch/powerpc/include/uapi/asm/perf_regs.h" +#include +#include + +#ifdef HAVE_LIBUNWIND_PPC64_SUPPORT +#include +#endif + +int __get_perf_regnum_for_unw_regnum_ppc64(int unw_regnum __maybe_unused) +{ +#ifndef HAVE_LIBUNWIND_PPC64_SUPPORT + return -EINVAL; +#else + switch (unw_regnum) { + case UNW_PPC64_R0 ... UNW_PPC64_31: + return unw_regnum - UNW_PPC64_R0 + PERF_REG_POWERPC_R0; + case UNW_PPC64_LR: + return PERF_REG_POWERPC_LINK; + case UNW_PPC64_CTR: + return PERF_REG_POWERPC_CTR; + case UNW_PPC64_XER: + return PERF_REG_POWERPC_XER; + case UNW_PPC64_NIP: + return PERF_REG_POWERPC_NIP; + default: + pr_err("unwind: invalid reg id %d\n", unw_regnum); + return -EINVAL; + } +#endif // HAVE_LIBUNWIND_PPC64_SUPPORT +} diff --git a/tools/perf/util/libunwind-arch/libunwind-s390.c b/tools/perf/u= til/libunwind-arch/libunwind-s390.c new file mode 100644 index 000000000000..9fcc7885ca55 --- /dev/null +++ b/tools/perf/util/libunwind-arch/libunwind-s390.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "libunwind-arch.h" +#include "../debug.h" +#include "../../../arch/s390/include/uapi/asm/perf_regs.h" +#include +#include + +#ifdef HAVE_LIBUNWIND_S390X_SUPPORT +#include +#endif + +int __get_perf_regnum_for_unw_regnum_s390(int unw_regnum __maybe_unused) +{ +#ifndef HAVE_LIBUNWIND_S390X_SUPPORT + return -EINVAL; +#else + switch (unw_regnum) { + case UNW_S390X_R0 ... UNW_S390_R15: + return unw_regnum - UNW_S390_R0 + PERF_REG_S390_R0; + case UNW_S390X_F0 ... UNW_S390_F15: + return unw_regnum - UNW_S390_F0 + PERF_REG_S390_FP0; + case UNW_S390X_IP: + return PERF_REG_S390_PC; + default: + pr_err("unwind: invalid reg id %d\n", unw_regnum); + return -EINVAL; + } +#endif // HAVE_LIBUNWIND_S390X_SUPPORT +} diff --git a/tools/perf/util/libunwind-arch/libunwind-x86_64.c b/tools/perf= /util/libunwind-arch/libunwind-x86_64.c new file mode 100644 index 000000000000..6072e3597e61 --- /dev/null +++ b/tools/perf/util/libunwind-arch/libunwind-x86_64.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "libunwind-arch.h" +#include "../debug.h" +#include "../../../arch/x86/include/uapi/asm/perf_regs.h" +#include +#include +#include + +#ifdef HAVE_LIBUNWIND_X86_64_SUPPORT +#include +#endif + +int __get_perf_regnum_for_unw_regnum_x86_64(int unw_regnum __maybe_unused) +{ +#ifndef HAVE_LIBUNWIND_X86_64_SUPPORT + return -EINVAL; +#else + static const int perf_x86_64_regnums[] =3D { +#define REGNUM(reg) [UNW_X86_64_R ## reg] =3D PERF_REG_X86_ ## reg + REGNUM(AX), + REGNUM(DX), + REGNUM(CX), + REGNUM(BX), + REGNUM(SI), + REGNUM(DI), + REGNUM(BP), + REGNUM(SP), + REGNUM(IP), +#undef REGNUM +#define REGNUM(reg) [UNW_X86_64_ ## reg] =3D PERF_REG_X86_ ## reg + REGNUM(R8), + REGNUM(R9), + REGNUM(R10), + REGNUM(R11), + REGNUM(R12), + REGNUM(R13), + REGNUM(R14), + REGNUM(R15), +#undef REGNUM + }; + + if (unw_regnum =3D=3D UNW_X86_64_RAX) + return PERF_REG_X86_AX; + + if (unw_regnum < 0 || unw_regnum > (int)ARRAY_SIZE(perf_x86_64_regnums) = || + perf_x86_64_regnums[unw_regnum] =3D=3D 0) { + pr_err("unwind: invalid reg id %d\n", unw_regnum); + return -EINVAL; + } + return perf_x86_64_regnums[unw_regnum]; +#endif // HAVE_LIBUNWIND_X86_64_SUPPORT +} diff --git a/tools/perf/util/libunwind/arm64.c b/tools/perf/util/libunwind/= arm64.c index 37ecef0c53b9..15670a964495 100644 --- a/tools/perf/util/libunwind/arm64.c +++ b/tools/perf/util/libunwind/arm64.c @@ -14,11 +14,6 @@ =20 #define REMOTE_UNWIND_LIBUNWIND =20 -/* Define arch specific functions & regs for libunwind, should be - * defined before including "unwind.h" - */ -#define LIBUNWIND__ARCH_REG_ID(regnum) libunwind__arm64_reg_id(regnum) - #include "unwind.h" #include "libunwind-aarch64.h" #define perf_event_arm_regs perf_event_arm64_regs diff --git a/tools/perf/util/libunwind/x86_32.c b/tools/perf/util/libunwind= /x86_32.c index 1697dece1b74..1e9fb8bfec44 100644 --- a/tools/perf/util/libunwind/x86_32.c +++ b/tools/perf/util/libunwind/x86_32.c @@ -14,20 +14,8 @@ =20 #define REMOTE_UNWIND_LIBUNWIND =20 -/* Define arch specific functions & regs for libunwind, should be - * defined before including "unwind.h" - */ -#define LIBUNWIND__ARCH_REG_ID(regnum) libunwind__x86_reg_id(regnum) - #include "unwind.h" #include "libunwind-x86.h" -#include <../../../../arch/x86/include/uapi/asm/perf_regs.h> - -/* HAVE_ARCH_X86_64_SUPPORT is used in'arch/x86/util/unwind-libunwind.c' - * for x86_32, we undef it to compile code for x86_32 only. - */ -#undef HAVE_ARCH_X86_64_SUPPORT -#include "../../arch/x86/util/unwind-libunwind.c" =20 /* Explicitly define NO_LIBUNWIND_DEBUG_FRAME, because non-ARM has no * dwarf_find_debug_frame() function. diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unw= ind-libunwind-local.c index 5b39ce21e333..3ecdb468b859 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -40,6 +40,7 @@ #include "debug.h" #include "asm/bug.h" #include "dso.h" +#include "libunwind-arch/libunwind-arch.h" =20 extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, @@ -96,6 +97,7 @@ struct unwind_info { struct perf_sample *sample; struct machine *machine; struct thread *thread; + uint16_t e_machine; bool best_effort; }; =20 @@ -584,9 +586,7 @@ static int access_mem(unw_addr_space_t __maybe_unused a= s, } =20 ret =3D perf_reg_value(&start, perf_sample__user_regs(ui->sample), - perf_arch_reg_sp(thread__e_machine(ui->thread, - ui->machine, - /*e_flags=3D*/NULL))); + perf_arch_reg_sp(ui->e_machine)); if (ret) return ret; =20 @@ -634,7 +634,7 @@ static int access_reg(unw_addr_space_t __maybe_unused a= s, return 0; } =20 - id =3D LIBUNWIND__ARCH_REG_ID(regnum); + id =3D get_perf_regnum_for_unw_regnum(ui->e_machine, regnum); if (id < 0) return -EINVAL; =20 @@ -735,7 +735,6 @@ static void _unwind__finish_access(struct maps *maps) static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, void *arg, int max_stack) { - uint16_t e_machine =3D thread__e_machine(ui->thread, ui->machine, /*e_fla= gs=3D*/NULL); u64 val; unw_word_t ips[max_stack]; unw_addr_space_t addr_space; @@ -743,7 +742,7 @@ static int get_entries(struct unwind_info *ui, unwind_e= ntry_cb_t cb, int ret, i =3D 0; =20 ret =3D perf_reg_value(&val, perf_sample__user_regs(ui->sample), - perf_arch_reg_ip(e_machine)); + perf_arch_reg_ip(ui->e_machine)); if (ret) return ret; =20 @@ -806,6 +805,7 @@ static int _unwind__get_entries(unwind_entry_cb_t cb, v= oid *arg, .sample =3D data, .thread =3D thread, .machine =3D maps__machine(thread__maps(thread)), + .e_machine =3D thread__e_machine(thread, /*machine=3D*/NULL, /*e_flag= s=3D*/NULL), .best_effort =3D best_effort }; =20 diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index 581d042e170a..e32d39ab41c6 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -53,11 +53,6 @@ int libunwind__get_entries(unwind_entry_cb_t cb, void *a= rg, 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 - -int LIBUNWIND__ARCH_REG_ID(int regnum); int unwind__prepare_access(struct maps *maps, struct map *map, bool *initi= alized); void unwind__flush_access(struct maps *maps); void unwind__finish_access(struct maps *maps); --=20 2.53.0.473.g4a7958ca14-goog From nobody Thu Apr 9 20:26:03 2026 Received: from mail-pl1-f202.google.com (mail-pl1-f202.google.com [209.85.214.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B7CCF363C78 for ; Thu, 5 Mar 2026 22:19:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772749195; cv=none; b=Dt2teulXv+P4RAUVkfg5/Jjc0SjnHnp4H0/DrK/wFsqRrtYfnmRnW5qYxfHj09aL7Bp8Ajx7B4nan5uJmsPda5O+5erLOUQSCBQ/AINBHKlXWwtS2jYuXz0fWCfYEmed+J+qULgFpKG9ZDX0xrLMAy642mPinr1oYD2uCmSDOes= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772749195; c=relaxed/simple; bh=VB5QMnu0uqrr6HRLNdlsb44M0iWCP6Rk2NU8XWcIUmA=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=R/e/7bYXlra/7FdiqO1v1/PxNBXpYjR3/V3jnroEXIHrrzmW5PcivtqkWIA4lK/6vO0EV+7r3m4rVSgVa8dQ1+a46DTqbCMhHbYoufyHevjEeMpTTbzynLdxiHxWlQAjlAQ2t3rhpjkXRg5vsovu2tHy5Ynr8fWnqn7XCKa7m9s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=qERjVLQL; arc=none smtp.client-ip=209.85.214.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="qERjVLQL" Received: by mail-pl1-f202.google.com with SMTP id d9443c01a7336-2ae47b3adacso49042755ad.3 for ; Thu, 05 Mar 2026 14:19:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1772749192; x=1773353992; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=8Rh1CphM4vSmmh9nZmvjtwuqLhln3KdVDQeaSzDgaBc=; b=qERjVLQLhnCP2YTi/Yx933928S8vP/mK7bLtcF1sIup9zEqRN3VqnWJSUtDCkVqwBp TofiEsQFiFaJkannR7cvbV8E2F0EwidXh88kbCyeuzTxgL17y1FTj2BEGGbQflr/4ffN Q3CXE0h4HuDRiV0QbI5gp5PM+6iAaHshM47XJ/DMY8teTphnusoV6JNXKojXmWKnmYgA bbTyt3mmqSL2ca7Th7wF9o49YXv86AoxsvryceCTLjIIUpmpacXo4k93hacFG41WXuVD zuDPplrwKFxtVsP2mNr/DG1DFdg/cn4lQvx2zjOvK1cUPIQyk/THHZWQtEKg15HPahFB Xohg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772749192; x=1773353992; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=8Rh1CphM4vSmmh9nZmvjtwuqLhln3KdVDQeaSzDgaBc=; b=KWeaq+9e+9WWeBlHfQsTT0x8Pcuo6fkQgkSf8tjgZSN5mjw2+PTMo7Hwa0sEkwl55a oYnjtVgKvadFDUuu98+rhIoKuQnfzcR85zDgOj2E5/+Hc3R+S0Rb7VdZlxw6rcM3F144 a1bxFPMA4FC2mRrgA60CnuKoGIinfrh2plD7Rutyc1UcjTwi0Su1PtqWgqA3SrU9XK+L 061THP/DQL0v5X/JA1COYHhER/TPI2mTTIavzpCQH9ANCgeeCchG185OyemZChB6WfWy 2SG2oy4Xk9nOUJz7giZh0IHVux5/rjvOALE6ZqpGzMsI0KSgTyKyG1OaRUxLqDn95xAs L3oQ== X-Forwarded-Encrypted: i=1; AJvYcCXj+/yj36U0Eu/zuD+VeeTrcwQCufi6rgTS20KC1U97e/Adg2Jcb3UD2CQuVRn3UsI+9VEGj6dC1k8h+II=@vger.kernel.org X-Gm-Message-State: AOJu0YwueuwKRPmPoY4i6rVXJOPo/SfYB2BMWxzUyuUFloZweAAT1ZAA Gqgo1IiAOnC4XdVIzlMFf6zAJERm+7gjcon+2Zxwr8UcZWKpiipMo0csLN2H3HAOA+eAOSoTwEj G8dU7yxJFsQ== X-Received: from plrd12.prod.google.com ([2002:a17:902:aa8c:b0:2ad:9a1a:f7de]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a17:903:3b8b:b0:2ae:4cb8:4848 with SMTP id d9443c01a7336-2ae82454ce0mr741075ad.19.1772749191802; Thu, 05 Mar 2026 14:19:51 -0800 (PST) Date: Thu, 5 Mar 2026 14:19:25 -0800 In-Reply-To: <20260305221927.3237145-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260305221927.3237145-1-irogers@google.com> X-Mailer: git-send-email 2.53.0.473.g4a7958ca14-goog Message-ID: <20260305221927.3237145-7-irogers@google.com> Subject: [PATCH v2 6/8] perf unwind-libunwind: Move flush/finish access out of local From: Ian Rogers 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 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Flush and finish access are relatively simple calls into libunwind, move them out struct unwind_libunwind_ops. So that the correct version can be called, add an e_machine variable to maps. This size regression will go away when the unwind_libunwind_ops no longer need stashing in the maps. To set the e_machine up pass it into unwind__prepare_access, which no longer needs to determine the unwind operations based on a map dso because of this. This also means the maps copying code can call unwind__prepare_access once for the e_machine rather than once per map. Signed-off-by: Ian Rogers --- .../perf/util/libunwind-arch/libunwind-arch.c | 82 +++++++++++++++++++ .../perf/util/libunwind-arch/libunwind-arch.h | 24 ++++++ .../perf/util/libunwind-arch/libunwind-arm.c | 19 +++++ .../util/libunwind-arch/libunwind-arm64.c | 20 +++++ .../perf/util/libunwind-arch/libunwind-i386.c | 15 ++++ .../util/libunwind-arch/libunwind-loongarch.c | 15 ++++ .../perf/util/libunwind-arch/libunwind-mips.c | 15 ++++ .../util/libunwind-arch/libunwind-ppc32.c | 15 ++++ .../util/libunwind-arch/libunwind-ppc64.c | 15 ++++ .../perf/util/libunwind-arch/libunwind-s390.c | 15 ++++ .../util/libunwind-arch/libunwind-x86_64.c | 15 ++++ tools/perf/util/maps.c | 31 ++++--- tools/perf/util/maps.h | 2 + tools/perf/util/thread.c | 29 +------ tools/perf/util/unwind-libunwind-local.c | 12 --- tools/perf/util/unwind-libunwind.c | 61 +++++--------- tools/perf/util/unwind.h | 8 +- 17 files changed, 299 insertions(+), 94 deletions(-) diff --git a/tools/perf/util/libunwind-arch/libunwind-arch.c b/tools/perf/u= til/libunwind-arch/libunwind-arch.c index 5439bf90d161..9692e6c81492 100644 --- a/tools/perf/util/libunwind-arch/libunwind-arch.c +++ b/tools/perf/util/libunwind-arch/libunwind-arch.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "libunwind-arch.h" #include "../debug.h" +#include "../maps.h" #include #include =20 @@ -30,3 +31,84 @@ int get_perf_regnum_for_unw_regnum(unsigned int e_machin= e, int unw_regnum) return -EINVAL; } } + + +void libunwind_arch__flush_access(struct maps *maps) +{ + unsigned int e_machine =3D maps__e_machine(maps); + + switch (e_machine) { + case EM_NONE: + break; // No libunwind info on the maps. + case EM_ARM: + __libunwind_arch__flush_access_arm(maps); + break; + case EM_AARCH64: + __libunwind_arch__flush_access_arm64(maps); + break; + case EM_LOONGARCH: + __libunwind_arch__flush_access_loongarch(maps); + break; + case EM_MIPS: + __libunwind_arch__flush_access_mips(maps); + break; + case EM_PPC: + __libunwind_arch__flush_access_ppc32(maps); + break; + case EM_PPC64: + __libunwind_arch__flush_access_ppc64(maps); + break; + case EM_S390: + __libunwind_arch__flush_access_s390(maps); + break; + case EM_386: + __libunwind_arch__flush_access_i386(maps); + break; + case EM_X86_64: + __libunwind_arch__flush_access_x86_64(maps); + break; + default: + pr_err("ELF MACHINE %x is not supported.\n", e_machine); + break; + } +} + +void libunwind_arch__finish_access(struct maps *maps) +{ + unsigned int e_machine =3D maps__e_machine(maps); + + switch (e_machine) { + case EM_NONE: + break; // No libunwind info on the maps. + case EM_ARM: + __libunwind_arch__finish_access_arm(maps); + break; + case EM_AARCH64: + __libunwind_arch__finish_access_arm64(maps); + break; + case EM_LOONGARCH: + __libunwind_arch__finish_access_loongarch(maps); + break; + case EM_MIPS: + __libunwind_arch__finish_access_mips(maps); + break; + case EM_PPC: + __libunwind_arch__finish_access_ppc32(maps); + break; + case EM_PPC64: + __libunwind_arch__finish_access_ppc64(maps); + break; + case EM_S390: + __libunwind_arch__finish_access_s390(maps); + break; + case EM_386: + __libunwind_arch__finish_access_i386(maps); + break; + case EM_X86_64: + __libunwind_arch__finish_access_x86_64(maps); + break; + default: + pr_err("ELF MACHINE %x is not supported.\n", e_machine); + break; + } +} diff --git a/tools/perf/util/libunwind-arch/libunwind-arch.h b/tools/perf/u= til/libunwind-arch/libunwind-arch.h index e1009c6cb965..c00277a5e914 100644 --- a/tools/perf/util/libunwind-arch/libunwind-arch.h +++ b/tools/perf/util/libunwind-arch/libunwind-arch.h @@ -2,6 +2,8 @@ #ifndef __LIBUNWIND_ARCH_H #define __LIBUNWIND_ARCH_H =20 +struct maps; + int __get_perf_regnum_for_unw_regnum_arm(int unw_regnum); int __get_perf_regnum_for_unw_regnum_arm64(int unw_regnum); int __get_perf_regnum_for_unw_regnum_loongarch(int unw_regnum); @@ -13,4 +15,26 @@ int __get_perf_regnum_for_unw_regnum_i386(int unw_regnum= ); int __get_perf_regnum_for_unw_regnum_x86_64(int unw_regnum); int get_perf_regnum_for_unw_regnum(unsigned int e_machine, int unw_regnum); =20 +void __libunwind_arch__flush_access_arm(struct maps *maps); +void __libunwind_arch__flush_access_arm64(struct maps *maps); +void __libunwind_arch__flush_access_loongarch(struct maps *maps); +void __libunwind_arch__flush_access_mips(struct maps *maps); +void __libunwind_arch__flush_access_ppc32(struct maps *maps); +void __libunwind_arch__flush_access_ppc64(struct maps *maps); +void __libunwind_arch__flush_access_s390(struct maps *maps); +void __libunwind_arch__flush_access_i386(struct maps *maps); +void __libunwind_arch__flush_access_x86_64(struct maps *maps); +void libunwind_arch__flush_access(struct maps *maps); + +void __libunwind_arch__finish_access_arm(struct maps *maps); +void __libunwind_arch__finish_access_arm64(struct maps *maps); +void __libunwind_arch__finish_access_loongarch(struct maps *maps); +void __libunwind_arch__finish_access_mips(struct maps *maps); +void __libunwind_arch__finish_access_ppc32(struct maps *maps); +void __libunwind_arch__finish_access_ppc64(struct maps *maps); +void __libunwind_arch__finish_access_s390(struct maps *maps); +void __libunwind_arch__finish_access_i386(struct maps *maps); +void __libunwind_arch__finish_access_x86_64(struct maps *maps); +void libunwind_arch__finish_access(struct maps *maps); + #endif /* __LIBUNWIND_ARCH_H */ diff --git a/tools/perf/util/libunwind-arch/libunwind-arm.c b/tools/perf/ut= il/libunwind-arch/libunwind-arm.c index 6740ee55b043..bbaf01406c52 100644 --- a/tools/perf/util/libunwind-arch/libunwind-arm.c +++ b/tools/perf/util/libunwind-arch/libunwind-arm.c @@ -1,10 +1,15 @@ // SPDX-License-Identifier: GPL-2.0 #include "libunwind-arch.h" #include "../debug.h" +#include "../maps.h" #include "../../../arch/arm/include/uapi/asm/perf_regs.h" #include #include =20 +#ifdef HAVE_LIBUNWIND_ARM_SUPPORT +#include +#endif + int __get_perf_regnum_for_unw_regnum_arm(int unw_regnum) { if (unw_regnum < 0 || unw_regnum >=3D PERF_REG_ARM_MAX) { @@ -13,3 +18,17 @@ int __get_perf_regnum_for_unw_regnum_arm(int unw_regnum) } return unw_regnum; } + +void __libunwind_arch__flush_access_arm(struct maps *maps __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_ARM_SUPPORT + unw_flush_cache(maps__addr_space(maps), 0, 0); +#endif +} + +void __libunwind_arch__finish_access_arm(struct maps *maps __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_ARM_SUPPORT + unw_destroy_addr_space(maps__addr_space(maps)); +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-arm64.c b/tools/perf/= util/libunwind-arch/libunwind-arm64.c index 53b1877dfa04..8ba510089736 100644 --- a/tools/perf/util/libunwind-arch/libunwind-arm64.c +++ b/tools/perf/util/libunwind-arch/libunwind-arm64.c @@ -1,9 +1,15 @@ // SPDX-License-Identifier: GPL-2.0 #include "libunwind-arch.h" #include "../debug.h" +#include "../maps.h" #include "../../../arch/arm64/include/uapi/asm/perf_regs.h" +#include #include =20 +#ifdef HAVE_LIBUNWIND_AARCH64_SUPPORT +#include +#endif + int __get_perf_regnum_for_unw_regnum_arm64(int unw_regnum) { if (unw_regnum < 0 || unw_regnum >=3D PERF_REG_ARM64_EXTENDED_MAX) { @@ -12,3 +18,17 @@ int __get_perf_regnum_for_unw_regnum_arm64(int unw_regnu= m) } return unw_regnum; } + +void __libunwind_arch__flush_access_arm64(struct maps *maps __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_AARCH64_SUPPORT + unw_flush_cache(maps__addr_space(maps), 0, 0); +#endif +} + +void __libunwind_arch__finish_access_arm64(struct maps *maps __maybe_unuse= d) +{ +#ifdef HAVE_LIBUNWIND_AARCH64_SUPPORT + unw_destroy_addr_space(maps__addr_space(maps)); +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-i386.c b/tools/perf/u= til/libunwind-arch/libunwind-i386.c index 9eaf4ebff0c2..45ff30c95c1b 100644 --- a/tools/perf/util/libunwind-arch/libunwind-i386.c +++ b/tools/perf/util/libunwind-arch/libunwind-i386.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "libunwind-arch.h" #include "../debug.h" +#include "../maps.h" #include "../../../arch/x86/include/uapi/asm/perf_regs.h" #include #include @@ -41,3 +42,17 @@ int __get_perf_regnum_for_unw_regnum_i386(int unw_regnum= __maybe_unused) return perf_i386_regnums[unw_regnum]; #endif // HAVE_LIBUNWIND_X86_SUPPORT } + +void __libunwind_arch__flush_access_i386(struct maps *maps __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_X86_SUPPORT + unw_flush_cache(maps__addr_space(maps), 0, 0); +#endif +} + +void __libunwind_arch__finish_access_i386(struct maps *maps __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_X86_SUPPORT + unw_destroy_addr_space(maps__addr_space(maps)); +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-loongarch.c b/tools/p= erf/util/libunwind-arch/libunwind-loongarch.c index 7009410989bc..837aa11e2b9f 100644 --- a/tools/perf/util/libunwind-arch/libunwind-loongarch.c +++ b/tools/perf/util/libunwind-arch/libunwind-loongarch.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "libunwind-arch.h" #include "../debug.h" +#include "../maps.h" #include "../../../arch/loongarch/include/uapi/asm/perf_regs.h" #include #include @@ -25,3 +26,17 @@ int __get_perf_regnum_for_unw_regnum_loongarch(int unw_r= egnum __maybe_unused) } #endif // HAVE_LIBUNWIND_LOONGARCH64_SUPPORT } + +void __libunwind_arch__flush_access_loongarch(struct maps *maps __maybe_un= used) +{ +#ifdef HAVE_LIBUNWIND_LOONGARCH64_SUPPORT + unw_flush_cache(maps__addr_space(maps), 0, 0); +#endif +} + +void __libunwind_arch__finish_access_loongarch(struct maps *maps __maybe_u= nused) +{ +#ifdef HAVE_LIBUNWIND_LOONGARCH64_SUPPORT + unw_destroy_addr_space(maps__addr_space(maps)); +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-mips.c b/tools/perf/u= til/libunwind-arch/libunwind-mips.c index 01a506c8079c..1fa81742ff4a 100644 --- a/tools/perf/util/libunwind-arch/libunwind-mips.c +++ b/tools/perf/util/libunwind-arch/libunwind-mips.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "libunwind-arch.h" #include "../debug.h" +#include "../maps.h" #include "../../../arch/mips/include/uapi/asm/perf_regs.h" #include #include @@ -27,3 +28,17 @@ int __get_perf_regnum_for_unw_regnum_mips(int unw_regnum= __maybe_unused) } #endif // HAVE_LIBUNWIND_MIPS_SUPPORT } + +void __libunwind_arch__flush_access_mips(struct maps *maps __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_MIPS_SUPPORT + unw_flush_cache(maps__addr_space(maps), 0, 0); +#endif +} + +void __libunwind_arch__finish_access_mips(struct maps *maps __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_MIPS_SUPPORT + unw_destroy_addr_space(maps__addr_space(maps)); +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-ppc32.c b/tools/perf/= util/libunwind-arch/libunwind-ppc32.c index edcb0ec95dd7..fa8471c74bf3 100644 --- a/tools/perf/util/libunwind-arch/libunwind-ppc32.c +++ b/tools/perf/util/libunwind-arch/libunwind-ppc32.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "libunwind-arch.h" #include "../debug.h" +#include "../maps.h" #include "../../../arch/powerpc/include/uapi/asm/perf_regs.h" #include #include @@ -29,3 +30,17 @@ int __get_perf_regnum_for_unw_regnum_ppc32(int unw_regnu= m __maybe_unused) } #endif // HAVE_LIBUNWIND_PPC32_SUPPORT } + +void __libunwind_arch__flush_access_ppc32(struct maps *maps __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_PPC32_SUPPORT + unw_flush_cache(maps__addr_space(maps), 0, 0); +#endif +} + +void __libunwind_arch__finish_access_ppc32(struct maps *maps __maybe_unuse= d) +{ +#ifdef HAVE_LIBUNWIND_PPC32_SUPPORT + unw_destroy_addr_space(maps__addr_space(maps)); +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-ppc64.c b/tools/perf/= util/libunwind-arch/libunwind-ppc64.c index 9f57a049600b..2f746e347336 100644 --- a/tools/perf/util/libunwind-arch/libunwind-ppc64.c +++ b/tools/perf/util/libunwind-arch/libunwind-ppc64.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "libunwind-arch.h" #include "../debug.h" +#include "../maps.h" #include "../../../arch/powerpc/include/uapi/asm/perf_regs.h" #include #include @@ -31,3 +32,17 @@ int __get_perf_regnum_for_unw_regnum_ppc64(int unw_regnu= m __maybe_unused) } #endif // HAVE_LIBUNWIND_PPC64_SUPPORT } + +void __libunwind_arch__flush_access_ppc64(struct maps *maps __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_PPC64_SUPPORT + unw_flush_cache(maps__addr_space(maps), 0, 0); +#endif +} + +void __libunwind_arch__finish_access_ppc64(struct maps *maps __maybe_unuse= d) +{ +#ifdef HAVE_LIBUNWIND_PPC64_SUPPORT + unw_destroy_addr_space(maps__addr_space(maps)); +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-s390.c b/tools/perf/u= til/libunwind-arch/libunwind-s390.c index 9fcc7885ca55..9f68d15438b2 100644 --- a/tools/perf/util/libunwind-arch/libunwind-s390.c +++ b/tools/perf/util/libunwind-arch/libunwind-s390.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "libunwind-arch.h" #include "../debug.h" +#include "../maps.h" #include "../../../arch/s390/include/uapi/asm/perf_regs.h" #include #include @@ -27,3 +28,17 @@ int __get_perf_regnum_for_unw_regnum_s390(int unw_regnum= __maybe_unused) } #endif // HAVE_LIBUNWIND_S390X_SUPPORT } + +void __libunwind_arch__flush_access_s390(struct maps *maps __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_S390X_SUPPORT + unw_flush_cache(maps__addr_space(maps), 0, 0); +#endif +} + +void __libunwind_arch__finish_access_s390(struct maps *maps __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_S390X_SUPPORT + unw_destroy_addr_space(maps__addr_space(maps)); +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-x86_64.c b/tools/perf= /util/libunwind-arch/libunwind-x86_64.c index 6072e3597e61..25e326bd3e15 100644 --- a/tools/perf/util/libunwind-arch/libunwind-x86_64.c +++ b/tools/perf/util/libunwind-arch/libunwind-x86_64.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "libunwind-arch.h" #include "../debug.h" +#include "../maps.h" #include "../../../arch/x86/include/uapi/asm/perf_regs.h" #include #include @@ -50,3 +51,17 @@ int __get_perf_regnum_for_unw_regnum_x86_64(int unw_regn= um __maybe_unused) return perf_x86_64_regnums[unw_regnum]; #endif // HAVE_LIBUNWIND_X86_64_SUPPORT } + +void __libunwind_arch__flush_access_x86_64(struct maps *maps __maybe_unuse= d) +{ +#ifdef HAVE_LIBUNWIND_X86_64_SUPPORT + unw_flush_cache(maps__addr_space(maps), 0, 0); +#endif +} + +void __libunwind_arch__finish_access_x86_64(struct maps *maps __maybe_unus= ed) +{ +#ifdef HAVE_LIBUNWIND_X86_64_SUPPORT + unw_destroy_addr_space(maps__addr_space(maps)); +#endif +} diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c index 4092211cff62..8c7b2a1e7642 100644 --- a/tools/perf/util/maps.c +++ b/tools/perf/util/maps.c @@ -40,6 +40,7 @@ DECLARE_RC_STRUCT(maps) { #ifdef HAVE_LIBUNWIND_SUPPORT void *addr_space; const struct unwind_libunwind_ops *unwind_libunwind_ops; + uint16_t e_machine; #endif #ifdef HAVE_LIBDW_SUPPORT void *libdw_addr_space_dwfl; @@ -206,6 +207,16 @@ void maps__set_unwind_libunwind_ops(struct maps *maps,= const struct unwind_libun { RC_CHK_ACCESS(maps)->unwind_libunwind_ops =3D ops; } + +uint16_t maps__e_machine(const struct maps *maps) +{ + return RC_CHK_ACCESS(maps)->e_machine; +} + +void maps__set_e_machine(struct maps *maps, uint16_t e_machine) +{ + RC_CHK_ACCESS(maps)->e_machine =3D e_machine; +} #endif #ifdef HAVE_LIBDW_SUPPORT void *maps__libdw_addr_space_dwfl(const struct maps *maps) @@ -1038,6 +1049,9 @@ int maps__copy_from(struct maps *dest, struct maps *p= arent) down_write(maps__lock(dest)); down_read(maps__lock(parent)); =20 +#ifdef HAVE_LIBUNWIND_SUPPORT + unwind__prepare_access(dest, maps__e_machine(parent)); +#endif parent_maps_by_address =3D maps__maps_by_address(parent); n =3D maps__nr_maps(parent); if (maps__nr_maps(dest) =3D=3D 0) { @@ -1067,14 +1081,11 @@ int maps__copy_from(struct maps *dest, struct maps = *parent) if (!new) err =3D -ENOMEM; else { - err =3D unwind__prepare_access(dest, new, NULL); - if (!err) { - dest_maps_by_address[i] =3D new; - map__set_kmap_maps(new, dest); - if (dest_maps_by_name) - dest_maps_by_name[i] =3D map__get(new); - RC_CHK_ACCESS(dest)->nr_maps =3D i + 1; - } + dest_maps_by_address[i] =3D new; + map__set_kmap_maps(new, dest); + if (dest_maps_by_name) + dest_maps_by_name[i] =3D map__get(new); + RC_CHK_ACCESS(dest)->nr_maps =3D i + 1; } if (err) map__put(new); @@ -1099,9 +1110,7 @@ int maps__copy_from(struct maps *dest, struct maps *p= arent) if (!new) err =3D -ENOMEM; else { - err =3D unwind__prepare_access(dest, new, NULL); - if (!err) - err =3D __maps__insert(dest, new); + err =3D __maps__insert(dest, new); } map__put(new); } diff --git a/tools/perf/util/maps.h b/tools/perf/util/maps.h index 20c52084ba9e..6469f62c41a8 100644 --- a/tools/perf/util/maps.h +++ b/tools/perf/util/maps.h @@ -51,6 +51,8 @@ void *maps__addr_space(const struct maps *maps); void maps__set_addr_space(struct maps *maps, void *addr_space); const struct unwind_libunwind_ops *maps__unwind_libunwind_ops(const struct= maps *maps); void maps__set_unwind_libunwind_ops(struct maps *maps, const struct unwind= _libunwind_ops *ops); +uint16_t maps__e_machine(const struct maps *maps); +void maps__set_e_machine(struct maps *maps, uint16_t e_machine); #endif #ifdef HAVE_LIBDW_SUPPORT void *maps__libdw_addr_space_dwfl(const struct maps *maps); diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 22be77225bb0..c5df11ad329c 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -358,41 +358,20 @@ size_t thread__fprintf(struct thread *thread, FILE *f= p) int thread__insert_map(struct thread *thread, struct map *map) { int ret; + uint16_t e_machine =3D thread__e_machine(thread, /*machine=3D*/NULL, /*e_= flags=3D*/NULL); =20 - ret =3D unwind__prepare_access(thread__maps(thread), map, NULL); + ret =3D unwind__prepare_access(thread__maps(thread), e_machine); if (ret) return ret; =20 return maps__fixup_overlap_and_insert(thread__maps(thread), map); } =20 -struct thread__prepare_access_maps_cb_args { - int err; - struct maps *maps; -}; - -static int thread__prepare_access_maps_cb(struct map *map, void *data) -{ - bool initialized =3D false; - struct thread__prepare_access_maps_cb_args *args =3D data; - - args->err =3D unwind__prepare_access(args->maps, map, &initialized); - - return (args->err || initialized) ? 1 : 0; -} - static int thread__prepare_access(struct thread *thread) { - struct thread__prepare_access_maps_cb_args args =3D { - .err =3D 0, - }; - - if (dwarf_callchain_users) { - args.maps =3D thread__maps(thread); - maps__for_each_map(thread__maps(thread), thread__prepare_access_maps_cb,= &args); - } + uint16_t e_machine =3D thread__e_machine(thread, /*machine=3D*/NULL, /*e_= flags=3D*/NULL); =20 - return args.err; + return unwind__prepare_access(thread__maps(thread), e_machine); } =20 static int thread__clone_maps(struct thread *thread, struct thread *parent= , bool do_maps_clone) diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unw= ind-libunwind-local.c index 3ecdb468b859..8f0128ba05a7 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -722,16 +722,6 @@ static int _unwind__prepare_access(struct maps *maps) return 0; } =20 -static void _unwind__flush_access(struct maps *maps) -{ - unw_flush_cache(maps__addr_space(maps), 0, 0); -} - -static void _unwind__finish_access(struct maps *maps) -{ - unw_destroy_addr_space(maps__addr_space(maps)); -} - static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, void *arg, int max_stack) { @@ -821,8 +811,6 @@ static int _unwind__get_entries(unwind_entry_cb_t cb, v= oid *arg, static struct unwind_libunwind_ops _unwind_libunwind_ops =3D { .prepare_access =3D _unwind__prepare_access, - .flush_access =3D _unwind__flush_access, - .finish_access =3D _unwind__finish_access, .get_entries =3D _unwind__get_entries, }; =20 diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-li= bunwind.c index a0016b897dae..eaee7b78d87c 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -7,76 +7,55 @@ #include "debug.h" #include "env.h" #include "callchain.h" +#include "libunwind-arch/libunwind-arch.h" +#include +#include =20 struct unwind_libunwind_ops __weak *local_unwind_libunwind_ops; struct unwind_libunwind_ops __weak *x86_32_unwind_libunwind_ops; struct unwind_libunwind_ops __weak *arm64_unwind_libunwind_ops; =20 -int unwind__prepare_access(struct maps *maps, struct map *map, bool *initi= alized) +int unwind__prepare_access(struct maps *maps, uint16_t e_machine) { - const char *arch; - enum dso_type dso_type; struct unwind_libunwind_ops *ops =3D local_unwind_libunwind_ops; - struct dso *dso =3D map__dso(map); - struct machine *machine; - int err; =20 if (!dwarf_callchain_users) return 0; =20 if (maps__addr_space(maps)) { - pr_debug("unwind: thread map already set, dso=3D%s\n", dso__name(dso)); - if (initialized) - *initialized =3D true; + pr_debug3("unwind: thread map already set\n"); return 0; } =20 - machine =3D maps__machine(maps); - /* env->arch is NULL for live-mode (i.e. perf top) */ - if (!machine->env || !machine->env->arch) - goto out_register; - - dso_type =3D dso__type(dso, machine); - if (dso_type =3D=3D DSO__TYPE_UNKNOWN) - return 0; - - arch =3D perf_env__arch(machine->env); - - if (!strcmp(arch, "x86")) { - if (dso_type !=3D DSO__TYPE_64BIT) + if (e_machine !=3D EM_HOST) { + /* If not live/local mode. */ + switch (e_machine) { + case EM_386: ops =3D x86_32_unwind_libunwind_ops; - } else if (!strcmp(arch, "arm64") || !strcmp(arch, "arm")) { - if (dso_type =3D=3D DSO__TYPE_64BIT) + break; + case EM_AARCH64: ops =3D arm64_unwind_libunwind_ops; - } - - if (!ops) { - pr_warning_once("unwind: target platform=3D%s is not supported\n", arch); + break; + default: + pr_warning_once("unwind: ELF machine type %d is not supported\n", + e_machine); return 0; + } } -out_register: maps__set_unwind_libunwind_ops(maps, ops); + maps__set_e_machine(maps, e_machine); =20 - err =3D maps__unwind_libunwind_ops(maps)->prepare_access(maps); - if (initialized) - *initialized =3D err ? false : true; - return err; + return maps__unwind_libunwind_ops(maps)->prepare_access(maps); } =20 void unwind__flush_access(struct maps *maps) { - const struct unwind_libunwind_ops *ops =3D maps__unwind_libunwind_ops(map= s); - - if (ops) - ops->flush_access(maps); + libunwind_arch__flush_access(maps); } =20 void unwind__finish_access(struct maps *maps) { - const struct unwind_libunwind_ops *ops =3D maps__unwind_libunwind_ops(map= s); - - if (ops) - ops->finish_access(maps); + libunwind_arch__finish_access(maps); } =20 int libunwind__get_entries(unwind_entry_cb_t cb, void *arg, diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index e32d39ab41c6..09fc60df262d 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -2,6 +2,7 @@ #ifndef __UNWIND_H #define __UNWIND_H =20 +#include #include #include #include "util/map_symbol.h" @@ -20,8 +21,6 @@ typedef int (*unwind_entry_cb_t)(struct unwind_entry *ent= ry, void *arg); =20 struct unwind_libunwind_ops { int (*prepare_access)(struct maps *maps); - void (*flush_access)(struct maps *maps); - void (*finish_access)(struct maps *maps); int (*get_entries)(unwind_entry_cb_t cb, void *arg, struct thread *thread, struct perf_sample *data, int max_stack, bool best_effort); @@ -53,13 +52,12 @@ int libunwind__get_entries(unwind_entry_cb_t cb, void *= arg, struct thread *thread, struct perf_sample *data, int max_stack, bool best_effort); -int unwind__prepare_access(struct maps *maps, struct map *map, bool *initi= alized); +int unwind__prepare_access(struct maps *maps, uint16_t e_machine); void unwind__flush_access(struct maps *maps); void unwind__finish_access(struct maps *maps); #else static inline int unwind__prepare_access(struct maps *maps __maybe_unused, - struct map *map __maybe_unused, - bool *initialized __maybe_unused) + uint16_t e_machine __maybe_unused) { return 0; } --=20 2.53.0.473.g4a7958ca14-goog From nobody Thu Apr 9 20:26:03 2026 Received: from mail-dy1-f201.google.com (mail-dy1-f201.google.com [74.125.82.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C3C42338597 for ; Thu, 5 Mar 2026 22:19:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772749201; cv=none; b=GGJc9AD9SE2130AJJuLz6WiDh7yin6hevlRO0moYzxnO2jnl/0PASYOP/L27+o8yfiYVz0BvZbHpJElFNrubkgfE82H6TlFuzI6B05D7Tkit9fcNR3ga5liA05Jw4ZuOAQP9KLQfx/4FFWamlJSCqDbGqIaHbbK5ZHmh/smHtd0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772749201; c=relaxed/simple; bh=NswgKruX1r2uFHQ+nqDjLjRXECddAcMEttkaR/OKrBg=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=OBewEvKLy4yMx5EIWPhL0k4PcMzxYgCG4G3/nd10kqIxNEDsgQ5NNUTx2wq861oIbAwYSXGm7vuVizYBmLvMSlP+kvc0j9oizf87g7nS2NSX6nrC31Q6Ep7k1oikPttuJq9QNfcn0akxS4RKtQIyWHaqcVfRcwBkW1kYkMgpnmM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=ujHjAL5t; arc=none smtp.client-ip=74.125.82.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="ujHjAL5t" Received: by mail-dy1-f201.google.com with SMTP id 5a478bee46e88-2ba9a744f7dso9910709eec.0 for ; Thu, 05 Mar 2026 14:19:54 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1772749194; x=1773353994; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=e+Qr/VHl14aHGIYy9eFtswAsduB5U30SZ0Kx4WrmrcY=; b=ujHjAL5temyCldE0mQcRgNjF3pOP99tRFTSxufvFvXE8nKj1cxgx9Q6gX+LNf6fSyZ lu1XPKDrtMYXH9IfFThOHFCR0w2ZHekpO693VMcA44lvqLVaDK4pDtZAS31ubSUrZ/zu TEFmzeCYlf6O+BNJeA6DCjLcxUUbQqNEBevONw2Bao9WIh1LDx8AfsahlPmH+j/BD+zb 84Vwqfh/yqzi4V9ewLxDFWD6duTDCGRIDbPN1FkBsQvxo5KVmrS4rZdOp8pTQ9UTtBiN uheP1xHw0VAXg29DUURQx58gizMFbsKiV9V3npBds/ihQq2x5TH5qNitFnIIxR54nvH1 etsQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772749194; x=1773353994; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=e+Qr/VHl14aHGIYy9eFtswAsduB5U30SZ0Kx4WrmrcY=; b=arsLN0jsGeaGtKY2Lw1H94u6sg8Sp2Mb9h9ggWTIC8Q2dGeopB0OMK+UKDA+rxvNqG WkxdaVQ/DI6KZSczX+Or8E5MpovBjvATfARs/nAx4/WgY9P8fKZbYeVlIoMKJzFd/gSt ThTLHQ2n8qr08E1rtsNCIUVWVZ0EQa88xmSdFtce9TkTf1H/RApp33leo+EjS48j/OZy 2u9ERpj4dlMPuBiRb3IT2I9M2N3uqmPrqYdQ7gm3YWoSN2l2wPnUbdYt2GS3jd/o4G1a kn0FgUYU1N7adtlLu7NezTsa52zyIi35AbpIEBV8wzAfBUxgt7xtvuGfOWf6sIEHFb5l 1AEg== X-Forwarded-Encrypted: i=1; AJvYcCUx1kSg7cGFwmrxGSgJpYzf9RLeC4tN6LwWHaI2pkUgtVQf1iETKa5W/t7JTPm3rxVaYGg/nJyET0he4pM=@vger.kernel.org X-Gm-Message-State: AOJu0Yzl0zcSn5bkNvUlK2sgyuSTMsDXnzcnEH3k2KhMYrqk5wv6pOXq Fe54KB7+OcbuMRLflRCrTYRICYQzcRXcSkgG8rw0DFN7hUsafzR7LXU9wtvLsufm712fqjj4Zsk u0No0j0evRg== X-Received: from dycmp13.prod.google.com ([2002:a05:7301:70d:b0:2be:2ed4:ab9b]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7300:ed01:b0:2ba:9cfb:2744 with SMTP id 5a478bee46e88-2be4e063ce8mr13569eec.30.1772749193635; Thu, 05 Mar 2026 14:19:53 -0800 (PST) Date: Thu, 5 Mar 2026 14:19:26 -0800 In-Reply-To: <20260305221927.3237145-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260305221927.3237145-1-irogers@google.com> X-Mailer: git-send-email 2.53.0.473.g4a7958ca14-goog Message-ID: <20260305221927.3237145-8-irogers@google.com> Subject: [PATCH v2 7/8] perf unwind-libunwind: Remove libunwind-local From: Ian Rogers 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 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Local unwinding only works on the machine libunwind is built for, rather than cross platform, the APIs for remote and local unwinding are similar but types like unw_word_t depend on the included header. Place the architecture specific code into the appropriate libunwind-.c file. Put generic code in unwind-libunwind.c and use libunwind-arch to choose the correct implementation based on the thread's e_machine. Structuring the code this way avoids including the unwind-libunwind-local.c for each architecture of remote unwinding. Data is moved into the struct unwind_info to simplify the architecture and generic code, trying to keep as much code as possible generic. Signed-off-by: Ian Rogers --- tools/perf/util/Build | 3 - .../perf/util/libunwind-arch/libunwind-arch.c | 184 ++++ .../perf/util/libunwind-arch/libunwind-arch.h | 234 +++++ .../perf/util/libunwind-arch/libunwind-arm.c | 256 ++++++ .../util/libunwind-arch/libunwind-arm64.c | 255 ++++++ .../perf/util/libunwind-arch/libunwind-i386.c | 254 ++++++ .../util/libunwind-arch/libunwind-loongarch.c | 255 ++++++ .../perf/util/libunwind-arch/libunwind-mips.c | 255 ++++++ .../util/libunwind-arch/libunwind-ppc32.c | 255 ++++++ .../util/libunwind-arch/libunwind-ppc64.c | 255 ++++++ .../perf/util/libunwind-arch/libunwind-s390.c | 255 ++++++ .../util/libunwind-arch/libunwind-x86_64.c | 253 ++++++ tools/perf/util/libunwind/arm64.c | 35 - tools/perf/util/libunwind/x86_32.c | 29 - tools/perf/util/maps.c | 10 - tools/perf/util/maps.h | 2 - tools/perf/util/unwind-libunwind-local.c | 820 ------------------ tools/perf/util/unwind-libunwind.c | 654 +++++++++++++- tools/perf/util/unwind.h | 7 - 19 files changed, 3334 insertions(+), 937 deletions(-) delete mode 100644 tools/perf/util/libunwind/arm64.c delete mode 100644 tools/perf/util/libunwind/x86_32.c delete mode 100644 tools/perf/util/unwind-libunwind-local.c diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 434dc6716a75..be2745567d61 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -228,11 +228,8 @@ perf-util-$(CONFIG_LIBDW) +=3D annotate-data.o perf-util-$(CONFIG_LIBDW) +=3D libdw.o perf-util-$(CONFIG_LIBDW) +=3D unwind-libdw.o =20 -perf-util-$(CONFIG_LOCAL_LIBUNWIND) +=3D unwind-libunwind-local.o perf-util-$(CONFIG_LIBUNWIND) +=3D unwind-libunwind.o perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-arch/ -perf-util-$(CONFIG_LIBUNWIND_X86) +=3D libunwind/x86_32.o -perf-util-$(CONFIG_LIBUNWIND_AARCH64) +=3D libunwind/arm64.o =20 ifeq ($(CONFIG_LIBTRACEEVENT),y) perf-util-$(CONFIG_LIBBABELTRACE) +=3D data-convert-bt.o diff --git a/tools/perf/util/libunwind-arch/libunwind-arch.c b/tools/perf/u= til/libunwind-arch/libunwind-arch.c index 9692e6c81492..8539b4233df4 100644 --- a/tools/perf/util/libunwind-arch/libunwind-arch.c +++ b/tools/perf/util/libunwind-arch/libunwind-arch.c @@ -112,3 +112,187 @@ void libunwind_arch__finish_access(struct maps *maps) break; } } + +void *libunwind_arch__create_addr_space(unsigned int e_machine) +{ + switch (e_machine) { + case EM_ARM: + return __libunwind_arch__create_addr_space_arm(); + case EM_AARCH64: + return __libunwind_arch__create_addr_space_arm64(); + case EM_LOONGARCH: + return __libunwind_arch__create_addr_space_loongarch(); + case EM_MIPS: + return __libunwind_arch__create_addr_space_mips(); + case EM_PPC: + return __libunwind_arch__create_addr_space_ppc32(); + case EM_PPC64: + return __libunwind_arch__create_addr_space_ppc64(); + case EM_S390: + return __libunwind_arch__create_addr_space_s390(); + case EM_386: + return __libunwind_arch__create_addr_space_i386(); + case EM_X86_64: + return __libunwind_arch__create_addr_space_x86_64(); + default: + pr_err("ELF MACHINE %x is not supported.\n", e_machine); + return NULL; + } +} + +int libunwind_arch__dwarf_search_unwind_table(unsigned int e_machine, + void *as, + uint64_t ip, + struct libarch_unwind__dyn_info *di, + void *pi, + int need_unwind_info, + void *arg) +{ + switch (e_machine) { + case EM_ARM: + return __libunwind_arch__dwarf_search_unwind_table_arm(as, ip, di, pi, + need_unwind_info, arg); + case EM_AARCH64: + return __libunwind_arch__dwarf_search_unwind_table_arm64(as, ip, di, pi, + need_unwind_info, arg); + case EM_LOONGARCH: + return __libunwind_arch__dwarf_search_unwind_table_loongarch(as, ip, di,= pi, + need_unwind_info, arg); + case EM_MIPS: + return __libunwind_arch__dwarf_search_unwind_table_mips(as, ip, di, pi, + need_unwind_info, arg); + case EM_PPC: + return __libunwind_arch__dwarf_search_unwind_table_ppc32(as, ip, di, pi, + need_unwind_info, arg); + case EM_PPC64: + return __libunwind_arch__dwarf_search_unwind_table_ppc64(as, ip, di, pi, + need_unwind_info, arg); + case EM_S390: + return __libunwind_arch__dwarf_search_unwind_table_s390(as, ip, di, pi, + need_unwind_info, arg); + case EM_386: + return __libunwind_arch__dwarf_search_unwind_table_i386(as, ip, di, pi, + need_unwind_info, arg); + case EM_X86_64: + return __libunwind_arch__dwarf_search_unwind_table_x86_64(as, ip, di, pi, + need_unwind_info, arg); + default: + pr_err("ELF MACHINE %x is not supported.\n", e_machine); + return -EINVAL; + } +} + +int libunwind_arch__dwarf_find_debug_frame(unsigned int e_machine, + int found, + struct libarch_unwind__dyn_info *di_debug, + uint64_t ip, + uint64_t segbase, + const char *obj_name, + uint64_t start, + uint64_t end) +{ + switch (e_machine) { + case EM_ARM: + return __libunwind_arch__dwarf_find_debug_frame_arm(found, di_debug, ip,= segbase, + obj_name, start, end); + case EM_AARCH64: + return __libunwind_arch__dwarf_find_debug_frame_arm64(found, di_debug, i= p, segbase, + obj_name, start, end); + case EM_LOONGARCH: + return __libunwind_arch__dwarf_find_debug_frame_loongarch(found, di_debu= g, ip, + segbase, obj_name, + start, end); + case EM_MIPS: + return __libunwind_arch__dwarf_find_debug_frame_mips(found, di_debug, ip= , segbase, + obj_name, start, end); + case EM_PPC: + return __libunwind_arch__dwarf_find_debug_frame_ppc32(found, di_debug, i= p, segbase, + obj_name, start, end); + case EM_PPC64: + return __libunwind_arch__dwarf_find_debug_frame_ppc64(found, di_debug, i= p, segbase, + obj_name, start, end); + case EM_S390: + return __libunwind_arch__dwarf_find_debug_frame_s390(found, di_debug, ip= , segbase, + obj_name, start, end); + case EM_386: + return __libunwind_arch__dwarf_find_debug_frame_i386(found, di_debug, ip= , segbase, + obj_name, start, end); + case EM_X86_64: + return __libunwind_arch__dwarf_find_debug_frame_x86_64(found, di_debug, = ip, segbase, + obj_name, start, end); + default: + pr_err("ELF MACHINE %x is not supported.\n", e_machine); + return -EINVAL; + } +} + +struct unwind_info *libunwind_arch_unwind_info__new(struct thread *thread, + struct perf_sample *sample, int max_stack, + bool best_effort, uint16_t e_machine, + uint64_t first_ip) +{ + switch (e_machine) { + case EM_ARM: + return __libunwind_arch_unwind_info__new_arm(thread, sample, max_stack, + best_effort, first_ip); + case EM_AARCH64: + return __libunwind_arch_unwind_info__new_arm64(thread, sample, max_stack, + best_effort, first_ip); + case EM_LOONGARCH: + return __libunwind_arch_unwind_info__new_loongarch(thread, sample, max_s= tack, + best_effort, first_ip); + case EM_MIPS: + return __libunwind_arch_unwind_info__new_mips(thread, sample, max_stack, + best_effort, first_ip); + case EM_PPC: + return __libunwind_arch_unwind_info__new_ppc32(thread, sample, max_stack, + best_effort, first_ip); + case EM_PPC64: + return __libunwind_arch_unwind_info__new_ppc64(thread, sample, max_stack, + best_effort, first_ip); + case EM_S390: + return __libunwind_arch_unwind_info__new_s390(thread, sample, max_stack, + best_effort, first_ip); + case EM_386: + return __libunwind_arch_unwind_info__new_i386(thread, sample, max_stack, + best_effort, first_ip); + case EM_X86_64: + return __libunwind_arch_unwind_info__new_x86_64(thread, sample, max_stac= k, + best_effort, first_ip); + default: + pr_err("ELF MACHINE %x is not supported.\n", e_machine); + return NULL; + } +} + +void libunwind_arch_unwind_info__delete(struct unwind_info *ui) +{ + free(ui); +} + +int libunwind_arch__unwind_step(struct unwind_info *ui) +{ + switch (ui->e_machine) { + case EM_ARM: + return __libunwind_arch__unwind_step_arm(ui); + case EM_AARCH64: + return __libunwind_arch__unwind_step_arm64(ui); + case EM_LOONGARCH: + return __libunwind_arch__unwind_step_loongarch(ui); + case EM_MIPS: + return __libunwind_arch__unwind_step_mips(ui); + case EM_PPC: + return __libunwind_arch__unwind_step_ppc32(ui); + case EM_PPC64: + return __libunwind_arch__unwind_step_ppc64(ui); + case EM_S390: + return __libunwind_arch__unwind_step_s390(ui); + case EM_386: + return __libunwind_arch__unwind_step_i386(ui); + case EM_X86_64: + return __libunwind_arch__unwind_step_x86_64(ui); + default: + pr_err("ELF MACHINE %x is not supported.\n", ui->e_machine); + return -EINVAL; + } +} diff --git a/tools/perf/util/libunwind-arch/libunwind-arch.h b/tools/perf/u= til/libunwind-arch/libunwind-arch.h index c00277a5e914..2bf7fc33313b 100644 --- a/tools/perf/util/libunwind-arch/libunwind-arch.h +++ b/tools/perf/util/libunwind-arch/libunwind-arch.h @@ -2,7 +2,36 @@ #ifndef __LIBUNWIND_ARCH_H #define __LIBUNWIND_ARCH_H =20 +#include +#include +#include + +struct machine; struct maps; +struct perf_sample; +struct thread; + +struct unwind_info { + struct machine *machine; + struct thread *thread; + struct perf_sample *sample; + void *cursor; + uint64_t *ips; + int cur_ip; + int max_ips; + unsigned int unw_word_t_size; + uint16_t e_machine; + bool best_effort; +}; + +struct libarch_unwind__dyn_info { + uint64_t start_ip; + uint64_t end_ip; + uint64_t segbase; + uint64_t table_data; + uint64_t table_len; +}; +struct libarch_unwind__proc_info; =20 int __get_perf_regnum_for_unw_regnum_arm(int unw_regnum); int __get_perf_regnum_for_unw_regnum_arm64(int unw_regnum); @@ -37,4 +66,209 @@ void __libunwind_arch__finish_access_i386(struct maps *= maps); void __libunwind_arch__finish_access_x86_64(struct maps *maps); void libunwind_arch__finish_access(struct maps *maps); =20 +void *__libunwind_arch__create_addr_space_arm(void); +void *__libunwind_arch__create_addr_space_arm64(void); +void *__libunwind_arch__create_addr_space_loongarch(void); +void *__libunwind_arch__create_addr_space_mips(void); +void *__libunwind_arch__create_addr_space_ppc32(void); +void *__libunwind_arch__create_addr_space_ppc64(void); +void *__libunwind_arch__create_addr_space_s390(void); +void *__libunwind_arch__create_addr_space_i386(void); +void *__libunwind_arch__create_addr_space_x86_64(void); +void *libunwind_arch__create_addr_space(unsigned int e_machine); + +int __libunwind__find_proc_info(void *as, uint64_t ip, void *pi, int need_= unwind_info, void *arg); +int __libunwind__access_mem(void *as, uint64_t addr, void *valp_word, int = __write, void *arg); +int __libunwind__access_reg(void *as, int regnum, void *valp_word, int __w= rite, void *arg); + +int __libunwind_arch__dwarf_search_unwind_table_arm(void *as, uint64_t ip, + struct libarch_unwind__dyn_info *di, + void *pi, + int need_unwind_info, + void *arg); +int __libunwind_arch__dwarf_search_unwind_table_arm64(void *as, uint64_t i= p, + struct libarch_unwind__dyn_info *di, + void *pi, + int need_unwind_info, + void *arg); +int __libunwind_arch__dwarf_search_unwind_table_loongarch(void *as, uint64= _t ip, + struct libarch_unwind__dyn_info *di, + void *pi, + int need_unwind_info, + void *arg); +int __libunwind_arch__dwarf_search_unwind_table_mips(void *as, uint64_t ip, + struct libarch_unwind__dyn_info *di, + void *pi, + int need_unwind_info, + void *arg); +int __libunwind_arch__dwarf_search_unwind_table_ppc32(void *as, uint64_t i= p, + struct libarch_unwind__dyn_info *di, + void *pi, + int need_unwind_info, + void *arg); +int __libunwind_arch__dwarf_search_unwind_table_ppc64(void *as, uint64_t i= p, + struct libarch_unwind__dyn_info *di, + void *pi, + int need_unwind_info, + void *arg); +int __libunwind_arch__dwarf_search_unwind_table_s390(void *as, uint64_t ip, + struct libarch_unwind__dyn_info *di, + void *pi, + int need_unwind_info, + void *arg); +int __libunwind_arch__dwarf_search_unwind_table_i386(void *as, uint64_t ip, + struct libarch_unwind__dyn_info *di, + void *pi, + int need_unwind_info, + void *arg); +int __libunwind_arch__dwarf_search_unwind_table_x86_64(void *as, uint64_t = ip, + struct libarch_unwind__dyn_info *di, + void *pi, + int need_unwind_info, + void *arg); +int libunwind_arch__dwarf_search_unwind_table(unsigned int e_machine, + void *as, + uint64_t ip, + struct libarch_unwind__dyn_info *di, + void *pi, + int need_unwind_info, + void *arg); + +int __libunwind_arch__dwarf_find_debug_frame_arm(int found, + struct libarch_unwind__dyn_info *di_debug, + uint64_t ip, + uint64_t segbase, + const char *obj_name, + uint64_t start, + uint64_t end); +int __libunwind_arch__dwarf_find_debug_frame_arm64(int found, + struct libarch_unwind__dyn_info *di_debug, + uint64_t ip, + uint64_t segbase, + const char *obj_name, + uint64_t start, + uint64_t end); +int __libunwind_arch__dwarf_find_debug_frame_loongarch(int found, + struct libarch_unwind__dyn_info *di_debug, + uint64_t ip, + uint64_t segbase, + const char *obj_name, + uint64_t start, + uint64_t end); +int __libunwind_arch__dwarf_find_debug_frame_mips(int found, + struct libarch_unwind__dyn_info *di_debug, + uint64_t ip, + uint64_t segbase, + const char *obj_name, + uint64_t start, + uint64_t end); +int __libunwind_arch__dwarf_find_debug_frame_ppc32(int found, + struct libarch_unwind__dyn_info *di_debug, + uint64_t ip, + uint64_t segbase, + const char *obj_name, + uint64_t start, + uint64_t end); +int __libunwind_arch__dwarf_find_debug_frame_ppc64(int found, + struct libarch_unwind__dyn_info *di_debug, + uint64_t ip, + uint64_t segbase, + const char *obj_name, + uint64_t start, + uint64_t end); +int __libunwind_arch__dwarf_find_debug_frame_s390(int found, + struct libarch_unwind__dyn_info *di_debug, + uint64_t ip, + uint64_t segbase, + const char *obj_name, + uint64_t start, + uint64_t end); +int __libunwind_arch__dwarf_find_debug_frame_i386(int found, + struct libarch_unwind__dyn_info *di_debug, + uint64_t ip, + uint64_t segbase, + const char *obj_name, + uint64_t start, + uint64_t end); +int __libunwind_arch__dwarf_find_debug_frame_x86_64(int found, + struct libarch_unwind__dyn_info *di_debug, + uint64_t ip, + uint64_t segbase, + const char *obj_name, + uint64_t start, + uint64_t end); +int libunwind_arch__dwarf_find_debug_frame(unsigned int e_machine, + int found, + struct libarch_unwind__dyn_info *di_debug, + uint64_t ip, + uint64_t segbase, + const char *obj_name, + uint64_t start, + uint64_t end); + +struct unwind_info *__libunwind_arch_unwind_info__new_arm(struct thread *t= hread, + struct perf_sample *sample, + int max_stack, + bool best_effort, + uint64_t first_ip); +struct unwind_info *__libunwind_arch_unwind_info__new_arm64(struct thread = *thread, + struct perf_sample *sample, + int max_stack, + bool best_effort, + uint64_t first_ip); +struct unwind_info *__libunwind_arch_unwind_info__new_loongarch(struct thr= ead *thread, + struct perf_sample *sample, + int max_stack, + bool best_effort, + uint64_t first_ip); +struct unwind_info *__libunwind_arch_unwind_info__new_mips(struct thread *= thread, + struct perf_sample *sample, + int max_stack, + bool best_effort, + uint64_t first_ip); +struct unwind_info *__libunwind_arch_unwind_info__new_ppc32(struct thread = *thread, + struct perf_sample *sample, + int max_stack, + bool best_effort, + uint64_t first_ip); +struct unwind_info *__libunwind_arch_unwind_info__new_ppc64(struct thread = *thread, + struct perf_sample *sample, + int max_stack, + bool best_effort, + uint64_t first_ip); +struct unwind_info *__libunwind_arch_unwind_info__new_s390(struct thread *= thread, + struct perf_sample *sample, + int max_stack, + bool best_effort, + uint64_t first_ip); +struct unwind_info *__libunwind_arch_unwind_info__new_i386(struct thread *= thread, + struct perf_sample *sample, + int max_stack, + bool best_effort, + uint64_t first_ip); +struct unwind_info *__libunwind_arch_unwind_info__new_x86_64(struct thread= *thread, + struct perf_sample *sample, + int max_stack, + bool best_effort, + uint64_t first_ip); +struct unwind_info *libunwind_arch_unwind_info__new(struct thread *thread, + struct perf_sample *sample, + int max_stack, + bool best_effort, + uint16_t e_machine, + uint64_t first_ip); + +void libunwind_arch_unwind_info__delete(struct unwind_info *ui); + +int __libunwind_arch__unwind_step_arm(struct unwind_info *ui); +int __libunwind_arch__unwind_step_arm64(struct unwind_info *ui); +int __libunwind_arch__unwind_step_loongarch(struct unwind_info *ui); +int __libunwind_arch__unwind_step_mips(struct unwind_info *ui); +int __libunwind_arch__unwind_step_ppc32(struct unwind_info *ui); +int __libunwind_arch__unwind_step_ppc64(struct unwind_info *ui); +int __libunwind_arch__unwind_step_s390(struct unwind_info *ui); +int __libunwind_arch__unwind_step_i386(struct unwind_info *ui); +int __libunwind_arch__unwind_step_x86_64(struct unwind_info *ui); +int libunwind_arch__unwind_step(struct unwind_info *ui); + #endif /* __LIBUNWIND_ARCH_H */ diff --git a/tools/perf/util/libunwind-arch/libunwind-arm.c b/tools/perf/ut= il/libunwind-arch/libunwind-arm.c index bbaf01406c52..b31aeeab1663 100644 --- a/tools/perf/util/libunwind-arch/libunwind-arm.c +++ b/tools/perf/util/libunwind-arch/libunwind-arm.c @@ -2,8 +2,12 @@ #include "libunwind-arch.h" #include "../debug.h" #include "../maps.h" +#include "../thread.h" #include "../../../arch/arm/include/uapi/asm/perf_regs.h" #include +#include +#include +#include #include =20 #ifdef HAVE_LIBUNWIND_ARM_SUPPORT @@ -32,3 +36,255 @@ void __libunwind_arch__finish_access_arm(struct maps *m= aps __maybe_unused) unw_destroy_addr_space(maps__addr_space(maps)); #endif } + + +#ifdef HAVE_LIBUNWIND_ARM_SUPPORT +static int find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_inf= o_t *pi, + int need_unwind_info, void *arg) +{ + return __libunwind__find_proc_info(as, ip, pi, need_unwind_info, arg, siz= eof(unw_word_t)); +} + +static void put_unwind_info(unw_addr_space_t __maybe_unused as, + unw_proc_info_t *pi __maybe_unused, + void *arg __maybe_unused) +{ + pr_debug("unwind: put_unwind_info called\n"); +} + +static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused *dil_addr, + void __maybe_unused *arg) +{ + return -UNW_ENOINFO; +} + +static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *va= lp, + int __write, void *arg) +{ + return __libunwind__access_mem(as, addr, valp, __write, arg, sizeof(unw_w= ord_t)); +} + +static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t= *valp, + int __write, void *arg) +{ + return __libunwind__access_reg(as, regnum, valp, __write, arg, sizeof(unw= _word_t)); +} + +static int access_fpreg(unw_addr_space_t __maybe_unused as, + unw_regnum_t __maybe_unused num, + unw_fpreg_t __maybe_unused *val, + int __maybe_unused __write, + void __maybe_unused *arg) +{ + pr_err("unwind: access_fpreg unsupported\n"); + return -UNW_EINVAL; +} + +static int resume(unw_addr_space_t __maybe_unused as, + unw_cursor_t __maybe_unused *cu, + void __maybe_unused *arg) +{ + pr_err("unwind: resume unsupported\n"); + return -UNW_EINVAL; +} + +static int get_proc_name(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused addr, + char __maybe_unused *bufp, size_t __maybe_unused buf_len, + unw_word_t __maybe_unused *offp, void __maybe_unused *arg) +{ + pr_err("unwind: get_proc_name unsupported\n"); + return -UNW_EINVAL; +} +#endif + +void *__libunwind_arch__create_addr_space_arm(void) +{ +#ifdef HAVE_LIBUNWIND_ARM_SUPPORT + static unw_accessors_t accessors =3D { + .find_proc_info =3D find_proc_info, + .put_unwind_info =3D put_unwind_info, + .get_dyn_info_list_addr =3D get_dyn_info_list_addr, + .access_mem =3D access_mem, + .access_reg =3D access_reg, + .access_fpreg =3D access_fpreg, + .resume =3D resume, + .get_proc_name =3D get_proc_name, + }; + unw_addr_space_t addr_space; + + addr_space =3D unw_create_addr_space(&accessors, /*byte_order=3D*/0); + unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); + return addr_space; +#else + return NULL; +#endif +} + +#ifdef HAVE_LIBUNWIND_ARM_SUPPORT +extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) +#endif + +int __libunwind_arch__dwarf_search_unwind_table_arm(void *as __maybe_unuse= d, + uint64_t ip __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + void *pi __maybe_unused, + int need_unwind_info __maybe_unused, + void *arg __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_ARM_SUPPORT + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, = arg); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +#if defined(HAVE_LIBUNWIND_ARM_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_FRA= ME_ARM) +extern int UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_= debug, + unw_word_t ip, + unw_word_t segbase, + const char *obj_name, unw_word_t start, + unw_word_t end); +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) +#endif + +int __libunwind_arch__dwarf_find_debug_frame_arm(int found __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + uint64_t ip __maybe_unused, + uint64_t segbase __maybe_unused, + const char *obj_name __maybe_unused, + uint64_t start __maybe_unused, + uint64_t end __maybe_unused) +{ +#if defined(HAVE_LIBUNWIND_ARM_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_FRA= ME_ARM) + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_find_debug_frame(found, &di, ip, segbase, obj_name, sta= rt, end); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +struct unwind_info *__libunwind_arch_unwind_info__new_arm(struct thread *t= hread __maybe_unused, + struct perf_sample *sample __maybe_unused, + int max_stack __maybe_unused, + bool best_effort __maybe_unused, + uint64_t first_ip __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_ARM_SUPPORT + struct arch_unwind_info { + struct unwind_info ui; + unw_cursor_t _cursor; + uint64_t _ips[]; + }; + + struct maps *maps =3D thread__maps(thread); + void *addr_space =3D maps__addr_space(maps); + struct arch_unwind_info *ui; + int ret; + + if (addr_space =3D=3D NULL) + return NULL; + + ui =3D zalloc(sizeof(*ui) + sizeof(ui->_ips[0]) * max_stack); + if (!ui) + return NULL; + + ui->ui.machine =3D maps__machine(maps); + ui->ui.thread =3D thread; + ui->ui.sample =3D sample; + ui->ui.cursor =3D &ui->_cursor; + ui->ui.ips =3D &ui->_ips[0]; + ui->ui.ips[0] =3D first_ip; + ui->ui.cur_ip =3D 1; + ui->ui.max_ips =3D max_stack; + ui->ui.unw_word_t_size =3D sizeof(unw_word_t); + ui->ui.e_machine =3D EM_ARM; + ui->ui.best_effort =3D best_effort; + + ret =3D unw_init_remote(&ui->_cursor, addr_space, &ui->ui); + if (ret) { + if (!best_effort) + pr_err("libunwind: %s\n", unw_strerror(ret)); + free(ui); + return NULL; + } + + return &ui->ui; +#else + return NULL; +#endif +} + +int __libunwind_arch__unwind_step_arm(struct unwind_info *ui __maybe_unuse= d) +{ +#ifdef HAVE_LIBUNWIND_ARM_SUPPORT + int ret; + + if (ui->cur_ip >=3D ui->max_ips) + return -1; + + ret =3D unw_step(ui->cursor); + if (ret > 0) { + uint64_t ip; + + unw_get_reg(ui->cursor, UNW_REG_IP, &ip); + + if (unw_is_signal_frame(ui->cursor) <=3D 0) { + /* + * Decrement the IP for any non-activation frames. This + * is required to properly find the srcline for caller + * frames. See also the documentation for + * dwfl_frame_pc(), which this code tries to replicate. + */ + --ip; + } + ui->ips[ui->cur_ip++] =3D ip; + } + return ret; +#else + return -EINVAL; +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-arm64.c b/tools/perf/= util/libunwind-arch/libunwind-arm64.c index 8ba510089736..ceeae2d0f8e9 100644 --- a/tools/perf/util/libunwind-arch/libunwind-arm64.c +++ b/tools/perf/util/libunwind-arch/libunwind-arm64.c @@ -2,8 +2,12 @@ #include "libunwind-arch.h" #include "../debug.h" #include "../maps.h" +#include "../thread.h" #include "../../../arch/arm64/include/uapi/asm/perf_regs.h" #include +#include +#include +#include #include =20 #ifdef HAVE_LIBUNWIND_AARCH64_SUPPORT @@ -32,3 +36,254 @@ void __libunwind_arch__finish_access_arm64(struct maps = *maps __maybe_unused) unw_destroy_addr_space(maps__addr_space(maps)); #endif } + +#ifdef HAVE_LIBUNWIND_AARCH64_SUPPORT +static int find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_inf= o_t *pi, + int need_unwind_info, void *arg) +{ + return __libunwind__find_proc_info(as, ip, pi, need_unwind_info, arg, siz= eof(unw_word_t)); +} + +static void put_unwind_info(unw_addr_space_t __maybe_unused as, + unw_proc_info_t *pi __maybe_unused, + void *arg __maybe_unused) +{ + pr_debug("unwind: put_unwind_info called\n"); +} + +static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused *dil_addr, + void __maybe_unused *arg) +{ + return -UNW_ENOINFO; +} + +static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *va= lp, + int __write, void *arg) +{ + return __libunwind__access_mem(as, addr, valp, __write, arg, sizeof(unw_w= ord_t)); +} + +static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t= *valp, + int __write, void *arg) +{ + return __libunwind__access_reg(as, regnum, valp, __write, arg, sizeof(unw= _word_t)); +} + +static int access_fpreg(unw_addr_space_t __maybe_unused as, + unw_regnum_t __maybe_unused num, + unw_fpreg_t __maybe_unused *val, + int __maybe_unused __write, + void __maybe_unused *arg) +{ + pr_err("unwind: access_fpreg unsupported\n"); + return -UNW_EINVAL; +} + +static int resume(unw_addr_space_t __maybe_unused as, + unw_cursor_t __maybe_unused *cu, + void __maybe_unused *arg) +{ + pr_err("unwind: resume unsupported\n"); + return -UNW_EINVAL; +} + +static int get_proc_name(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused addr, + char __maybe_unused *bufp, size_t __maybe_unused buf_len, + unw_word_t __maybe_unused *offp, void __maybe_unused *arg) +{ + pr_err("unwind: get_proc_name unsupported\n"); + return -UNW_EINVAL; +} +#endif + +void *__libunwind_arch__create_addr_space_arm64(void) +{ +#ifdef HAVE_LIBUNWIND_AARCH64_SUPPORT + static unw_accessors_t accessors =3D { + .find_proc_info =3D find_proc_info, + .put_unwind_info =3D put_unwind_info, + .get_dyn_info_list_addr =3D get_dyn_info_list_addr, + .access_mem =3D access_mem, + .access_reg =3D access_reg, + .access_fpreg =3D access_fpreg, + .resume =3D resume, + .get_proc_name =3D get_proc_name, + }; + unw_addr_space_t addr_space; + + addr_space =3D unw_create_addr_space(&accessors, /*byte_order=3D*/0); + unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); + return addr_space; +#else + return NULL; +#endif +} + +#ifdef HAVE_LIBUNWIND_ARM64_SUPPORT +extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) +#endif + +int __libunwind_arch__dwarf_search_unwind_table_arm64(void *as __maybe_unu= sed, + uint64_t ip __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + void *pi __maybe_unused, + int need_unwind_info __maybe_unused, + void *arg __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_ARM64_SUPPORT + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, = arg); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +#if defined(HAVE_LIBUNWIND_ARM64_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_F= RAME_ARM64) +extern int UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_= debug, + unw_word_t ip, + unw_word_t segbase, + const char *obj_name, unw_word_t start, + unw_word_t end); +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) +#endif + +int __libunwind_arch__dwarf_find_debug_frame_arm64(int found __maybe_unuse= d, + struct libarch_unwind__dyn_info *_di __maybe_unused, + uint64_t ip __maybe_unused, + uint64_t segbase __maybe_unused, + const char *obj_name __maybe_unused, + uint64_t start __maybe_unused, + uint64_t end __maybe_unused) +{ +#if defined(HAVE_LIBUNWIND_ARM64_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_F= RAME_ARM64) + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_find_debug_frame(found, &di, ip, segbase, obj_name, sta= rt, end); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +struct unwind_info *__libunwind_arch_unwind_info__new_arm64(struct thread = *thread __maybe_unused, + struct perf_sample *sample __maybe_unused, + int max_stack __maybe_unused, + bool best_effort __maybe_unused, + uint64_t first_ip __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_ARM64_SUPPORT + struct arch_unwind_info { + struct unwind_info ui; + unw_cursor_t _cursor; + uint64_t _ips[]; + }; + + struct maps *maps =3D thread__maps(thread); + void *addr_space =3D maps__addr_space(maps); + struct arch_unwind_info *ui; + int ret; + + if (addr_space =3D=3D NULL) + return NULL; + + ui =3D zalloc(sizeof(*ui) + sizeof(ui->_ips[0]) * max_stack); + if (!ui) + return NULL; + + ui->ui.machine =3D maps__machine(maps); + ui->ui.thread =3D thread; + ui->ui.sample =3D sample; + ui->ui.cursor =3D &ui->_cursor; + ui->ui.ips =3D &ui->_ips[0]; + ui->ui.ips[0] =3D first_ip; + ui->ui.cur_ip =3D 1; + ui->ui.max_ips =3D max_stack; + ui->ui.unw_word_t_size =3D sizeof(unw_word_t); + ui->ui.e_machine =3D EM_AARCH64; + ui->ui.best_effort =3D best_effort; + + ret =3D unw_init_remote(&ui->_cursor, addr_space, &ui->ui); + if (ret) { + if (!best_effort) + pr_err("libunwind: %s\n", unw_strerror(ret)); + free(ui); + return NULL; + } + + return &ui->ui; +#else + return NULL; +#endif +} + +int __libunwind_arch__unwind_step_arm64(struct unwind_info *ui __maybe_unu= sed) +{ +#ifdef HAVE_LIBUNWIND_ARM64_SUPPORT + int ret; + + if (ui->cur_ip >=3D ui->max_ips) + return -1; + + ret =3D unw_step(ui->cursor); + if (ret > 0) { + uint64_t ip; + + unw_get_reg(ui->cursor, UNW_REG_IP, &ip); + + if (unw_is_signal_frame(ui->cursor) <=3D 0) { + /* + * Decrement the IP for any non-activation frames. This + * is required to properly find the srcline for caller + * frames. See also the documentation for + * dwfl_frame_pc(), which this code tries to replicate. + */ + --ip; + } + ui->ips[ui->cur_ip++] =3D ip; + } + return ret; +#else + return -EINVAL; +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-i386.c b/tools/perf/u= til/libunwind-arch/libunwind-i386.c index 45ff30c95c1b..fde40872a610 100644 --- a/tools/perf/util/libunwind-arch/libunwind-i386.c +++ b/tools/perf/util/libunwind-arch/libunwind-i386.c @@ -2,9 +2,12 @@ #include "libunwind-arch.h" #include "../debug.h" #include "../maps.h" +#include "../thread.h" #include "../../../arch/x86/include/uapi/asm/perf_regs.h" #include #include +#include +#include #include =20 #ifdef HAVE_LIBUNWIND_X86_SUPPORT @@ -56,3 +59,254 @@ void __libunwind_arch__finish_access_i386(struct maps *= maps __maybe_unused) unw_destroy_addr_space(maps__addr_space(maps)); #endif } + +#ifdef HAVE_LIBUNWIND_X86_SUPPORT +static int find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_inf= o_t *pi, + int need_unwind_info, void *arg) +{ + return __libunwind__find_proc_info(as, ip, pi, need_unwind_info, arg, siz= eof(unw_word_t)); +} + +static void put_unwind_info(unw_addr_space_t __maybe_unused as, + unw_proc_info_t *pi __maybe_unused, + void *arg __maybe_unused) +{ + pr_debug("unwind: put_unwind_info called\n"); +} + +static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused *dil_addr, + void __maybe_unused *arg) +{ + return -UNW_ENOINFO; +} + +static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *va= lp, + int __write, void *arg) +{ + return __libunwind__access_mem(as, addr, valp, __write, arg, sizeof(unw_w= ord_t)); +} + +static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t= *valp, + int __write, void *arg) +{ + return __libunwind__access_reg(as, regnum, valp, __write, arg, sizeof(unw= _word_t)); +} + +static int access_fpreg(unw_addr_space_t __maybe_unused as, + unw_regnum_t __maybe_unused num, + unw_fpreg_t __maybe_unused *val, + int __maybe_unused __write, + void __maybe_unused *arg) +{ + pr_err("unwind: access_fpreg unsupported\n"); + return -UNW_EINVAL; +} + +static int resume(unw_addr_space_t __maybe_unused as, + unw_cursor_t __maybe_unused *cu, + void __maybe_unused *arg) +{ + pr_err("unwind: resume unsupported\n"); + return -UNW_EINVAL; +} + +static int get_proc_name(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused addr, + char __maybe_unused *bufp, size_t __maybe_unused buf_len, + unw_word_t __maybe_unused *offp, void __maybe_unused *arg) +{ + pr_err("unwind: get_proc_name unsupported\n"); + return -UNW_EINVAL; +} +#endif + +void *__libunwind_arch__create_addr_space_i386(void) +{ +#ifdef HAVE_LIBUNWIND_X86_SUPPORT + static unw_accessors_t accessors =3D { + .find_proc_info =3D find_proc_info, + .put_unwind_info =3D put_unwind_info, + .get_dyn_info_list_addr =3D get_dyn_info_list_addr, + .access_mem =3D access_mem, + .access_reg =3D access_reg, + .access_fpreg =3D access_fpreg, + .resume =3D resume, + .get_proc_name =3D get_proc_name, + }; + unw_addr_space_t addr_space; + + addr_space =3D unw_create_addr_space(&accessors, /*byte_order=3D*/0); + unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); + return addr_space; +#else + return NULL; +#endif +} + +#ifdef HAVE_LIBUNWIND_X86_SUPPORT +extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) +#endif + +int __libunwind_arch__dwarf_search_unwind_table_i386(void *as __maybe_unus= ed, + uint64_t ip __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + void *pi __maybe_unused, + int need_unwind_info __maybe_unused, + void *arg __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_X86_SUPPORT + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, = arg); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +#if defined(HAVE_LIBUNWIND_X86_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_FRA= ME_X86) +extern int UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_= debug, + unw_word_t ip, + unw_word_t segbase, + const char *obj_name, unw_word_t start, + unw_word_t end); +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) +#endif + +int __libunwind_arch__dwarf_find_debug_frame_i386(int found __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + uint64_t ip __maybe_unused, + uint64_t segbase __maybe_unused, + const char *obj_name __maybe_unused, + uint64_t start __maybe_unused, + uint64_t end __maybe_unused) +{ +#if defined(HAVE_LIBUNWIND_X86_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_FRA= ME_X86) + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_find_debug_frame(found, &di, ip, segbase, obj_name, sta= rt, end); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +struct unwind_info *__libunwind_arch_unwind_info__new_i386(struct thread *= thread __maybe_unused, + struct perf_sample *sample __maybe_unused, + int max_stack __maybe_unused, + bool best_effort __maybe_unused, + uint64_t first_ip __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_X86_SUPPORT + struct arch_unwind_info { + struct unwind_info ui; + unw_cursor_t _cursor; + uint64_t _ips[]; + }; + + struct maps *maps =3D thread__maps(thread); + void *addr_space =3D maps__addr_space(maps); + struct arch_unwind_info *ui; + int ret; + + if (addr_space =3D=3D NULL) + return NULL; + + ui =3D zalloc(sizeof(*ui) + sizeof(ui->_ips[0]) * max_stack); + if (!ui) + return NULL; + + ui->ui.machine =3D maps__machine(maps); + ui->ui.thread =3D thread; + ui->ui.sample =3D sample; + ui->ui.cursor =3D &ui->_cursor; + ui->ui.ips =3D &ui->_ips[0]; + ui->ui.ips[0] =3D first_ip; + ui->ui.cur_ip =3D 1; + ui->ui.max_ips =3D max_stack; + ui->ui.unw_word_t_size =3D sizeof(unw_word_t); + ui->ui.e_machine =3D EM_I386; + ui->ui.best_effort =3D best_effort; + + ret =3D unw_init_remote(&ui->_cursor, addr_space, &ui->ui); + if (ret) { + if (!best_effort) + pr_err("libunwind: %s\n", unw_strerror(ret)); + free(ui); + return NULL; + } + + return &ui->ui; +#else + return NULL; +#endif +} + +int __libunwind_arch__unwind_step_i386(struct unwind_info *ui __maybe_unus= ed) +{ +#ifdef HAVE_LIBUNWIND_X86_SUPPORT + int ret; + + if (ui->cur_ip >=3D ui->max_ips) + return -1; + + ret =3D unw_step(ui->cursor); + if (ret > 0) { + uint64_t ip; + + unw_get_reg(ui->cursor, UNW_REG_IP, &ip); + + if (unw_is_signal_frame(ui->cursor) <=3D 0) { + /* + * Decrement the IP for any non-activation frames. This + * is required to properly find the srcline for caller + * frames. See also the documentation for + * dwfl_frame_pc(), which this code tries to replicate. + */ + --ip; + } + ui->ips[ui->cur_ip++] =3D ip; + } + return ret; +#else + return -EINVAL; +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-loongarch.c b/tools/p= erf/util/libunwind-arch/libunwind-loongarch.c index 837aa11e2b9f..d86397598a9d 100644 --- a/tools/perf/util/libunwind-arch/libunwind-loongarch.c +++ b/tools/perf/util/libunwind-arch/libunwind-loongarch.c @@ -2,8 +2,12 @@ #include "libunwind-arch.h" #include "../debug.h" #include "../maps.h" +#include "../thread.h" #include "../../../arch/loongarch/include/uapi/asm/perf_regs.h" #include +#include +#include +#include #include =20 #ifdef HAVE_LIBUNWIND_LOONGARCH64_SUPPORT @@ -40,3 +44,254 @@ void __libunwind_arch__finish_access_loongarch(struct m= aps *maps __maybe_unused) unw_destroy_addr_space(maps__addr_space(maps)); #endif } + +#ifdef HAVE_LIBUNWIND_LOONGARCH64_SUPPORT +static int find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_inf= o_t *pi, + int need_unwind_info, void *arg) +{ + return __libunwind__find_proc_info(as, ip, pi, need_unwind_info, arg, siz= eof(unw_word_t)); +} + +static void put_unwind_info(unw_addr_space_t __maybe_unused as, + unw_proc_info_t *pi __maybe_unused, + void *arg __maybe_unused) +{ + pr_debug("unwind: put_unwind_info called\n"); +} + +static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused *dil_addr, + void __maybe_unused *arg) +{ + return -UNW_ENOINFO; +} + +static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *va= lp, + int __write, void *arg) +{ + return __libunwind__access_mem(as, addr, valp, __write, arg, sizeof(unw_w= ord_t)); +} + +static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t= *valp, + int __write, void *arg) +{ + return __libunwind__access_reg(as, regnum, valp, __write, arg, sizeof(unw= _word_t)); +} + +static int access_fpreg(unw_addr_space_t __maybe_unused as, + unw_regnum_t __maybe_unused num, + unw_fpreg_t __maybe_unused *val, + int __maybe_unused __write, + void __maybe_unused *arg) +{ + pr_err("unwind: access_fpreg unsupported\n"); + return -UNW_EINVAL; +} + +static int resume(unw_addr_space_t __maybe_unused as, + unw_cursor_t __maybe_unused *cu, + void __maybe_unused *arg) +{ + pr_err("unwind: resume unsupported\n"); + return -UNW_EINVAL; +} + +static int get_proc_name(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused addr, + char __maybe_unused *bufp, size_t __maybe_unused buf_len, + unw_word_t __maybe_unused *offp, void __maybe_unused *arg) +{ + pr_err("unwind: get_proc_name unsupported\n"); + return -UNW_EINVAL; +} +#endif + +void *__libunwind_arch__create_addr_space_loongarch(void) +{ +#ifdef HAVE_LIBUNWIND_LOONGARCH64_SUPPORT + static unw_accessors_t accessors =3D { + .find_proc_info =3D find_proc_info, + .put_unwind_info =3D put_unwind_info, + .get_dyn_info_list_addr =3D get_dyn_info_list_addr, + .access_mem =3D access_mem, + .access_reg =3D access_reg, + .access_fpreg =3D access_fpreg, + .resume =3D resume, + .get_proc_name =3D get_proc_name, + }; + unw_addr_space_t addr_space; + + addr_space =3D unw_create_addr_space(&accessors, /*byte_order=3D*/0); + unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); + return addr_space; +#else + return NULL; +#endif +} + +#ifdef HAVE_LIBUNWIND_LOONGARCH_SUPPORT +extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) +#endif + +int __libunwind_arch__dwarf_search_unwind_table_loongarch(void *as __maybe= _unused, + uint64_t ip __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + void *pi __maybe_unused, + int need_unwind_info __maybe_unused, + void *arg __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_LOONGARCH_SUPPORT + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, = arg); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +#if defined(HAVE_LIBUNWIND_LOONGARCH_SUPPORT) && !defined(NO_LIBUNWIND_DEB= UG_FRAME_LOONGARCH) +extern int UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_= debug, + unw_word_t ip, + unw_word_t segbase, + const char *obj_name, unw_word_t start, + unw_word_t end); +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) +#endif + +int __libunwind_arch__dwarf_find_debug_frame_loongarch(int found __maybe_u= nused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + uint64_t ip __maybe_unused, + uint64_t segbase __maybe_unused, + const char *obj_name __maybe_unused, + uint64_t start __maybe_unused, + uint64_t end __maybe_unused) +{ +#if defined(HAVE_LIBUNWIND_LOONGARCH_SUPPORT) && !defined(NO_LIBUNWIND_DEB= UG_FRAME_LOONGARCH) + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_find_debug_frame(found, &di, ip, segbase, obj_name, sta= rt, end); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +struct unwind_info *__libunwind_arch_unwind_info__new_loongarch(struct thr= ead *thread __maybe_unused, + struct perf_sample *sample __maybe_unused, + int max_stack __maybe_unused, + bool best_effort __maybe_unused, + uint64_t first_ip __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_LOONGARCH_SUPPORT + struct arch_unwind_info { + struct unwind_info ui; + unw_cursor_t _cursor; + uint64_t _ips[]; + }; + + struct maps *maps =3D thread__maps(thread); + void *addr_space =3D maps__addr_space(maps); + struct arch_unwind_info *ui; + int ret; + + if (addr_space =3D=3D NULL) + return NULL; + + ui =3D zalloc(sizeof(*ui) + sizeof(ui->_ips[0]) * max_stack); + if (!ui) + return NULL; + + ui->ui.machine =3D maps__machine(maps); + ui->ui.thread =3D thread; + ui->ui.sample =3D sample; + ui->ui.cursor =3D &ui->_cursor; + ui->ui.ips =3D &ui->_ips[0]; + ui->ui.ips[0] =3D first_ip; + ui->ui.cur_ip =3D 1; + ui->ui.max_ips =3D max_stack; + ui->ui.unw_word_t_size =3D sizeof(unw_word_t); + ui->ui.e_machine =3D EM_LOONGARCH; + ui->ui.best_effort =3D best_effort; + + ret =3D unw_init_remote(&ui->_cursor, addr_space, &ui->ui); + if (ret) { + if (!best_effort) + pr_err("libunwind: %s\n", unw_strerror(ret)); + free(ui); + return NULL; + } + + return &ui->ui; +#else + return NULL; +#endif +} + +int __libunwind_arch__unwind_step_loongarch(struct unwind_info *ui __maybe= _unused) +{ +#ifdef HAVE_LIBUNWIND_LOONGARCH_SUPPORT + int ret; + + if (ui->cur_ip >=3D ui->max_ips) + return -1; + + ret =3D unw_step(ui->cursor); + if (ret > 0) { + uint64_t ip; + + unw_get_reg(ui->cursor, UNW_REG_IP, &ip); + + if (unw_is_signal_frame(ui->cursor) <=3D 0) { + /* + * Decrement the IP for any non-activation frames. This + * is required to properly find the srcline for caller + * frames. See also the documentation for + * dwfl_frame_pc(), which this code tries to replicate. + */ + --ip; + } + ui->ips[ui->cur_ip++] =3D ip; + } + return ret; +#else + return -EINVAL; +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-mips.c b/tools/perf/u= til/libunwind-arch/libunwind-mips.c index 1fa81742ff4a..91ee3c27d159 100644 --- a/tools/perf/util/libunwind-arch/libunwind-mips.c +++ b/tools/perf/util/libunwind-arch/libunwind-mips.c @@ -2,8 +2,12 @@ #include "libunwind-arch.h" #include "../debug.h" #include "../maps.h" +#include "../thread.h" #include "../../../arch/mips/include/uapi/asm/perf_regs.h" #include +#include +#include +#include #include =20 #ifdef HAVE_LIBUNWIND_MIPS_SUPPORT @@ -42,3 +46,254 @@ void __libunwind_arch__finish_access_mips(struct maps *= maps __maybe_unused) unw_destroy_addr_space(maps__addr_space(maps)); #endif } + +#ifdef HAVE_LIBUNWIND_MIPS_SUPPORT +static int find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_inf= o_t *pi, + int need_unwind_info, void *arg) +{ + return __libunwind__find_proc_info(as, ip, pi, need_unwind_info, arg, siz= eof(unw_word_t)); +} + +static void put_unwind_info(unw_addr_space_t __maybe_unused as, + unw_proc_info_t *pi __maybe_unused, + void *arg __maybe_unused) +{ + pr_debug("unwind: put_unwind_info called\n"); +} + +static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused *dil_addr, + void __maybe_unused *arg) +{ + return -UNW_ENOINFO; +} + +static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *va= lp, + int __write, void *arg) +{ + return __libunwind__access_mem(as, addr, valp, __write, arg, sizeof(unw_w= ord_t)); +} + +static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t= *valp, + int __write, void *arg) +{ + return __libunwind__access_reg(as, regnum, valp, __write, arg, sizeof(unw= _word_t)); +} + +static int access_fpreg(unw_addr_space_t __maybe_unused as, + unw_regnum_t __maybe_unused num, + unw_fpreg_t __maybe_unused *val, + int __maybe_unused __write, + void __maybe_unused *arg) +{ + pr_err("unwind: access_fpreg unsupported\n"); + return -UNW_EINVAL; +} + +static int resume(unw_addr_space_t __maybe_unused as, + unw_cursor_t __maybe_unused *cu, + void __maybe_unused *arg) +{ + pr_err("unwind: resume unsupported\n"); + return -UNW_EINVAL; +} + +static int get_proc_name(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused addr, + char __maybe_unused *bufp, size_t __maybe_unused buf_len, + unw_word_t __maybe_unused *offp, void __maybe_unused *arg) +{ + pr_err("unwind: get_proc_name unsupported\n"); + return -UNW_EINVAL; +} +#endif + +void *__libunwind_arch__create_addr_space_mips(void) +{ +#ifdef HAVE_LIBUNWIND_MIPS_SUPPORT + static unw_accessors_t accessors =3D { + .find_proc_info =3D find_proc_info, + .put_unwind_info =3D put_unwind_info, + .get_dyn_info_list_addr =3D get_dyn_info_list_addr, + .access_mem =3D access_mem, + .access_reg =3D access_reg, + .access_fpreg =3D access_fpreg, + .resume =3D resume, + .get_proc_name =3D get_proc_name, + }; + unw_addr_space_t addr_space; + + addr_space =3D unw_create_addr_space(&accessors, /*byte_order=3D*/0); + unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); + return addr_space; +#else + return NULL; +#endif +} + +#ifdef HAVE_LIBUNWIND_MIPS_SUPPORT +extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) +#endif + +int __libunwind_arch__dwarf_search_unwind_table_mips(void *as __maybe_unus= ed, + uint64_t ip __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + void *pi __maybe_unused, + int need_unwind_info __maybe_unused, + void *arg __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_MIPS_SUPPORT + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, = arg); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +#if defined(HAVE_LIBUNWIND_MIPS_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_FR= AME_MIPS) +extern int UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_= debug, + unw_word_t ip, + unw_word_t segbase, + const char *obj_name, unw_word_t start, + unw_word_t end); +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) +#endif + +int __libunwind_arch__dwarf_find_debug_frame_mips(int found __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + uint64_t ip __maybe_unused, + uint64_t segbase __maybe_unused, + const char *obj_name __maybe_unused, + uint64_t start __maybe_unused, + uint64_t end __maybe_unused) +{ +#if defined(HAVE_LIBUNWIND_MIPS_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_FR= AME_MIPS) + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_find_debug_frame(found, &di, ip, segbase, obj_name, sta= rt, end); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +struct unwind_info *__libunwind_arch_unwind_info__new_mips(struct thread *= thread __maybe_unused, + struct perf_sample *sample __maybe_unused, + int max_stack __maybe_unused, + bool best_effort __maybe_unused, + uint64_t first_ip __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_MIPS_SUPPORT + struct arch_unwind_info { + struct unwind_info ui; + unw_cursor_t _cursor; + uint64_t _ips[]; + }; + + struct maps *maps =3D thread__maps(thread); + void *addr_space =3D maps__addr_space(maps); + struct arch_unwind_info *ui; + int ret; + + if (addr_space =3D=3D NULL) + return NULL; + + ui =3D zalloc(sizeof(*ui) + sizeof(ui->_ips[0]) * max_stack); + if (!ui) + return NULL; + + ui->ui.machine =3D maps__machine(maps); + ui->ui.thread =3D thread; + ui->ui.sample =3D sample; + ui->ui.cursor =3D &ui->_cursor; + ui->ui.ips =3D &ui->_ips[0]; + ui->ui.ips[0] =3D first_ip; + ui->ui.cur_ip =3D 1; + ui->ui.max_ips =3D max_stack; + ui->ui.unw_word_t_size =3D sizeof(unw_word_t); + ui->ui.e_machine =3D EM_MIPS; + ui->ui.best_effort =3D best_effort; + + ret =3D unw_init_remote(&ui->_cursor, addr_space, &ui->ui); + if (ret) { + if (!best_effort) + pr_err("libunwind: %s\n", unw_strerror(ret)); + free(ui); + return NULL; + } + + return &ui->ui; +#else + return NULL; +#endif +} + +int __libunwind_arch__unwind_step_mips(struct unwind_info *ui __maybe_unus= ed) +{ +#ifdef HAVE_LIBUNWIND_MIPS_SUPPORT + int ret; + + if (ui->cur_ip >=3D ui->max_ips) + return -1; + + ret =3D unw_step(ui->cursor); + if (ret > 0) { + uint64_t ip; + + unw_get_reg(ui->cursor, UNW_REG_IP, &ip); + + if (unw_is_signal_frame(ui->cursor) <=3D 0) { + /* + * Decrement the IP for any non-activation frames. This + * is required to properly find the srcline for caller + * frames. See also the documentation for + * dwfl_frame_pc(), which this code tries to replicate. + */ + --ip; + } + ui->ips[ui->cur_ip++] =3D ip; + } + return ret; +#else + return -EINVAL; +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-ppc32.c b/tools/perf/= util/libunwind-arch/libunwind-ppc32.c index fa8471c74bf3..b80d3184a28d 100644 --- a/tools/perf/util/libunwind-arch/libunwind-ppc32.c +++ b/tools/perf/util/libunwind-arch/libunwind-ppc32.c @@ -2,8 +2,12 @@ #include "libunwind-arch.h" #include "../debug.h" #include "../maps.h" +#include "../thread.h" #include "../../../arch/powerpc/include/uapi/asm/perf_regs.h" #include +#include +#include +#include #include =20 #ifdef HAVE_LIBUNWIND_PPC32_SUPPORT @@ -44,3 +48,254 @@ void __libunwind_arch__finish_access_ppc32(struct maps = *maps __maybe_unused) unw_destroy_addr_space(maps__addr_space(maps)); #endif } + +#ifdef HAVE_LIBUNWIND_PPC32_SUPPORT +static int find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_inf= o_t *pi, + int need_unwind_info, void *arg) +{ + return __libunwind__find_proc_info(as, ip, pi, need_unwind_info, arg, siz= eof(unw_word_t)); +} + +static void put_unwind_info(unw_addr_space_t __maybe_unused as, + unw_proc_info_t *pi __maybe_unused, + void *arg __maybe_unused) +{ + pr_debug("unwind: put_unwind_info called\n"); +} + +static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused *dil_addr, + void __maybe_unused *arg) +{ + return -UNW_ENOINFO; +} + +static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *va= lp, + int __write, void *arg) +{ + return __libunwind__access_mem(as, addr, valp, __write, arg, sizeof(unw_w= ord_t)); +} + +static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t= *valp, + int __write, void *arg) +{ + return __libunwind__access_reg(as, regnum, valp, __write, arg, sizeof(unw= _word_t)); +} + +static int access_fpreg(unw_addr_space_t __maybe_unused as, + unw_regnum_t __maybe_unused num, + unw_fpreg_t __maybe_unused *val, + int __maybe_unused __write, + void __maybe_unused *arg) +{ + pr_err("unwind: access_fpreg unsupported\n"); + return -UNW_EINVAL; +} + +static int resume(unw_addr_space_t __maybe_unused as, + unw_cursor_t __maybe_unused *cu, + void __maybe_unused *arg) +{ + pr_err("unwind: resume unsupported\n"); + return -UNW_EINVAL; +} + +static int get_proc_name(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused addr, + char __maybe_unused *bufp, size_t __maybe_unused buf_len, + unw_word_t __maybe_unused *offp, void __maybe_unused *arg) +{ + pr_err("unwind: get_proc_name unsupported\n"); + return -UNW_EINVAL; +} +#endif + +void *__libunwind_arch__create_addr_space_ppc32(void) +{ +#ifdef HAVE_LIBUNWIND_PPC32_SUPPORT + static unw_accessors_t accessors =3D { + .find_proc_info =3D find_proc_info, + .put_unwind_info =3D put_unwind_info, + .get_dyn_info_list_addr =3D get_dyn_info_list_addr, + .access_mem =3D access_mem, + .access_reg =3D access_reg, + .access_fpreg =3D access_fpreg, + .resume =3D resume, + .get_proc_name =3D get_proc_name, + }; + unw_addr_space_t addr_space; + + addr_space =3D unw_create_addr_space(&accessors, /*byte_order=3D*/0); + unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); + return addr_space; +#else + return NULL; +#endif +} + +#ifdef HAVE_LIBUNWIND_PPC32_SUPPORT +extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) +#endif + +int __libunwind_arch__dwarf_search_unwind_table_ppc32(void *as __maybe_unu= sed, + uint64_t ip __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + void *pi __maybe_unused, + int need_unwind_info __maybe_unused, + void *arg __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_PPC32_SUPPORT + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, = arg); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +#if defined(HAVE_LIBUNWIND_PPC32_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_F= RAME_PPC32) +extern int UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_= debug, + unw_word_t ip, + unw_word_t segbase, + const char *obj_name, unw_word_t start, + unw_word_t end); +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) +#endif + +int __libunwind_arch__dwarf_find_debug_frame_ppc32(int found __maybe_unuse= d, + struct libarch_unwind__dyn_info *_di __maybe_unused, + uint64_t ip __maybe_unused, + uint64_t segbase __maybe_unused, + const char *obj_name __maybe_unused, + uint64_t start __maybe_unused, + uint64_t end __maybe_unused) +{ +#if defined(HAVE_LIBUNWIND_PPC32_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_F= RAME_PPC32) + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_find_debug_frame(found, &di, ip, segbase, obj_name, sta= rt, end); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +struct unwind_info *__libunwind_arch_unwind_info__new_ppc32(struct thread = *thread __maybe_unused, + struct perf_sample *sample __maybe_unused, + int max_stack __maybe_unused, + bool best_effort __maybe_unused, + uint64_t first_ip __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_PPC32_SUPPORT + struct arch_unwind_info { + struct unwind_info ui; + unw_cursor_t _cursor; + uint64_t _ips[]; + }; + + struct maps *maps =3D thread__maps(thread); + void *addr_space =3D maps__addr_space(maps); + struct arch_unwind_info *ui; + int ret; + + if (addr_space =3D=3D NULL) + return NULL; + + ui =3D zalloc(sizeof(*ui) + sizeof(ui->_ips[0]) * max_stack); + if (!ui) + return NULL; + + ui->ui.machine =3D maps__machine(maps); + ui->ui.thread =3D thread; + ui->ui.sample =3D sample; + ui->ui.cursor =3D &ui->_cursor; + ui->ui.ips =3D &ui->_ips[0]; + ui->ui.ips[0] =3D first_ip; + ui->ui.cur_ip =3D 1; + ui->ui.max_ips =3D max_stack; + ui->ui.unw_word_t_size =3D sizeof(unw_word_t); + ui->ui.e_machine =3D EM_PPC; + ui->ui.best_effort =3D best_effort; + + ret =3D unw_init_remote(&ui->_cursor, addr_space, &ui->ui); + if (ret) { + if (!best_effort) + pr_err("libunwind: %s\n", unw_strerror(ret)); + free(ui); + return NULL; + } + + return &ui->ui; +#else + return NULL; +#endif +} + +int __libunwind_arch__unwind_step_ppc32(struct unwind_info *ui __maybe_unu= sed) +{ +#ifdef HAVE_LIBUNWIND_PPC32_SUPPORT + int ret; + + if (ui->cur_ip >=3D ui->max_ips) + return -1; + + ret =3D unw_step(ui->cursor); + if (ret > 0) { + uint64_t ip; + + unw_get_reg(ui->cursor, UNW_REG_IP, &ip); + + if (unw_is_signal_frame(ui->cursor) <=3D 0) { + /* + * Decrement the IP for any non-activation frames. This + * is required to properly find the srcline for caller + * frames. See also the documentation for + * dwfl_frame_pc(), which this code tries to replicate. + */ + --ip; + } + ui->ips[ui->cur_ip++] =3D ip; + } + return ret; +#else + return -EINVAL; +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-ppc64.c b/tools/perf/= util/libunwind-arch/libunwind-ppc64.c index 2f746e347336..cbe3b476203f 100644 --- a/tools/perf/util/libunwind-arch/libunwind-ppc64.c +++ b/tools/perf/util/libunwind-arch/libunwind-ppc64.c @@ -2,8 +2,12 @@ #include "libunwind-arch.h" #include "../debug.h" #include "../maps.h" +#include "../thread.h" #include "../../../arch/powerpc/include/uapi/asm/perf_regs.h" #include +#include +#include +#include #include =20 #ifdef HAVE_LIBUNWIND_PPC64_SUPPORT @@ -46,3 +50,254 @@ void __libunwind_arch__finish_access_ppc64(struct maps = *maps __maybe_unused) unw_destroy_addr_space(maps__addr_space(maps)); #endif } + +#ifdef HAVE_LIBUNWIND_PPC64_SUPPORT +static int find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_inf= o_t *pi, + int need_unwind_info, void *arg) +{ + return __libunwind__find_proc_info(as, ip, pi, need_unwind_info, arg, siz= eof(unw_word_t)); +} + +static void put_unwind_info(unw_addr_space_t __maybe_unused as, + unw_proc_info_t *pi __maybe_unused, + void *arg __maybe_unused) +{ + pr_debug("unwind: put_unwind_info called\n"); +} + +static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused *dil_addr, + void __maybe_unused *arg) +{ + return -UNW_ENOINFO; +} + +static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *va= lp, + int __write, void *arg) +{ + return __libunwind__access_mem(as, addr, valp, __write, arg, sizeof(unw_w= ord_t)); +} + +static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t= *valp, + int __write, void *arg) +{ + return __libunwind__access_reg(as, regnum, valp, __write, arg, sizeof(unw= _word_t)); +} + +static int access_fpreg(unw_addr_space_t __maybe_unused as, + unw_regnum_t __maybe_unused num, + unw_fpreg_t __maybe_unused *val, + int __maybe_unused __write, + void __maybe_unused *arg) +{ + pr_err("unwind: access_fpreg unsupported\n"); + return -UNW_EINVAL; +} + +static int resume(unw_addr_space_t __maybe_unused as, + unw_cursor_t __maybe_unused *cu, + void __maybe_unused *arg) +{ + pr_err("unwind: resume unsupported\n"); + return -UNW_EINVAL; +} + +static int get_proc_name(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused addr, + char __maybe_unused *bufp, size_t __maybe_unused buf_len, + unw_word_t __maybe_unused *offp, void __maybe_unused *arg) +{ + pr_err("unwind: get_proc_name unsupported\n"); + return -UNW_EINVAL; +} +#endif + +void *__libunwind_arch__create_addr_space_ppc64(void) +{ +#ifdef HAVE_LIBUNWIND_PPC64_SUPPORT + static unw_accessors_t accessors =3D { + .find_proc_info =3D find_proc_info, + .put_unwind_info =3D put_unwind_info, + .get_dyn_info_list_addr =3D get_dyn_info_list_addr, + .access_mem =3D access_mem, + .access_reg =3D access_reg, + .access_fpreg =3D access_fpreg, + .resume =3D resume, + .get_proc_name =3D get_proc_name, + }; + unw_addr_space_t addr_space; + + addr_space =3D unw_create_addr_space(&accessors, /*byte_order=3D*/0); + unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); + return addr_space; +#else + return NULL; +#endif +} + +#ifdef HAVE_LIBUNWIND_PPC64_SUPPORT +extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) +#endif + +int __libunwind_arch__dwarf_search_unwind_table_ppc64(void *as __maybe_unu= sed, + uint64_t ip __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + void *pi __maybe_unused, + int need_unwind_info __maybe_unused, + void *arg __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_PPC64_SUPPORT + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, = arg); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +#if defined(HAVE_LIBUNWIND_PPC64_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_F= RAME_PPC64) +extern int UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_= debug, + unw_word_t ip, + unw_word_t segbase, + const char *obj_name, unw_word_t start, + unw_word_t end); +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) +#endif + +int __libunwind_arch__dwarf_find_debug_frame_ppc64(int found __maybe_unuse= d, + struct libarch_unwind__dyn_info *_di __maybe_unused, + uint64_t ip __maybe_unused, + uint64_t segbase __maybe_unused, + const char *obj_name __maybe_unused, + uint64_t start __maybe_unused, + uint64_t end __maybe_unused) +{ +#if defined(HAVE_LIBUNWIND_PPC64_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_F= RAME_PPC64) + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_find_debug_frame(found, &di, ip, segbase, obj_name, sta= rt, end); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +struct unwind_info *__libunwind_arch_unwind_info__new_ppc64(struct thread = *thread __maybe_unused, + struct perf_sample *sample __maybe_unused, + int max_stack __maybe_unused, + bool best_effort __maybe_unused, + uint64_t first_ip __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_PPC64_SUPPORT + struct arch_unwind_info { + struct unwind_info ui; + unw_cursor_t _cursor; + uint64_t _ips[]; + }; + + struct maps *maps =3D thread__maps(thread); + void *addr_space =3D maps__addr_space(maps); + struct arch_unwind_info *ui; + int ret; + + if (addr_space =3D=3D NULL) + return NULL; + + ui =3D zalloc(sizeof(*ui) + sizeof(ui->_ips[0]) * max_stack); + if (!ui) + return NULL; + + ui->ui.machine =3D maps__machine(maps); + ui->ui.thread =3D thread; + ui->ui.sample =3D sample; + ui->ui.cursor =3D &ui->_cursor; + ui->ui.ips =3D &ui->_ips[0]; + ui->ui.ips[0] =3D first_ip; + ui->ui.cur_ip =3D 1; + ui->ui.max_ips =3D max_stack; + ui->ui.unw_word_t_size =3D sizeof(unw_word_t); + ui->ui.e_machine =3D EM_PPC64; + ui->ui.best_effort =3D best_effort; + + ret =3D unw_init_remote(&ui->_cursor, addr_space, &ui->ui); + if (ret) { + if (!best_effort) + pr_err("libunwind: %s\n", unw_strerror(ret)); + free(ui); + return NULL; + } + + return &ui->ui; +#else + return NULL; +#endif +} + +int __libunwind_arch__unwind_step_ppc64(struct unwind_info *ui __maybe_unu= sed) +{ +#ifdef HAVE_LIBUNWIND_PPC64_SUPPORT + int ret; + + if (ui->cur_ip >=3D ui->max_ips) + return -1; + + ret =3D unw_step(ui->cursor); + if (ret > 0) { + uint64_t ip; + + unw_get_reg(ui->cursor, UNW_REG_IP, &ip); + + if (unw_is_signal_frame(ui->cursor) <=3D 0) { + /* + * Decrement the IP for any non-activation frames. This + * is required to properly find the srcline for caller + * frames. See also the documentation for + * dwfl_frame_pc(), which this code tries to replicate. + */ + --ip; + } + ui->ips[ui->cur_ip++] =3D ip; + } + return ret; +#else + return -EINVAL; +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-s390.c b/tools/perf/u= til/libunwind-arch/libunwind-s390.c index 9f68d15438b2..ce3788e86d1f 100644 --- a/tools/perf/util/libunwind-arch/libunwind-s390.c +++ b/tools/perf/util/libunwind-arch/libunwind-s390.c @@ -2,8 +2,12 @@ #include "libunwind-arch.h" #include "../debug.h" #include "../maps.h" +#include "../thread.h" #include "../../../arch/s390/include/uapi/asm/perf_regs.h" #include +#include +#include +#include #include =20 #ifdef HAVE_LIBUNWIND_S390X_SUPPORT @@ -42,3 +46,254 @@ void __libunwind_arch__finish_access_s390(struct maps *= maps __maybe_unused) unw_destroy_addr_space(maps__addr_space(maps)); #endif } + +#ifdef HAVE_LIBUNWIND_S390X_SUPPORT +static int find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_inf= o_t *pi, + int need_unwind_info, void *arg) +{ + return __libunwind__find_proc_info(as, ip, pi, need_unwind_info, arg, siz= eof(unw_word_t)); +} + +static void put_unwind_info(unw_addr_space_t __maybe_unused as, + unw_proc_info_t *pi __maybe_unused, + void *arg __maybe_unused) +{ + pr_debug("unwind: put_unwind_info called\n"); +} + +static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused *dil_addr, + void __maybe_unused *arg) +{ + return -UNW_ENOINFO; +} + +static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *va= lp, + int __write, void *arg) +{ + return __libunwind__access_mem(as, addr, valp, __write, arg, sizeof(unw_w= ord_t)); +} + +static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t= *valp, + int __write, void *arg) +{ + return __libunwind__access_reg(as, regnum, valp, __write, arg, sizeof(unw= _word_t)); +} + +static int access_fpreg(unw_addr_space_t __maybe_unused as, + unw_regnum_t __maybe_unused num, + unw_fpreg_t __maybe_unused *val, + int __maybe_unused __write, + void __maybe_unused *arg) +{ + pr_err("unwind: access_fpreg unsupported\n"); + return -UNW_EINVAL; +} + +static int resume(unw_addr_space_t __maybe_unused as, + unw_cursor_t __maybe_unused *cu, + void __maybe_unused *arg) +{ + pr_err("unwind: resume unsupported\n"); + return -UNW_EINVAL; +} + +static int get_proc_name(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused addr, + char __maybe_unused *bufp, size_t __maybe_unused buf_len, + unw_word_t __maybe_unused *offp, void __maybe_unused *arg) +{ + pr_err("unwind: get_proc_name unsupported\n"); + return -UNW_EINVAL; +} +#endif + +void *__libunwind_arch__create_addr_space_s390(void) +{ +#ifdef HAVE_LIBUNWIND_S390X_SUPPORT + static unw_accessors_t accessors =3D { + .find_proc_info =3D find_proc_info, + .put_unwind_info =3D put_unwind_info, + .get_dyn_info_list_addr =3D get_dyn_info_list_addr, + .access_mem =3D access_mem, + .access_reg =3D access_reg, + .access_fpreg =3D access_fpreg, + .resume =3D resume, + .get_proc_name =3D get_proc_name, + }; + unw_addr_space_t addr_space; + + addr_space =3D unw_create_addr_space(&accessors, /*byte_order=3D*/0); + unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); + return addr_space; +#else + return NULL; +#endif +} + +#ifdef HAVE_LIBUNWIND_S390X_SUPPORT +extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) +#endif + +int __libunwind_arch__dwarf_search_unwind_table_s390(void *as __maybe_unus= ed, + uint64_t ip __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + void *pi __maybe_unused, + int need_unwind_info __maybe_unused, + void *arg __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_S390X_SUPPORT + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, = arg); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +#if defined(HAVE_LIBUNWIND_S390X_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_F= RAME_S390X) +extern int UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_= debug, + unw_word_t ip, + unw_word_t segbase, + const char *obj_name, unw_word_t start, + unw_word_t end); +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) +#endif + +int __libunwind_arch__dwarf_find_debug_frame_s390(int found __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + uint64_t ip __maybe_unused, + uint64_t segbase __maybe_unused, + const char *obj_name __maybe_unused, + uint64_t start __maybe_unused, + uint64_t end __maybe_unused) +{ +#if defined(HAVE_LIBUNWIND_S390X_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_F= RAME_S390X) + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_find_debug_frame(found, &di, ip, segbase, obj_name, sta= rt, end); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +struct unwind_info *__libunwind_arch_unwind_info__new_s390(struct thread *= thread __maybe_unused, + struct perf_sample *sample __maybe_unused, + int max_stack __maybe_unused, + bool best_effort __maybe_unused, + uint64_t first_ip __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_S390X_SUPPORT + struct arch_unwind_info { + struct unwind_info ui; + unw_cursor_t _cursor; + uint64_t _ips[]; + }; + + struct maps *maps =3D thread__maps(thread); + void *addr_space =3D maps__addr_space(maps); + struct arch_unwind_info *ui; + int ret; + + if (addr_space =3D=3D NULL) + return NULL; + + ui =3D zalloc(sizeof(*ui) + sizeof(ui->_ips[0]) * max_stack); + if (!ui) + return NULL; + + ui->ui.machine =3D maps__machine(maps); + ui->ui.thread =3D thread; + ui->ui.sample =3D sample; + ui->ui.cursor =3D &ui->_cursor; + ui->ui.ips =3D &ui->_ips[0]; + ui->ui.ips[0] =3D first_ip; + ui->ui.cur_ip =3D 1; + ui->ui.max_ips =3D max_stack; + ui->ui.unw_word_t_size =3D sizeof(unw_word_t); + ui->ui.e_machine =3D EM_S390; + ui->ui.best_effort =3D best_effort; + + ret =3D unw_init_remote(&ui->_cursor, addr_space, &ui->ui); + if (ret) { + if (!best_effort) + pr_err("libunwind: %s\n", unw_strerror(ret)); + free(ui); + return NULL; + } + + return &ui->ui; +#else + return NULL; +#endif +} + +int __libunwind_arch__unwind_step_s390(struct unwind_info *ui __maybe_unus= ed) +{ +#ifdef HAVE_LIBUNWIND_S390X_SUPPORT + int ret; + + if (ui->cur_ip >=3D ui->max_ips) + return -1; + + ret =3D unw_step(ui->cursor); + if (ret > 0) { + uint64_t ip; + + unw_get_reg(ui->cursor, UNW_REG_IP, &ip); + + if (unw_is_signal_frame(ui->cursor) <=3D 0) { + /* + * Decrement the IP for any non-activation frames. This + * is required to properly find the srcline for caller + * frames. See also the documentation for + * dwfl_frame_pc(), which this code tries to replicate. + */ + --ip; + } + ui->ips[ui->cur_ip++] =3D ip; + } + return ret; +#else + return -EINVAL; +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-x86_64.c b/tools/perf= /util/libunwind-arch/libunwind-x86_64.c index 25e326bd3e15..8ca66d442ffc 100644 --- a/tools/perf/util/libunwind-arch/libunwind-x86_64.c +++ b/tools/perf/util/libunwind-arch/libunwind-x86_64.c @@ -2,9 +2,12 @@ #include "libunwind-arch.h" #include "../debug.h" #include "../maps.h" +#include "../thread.h" #include "../../../arch/x86/include/uapi/asm/perf_regs.h" #include #include +#include +#include #include =20 #ifdef HAVE_LIBUNWIND_X86_64_SUPPORT @@ -65,3 +68,253 @@ void __libunwind_arch__finish_access_x86_64(struct maps= *maps __maybe_unused) unw_destroy_addr_space(maps__addr_space(maps)); #endif } + +#ifdef HAVE_LIBUNWIND_X86_64_SUPPORT +static int find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_inf= o_t *pi, + int need_unwind_info, void *arg) +{ + return __libunwind__find_proc_info(as, ip, pi, need_unwind_info, arg); +} + +static void put_unwind_info(unw_addr_space_t __maybe_unused as, + unw_proc_info_t *pi __maybe_unused, + void *arg __maybe_unused) +{ + pr_debug("unwind: put_unwind_info called\n"); +} + +static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused *dil_addr, + void __maybe_unused *arg) +{ + return -UNW_ENOINFO; +} + +static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *va= lp, + int __write, void *arg) +{ + return __libunwind__access_mem(as, addr, valp, __write, arg); +} + +static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t= *valp, + int __write, void *arg) +{ + return __libunwind__access_reg(as, regnum, valp, __write, arg); +} + +static int access_fpreg(unw_addr_space_t __maybe_unused as, + unw_regnum_t __maybe_unused num, + unw_fpreg_t __maybe_unused *val, + int __maybe_unused __write, + void __maybe_unused *arg) +{ + pr_err("unwind: access_fpreg unsupported\n"); + return -UNW_EINVAL; +} + +static int resume(unw_addr_space_t __maybe_unused as, + unw_cursor_t __maybe_unused *cu, + void __maybe_unused *arg) +{ + pr_err("unwind: resume unsupported\n"); + return -UNW_EINVAL; +} + +static int get_proc_name(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused addr, + char __maybe_unused *bufp, size_t __maybe_unused buf_len, + unw_word_t __maybe_unused *offp, void __maybe_unused *arg) +{ + pr_err("unwind: get_proc_name unsupported\n"); + return -UNW_EINVAL; +} +#endif + +void *__libunwind_arch__create_addr_space_x86_64(void) +{ +#ifdef HAVE_LIBUNWIND_X86_64_SUPPORT + static unw_accessors_t accessors =3D { + .find_proc_info =3D find_proc_info, + .put_unwind_info =3D put_unwind_info, + .get_dyn_info_list_addr =3D get_dyn_info_list_addr, + .access_mem =3D access_mem, + .access_reg =3D access_reg, + .access_fpreg =3D access_fpreg, + .resume =3D resume, + .get_proc_name =3D get_proc_name, + }; + unw_addr_space_t addr_space; + + addr_space =3D unw_create_addr_space(&accessors, /*byte_order=3D*/0); + unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); + return addr_space; +#else + return NULL; +#endif +} + +#ifdef HAVE_LIBUNWIND_X86_64_SUPPORT +extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) +#endif + +int __libunwind_arch__dwarf_search_unwind_table_x86_64(void *as __maybe_un= used, + uint64_t ip __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + void *pi __maybe_unused, + int need_unwind_info __maybe_unused, + void *arg __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_X86_64_SUPPORT + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, = arg); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +#if defined(HAVE_LIBUNWIND_X86_64_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_= FRAME_X86_64) +extern int UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_= debug, + unw_word_t ip, + unw_word_t segbase, + const char *obj_name, unw_word_t start, + unw_word_t end); +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) +#endif + +int __libunwind_arch__dwarf_find_debug_frame_x86_64(int found __maybe_unus= ed, + struct libarch_unwind__dyn_info *_di __maybe_unused, + uint64_t ip __maybe_unused, + uint64_t segbase __maybe_unused, + const char *obj_name __maybe_unused, + uint64_t start __maybe_unused, + uint64_t end __maybe_unused) +{ +#if defined(HAVE_LIBUNWIND_X86_64_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_= FRAME_X86_64) + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_find_debug_frame(found, &di, ip, segbase, obj_name, sta= rt, end); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +struct unwind_info *__libunwind_arch_unwind_info__new_x86_64(struct thread= *thread __maybe_unused, + struct perf_sample *sample __maybe_unused, + int max_stack __maybe_unused, + bool best_effort __maybe_unused, + uint64_t first_ip __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_X86_64_SUPPORT + struct arch_unwind_info { + struct unwind_info ui; + unw_cursor_t _cursor; + uint64_t _ips[]; + }; + + struct maps *maps =3D thread__maps(thread); + void *addr_space =3D maps__addr_space(maps); + struct arch_unwind_info *ui; + int ret; + + if (addr_space =3D=3D NULL) + return NULL; + + ui =3D zalloc(sizeof(*ui) + sizeof(ui->_ips[0]) * max_stack); + if (!ui) + return NULL; + + ui->ui.machine =3D maps__machine(maps); + ui->ui.thread =3D thread; + ui->ui.sample =3D sample; + ui->ui.cursor =3D &ui->_cursor; + ui->ui.ips =3D &ui->_ips[0]; + ui->ui.ips[0] =3D first_ip; + ui->ui.cur_ip =3D 1; + ui->ui.max_ips =3D max_stack; + ui->ui.unw_word_t_size =3D sizeof(unw_word_t); + ui->ui.e_machine =3D EM_X86_64; + ui->ui.best_effort =3D best_effort; + + ret =3D unw_init_remote(&ui->_cursor, addr_space, &ui->ui); + if (ret) { + if (!best_effort) + pr_err("libunwind: %s\n", unw_strerror(ret)); + free(ui); + return NULL; + } + return &ui->ui; +#else + return NULL; +#endif +} + +int __libunwind_arch__unwind_step_x86_64(struct unwind_info *ui __maybe_un= used) +{ +#ifdef HAVE_LIBUNWIND_X86_64_SUPPORT + int ret; + + if (ui->cur_ip >=3D ui->max_ips) + return 0; + + ret =3D unw_step(ui->cursor); + if (ret > 0) { + uint64_t ip; + + unw_get_reg(ui->cursor, UNW_REG_IP, &ip); + + if (unw_is_signal_frame(ui->cursor) <=3D 0) { + /* + * Decrement the IP for any non-activation frames. This + * is required to properly find the srcline for caller + * frames. See also the documentation for + * dwfl_frame_pc(), which this code tries to replicate. + */ + --ip; + } + ui->ips[ui->cur_ip++] =3D ip; + } + return ret; +#else + return -EINVAL; +#endif +} diff --git a/tools/perf/util/libunwind/arm64.c b/tools/perf/util/libunwind/= arm64.c deleted file mode 100644 index 15670a964495..000000000000 --- a/tools/perf/util/libunwind/arm64.c +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * This file setups defines to compile arch specific binary from the - * generic one. - * - * The function 'LIBUNWIND__ARCH_REG_ID' name is set according to arch - * name and the definition of this function is included directly from - * 'arch/arm64/util/unwind-libunwind.c', to make sure that this function - * is defined no matter what arch the host is. - * - * Finally, the arch specific unwind methods are exported which will - * be assigned to each arm64 thread. - */ - -#define REMOTE_UNWIND_LIBUNWIND - -#include "unwind.h" -#include "libunwind-aarch64.h" -#define perf_event_arm_regs perf_event_arm64_regs -#include <../../../arch/arm64/include/uapi/asm/perf_regs.h> -#undef perf_event_arm_regs -#include "../../arch/arm64/util/unwind-libunwind.c" - -/* NO_LIBUNWIND_DEBUG_FRAME is a feature flag for local libunwind, - * assign NO_LIBUNWIND_DEBUG_FRAME_AARCH64 to it for compiling arm64 - * unwind methods. - */ -#undef NO_LIBUNWIND_DEBUG_FRAME -#ifdef NO_LIBUNWIND_DEBUG_FRAME_AARCH64 -#define NO_LIBUNWIND_DEBUG_FRAME -#endif -#include "util/unwind-libunwind-local.c" - -struct unwind_libunwind_ops * -arm64_unwind_libunwind_ops =3D &_unwind_libunwind_ops; diff --git a/tools/perf/util/libunwind/x86_32.c b/tools/perf/util/libunwind= /x86_32.c deleted file mode 100644 index 1e9fb8bfec44..000000000000 --- a/tools/perf/util/libunwind/x86_32.c +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * This file setups defines to compile arch specific binary from the - * generic one. - * - * The function 'LIBUNWIND__ARCH_REG_ID' name is set according to arch - * name and the definition of this function is included directly from - * 'arch/x86/util/unwind-libunwind.c', to make sure that this function - * is defined no matter what arch the host is. - * - * Finally, the arch specific unwind methods are exported which will - * be assigned to each x86 thread. - */ - -#define REMOTE_UNWIND_LIBUNWIND - -#include "unwind.h" -#include "libunwind-x86.h" - -/* Explicitly define NO_LIBUNWIND_DEBUG_FRAME, because non-ARM has no - * dwarf_find_debug_frame() function. - */ -#ifndef NO_LIBUNWIND_DEBUG_FRAME -#define NO_LIBUNWIND_DEBUG_FRAME -#endif -#include "util/unwind-libunwind-local.c" - -struct unwind_libunwind_ops * -x86_32_unwind_libunwind_ops =3D &_unwind_libunwind_ops; diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c index 8c7b2a1e7642..7ba82024fb11 100644 --- a/tools/perf/util/maps.c +++ b/tools/perf/util/maps.c @@ -198,16 +198,6 @@ void maps__set_addr_space(struct maps *maps, void *add= r_space) RC_CHK_ACCESS(maps)->addr_space =3D addr_space; } =20 -const struct unwind_libunwind_ops *maps__unwind_libunwind_ops(const struct= maps *maps) -{ - return RC_CHK_ACCESS(maps)->unwind_libunwind_ops; -} - -void maps__set_unwind_libunwind_ops(struct maps *maps, const struct unwind= _libunwind_ops *ops) -{ - RC_CHK_ACCESS(maps)->unwind_libunwind_ops =3D ops; -} - uint16_t maps__e_machine(const struct maps *maps) { return RC_CHK_ACCESS(maps)->e_machine; diff --git a/tools/perf/util/maps.h b/tools/perf/util/maps.h index 6469f62c41a8..5b80b199685e 100644 --- a/tools/perf/util/maps.h +++ b/tools/perf/util/maps.h @@ -49,8 +49,6 @@ refcount_t *maps__refcnt(struct maps *maps); /* Test only= . */ #ifdef HAVE_LIBUNWIND_SUPPORT void *maps__addr_space(const struct maps *maps); void maps__set_addr_space(struct maps *maps, void *addr_space); -const struct unwind_libunwind_ops *maps__unwind_libunwind_ops(const struct= maps *maps); -void maps__set_unwind_libunwind_ops(struct maps *maps, const struct unwind= _libunwind_ops *ops); uint16_t maps__e_machine(const struct maps *maps); void maps__set_e_machine(struct maps *maps, uint16_t e_machine); #endif diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unw= ind-libunwind-local.c deleted file mode 100644 index 8f0128ba05a7..000000000000 --- a/tools/perf/util/unwind-libunwind-local.c +++ /dev/null @@ -1,820 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Post mortem Dwarf CFI based unwinding on top of regs and stack dumps. - * - * Lots of this code have been borrowed or heavily inspired from parts of - * the libunwind 0.99 code which are (amongst other contributors I may have - * forgotten): - * - * Copyright (C) 2002-2007 Hewlett-Packard Co - * Contributed by David Mosberger-Tang - * - * And the bugs have been added by: - * - * Copyright (C) 2010, Frederic Weisbecker - * Copyright (C) 2012, Jiri Olsa - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef REMOTE_UNWIND_LIBUNWIND -#include -#include -#endif -#include "callchain.h" -#include "thread.h" -#include "session.h" -#include "perf_regs.h" -#include "unwind.h" -#include "map.h" -#include "symbol.h" -#include "debug.h" -#include "asm/bug.h" -#include "dso.h" -#include "libunwind-arch/libunwind-arch.h" - -extern int -UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, - unw_word_t ip, - unw_dyn_info_t *di, - unw_proc_info_t *pi, - int need_unwind_info, void *arg); - -#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) - -extern int -UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug, - unw_word_t ip, - unw_word_t segbase, - const char *obj_name, unw_word_t start, - unw_word_t end); - -#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) - -#define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */ -#define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */ - -/* Pointer-encoding formats: */ -#define DW_EH_PE_omit 0xff -#define DW_EH_PE_ptr 0x00 /* pointer-sized unsigned value */ -#define DW_EH_PE_udata4 0x03 /* unsigned 32-bit value */ -#define DW_EH_PE_udata8 0x04 /* unsigned 64-bit value */ -#define DW_EH_PE_sdata4 0x0b /* signed 32-bit value */ -#define DW_EH_PE_sdata8 0x0c /* signed 64-bit value */ - -/* Pointer-encoding application: */ -#define DW_EH_PE_absptr 0x00 /* absolute value */ -#define DW_EH_PE_pcrel 0x10 /* rel. to addr. of encoded value */ - -/* - * The following are not documented by LSB v1.3, yet they are used by - * GCC, presumably they aren't documented by LSB since they aren't - * used on Linux: - */ -#define DW_EH_PE_funcrel 0x40 /* start-of-procedure-relative */ -#define DW_EH_PE_aligned 0x50 /* aligned pointer */ - -/* Flags intentionally not handled, since they're not needed: - * #define DW_EH_PE_indirect 0x80 - * #define DW_EH_PE_uleb128 0x01 - * #define DW_EH_PE_udata2 0x02 - * #define DW_EH_PE_sleb128 0x09 - * #define DW_EH_PE_sdata2 0x0a - * #define DW_EH_PE_textrel 0x20 - * #define DW_EH_PE_datarel 0x30 - */ - -struct unwind_info { - struct perf_sample *sample; - struct machine *machine; - struct thread *thread; - uint16_t e_machine; - bool best_effort; -}; - -#define dw_read(ptr, type, end) ({ \ - type *__p =3D (type *) ptr; \ - type __v; \ - if ((__p + 1) > (type *) end) \ - return -EINVAL; \ - __v =3D *__p++; \ - ptr =3D (typeof(ptr)) __p; \ - __v; \ - }) - -static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val, - u8 encoding) -{ - u8 *cur =3D *p; - *val =3D 0; - - switch (encoding) { - case DW_EH_PE_omit: - *val =3D 0; - goto out; - case DW_EH_PE_ptr: - *val =3D dw_read(cur, unsigned long, end); - goto out; - default: - break; - } - - switch (encoding & DW_EH_PE_APPL_MASK) { - case DW_EH_PE_absptr: - break; - case DW_EH_PE_pcrel: - *val =3D (unsigned long) cur; - break; - default: - return -EINVAL; - } - - if ((encoding & 0x07) =3D=3D 0x00) - encoding |=3D DW_EH_PE_udata4; - - switch (encoding & DW_EH_PE_FORMAT_MASK) { - case DW_EH_PE_sdata4: - *val +=3D dw_read(cur, s32, end); - break; - case DW_EH_PE_udata4: - *val +=3D dw_read(cur, u32, end); - break; - case DW_EH_PE_sdata8: - *val +=3D dw_read(cur, s64, end); - break; - case DW_EH_PE_udata8: - *val +=3D dw_read(cur, u64, end); - break; - default: - return -EINVAL; - } - - out: - *p =3D cur; - return 0; -} - -#define dw_read_encoded_value(ptr, end, enc) ({ \ - u64 __v; \ - if (__dw_read_encoded_value(&ptr, end, &__v, enc)) { \ - return -EINVAL; \ - } \ - __v; \ - }) - -static int elf_section_address_and_offset(int fd, const char *name, u64 *a= ddress, u64 *offset) -{ - Elf *elf; - GElf_Ehdr ehdr; - GElf_Shdr shdr; - int ret =3D -1; - - elf =3D elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); - if (elf =3D=3D NULL) - return -1; - - if (gelf_getehdr(elf, &ehdr) =3D=3D NULL) - goto out_err; - - if (!elf_section_by_name(elf, &ehdr, &shdr, name, NULL)) - goto out_err; - - *address =3D shdr.sh_addr; - *offset =3D shdr.sh_offset; - ret =3D 0; -out_err: - elf_end(elf); - return ret; -} - -#ifndef NO_LIBUNWIND_DEBUG_FRAME -static u64 elf_section_offset(int fd, const char *name) -{ - u64 address, offset =3D 0; - - if (elf_section_address_and_offset(fd, name, &address, &offset)) - return 0; - - return offset; -} -#endif - -static u64 elf_base_address(int fd) -{ - Elf *elf =3D elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); - GElf_Phdr phdr; - u64 retval =3D 0; - size_t i, phdrnum =3D 0; - - if (elf =3D=3D NULL) - return 0; - (void)elf_getphdrnum(elf, &phdrnum); - /* PT_LOAD segments are sorted by p_vaddr, so the first has the minimum p= _vaddr. */ - for (i =3D 0; i < phdrnum; i++) { - if (gelf_getphdr(elf, i, &phdr) && phdr.p_type =3D=3D PT_LOAD) { - retval =3D phdr.p_vaddr & -getpagesize(); - break; - } - } - - elf_end(elf); - return retval; -} - -#ifndef NO_LIBUNWIND_DEBUG_FRAME -static int elf_is_exec(int fd, const char *name) -{ - Elf *elf; - GElf_Ehdr ehdr; - int retval =3D 0; - - elf =3D elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); - if (elf =3D=3D NULL) - return 0; - if (gelf_getehdr(elf, &ehdr) =3D=3D NULL) - goto out; - - retval =3D (ehdr.e_type =3D=3D ET_EXEC); - -out: - elf_end(elf); - pr_debug("unwind: elf_is_exec(%s): %d\n", name, retval); - return retval; -} -#endif - -struct table_entry { - u32 start_ip_offset; - u32 fde_offset; -}; - -struct eh_frame_hdr { - unsigned char version; - unsigned char eh_frame_ptr_enc; - unsigned char fde_count_enc; - unsigned char table_enc; - - /* - * The rest of the header is variable-length and consists of the - * following members: - * - * encoded_t eh_frame_ptr; - * encoded_t fde_count; - */ - - /* A single encoded pointer should not be more than 8 bytes. */ - u64 enc[2]; - - /* - * struct { - * encoded_t start_ip; - * encoded_t fde_addr; - * } binary_search_table[fde_count]; - */ - char data[]; -} __packed; - -static int unwind_spec_ehframe(struct dso *dso, struct machine *machine, - u64 offset, u64 *table_data_offset, u64 *fde_count) -{ - struct eh_frame_hdr hdr; - u8 *enc =3D (u8 *) &hdr.enc; - u8 *end =3D (u8 *) &hdr.data; - ssize_t r; - - r =3D dso__data_read_offset(dso, machine, offset, - (u8 *) &hdr, sizeof(hdr)); - if (r !=3D sizeof(hdr)) - return -EINVAL; - - /* We dont need eh_frame_ptr, just skip it. */ - dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc); - - *fde_count =3D dw_read_encoded_value(enc, end, hdr.fde_count_enc); - *table_data_offset =3D enc - (u8 *) &hdr; - return 0; -} - -struct read_unwind_spec_eh_frame_maps_cb_args { - struct dso *dso; - u64 base_addr; -}; - -static int read_unwind_spec_eh_frame_maps_cb(struct map *map, void *data) -{ - - struct read_unwind_spec_eh_frame_maps_cb_args *args =3D data; - - if (map__dso(map) =3D=3D args->dso && map__start(map) - map__pgoff(map) <= args->base_addr) - args->base_addr =3D map__start(map) - map__pgoff(map); - - return 0; -} - - -static int read_unwind_spec_eh_frame(struct dso *dso, struct unwind_info *= ui, - u64 *table_data, u64 *segbase, - u64 *fde_count) -{ - struct read_unwind_spec_eh_frame_maps_cb_args args =3D { - .dso =3D dso, - .base_addr =3D UINT64_MAX, - }; - int ret, fd; - - if (dso__data(dso)->eh_frame_hdr_offset =3D=3D 0) { - if (!dso__data_get_fd(dso, ui->machine, &fd)) - return -EINVAL; - - /* Check the .eh_frame section for unwinding info */ - ret =3D elf_section_address_and_offset(fd, ".eh_frame_hdr", - &dso__data(dso)->eh_frame_hdr_addr, - &dso__data(dso)->eh_frame_hdr_offset); - dso__data(dso)->elf_base_addr =3D elf_base_address(fd); - dso__data_put_fd(dso); - if (ret || dso__data(dso)->eh_frame_hdr_offset =3D=3D 0) - return -EINVAL; - } - - maps__for_each_map(thread__maps(ui->thread), read_unwind_spec_eh_frame_ma= ps_cb, &args); - - args.base_addr -=3D dso__data(dso)->elf_base_addr; - /* Address of .eh_frame_hdr */ - *segbase =3D args.base_addr + dso__data(dso)->eh_frame_hdr_addr; - ret =3D unwind_spec_ehframe(dso, ui->machine, dso__data(dso)->eh_frame_hd= r_offset, - table_data, fde_count); - if (ret) - return ret; - /* binary_search_table offset plus .eh_frame_hdr address */ - *table_data +=3D *segbase; - return 0; -} - -#ifndef NO_LIBUNWIND_DEBUG_FRAME -static int read_unwind_spec_debug_frame(struct dso *dso, - struct machine *machine, u64 *offset) -{ - int fd; - u64 ofs =3D dso__data(dso)->debug_frame_offset; - - /* debug_frame can reside in: - * - dso - * - debug pointed by symsrc_filename - * - gnu_debuglink, which doesn't necessary - * has to be pointed by symsrc_filename - */ - if (ofs =3D=3D 0) { - if (dso__data_get_fd(dso, machine, &fd)) { - ofs =3D elf_section_offset(fd, ".debug_frame"); - dso__data_put_fd(dso); - } - - if (ofs <=3D 0) { - fd =3D open(dso__symsrc_filename(dso), O_RDONLY); - if (fd >=3D 0) { - ofs =3D elf_section_offset(fd, ".debug_frame"); - close(fd); - } - } - - if (ofs <=3D 0) { - char *debuglink =3D malloc(PATH_MAX); - int ret =3D 0; - - if (debuglink =3D=3D NULL) { - pr_err("unwind: Can't read unwind spec debug frame.\n"); - return -ENOMEM; - } - - ret =3D dso__read_binary_type_filename( - dso, DSO_BINARY_TYPE__DEBUGLINK, - machine->root_dir, debuglink, PATH_MAX); - if (!ret) { - fd =3D open(debuglink, O_RDONLY); - if (fd >=3D 0) { - ofs =3D elf_section_offset(fd, - ".debug_frame"); - close(fd); - } - } - if (ofs > 0) { - if (dso__symsrc_filename(dso) !=3D NULL) { - pr_warning( - "%s: overwrite symsrc(%s,%s)\n", - __func__, - dso__symsrc_filename(dso), - debuglink); - dso__free_symsrc_filename(dso); - } - dso__set_symsrc_filename(dso, debuglink); - } else { - free(debuglink); - } - } - - dso__data(dso)->debug_frame_offset =3D ofs; - } - - *offset =3D ofs; - if (*offset) - return 0; - - return -EINVAL; -} -#endif - -static struct map *find_map(unw_word_t ip, struct unwind_info *ui) -{ - struct addr_location al; - struct map *ret; - - addr_location__init(&al); - thread__find_map(ui->thread, PERF_RECORD_MISC_USER, ip, &al); - ret =3D map__get(al.map); - addr_location__exit(&al); - return ret; -} - -static int -find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, - int need_unwind_info, void *arg) -{ - struct unwind_info *ui =3D arg; - struct map *map; - struct dso *dso; - unw_dyn_info_t di; - u64 table_data, segbase, fde_count; - int ret =3D -EINVAL; - - map =3D find_map(ip, ui); - if (!map) - return -EINVAL; - - dso =3D map__dso(map); - if (!dso) { - map__put(map); - return -EINVAL; - } - - pr_debug("unwind: find_proc_info dso %s\n", dso__name(dso)); - - /* Check the .eh_frame section for unwinding info */ - if (!read_unwind_spec_eh_frame(dso, ui, &table_data, &segbase, &fde_count= )) { - memset(&di, 0, sizeof(di)); - di.format =3D UNW_INFO_FORMAT_REMOTE_TABLE; - di.start_ip =3D map__start(map); - di.end_ip =3D map__end(map); - di.u.rti.segbase =3D segbase; - di.u.rti.table_data =3D table_data; - di.u.rti.table_len =3D fde_count * sizeof(struct table_entry) - / sizeof(unw_word_t); - ret =3D dwarf_search_unwind_table(as, ip, &di, pi, - need_unwind_info, arg); - } - -#ifndef NO_LIBUNWIND_DEBUG_FRAME - /* Check the .debug_frame section for unwinding info */ - if (ret < 0 && - !read_unwind_spec_debug_frame(dso, ui->machine, &segbase)) { - int fd; - u64 start =3D map__start(map); - unw_word_t base =3D start; - const char *symfile; - - if (dso__data_get_fd(dso, ui->machine, &fd)) { - if (elf_is_exec(fd, dso__name(dso))) - base =3D 0; - dso__data_put_fd(dso); - } - - symfile =3D dso__symsrc_filename(dso) ?: dso__name(dso); - - memset(&di, 0, sizeof(di)); - if (dwarf_find_debug_frame(0, &di, ip, base, symfile, start, map__end(ma= p))) - ret =3D dwarf_search_unwind_table(as, ip, &di, pi, - need_unwind_info, arg); - } -#endif - map__put(map); - return ret; -} - -static int access_fpreg(unw_addr_space_t __maybe_unused as, - unw_regnum_t __maybe_unused num, - unw_fpreg_t __maybe_unused *val, - int __maybe_unused __write, - void __maybe_unused *arg) -{ - pr_err("unwind: access_fpreg unsupported\n"); - return -UNW_EINVAL; -} - -static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, - unw_word_t __maybe_unused *dil_addr, - void __maybe_unused *arg) -{ - return -UNW_ENOINFO; -} - -static int resume(unw_addr_space_t __maybe_unused as, - unw_cursor_t __maybe_unused *cu, - void __maybe_unused *arg) -{ - pr_err("unwind: resume unsupported\n"); - return -UNW_EINVAL; -} - -static int -get_proc_name(unw_addr_space_t __maybe_unused as, - unw_word_t __maybe_unused addr, - char __maybe_unused *bufp, size_t __maybe_unused buf_len, - unw_word_t __maybe_unused *offp, void __maybe_unused *arg) -{ - pr_err("unwind: get_proc_name unsupported\n"); - return -UNW_EINVAL; -} - -static int access_dso_mem(struct unwind_info *ui, unw_word_t addr, - unw_word_t *data) -{ - struct map *map; - struct dso *dso; - ssize_t size; - - map =3D find_map(addr, ui); - if (!map) { - pr_debug("unwind: no map for %lx\n", (unsigned long)addr); - return -1; - } - - dso =3D map__dso(map); - - if (!dso) { - map__put(map); - return -1; - } - - size =3D dso__data_read_addr(dso, map, ui->machine, - addr, (u8 *) data, sizeof(*data)); - map__put(map); - return !(size =3D=3D sizeof(*data)); -} - -static int access_mem(unw_addr_space_t __maybe_unused as, - unw_word_t addr, unw_word_t *valp, - int __write, void *arg) -{ - struct unwind_info *ui =3D arg; - struct stack_dump *stack =3D &ui->sample->user_stack; - u64 start, end; - int offset; - int ret; - - /* Don't support write, probably not needed. */ - if (__write || !stack || !ui->sample->user_regs || !ui->sample->user_regs= ->regs) { - *valp =3D 0; - return 0; - } - - ret =3D perf_reg_value(&start, perf_sample__user_regs(ui->sample), - perf_arch_reg_sp(ui->e_machine)); - if (ret) - return ret; - - end =3D start + stack->size; - - /* Check overflow. */ - if (addr + sizeof(unw_word_t) < addr) - return -EINVAL; - - if (addr < start || addr + sizeof(unw_word_t) >=3D end) { - ret =3D access_dso_mem(ui, addr, valp); - if (ret) { - pr_debug("unwind: access_mem %p not inside range" - " 0x%" PRIx64 "-0x%" PRIx64 "\n", - (void *) (uintptr_t) addr, start, end); - *valp =3D 0; - return ret; - } - return 0; - } - - offset =3D addr - start; - *valp =3D *(unw_word_t *)&stack->data[offset]; - pr_debug("unwind: access_mem addr %p val %lx, offset %d\n", - (void *) (uintptr_t) addr, (unsigned long)*valp, offset); - return 0; -} - -static int access_reg(unw_addr_space_t __maybe_unused as, - unw_regnum_t regnum, unw_word_t *valp, - int __write, void *arg) -{ - struct unwind_info *ui =3D arg; - int id, ret; - u64 val; - - /* Don't support write, I suspect we don't need it. */ - if (__write) { - pr_err("unwind: access_reg w %d\n", regnum); - return 0; - } - - if (!ui->sample->user_regs || !ui->sample->user_regs->regs) { - *valp =3D 0; - return 0; - } - - id =3D get_perf_regnum_for_unw_regnum(ui->e_machine, regnum); - if (id < 0) - return -EINVAL; - - ret =3D perf_reg_value(&val, perf_sample__user_regs(ui->sample), id); - if (ret) { - if (!ui->best_effort) - pr_err("unwind: can't read reg %d\n", regnum); - return ret; - } - - *valp =3D (unw_word_t) val; - pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp); - return 0; -} - -static void put_unwind_info(unw_addr_space_t __maybe_unused as, - unw_proc_info_t *pi __maybe_unused, - void *arg __maybe_unused) -{ - pr_debug("unwind: put_unwind_info called\n"); -} - -static int entry(u64 ip, struct thread *thread, - unwind_entry_cb_t cb, void *arg) -{ - struct unwind_entry e; - struct addr_location al; - int ret; - - addr_location__init(&al); - e.ms.sym =3D thread__find_symbol(thread, PERF_RECORD_MISC_USER, ip, &al); - e.ip =3D ip; - e.ms.map =3D al.map; - e.ms.thread =3D thread__get(al.thread); - - pr_debug("unwind: %s:ip =3D 0x%" PRIx64 " (0x%" PRIx64 ")\n", - al.sym ? al.sym->name : "''", - ip, - al.map ? map__map_ip(al.map, ip) : (u64) 0); - - ret =3D cb(&e, arg); - addr_location__exit(&al); - return ret; -} - -static void display_error(int err) -{ - switch (err) { - case UNW_EINVAL: - pr_err("unwind: Only supports local.\n"); - break; - case UNW_EUNSPEC: - pr_err("unwind: Unspecified error.\n"); - break; - case UNW_EBADREG: - pr_err("unwind: Register unavailable.\n"); - break; - default: - break; - } -} - -static unw_accessors_t accessors =3D { - .find_proc_info =3D find_proc_info, - .put_unwind_info =3D put_unwind_info, - .get_dyn_info_list_addr =3D get_dyn_info_list_addr, - .access_mem =3D access_mem, - .access_reg =3D access_reg, - .access_fpreg =3D access_fpreg, - .resume =3D resume, - .get_proc_name =3D get_proc_name, -}; - -static int _unwind__prepare_access(struct maps *maps) -{ - void *addr_space =3D unw_create_addr_space(&accessors, 0); - - maps__set_addr_space(maps, addr_space); - if (!addr_space) { - pr_err("unwind: Can't create unwind address space.\n"); - return -ENOMEM; - } - - unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); - return 0; -} - -static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, - void *arg, int max_stack) -{ - u64 val; - unw_word_t ips[max_stack]; - unw_addr_space_t addr_space; - unw_cursor_t c; - int ret, i =3D 0; - - ret =3D perf_reg_value(&val, perf_sample__user_regs(ui->sample), - perf_arch_reg_ip(ui->e_machine)); - if (ret) - return ret; - - ips[i++] =3D (unw_word_t) val; - - /* - * If we need more than one entry, do the DWARF - * unwind itself. - */ - if (max_stack - 1 > 0) { - WARN_ONCE(!ui->thread, "WARNING: ui->thread is NULL"); - addr_space =3D maps__addr_space(thread__maps(ui->thread)); - - if (addr_space =3D=3D NULL) - return -1; - - ret =3D unw_init_remote(&c, addr_space, ui); - if (ret && !ui->best_effort) - display_error(ret); - - while (!ret && (unw_step(&c) > 0) && i < max_stack) { - unw_get_reg(&c, UNW_REG_IP, &ips[i]); - - /* - * Decrement the IP for any non-activation frames. - * this is required to properly find the srcline - * for caller frames. - * See also the documentation for dwfl_frame_pc(), - * which this code tries to replicate. - */ - if (unw_is_signal_frame(&c) <=3D 0) - --ips[i]; - - ++i; - } - - max_stack =3D i; - } - - /* - * Display what we got based on the order setup. - */ - for (i =3D 0; i < max_stack && !ret; i++) { - int j =3D i; - - if (callchain_param.order =3D=3D ORDER_CALLER) - j =3D max_stack - i - 1; - ret =3D ips[j] ? entry(ips[j], ui->thread, cb, arg) : 0; - } - - return ret; -} - -static int _unwind__get_entries(unwind_entry_cb_t cb, void *arg, - struct thread *thread, - struct perf_sample *data, int max_stack, - bool best_effort) -{ - struct unwind_info ui =3D { - .sample =3D data, - .thread =3D thread, - .machine =3D maps__machine(thread__maps(thread)), - .e_machine =3D thread__e_machine(thread, /*machine=3D*/NULL, /*e_flag= s=3D*/NULL), - .best_effort =3D best_effort - }; - - if (!data->user_regs || !data->user_regs->regs) - return -EINVAL; - - if (max_stack <=3D 0) - return -EINVAL; - - return get_entries(&ui, cb, arg, max_stack); -} - -static struct unwind_libunwind_ops -_unwind_libunwind_ops =3D { - .prepare_access =3D _unwind__prepare_access, - .get_entries =3D _unwind__get_entries, -}; - -#ifndef REMOTE_UNWIND_LIBUNWIND -struct unwind_libunwind_ops * -local_unwind_libunwind_ops =3D &_unwind_libunwind_ops; -#endif diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-li= bunwind.c index eaee7b78d87c..66e7b7a26aad 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -1,23 +1,557 @@ // SPDX-License-Identifier: GPL-2.0 -#include "unwind.h" +#include "callchain.h" +#include "debug.h" #include "dso.h" +#include "env.h" #include "map.h" -#include "thread.h" +#include "perf_regs.h" #include "session.h" -#include "debug.h" -#include "env.h" -#include "callchain.h" +#include "symbol.h" +#include "thread.h" +#include "unwind.h" #include "libunwind-arch/libunwind-arch.h" #include #include +#include +#include +#include + +#define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */ +#define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */ + +/* Pointer-encoding formats: */ +#define DW_EH_PE_omit 0xff +#define DW_EH_PE_ptr 0x00 /* pointer-sized unsigned value */ +#define DW_EH_PE_udata4 0x03 /* unsigned 32-bit value */ +#define DW_EH_PE_udata8 0x04 /* unsigned 64-bit value */ +#define DW_EH_PE_sdata4 0x0b /* signed 32-bit value */ +#define DW_EH_PE_sdata8 0x0c /* signed 64-bit value */ + +/* Pointer-encoding application: */ +#define DW_EH_PE_absptr 0x00 /* absolute value */ +#define DW_EH_PE_pcrel 0x10 /* rel. to addr. of encoded value */ + +/* + * The following are not documented by LSB v1.3, yet they are used by + * GCC, presumably they aren't documented by LSB since they aren't + * used on Linux: + */ +#define DW_EH_PE_funcrel 0x40 /* start-of-procedure-relative */ +#define DW_EH_PE_aligned 0x50 /* aligned pointer */ + +/* Flags intentionally not handled, since they're not needed: + * #define DW_EH_PE_indirect 0x80 + * #define DW_EH_PE_uleb128 0x01 + * #define DW_EH_PE_udata2 0x02 + * #define DW_EH_PE_sleb128 0x09 + * #define DW_EH_PE_sdata2 0x0a + * #define DW_EH_PE_textrel 0x20 + * #define DW_EH_PE_datarel 0x30 + */ + +#define dw_read(ptr, type, end) ({ \ + type *__p =3D (type *) ptr; \ + type __v; \ + if ((__p + 1) > (type *) end) \ + return -EINVAL; \ + __v =3D *__p++; \ + ptr =3D (typeof(ptr)) __p; \ + __v; \ + }) + +static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val, + u8 encoding) +{ + u8 *cur =3D *p; + *val =3D 0; + + switch (encoding) { + case DW_EH_PE_omit: + *val =3D 0; + goto out; + case DW_EH_PE_ptr: + *val =3D dw_read(cur, unsigned long, end); + goto out; + default: + break; + } + + switch (encoding & DW_EH_PE_APPL_MASK) { + case DW_EH_PE_absptr: + break; + case DW_EH_PE_pcrel: + *val =3D (unsigned long) cur; + break; + default: + return -EINVAL; + } + + if ((encoding & 0x07) =3D=3D 0x00) + encoding |=3D DW_EH_PE_udata4; + + switch (encoding & DW_EH_PE_FORMAT_MASK) { + case DW_EH_PE_sdata4: + *val +=3D dw_read(cur, s32, end); + break; + case DW_EH_PE_udata4: + *val +=3D dw_read(cur, u32, end); + break; + case DW_EH_PE_sdata8: + *val +=3D dw_read(cur, s64, end); + break; + case DW_EH_PE_udata8: + *val +=3D dw_read(cur, u64, end); + break; + default: + return -EINVAL; + } + + out: + *p =3D cur; + return 0; +} + +#define dw_read_encoded_value(ptr, end, enc) ({ \ + u64 __v; \ + if (__dw_read_encoded_value(&ptr, end, &__v, enc)) { \ + return -EINVAL; \ + } \ + __v; \ + }) + +static u64 elf_base_address(int fd) +{ + Elf *elf =3D elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); + GElf_Phdr phdr; + u64 retval =3D 0; + size_t i, phdrnum =3D 0; + + if (elf =3D=3D NULL) + return 0; + (void)elf_getphdrnum(elf, &phdrnum); + /* PT_LOAD segments are sorted by p_vaddr, so the first has the minimum p= _vaddr. */ + for (i =3D 0; i < phdrnum; i++) { + if (gelf_getphdr(elf, i, &phdr) && phdr.p_type =3D=3D PT_LOAD) { + retval =3D phdr.p_vaddr & -getpagesize(); + break; + } + } + + elf_end(elf); + return retval; +} + +static int unwind_spec_ehframe(struct dso *dso, struct machine *machine, + u64 offset, u64 *table_data_offset, u64 *fde_count) +{ + struct eh_frame_hdr { + unsigned char version; + unsigned char eh_frame_ptr_enc; + unsigned char fde_count_enc; + unsigned char table_enc; + + /* + * The rest of the header is variable-length and consists of the + * following members: + * + * encoded_t eh_frame_ptr; + * encoded_t fde_count; + */ + + /* A single encoded pointer should not be more than 8 bytes. */ + u64 enc[2]; + + /* + * struct { + * encoded_t start_ip; + * encoded_t fde_addr; + * } binary_search_table[fde_count]; + */ + char data[]; + } __packed hdr; + u8 *enc =3D (u8 *) &hdr.enc; + u8 *end =3D (u8 *) &hdr.data; + ssize_t r; + + r =3D dso__data_read_offset(dso, machine, offset, (u8 *) &hdr, sizeof(hdr= )); + if (r !=3D sizeof(hdr)) + return -EINVAL; + + /* We dont need eh_frame_ptr, just skip it. */ + dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc); + + *fde_count =3D dw_read_encoded_value(enc, end, hdr.fde_count_enc); + *table_data_offset =3D enc - (u8 *) &hdr; + return 0; +} + +struct read_unwind_spec_eh_frame_maps_cb_args { + struct dso *dso; + u64 base_addr; +}; + +static int read_unwind_spec_eh_frame_maps_cb(struct map *map, void *data) +{ + + struct read_unwind_spec_eh_frame_maps_cb_args *args =3D data; + + if (map__dso(map) =3D=3D args->dso && map__start(map) - map__pgoff(map) <= args->base_addr) + args->base_addr =3D map__start(map) - map__pgoff(map); + + return 0; +} + +static int elf_section_address_and_offset(int fd, const char *name, u64 *a= ddress, u64 *offset) +{ + Elf *elf; + GElf_Ehdr ehdr; + GElf_Shdr shdr; + int ret =3D -1; + + elf =3D elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); + if (elf =3D=3D NULL) + return -1; =20 -struct unwind_libunwind_ops __weak *local_unwind_libunwind_ops; -struct unwind_libunwind_ops __weak *x86_32_unwind_libunwind_ops; -struct unwind_libunwind_ops __weak *arm64_unwind_libunwind_ops; + if (gelf_getehdr(elf, &ehdr) =3D=3D NULL) + goto out_err; + + if (!elf_section_by_name(elf, &ehdr, &shdr, name, NULL)) + goto out_err; + + *address =3D shdr.sh_addr; + *offset =3D shdr.sh_offset; + ret =3D 0; +out_err: + elf_end(elf); + return ret; +} + +static int read_unwind_spec_eh_frame(struct dso *dso, struct unwind_info *= ui, + u64 *table_data, u64 *segbase, + u64 *fde_count) +{ + struct read_unwind_spec_eh_frame_maps_cb_args args =3D { + .dso =3D dso, + .base_addr =3D UINT64_MAX, + }; + int ret, fd; + + if (dso__data(dso)->eh_frame_hdr_offset =3D=3D 0) { + if (!dso__data_get_fd(dso, ui->machine, &fd)) + return -EINVAL; + + /* Check the .eh_frame section for unwinding info */ + ret =3D elf_section_address_and_offset(fd, ".eh_frame_hdr", + &dso__data(dso)->eh_frame_hdr_addr, + &dso__data(dso)->eh_frame_hdr_offset); + dso__data(dso)->elf_base_addr =3D elf_base_address(fd); + dso__data_put_fd(dso); + if (ret || dso__data(dso)->eh_frame_hdr_offset =3D=3D 0) + return -EINVAL; + } + + maps__for_each_map(thread__maps(ui->thread), read_unwind_spec_eh_frame_ma= ps_cb, &args); + + args.base_addr -=3D dso__data(dso)->elf_base_addr; + /* Address of .eh_frame_hdr */ + *segbase =3D args.base_addr + dso__data(dso)->eh_frame_hdr_addr; + ret =3D unwind_spec_ehframe(dso, ui->machine, dso__data(dso)->eh_frame_hd= r_offset, + table_data, fde_count); + if (ret) + return ret; + /* binary_search_table offset plus .eh_frame_hdr address */ + *table_data +=3D *segbase; + return 0; +} + +static u64 elf_section_offset(int fd, const char *name) +{ + u64 address, offset =3D 0; + + if (elf_section_address_and_offset(fd, name, &address, &offset)) + return 0; + + return offset; +} + +static int read_unwind_spec_debug_frame(struct dso *dso, + struct machine *machine, u64 *offset) +{ + int fd; + u64 ofs =3D dso__data(dso)->debug_frame_offset; + + /* debug_frame can reside in: + * - dso + * - debug pointed by symsrc_filename + * - gnu_debuglink, which doesn't necessary + * has to be pointed by symsrc_filename + */ + if (ofs =3D=3D 0) { + if (dso__data_get_fd(dso, machine, &fd)) { + ofs =3D elf_section_offset(fd, ".debug_frame"); + dso__data_put_fd(dso); + } + + if (ofs <=3D 0) { + fd =3D open(dso__symsrc_filename(dso), O_RDONLY); + if (fd >=3D 0) { + ofs =3D elf_section_offset(fd, ".debug_frame"); + close(fd); + } + } + + if (ofs <=3D 0) { + char *debuglink =3D malloc(PATH_MAX); + int ret =3D 0; + + if (debuglink =3D=3D NULL) { + pr_err("unwind: Can't read unwind spec debug frame.\n"); + return -ENOMEM; + } + + ret =3D dso__read_binary_type_filename( + dso, DSO_BINARY_TYPE__DEBUGLINK, + machine->root_dir, debuglink, PATH_MAX); + if (!ret) { + fd =3D open(debuglink, O_RDONLY); + if (fd >=3D 0) { + ofs =3D elf_section_offset(fd, + ".debug_frame"); + close(fd); + } + } + if (ofs > 0) { + if (dso__symsrc_filename(dso) !=3D NULL) { + pr_warning( + "%s: overwrite symsrc(%s,%s)\n", + __func__, + dso__symsrc_filename(dso), + debuglink); + dso__free_symsrc_filename(dso); + } + dso__set_symsrc_filename(dso, debuglink); + } else { + free(debuglink); + } + } + + dso__data(dso)->debug_frame_offset =3D ofs; + } + + *offset =3D ofs; + if (*offset) + return 0; + + return -EINVAL; +} + +static struct map *find_map(uint64_t ip, struct unwind_info *ui) +{ + struct addr_location al; + struct map *ret; + + addr_location__init(&al); + thread__find_map(ui->thread, PERF_RECORD_MISC_USER, ip, &al); + ret =3D map__get(al.map); + addr_location__exit(&al); + return ret; +} + +static int elf_is_exec(int fd, const char *name) +{ + Elf *elf; + GElf_Ehdr ehdr; + int retval =3D 0; + + elf =3D elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); + if (elf =3D=3D NULL) + return 0; + if (gelf_getehdr(elf, &ehdr) =3D=3D NULL) + goto out; + + retval =3D (ehdr.e_type =3D=3D ET_EXEC); + +out: + elf_end(elf); + pr_debug3("unwind: elf_is_exec(%s): %d\n", name, retval); + return retval; +} + +int __libunwind__find_proc_info(void *as, uint64_t ip, void *pi, int need_= unwind_info, void *arg) +{ + struct unwind_info *ui =3D arg; + struct map *map; + struct dso *dso; + u64 table_data, segbase, fde_count; + int ret =3D -EINVAL; + + map =3D find_map(ip, ui); + if (!map) + return -EINVAL; + + dso =3D map__dso(map); + if (!dso) { + map__put(map); + return -EINVAL; + } + + pr_debug3("unwind: find_proc_info dso %s\n", dso__name(dso)); + + /* Check the .eh_frame section for unwinding info */ + if (!read_unwind_spec_eh_frame(dso, ui, &table_data, &segbase, &fde_count= )) { + struct table_entry { + u32 start_ip_offset; + u32 fde_offset; + }; + struct libarch_unwind__dyn_info di =3D { + .start_ip =3D map__start(map), + .end_ip =3D map__end(map), + .segbase =3D segbase, + .table_data =3D table_data, + .table_len =3D fde_count * sizeof(struct table_entry) / ui->unw_word_t= _size, + }; + + ret =3D libunwind_arch__dwarf_search_unwind_table(ui->e_machine, as, ip,= &di, pi, + need_unwind_info, arg); + } + + /* Check the .debug_frame section for unwinding info */ + if (ret < 0 && !read_unwind_spec_debug_frame(dso, ui->machine, &segbase))= { + int fd; + u64 start =3D map__start(map); + u64 base =3D start; + const char *symfile; + struct libarch_unwind__dyn_info di =3D {}; + + if (dso__data_get_fd(dso, ui->machine, &fd)) { + if (elf_is_exec(fd, dso__name(dso))) + base =3D 0; + dso__data_put_fd(dso); + } + + symfile =3D dso__symsrc_filename(dso) ?: dso__name(dso); + + if (libunwind_arch__dwarf_find_debug_frame(ui->e_machine, /*found=3D*/0,= &di, ip, + base, symfile, start, map__end(map))) { + ret =3D libunwind_arch__dwarf_search_unwind_table(ui->e_machine, as, ip= , &di, pi, + need_unwind_info, arg); + } + } + map__put(map); + return ret; +} + +static int access_dso_mem(struct unwind_info *ui, uint64_t addr, void *dat= a_word) +{ + struct map *map; + struct dso *dso; + ssize_t size; + + map =3D find_map(addr, ui); + if (!map) { + pr_debug("unwind: no map for %lx\n", (unsigned long)addr); + return -1; + } + + dso =3D map__dso(map); + + if (!dso) { + map__put(map); + return -1; + } + + size =3D dso__data_read_addr(dso, map, ui->machine, + addr, + (u8 *) data_word, + ui->unw_word_t_size); + map__put(map); + return !((size_t)size =3D=3D ui->unw_word_t_size); +} + +int __libunwind__access_mem(void *as __maybe_unused, uint64_t addr, void *= valp_word, + int __write, void *arg) +{ + struct unwind_info *ui =3D arg; + struct stack_dump *stack =3D &ui->sample->user_stack; + u64 start, end; + int offset; + int ret; + + /* Don't support write, probably not needed. */ + if (__write || !stack || !ui->sample->user_regs || !ui->sample->user_regs= ->regs) { + uint64_t zero =3D 0; + + memcpy(valp_word, &zero, ui->unw_word_t_size); + return 0; + } + + ret =3D perf_reg_value(&start, perf_sample__user_regs(ui->sample), + perf_arch_reg_sp(ui->e_machine)); + if (ret) + return ret; + + end =3D start + stack->size; + + /* Check overflow. */ + if (addr + ui->unw_word_t_size < addr) + return -EINVAL; + + if (addr < start || addr + ui->unw_word_t_size >=3D end) { + ret =3D access_dso_mem(ui, addr, valp_word); + if (ret) { + pr_debug3("unwind: access_mem %p not inside range" + " 0x%" PRIx64 "-0x%" PRIx64 "\n", + (void *) (uintptr_t) addr, start, end); + memset(valp_word, 0, ui->unw_word_t_size); + return ret; + } + return 0; + } + + offset =3D addr - start; + memcpy(valp_word, &stack->data[offset], ui->unw_word_t_size); + pr_debug3("unwind: access_mem addr %p val %lx, offset %d\n", + (void *) (uintptr_t) addr, *((unsigned long *)valp_word), offset); + return 0; +} + +int __libunwind__access_reg(void *as __maybe_unused, int regnum, void *val= p_word, int __write, + void *arg) +{ + struct unwind_info *ui =3D arg; + int id, ret; + u64 val; + + /* Don't support write, I suspect we don't need it. */ + if (__write) { + pr_err("unwind: access_reg w %d\n", regnum); + return 0; + } + + if (!ui->sample->user_regs || !ui->sample->user_regs->regs) { + memset(valp_word, 0, ui->unw_word_t_size); + return 0; + } + + id =3D get_perf_regnum_for_unw_regnum(ui->e_machine, regnum); + if (id < 0) + return -EINVAL; + + ret =3D perf_reg_value(&val, perf_sample__user_regs(ui->sample), id); + if (ret) { + if (!ui->best_effort) + pr_err("unwind: can't read reg %d\n", regnum); + return ret; + } + + memcpy(valp_word, &val, ui->unw_word_t_size); + pr_debug3("unwind: reg %d, val %lx\n", regnum, val); + return 0; +} =20 int unwind__prepare_access(struct maps *maps, uint16_t e_machine) { - struct unwind_libunwind_ops *ops =3D local_unwind_libunwind_ops; + void *addr_space; =20 if (!dwarf_callchain_users) return 0; @@ -27,25 +561,16 @@ int unwind__prepare_access(struct maps *maps, uint16_t= e_machine) return 0; } =20 - if (e_machine !=3D EM_HOST) { - /* If not live/local mode. */ - switch (e_machine) { - case EM_386: - ops =3D x86_32_unwind_libunwind_ops; - break; - case EM_AARCH64: - ops =3D arm64_unwind_libunwind_ops; - break; - default: - pr_warning_once("unwind: ELF machine type %d is not supported\n", - e_machine); - return 0; - } - } - maps__set_unwind_libunwind_ops(maps, ops); maps__set_e_machine(maps, e_machine); + addr_space =3D libunwind_arch__create_addr_space(e_machine); + + maps__set_addr_space(maps, addr_space); + if (!addr_space) { + pr_err("unwind: Can't create unwind address space.\n"); + return -ENOMEM; + } =20 - return maps__unwind_libunwind_ops(maps)->prepare_access(maps); + return 0; } =20 void unwind__flush_access(struct maps *maps) @@ -58,14 +583,81 @@ void unwind__finish_access(struct maps *maps) libunwind_arch__finish_access(maps); } =20 +static int entry(uint64_t ip, struct thread *thread, unwind_entry_cb_t cb,= void *arg) +{ + struct unwind_entry e; + struct addr_location al; + int ret; + + addr_location__init(&al); + e.ms.sym =3D thread__find_symbol(thread, PERF_RECORD_MISC_USER, ip, &al); + e.ip =3D ip; + e.ms.map =3D al.map; + e.ms.thread =3D thread__get(al.thread); + + pr_debug("unwind: %s:ip =3D 0x%" PRIx64 " (0x%" PRIx64 ")\n", + al.sym ? al.sym->name : "''", + ip, + al.map ? map__map_ip(al.map, ip) : (u64) 0); + + ret =3D cb(&e, arg); + addr_location__exit(&al); + return ret; +} + int libunwind__get_entries(unwind_entry_cb_t cb, void *arg, struct thread *thread, - struct perf_sample *data, int max_stack, + struct perf_sample *sample, int max_stack, bool best_effort) { - const struct unwind_libunwind_ops *ops =3D maps__unwind_libunwind_ops(thr= ead__maps(thread)); + struct unwind_info *ui; + uint64_t first_ip; + int ret, i =3D 0; + uint16_t e_machine; =20 - if (ops) - return ops->get_entries(cb, arg, thread, data, max_stack, best_effort); - return 0; + if (!sample->user_regs || !sample->user_regs->regs) + return -EINVAL; + + if (max_stack <=3D 0) + return -EINVAL; + + if (!thread) { + pr_warning_once("WARNING: thread is NULL"); + return -EINVAL; + } + + e_machine =3D thread__e_machine(thread, /*machine=3D*/NULL, /*e_flags=3D*= /NULL); + ret =3D perf_reg_value(&first_ip, perf_sample__user_regs(sample), + perf_arch_reg_ip(e_machine)); + if (ret) + return ret; + + if (max_stack =3D=3D 1) { + /* Special case for a single entry. */ + return entry(first_ip, thread, cb, arg); + } + + ui =3D libunwind_arch_unwind_info__new(thread, sample, max_stack, best_ef= fort, e_machine, first_ip); + if (!ui) + return -1; + + do { + ret =3D libunwind_arch__unwind_step(ui); + if (ret < 0) + goto out; + + } while (ret); + + /* + * Display what we got based on the order setup. + */ + for (i =3D 0; i < ui->cur_ip; i++) { + int j =3D callchain_param.order =3D=3D ORDER_CALLEE ? i : ui->cur_ip - i= - 1; + + if (ui->ips[j]) + ret =3D entry(ui->ips[j], thread, cb, arg); + } +out: + libunwind_arch_unwind_info__delete(ui); + return ret; } diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index 09fc60df262d..e06c090c6685 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -19,13 +19,6 @@ struct unwind_entry { =20 typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg); =20 -struct unwind_libunwind_ops { - int (*prepare_access)(struct maps *maps); - int (*get_entries)(unwind_entry_cb_t cb, void *arg, - struct thread *thread, - struct perf_sample *data, int max_stack, bool best_effort); -}; - int unwind__configure(const char *var, const char *value, void *cb); int unwind__option(const struct option *opt, const char *arg, int unset); =20 --=20 2.53.0.473.g4a7958ca14-goog From nobody Thu Apr 9 20:26:03 2026 Received: from mail-dy1-f201.google.com (mail-dy1-f201.google.com [74.125.82.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AB763364040 for ; Thu, 5 Mar 2026 22:19:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772749198; cv=none; b=H4PzYQys7PBb3k/r1v6f+o8FZ9dbTBHuTymmY7ZOyCWEDua7v+TJUcjM8YRElCJfJ1Iw+MCkpkT9zW/Tb28zEhLUxLAFs+8ULS3pL/URULi3JsG/fflYP6grt2sGHcXv6UNaKV0z/Z7AIbyWZG+hkTHJuXNvWNrbylyCTktP0RI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772749198; c=relaxed/simple; bh=Xaxz649GmfIxie3kVaiIaJT56p+J31sskncWdfOZwcg=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=rdbaQRwAU68TZzmqYs2XE0VaIjLVt/X6vrqojlOyW7hJt30SzRQWancNTcuFXhp+Gsz4K9yiBak5fN23SgtEFtjGRF4rWSvXItZSnVm4xXXOKc0JWzQMgpdfDkWGA8wCNcCusq/s8nhm6s8vod/j80t5GebpI5qkGEi6J/VyH/k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=EZgdk/sa; arc=none smtp.client-ip=74.125.82.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="EZgdk/sa" Received: by mail-dy1-f201.google.com with SMTP id 5a478bee46e88-2bdff07d8f4so8011931eec.1 for ; Thu, 05 Mar 2026 14:19:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1772749196; x=1773353996; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=CNkWV5yyzgNwpNnLJuF+PzD843L6NDQ9zKEGjRbCg+s=; b=EZgdk/saZGHTGfLyDs+Mva9QI+IKuPRCMqojJ36ihCAXp6hPSDPp54PqAx41FLE38Q jYd1XKL7X+wcR2ha4iOOBpco3TlrtLr9YwO7Za8Bti4uHmEHhUW9wFkfnw6rGtMyRch+ TKI1O23glQcn4kNzWFGok+RZvdhECyg7818tBwvUXstRQC2vB0A/A1xXq9WKpaob/GVE tZGGuZo8Jy3Pcx4fbV2Z6X0nMOtwei7YNQo+Q2cGXBFKWD2wXzbDbVuRDYhNN0L8wETz lr5/T6I6u4UZXOvybGJYTlOmJKMTwjC65fvyKWgOUz1Z7rTgVFBYUTCVnE6NorYwB02Z bNAA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772749196; x=1773353996; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=CNkWV5yyzgNwpNnLJuF+PzD843L6NDQ9zKEGjRbCg+s=; b=d/76pbxVjSOPTRFgTpsQFRyHBTUBbACNIkTbG+zaSEi8hLI62VRMfQeswhPVWpDk+1 Mli1usGCiMEpL0xfsMq9XqNPBAPuRjYny3d6CX6qpmXOhZa6TDDn9YDs3HRAkB6kUYZA wF8OBnfVG5CSsqRNv/ERHGWPkoc3bV3i40M70vbqAWilzNPQSWMh7j/ljvAkwhElBI6y 0sVo5mC+oPb0bhay5uA7H6QNm/JjOpHTHYcsnp+8H7ZUY/CsNk15Y1oKkQDhvqlIw+8l IM2Cu4ZCxvVIzqwrNWZ1QAlc30TJX5traYhG8fQdzggddmd/3JBFd7gxVvQSdb4BXI61 OXgA== X-Forwarded-Encrypted: i=1; AJvYcCVCG8lo5Fy3sfNBIn7WB+k6/Kf1qsEjNdeUnbtN9N+HlnrgwoGo1N3IZ+1KwlnyqBeCktWjB1hgiGLEsdM=@vger.kernel.org X-Gm-Message-State: AOJu0Yx1//Up7COA2fz0K7GkexkKxW3R3yoaM7qR6L59k3WKw3gFIodL p8bu4xgwLwO9aFsRrLyo6j/L4UJ2pUsIyqUIvWe+/rYryXLUDVM80/2cNU6r+elB7abxuwzTZon mpvrdFYL+0A== X-Received: from dlbbz39.prod.google.com ([2002:a05:7022:23a7:b0:127:c11:f47a]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7022:217:b0:124:b11f:67ec with SMTP id a92af1059eb24-128c2ec736dmr2440c88.39.1772749195634; Thu, 05 Mar 2026 14:19:55 -0800 (PST) Date: Thu, 5 Mar 2026 14:19:27 -0800 In-Reply-To: <20260305221927.3237145-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260305221927.3237145-1-irogers@google.com> X-Mailer: git-send-email 2.53.0.473.g4a7958ca14-goog Message-ID: <20260305221927.3237145-9-irogers@google.com> Subject: [PATCH v2 8/8] perf unwind-libunwind: Add RISC-V libunwind support From: Ian Rogers 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 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a RISC-V implementation for unwinding. Signed-off-by: Ian Rogers --- tools/perf/util/libunwind-arch/Build | 1 + .../perf/util/libunwind-arch/libunwind-arch.c | 21 ++ .../perf/util/libunwind-arch/libunwind-arch.h | 22 ++ .../util/libunwind-arch/libunwind-riscv.c | 297 ++++++++++++++++++ 4 files changed, 341 insertions(+) create mode 100644 tools/perf/util/libunwind-arch/libunwind-riscv.c diff --git a/tools/perf/util/libunwind-arch/Build b/tools/perf/util/libunwi= nd-arch/Build index 87fd657a3248..80d3571918b1 100644 --- a/tools/perf/util/libunwind-arch/Build +++ b/tools/perf/util/libunwind-arch/Build @@ -5,6 +5,7 @@ perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-loongarch.o perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-mips.o perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-ppc32.o perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-ppc64.o +perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-riscv.o perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-s390.o perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-i386.o perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-x86_64.o diff --git a/tools/perf/util/libunwind-arch/libunwind-arch.c b/tools/perf/u= til/libunwind-arch/libunwind-arch.c index 8539b4233df4..9a74cf3c8729 100644 --- a/tools/perf/util/libunwind-arch/libunwind-arch.c +++ b/tools/perf/util/libunwind-arch/libunwind-arch.c @@ -20,6 +20,8 @@ int get_perf_regnum_for_unw_regnum(unsigned int e_machine= , int unw_regnum) return __get_perf_regnum_for_unw_regnum_ppc32(unw_regnum); case EM_PPC64: return __get_perf_regnum_for_unw_regnum_ppc64(unw_regnum); + case EM_RISCV: + return __get_perf_regnum_for_unw_regnum_riscv(unw_regnum); case EM_S390: return __get_perf_regnum_for_unw_regnum_s390(unw_regnum); case EM_386: @@ -58,6 +60,9 @@ void libunwind_arch__flush_access(struct maps *maps) case EM_PPC64: __libunwind_arch__flush_access_ppc64(maps); break; + case EM_RISCV: + __libunwind_arch__flush_access_riscv(maps); + break; case EM_S390: __libunwind_arch__flush_access_s390(maps); break; @@ -98,6 +103,9 @@ void libunwind_arch__finish_access(struct maps *maps) case EM_PPC64: __libunwind_arch__finish_access_ppc64(maps); break; + case EM_RISCV: + __libunwind_arch__finish_access_riscv(maps); + break; case EM_S390: __libunwind_arch__finish_access_s390(maps); break; @@ -128,6 +136,8 @@ void *libunwind_arch__create_addr_space(unsigned int e_= machine) return __libunwind_arch__create_addr_space_ppc32(); case EM_PPC64: return __libunwind_arch__create_addr_space_ppc64(); + case EM_RISCV: + return __libunwind_arch__create_addr_space_riscv(); case EM_S390: return __libunwind_arch__create_addr_space_s390(); case EM_386: @@ -167,6 +177,9 @@ int libunwind_arch__dwarf_search_unwind_table(unsigned = int e_machine, case EM_PPC64: return __libunwind_arch__dwarf_search_unwind_table_ppc64(as, ip, di, pi, need_unwind_info, arg); + case EM_RISCV: + return __libunwind_arch__dwarf_search_unwind_table_riscv(as, ip, di, pi, + need_unwind_info, arg); case EM_S390: return __libunwind_arch__dwarf_search_unwind_table_s390(as, ip, di, pi, need_unwind_info, arg); @@ -211,6 +224,9 @@ int libunwind_arch__dwarf_find_debug_frame(unsigned int= e_machine, case EM_PPC64: return __libunwind_arch__dwarf_find_debug_frame_ppc64(found, di_debug, i= p, segbase, obj_name, start, end); + case EM_RISCV: + return __libunwind_arch__dwarf_find_debug_frame_riscv(found, di_debug, i= p, segbase, + obj_name, start, end); case EM_S390: return __libunwind_arch__dwarf_find_debug_frame_s390(found, di_debug, ip= , segbase, obj_name, start, end); @@ -250,6 +266,9 @@ struct unwind_info *libunwind_arch_unwind_info__new(str= uct thread *thread, case EM_PPC64: return __libunwind_arch_unwind_info__new_ppc64(thread, sample, max_stack, best_effort, first_ip); + case EM_RISCV: + return __libunwind_arch_unwind_info__new_riscv(thread, sample, max_stack, + best_effort, first_ip); case EM_S390: return __libunwind_arch_unwind_info__new_s390(thread, sample, max_stack, best_effort, first_ip); @@ -285,6 +304,8 @@ int libunwind_arch__unwind_step(struct unwind_info *ui) return __libunwind_arch__unwind_step_ppc32(ui); case EM_PPC64: return __libunwind_arch__unwind_step_ppc64(ui); + case EM_RISCV: + return __libunwind_arch__unwind_step_riscv(ui); case EM_S390: return __libunwind_arch__unwind_step_s390(ui); case EM_386: diff --git a/tools/perf/util/libunwind-arch/libunwind-arch.h b/tools/perf/u= til/libunwind-arch/libunwind-arch.h index 2bf7fc33313b..74a09cd58f38 100644 --- a/tools/perf/util/libunwind-arch/libunwind-arch.h +++ b/tools/perf/util/libunwind-arch/libunwind-arch.h @@ -39,6 +39,7 @@ int __get_perf_regnum_for_unw_regnum_loongarch(int unw_re= gnum); int __get_perf_regnum_for_unw_regnum_mips(int unw_regnum); int __get_perf_regnum_for_unw_regnum_ppc32(int unw_regnum); int __get_perf_regnum_for_unw_regnum_ppc64(int unw_regnum); +int __get_perf_regnum_for_unw_regnum_riscv(int unw_regnum); int __get_perf_regnum_for_unw_regnum_s390(int unw_regnum); int __get_perf_regnum_for_unw_regnum_i386(int unw_regnum); int __get_perf_regnum_for_unw_regnum_x86_64(int unw_regnum); @@ -50,6 +51,7 @@ void __libunwind_arch__flush_access_loongarch(struct maps= *maps); void __libunwind_arch__flush_access_mips(struct maps *maps); void __libunwind_arch__flush_access_ppc32(struct maps *maps); void __libunwind_arch__flush_access_ppc64(struct maps *maps); +void __libunwind_arch__flush_access_riscv(struct maps *maps); void __libunwind_arch__flush_access_s390(struct maps *maps); void __libunwind_arch__flush_access_i386(struct maps *maps); void __libunwind_arch__flush_access_x86_64(struct maps *maps); @@ -61,6 +63,7 @@ void __libunwind_arch__finish_access_loongarch(struct map= s *maps); void __libunwind_arch__finish_access_mips(struct maps *maps); void __libunwind_arch__finish_access_ppc32(struct maps *maps); void __libunwind_arch__finish_access_ppc64(struct maps *maps); +void __libunwind_arch__finish_access_riscv(struct maps *maps); void __libunwind_arch__finish_access_s390(struct maps *maps); void __libunwind_arch__finish_access_i386(struct maps *maps); void __libunwind_arch__finish_access_x86_64(struct maps *maps); @@ -72,6 +75,7 @@ void *__libunwind_arch__create_addr_space_loongarch(void); void *__libunwind_arch__create_addr_space_mips(void); void *__libunwind_arch__create_addr_space_ppc32(void); void *__libunwind_arch__create_addr_space_ppc64(void); +void *__libunwind_arch__create_addr_space_riscv(void); void *__libunwind_arch__create_addr_space_s390(void); void *__libunwind_arch__create_addr_space_i386(void); void *__libunwind_arch__create_addr_space_x86_64(void); @@ -111,6 +115,11 @@ int __libunwind_arch__dwarf_search_unwind_table_ppc64(= void *as, uint64_t ip, void *pi, int need_unwind_info, void *arg); +int __libunwind_arch__dwarf_search_unwind_table_riscv(void *as, uint64_t i= p, + struct libarch_unwind__dyn_info *di, + void *pi, + int need_unwind_info, + void *arg); int __libunwind_arch__dwarf_search_unwind_table_s390(void *as, uint64_t ip, struct libarch_unwind__dyn_info *di, void *pi, @@ -176,6 +185,13 @@ int __libunwind_arch__dwarf_find_debug_frame_ppc64(int= found, const char *obj_name, uint64_t start, uint64_t end); +int __libunwind_arch__dwarf_find_debug_frame_riscv(int found, + struct libarch_unwind__dyn_info *di_debug, + uint64_t ip, + uint64_t segbase, + const char *obj_name, + uint64_t start, + uint64_t end); int __libunwind_arch__dwarf_find_debug_frame_s390(int found, struct libarch_unwind__dyn_info *di_debug, uint64_t ip, @@ -236,6 +252,11 @@ struct unwind_info *__libunwind_arch_unwind_info__new_= ppc64(struct thread *threa int max_stack, bool best_effort, uint64_t first_ip); +struct unwind_info *__libunwind_arch_unwind_info__new_riscv(struct thread = *thread, + struct perf_sample *sample, + int max_stack, + bool best_effort, + uint64_t first_ip); struct unwind_info *__libunwind_arch_unwind_info__new_s390(struct thread *= thread, struct perf_sample *sample, int max_stack, @@ -266,6 +287,7 @@ int __libunwind_arch__unwind_step_loongarch(struct unwi= nd_info *ui); int __libunwind_arch__unwind_step_mips(struct unwind_info *ui); int __libunwind_arch__unwind_step_ppc32(struct unwind_info *ui); int __libunwind_arch__unwind_step_ppc64(struct unwind_info *ui); +int __libunwind_arch__unwind_step_riscv(struct unwind_info *ui); int __libunwind_arch__unwind_step_s390(struct unwind_info *ui); int __libunwind_arch__unwind_step_i386(struct unwind_info *ui); int __libunwind_arch__unwind_step_x86_64(struct unwind_info *ui); diff --git a/tools/perf/util/libunwind-arch/libunwind-riscv.c b/tools/perf/= util/libunwind-arch/libunwind-riscv.c new file mode 100644 index 000000000000..a70a2ea96644 --- /dev/null +++ b/tools/perf/util/libunwind-arch/libunwind-riscv.c @@ -0,0 +1,297 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "libunwind-arch.h" +#include "../debug.h" +#include "../maps.h" +#include "../thread.h" +#include "../../../arch/riscv/include/uapi/asm/perf_regs.h" +#include +#include +#include +#include +#include + +#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT +#include +#endif + +int __get_perf_regnum_for_unw_regnum_riscv(int unw_regnum __maybe_unused) +{ +#ifndef HAVE_LIBUNWIND_RISCV_SUPPORT + return -EINVAL; +#else + switch (unw_regnum) { + case UNW_RISCV_X1 ... UNW_RISCV_X31: + return unw_regnum - UNW_RISCV_X1 + PERF_REG_RISCV_RA; + case UNW_RISCV_PC: + return PERF_REG_RISCV_PC; + default: + pr_err("unwind: invalid reg id %d\n", unw_regnum); + return -EINVAL; + } +#endif // HAVE_LIBUNWIND_RISCV_SUPPORT +} + +void __libunwind_arch__flush_access_riscv(struct maps *maps __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT + unw_flush_cache(maps__addr_space(maps), 0, 0); +#endif +} + +void __libunwind_arch__finish_access_riscv(struct maps *maps __maybe_unuse= d) +{ +#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT + unw_destroy_addr_space(maps__addr_space(maps)); +#endif +} + +#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT +static int find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_inf= o_t *pi, + int need_unwind_info, void *arg) +{ + return __libunwind__find_proc_info(as, ip, pi, need_unwind_info, arg, siz= eof(unw_word_t)); +} + +static void put_unwind_info(unw_addr_space_t __maybe_unused as, + unw_proc_info_t *pi __maybe_unused, + void *arg __maybe_unused) +{ + pr_debug("unwind: put_unwind_info called\n"); +} + +static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused *dil_addr, + void __maybe_unused *arg) +{ + return -UNW_ENOINFO; +} + +static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *va= lp, + int __write, void *arg) +{ + return __libunwind__access_mem(as, addr, valp, __write, arg, sizeof(unw_w= ord_t)); +} + +static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t= *valp, + int __write, void *arg) +{ + return __libunwind__access_reg(as, regnum, valp, __write, arg, sizeof(unw= _word_t)); +} + +static int access_fpreg(unw_addr_space_t __maybe_unused as, + unw_regnum_t __maybe_unused num, + unw_fpreg_t __maybe_unused *val, + int __maybe_unused __write, + void __maybe_unused *arg) +{ + pr_err("unwind: access_fpreg unsupported\n"); + return -UNW_EINVAL; +} + +static int resume(unw_addr_space_t __maybe_unused as, + unw_cursor_t __maybe_unused *cu, + void __maybe_unused *arg) +{ + pr_err("unwind: resume unsupported\n"); + return -UNW_EINVAL; +} + +static int get_proc_name(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused addr, + char __maybe_unused *bufp, size_t __maybe_unused buf_len, + unw_word_t __maybe_unused *offp, void __maybe_unused *arg) +{ + pr_err("unwind: get_proc_name unsupported\n"); + return -UNW_EINVAL; +} +#endif + +void *__libunwind_arch__create_addr_space_riscv(void) +{ +#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT + static unw_accessors_t accessors =3D { + .find_proc_info =3D find_proc_info, + .put_unwind_info =3D put_unwind_info, + .get_dyn_info_list_addr =3D get_dyn_info_list_addr, + .access_mem =3D access_mem, + .access_reg =3D access_reg, + .access_fpreg =3D access_fpreg, + .resume =3D resume, + .get_proc_name =3D get_proc_name, + }; + unw_addr_space_t addr_space; + + addr_space =3D unw_create_addr_space(&accessors, /*byte_order=3D*/0); + unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); + return addr_space; +#else + return NULL; +#endif +} + +#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT +extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) +#endif + +int __libunwind_arch__dwarf_search_unwind_table_riscv(void *as __maybe_unu= sed, + uint64_t ip __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + void *pi __maybe_unused, + int need_unwind_info __maybe_unused, + void *arg __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, = arg); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +#if defined(HAVE_LIBUNWIND_RISCV_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_F= RAME_RISCV) +extern int UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_= debug, + unw_word_t ip, + unw_word_t segbase, + const char *obj_name, unw_word_t start, + unw_word_t end); +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) +#endif + +int __libunwind_arch__dwarf_find_debug_frame_riscv(int found __maybe_unuse= d, + struct libarch_unwind__dyn_info *_di __maybe_unused, + uint64_t ip __maybe_unused, + uint64_t segbase __maybe_unused, + const char *obj_name __maybe_unused, + uint64_t start __maybe_unused, + uint64_t end __maybe_unused) +{ +#if defined(HAVE_LIBUNWIND_RISCV_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_F= RAME_RISCV) + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_find_debug_frame(found, &di, ip, segbase, obj_name, sta= rt, end); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +struct unwind_info *__libunwind_arch_unwind_info__new_riscv(struct thread = *thread __maybe_unused, + struct perf_sample *sample __maybe_unused, + int max_stack __maybe_unused, + bool best_effort __maybe_unused, + uint64_t first_ip __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT + struct arch_unwind_info { + struct unwind_info ui; + unw_cursor_t _cursor; + uint64_t _ips[]; + }; + + struct maps *maps =3D thread__maps(thread); + void *addr_space =3D maps__addr_space(maps); + struct arch_unwind_info *ui; + int ret; + + if (addr_space =3D=3D NULL) + return NULL; + + ui =3D zalloc(sizeof(*ui) + sizeof(ui->_ips[0]) * max_stack); + if (!ui) + return NULL; + + ui->ui.machine =3D maps__machine(maps); + ui->ui.thread =3D thread; + ui->ui.sample =3D sample; + ui->ui.cursor =3D &ui->_cursor; + ui->ui.ips =3D &ui->_ips[0]; + ui->ui.ips[0] =3D first_ip; + ui->ui.cur_ip =3D 1; + ui->ui.max_ips =3D max_stack; + ui->ui.unw_word_t_size =3D sizeof(unw_word_t); + ui->ui.e_machine =3D EM_RISCV; + ui->ui.best_effort =3D best_effort; + + ret =3D unw_init_remote(&ui->_cursor, addr_space, &ui->ui); + if (ret) { + if (!best_effort) + pr_err("libunwind: %s\n", unw_strerror(ret)); + free(ui); + return NULL; + } + + return &ui->ui; +#else + return NULL; +#endif +} + +int __libunwind_arch__unwind_step_riscv(struct unwind_info *ui __maybe_unu= sed) +{ +#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT + int ret; + + if (ui->cur_ip >=3D ui->max_ips) + return -1; + + ret =3D unw_step(ui->cursor); + if (ret > 0) { + uint64_t ip; + + unw_get_reg(ui->cursor, UNW_REG_IP, &ip); + + if (unw_is_signal_frame(ui->cursor) <=3D 0) { + /* + * Decrement the IP for any non-activation frames. This + * is required to properly find the srcline for caller + * frames. See also the documentation for + * dwfl_frame_pc(), which this code tries to replicate. + */ + --ip; + } + ui->ips[ui->cur_ip++] =3D ip; + } + return ret; +#else + return -EINVAL; +#endif +} --=20 2.53.0.473.g4a7958ca14-goog