Linux Perf Users
 help / color / mirror / Atom feed
* [RFC PATCH v3 0/3] perf: sparc64 user regs and stack dump, with arch hooks
@ 2026-09-23  9:04 Stian Halseth
  2026-09-23  9:04 ` [RFC PATCH v3 1/3] perf/core: Let an arch prepare and locate the user stack dump Stian Halseth
                   ` (4 more replies)
  0 siblings, 5 replies; 18+ messages in thread
From: Stian Halseth @ 2026-09-23  9:04 UTC (permalink / raw)
  To: Peter Zijlstra, Ingo Molnar, Andreas Larsson, David S. Miller
  Cc: Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
	James Clark, Jonathan Corbet, Shuah Khan, Randy Dunlap,
	Magnus Lindholm, linux-perf-users, sparclinux, linux-doc,
	linux-kernel, Stian Halseth

This adds HAVE_PERF_REGS and HAVE_PERF_USER_STACK_DUMP to sparc64, so
that perf record --call-graph dwarf and elfutils' eu-stackprof work
there.

Two things about the user stack dump do not fit in arch code. The
sampled register window's %l/%i registers, which hold the frame pointer
and return address the unwinder starts from, stay in the register file
until a window spills. The kernel already flushes them wherever it
exposes user stack memory (perf_callchain_user(), ptrace), but the stack
dump has no arch entry point where that could happen. And a 64-bit
sparc stack pointer is biased by 2047, so a dump that starts at the
register value begins 2047 bytes below the frame, and is empty when that
page has never been touched.

Patch 1 therefore adds two hooks in the style of perf_arch_misc_flags(),
both no-ops by default. Patch 2 is the sparc64 implementation and their
user. Patch 3 teaches tools/perf the sparc registers and DWARF unwinding
from the dump. The matching elfutils changes are attached to the
tracking issue:

  https://github.com/sparclinux/issues/issues/99

Tested on an UltraSPARC T4-1 on 7.3-rc4: register values check out
against known contents, --call-graph dwarf unwinds correctly for both
cycles and cpu-clock, as does eu-stackprof, and perf stat/record/record
-g are unchanged. Starting the dump at the stack's actual address
matters in practice: with the dump at the biased register value, 94% of
the user samples of xz -T4 had an empty stack dump; with this series,
none do.

Changes since v2:
- Patch 1: add perf_arch_user_stack_pointer(), so an arch can start the
  dump at the stack's actual address (sashiko review).
- Patch 2: drop %g0 from the uapi, as trap entry does not save it; the
  PC takes its slot, as on mips and loongarch (sashiko review).
- Patch 2: start the dump at %sp + 2047 for a 64-bit stack (sashiko
  review).
- Patch 3: follow both, and comment the max_dwarf_reg adjustment (Ian).
  Drop the memcpy() change to memory_read(), which the unbiased dump
  start makes unnecessary.

v2: https://lore.kernel.org/all/20260922201507.1719668-1-stian@itx.no/
v1: https://lore.kernel.org/all/20260922135653.1622301-1-stian@itx.no/

Stian Halseth (3):
  perf/core: Let an arch prepare and locate the user stack dump
  sparc64: Support PERF_SAMPLE_REGS_USER and PERF_SAMPLE_STACK_USER
  perf tools: Support sparc user register samples and dwarf unwinding

 .../features/perf/perf-regs/arch-support.txt  |  2 +-
 .../perf/perf-stackdump/arch-support.txt      |  2 +-
 arch/sparc/Kconfig                            |  2 +
 arch/sparc/include/asm/perf_event.h           |  5 ++
 arch/sparc/include/uapi/asm/perf_regs.h       | 34 +++++++++
 arch/sparc/kernel/Makefile                    |  2 +-
 arch/sparc/kernel/perf_regs.c                 | 74 +++++++++++++++++++
 include/linux/perf_event.h                    | 11 +++
 kernel/events/core.c                          |  2 +
 kernel/events/internal.h                      |  2 +-
 tools/arch/sparc/include/uapi/asm/perf_regs.h | 34 +++++++++
 tools/perf/arch/sparc/include/perf_regs.h     | 18 +++++
 tools/perf/check-headers.sh                   |  1 +
 tools/perf/util/dwarf-regs-arch/Build         |  1 +
 .../util/dwarf-regs-arch/dwarf-regs-sparc.c   | 12 +++
 tools/perf/util/dwarf-regs.c                  |  4 +
 tools/perf/util/include/dwarf-regs.h          |  1 +
 tools/perf/util/perf-regs-arch/Build          |  1 +
 .../util/perf-regs-arch/perf_regs_sparc.c     | 67 +++++++++++++++++
 tools/perf/util/perf_regs.c                   | 18 +++++
 tools/perf/util/perf_regs.h                   |  5 ++
 tools/perf/util/unwind-libdw.c                | 37 ++++++++++
 22 files changed, 331 insertions(+), 4 deletions(-)
 create mode 100644 arch/sparc/include/uapi/asm/perf_regs.h
 create mode 100644 arch/sparc/kernel/perf_regs.c
 create mode 100644 tools/arch/sparc/include/uapi/asm/perf_regs.h
 create mode 100644 tools/perf/arch/sparc/include/perf_regs.h
 create mode 100644 tools/perf/util/dwarf-regs-arch/dwarf-regs-sparc.c
 create mode 100644 tools/perf/util/perf-regs-arch/perf_regs_sparc.c

-- 
2.55.0


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [RFC PATCH v3 1/3] perf/core: Let an arch prepare and locate the user stack dump
  2026-09-23  9:04 [RFC PATCH v3 0/3] perf: sparc64 user regs and stack dump, with arch hooks Stian Halseth
@ 2026-09-23  9:04 ` Stian Halseth
  2026-09-23  9:16   ` sashiko-bot
  2026-09-23  9:04 ` [RFC PATCH v3 2/3] sparc64: Support PERF_SAMPLE_REGS_USER and PERF_SAMPLE_STACK_USER Stian Halseth
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 18+ messages in thread
From: Stian Halseth @ 2026-09-23  9:04 UTC (permalink / raw)
  To: Peter Zijlstra, Ingo Molnar, Andreas Larsson, David S. Miller
  Cc: Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
	James Clark, Jonathan Corbet, Shuah Khan, Randy Dunlap,
	Magnus Lindholm, linux-perf-users, sparclinux, linux-doc,
	linux-kernel, Stian Halseth

PERF_SAMPLE_STACK_USER copies the user stack as it is in memory,
starting at the user stack pointer. Two things about sparc64 do not
fit that.

The sampled window's %l and %i registers, including the frame pointer
and return address an unwinder starts from, may still be in the
register file: they only reach the stack when a window spills.
perf_callchain_user() already handles this for the callchain by calling
flushw_user() first; the user stack dump has no equivalent arch entry
point.

And a 64-bit stack pointer is biased by 2047: the stack starts at
%sp + 2047. Starting the dump at the register value spends a quarter of
an 8K dump on memory below the frame, and gives no dump at all when that
page has never been touched, as for a leaf frame at the deepest point a
thread's stack has reached.

Add two hooks in the style of perf_arch_misc_flags():
perf_arch_prepare_ustack(), a no-op by default, called from
perf_prepare_sample() before the dump size is computed, and
perf_arch_user_stack_pointer(), user_stack_pointer() by default, the
address the dump starts at. Flushing in the arch PMU interrupt handler
instead would not do: software events such as cpu-clock reach
perf_event_overflow() without passing through it.

Signed-off-by: Stian Halseth <stian@itx.no>
---
 include/linux/perf_event.h | 11 +++++++++++
 kernel/events/core.c       |  2 ++
 kernel/events/internal.h   |  2 +-
 3 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 5842552294c1..49aa22db43c0 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -1815,6 +1815,17 @@ extern unsigned long perf_instruction_pointer(struct perf_event *event,
 #ifndef perf_arch_bpf_user_pt_regs
 # define perf_arch_bpf_user_pt_regs(regs) regs
 #endif
+/*
+ * Called before the user stack of the current task is dumped, for an arch
+ * that still holds part of the user's stack state in registers.
+ */
+#ifndef perf_arch_prepare_ustack
+static inline void perf_arch_prepare_ustack(void) { }
+#endif
+/* Where the user stack dump starts, for an arch with a biased stack pointer. */
+#ifndef perf_arch_user_stack_pointer
+# define perf_arch_user_stack_pointer(regs)	user_stack_pointer(regs)
+#endif
 
 #ifndef perf_arch_guest_misc_flags
 static inline unsigned long perf_arch_guest_misc_flags(struct pt_regs *regs)
diff --git a/kernel/events/core.c b/kernel/events/core.c
index db7b76d6b68a..90fb35c7d279 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -8718,6 +8718,8 @@ void perf_prepare_sample(struct perf_sample_data *data,
 		u16 header_size = perf_sample_data_size(data, event);
 		u16 size = sizeof(u64);
 
+		if (data->regs_user.regs)
+			perf_arch_prepare_ustack();
 		stack_size = perf_sample_ustack_size(stack_size, header_size,
 						     data->regs_user.regs);
 
diff --git a/kernel/events/internal.h b/kernel/events/internal.h
index c03c4f2eea57..01b5f53d01d7 100644
--- a/kernel/events/internal.h
+++ b/kernel/events/internal.h
@@ -236,7 +236,7 @@ static inline bool arch_perf_have_user_stack_dump(void)
 	return true;
 }
 
-#define perf_user_stack_pointer(regs) user_stack_pointer(regs)
+#define perf_user_stack_pointer(regs) perf_arch_user_stack_pointer(regs)
 #else
 static inline bool arch_perf_have_user_stack_dump(void)
 {
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [RFC PATCH v3 2/3] sparc64: Support PERF_SAMPLE_REGS_USER and PERF_SAMPLE_STACK_USER
  2026-09-23  9:04 [RFC PATCH v3 0/3] perf: sparc64 user regs and stack dump, with arch hooks Stian Halseth
  2026-09-23  9:04 ` [RFC PATCH v3 1/3] perf/core: Let an arch prepare and locate the user stack dump Stian Halseth
@ 2026-09-23  9:04 ` Stian Halseth
  2026-09-23  9:14   ` sashiko-bot
  2026-09-23  9:04 ` [RFC PATCH v3 3/3] perf tools: Support sparc user register samples and dwarf unwinding Stian Halseth
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 18+ messages in thread
From: Stian Halseth @ 2026-09-23  9:04 UTC (permalink / raw)
  To: Peter Zijlstra, Ingo Molnar, Andreas Larsson, David S. Miller
  Cc: Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
	James Clark, Jonathan Corbet, Shuah Khan, Randy Dunlap,
	Magnus Lindholm, linux-perf-users, sparclinux, linux-doc,
	linux-kernel, Stian Halseth

Select HAVE_PERF_REGS and HAVE_PERF_USER_STACK_DUMP and add the
perf_regs implementation. The exposed registers mirror struct pt_regs:
%g1-%g7, %o0-%o7 (named from the user's point of view; pt_regs calls
them UREG_I*), %tstate, NPC and %y, with the PC in the slot of %g0, as
mips and loongarch do for their hardwired-zero register. Trap entry
does not save %g0, so its pt_regs slot holds stale stack contents for
a trap taken in the kernel and must not be exposed.

%o6 is reported as held in the register, i.e. with the 2047 stack bias
for a 64-bit stack, the same as ptrace and user_stack_pointer(). The
stack dump starts at the stack's actual address instead, %o6 + 2047
when test_thread_64bit_stack() says so, so that it begins at the
sampled frame; the uapi header documents this for consumers.

User-mode values of a 32-bit task are truncated to 32 bits as
genregs32_get() does, since the hardware does not zero-extend them.
Kernel-mode registers, as seen by PERF_SAMPLE_REGS_INTR, are left
alone.

perf_arch_prepare_ustack() flushes the user register windows so the
sampled window's %l and %i registers are in the dumped stack, where a
DWARF unwinder needs them: the CFI of a function after `save` defines
the CFA in terms of %i6.

This makes perf record --call-graph dwarf and eu-stackprof usable on
sparc64.

Signed-off-by: Stian Halseth <stian@itx.no>
---
 .../features/perf/perf-regs/arch-support.txt  |  2 +-
 .../perf/perf-stackdump/arch-support.txt      |  2 +-
 arch/sparc/Kconfig                            |  2 +
 arch/sparc/include/asm/perf_event.h           |  5 ++
 arch/sparc/include/uapi/asm/perf_regs.h       | 34 +++++++++
 arch/sparc/kernel/Makefile                    |  2 +-
 arch/sparc/kernel/perf_regs.c                 | 74 +++++++++++++++++++
 7 files changed, 118 insertions(+), 3 deletions(-)
 create mode 100644 arch/sparc/include/uapi/asm/perf_regs.h
 create mode 100644 arch/sparc/kernel/perf_regs.c

diff --git a/Documentation/features/perf/perf-regs/arch-support.txt b/Documentation/features/perf/perf-regs/arch-support.txt
index 4c9a5a012075..41ab622efa15 100644
--- a/Documentation/features/perf/perf-regs/arch-support.txt
+++ b/Documentation/features/perf/perf-regs/arch-support.txt
@@ -23,7 +23,7 @@
     |       riscv: |  ok  |
     |        s390: |  ok  |
     |          sh: | TODO |
-    |       sparc: | TODO |
+    |       sparc: |  ok  |
     |          um: | TODO |
     |         x86: |  ok  |
     |      xtensa: | TODO |
diff --git a/Documentation/features/perf/perf-stackdump/arch-support.txt b/Documentation/features/perf/perf-stackdump/arch-support.txt
index dd362b5cb638..cafa6fae7704 100644
--- a/Documentation/features/perf/perf-stackdump/arch-support.txt
+++ b/Documentation/features/perf/perf-stackdump/arch-support.txt
@@ -23,7 +23,7 @@
     |       riscv: |  ok  |
     |        s390: |  ok  |
     |          sh: | TODO |
-    |       sparc: | TODO |
+    |       sparc: |  ok  |
     |          um: | TODO |
     |         x86: |  ok  |
     |      xtensa: | TODO |
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index ab77d3f2536e..9d7f575f359d 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -93,6 +93,8 @@ config SPARC64
 	select RTC_DRV_SUN4V
 	select RTC_DRV_STARFIRE
 	select HAVE_PERF_EVENTS
+	select HAVE_PERF_REGS
+	select HAVE_PERF_USER_STACK_DUMP
 	select PERF_USE_VMALLOC
 	select ARCH_HAVE_NMI_SAFE_CMPXCHG
 	select HAVE_C_RECORDMCOUNT
diff --git a/arch/sparc/include/asm/perf_event.h b/arch/sparc/include/asm/perf_event.h
index c2aec0c7f4f5..3e70c23e7714 100644
--- a/arch/sparc/include/asm/perf_event.h
+++ b/arch/sparc/include/asm/perf_event.h
@@ -25,6 +25,11 @@ do {							\
 	(regs)->u_regs[UREG_I6] = _fp;			\
 	(regs)->u_regs[UREG_I7] = _i7;			\
 } while (0)
+
+void perf_arch_prepare_ustack(void);
+#define perf_arch_prepare_ustack	perf_arch_prepare_ustack
+unsigned long perf_arch_user_stack_pointer(struct pt_regs *regs);
+#define perf_arch_user_stack_pointer	perf_arch_user_stack_pointer
 #endif
 
 #endif
diff --git a/arch/sparc/include/uapi/asm/perf_regs.h b/arch/sparc/include/uapi/asm/perf_regs.h
new file mode 100644
index 000000000000..0621ffbdafce
--- /dev/null
+++ b/arch/sparc/include/uapi/asm/perf_regs.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_ASM_SPARC_PERF_REGS_H
+#define _UAPI_ASM_SPARC_PERF_REGS_H
+
+/*
+ * Mirrors struct pt_regs, with the PC in the slot of the hardwired-zero
+ * %g0.  O6 is %sp as held in the register: for a 64-bit stack (odd O6)
+ * it is biased by 2047, and the PERF_SAMPLE_STACK_USER dump starts at
+ * O6 + 2047.
+ */
+enum perf_event_sparc_regs {
+	PERF_REG_SPARC_PC,
+	PERF_REG_SPARC_G1,
+	PERF_REG_SPARC_G2,
+	PERF_REG_SPARC_G3,
+	PERF_REG_SPARC_G4,
+	PERF_REG_SPARC_G5,
+	PERF_REG_SPARC_G6,
+	PERF_REG_SPARC_G7,
+	PERF_REG_SPARC_O0,
+	PERF_REG_SPARC_O1,
+	PERF_REG_SPARC_O2,
+	PERF_REG_SPARC_O3,
+	PERF_REG_SPARC_O4,
+	PERF_REG_SPARC_O5,
+	PERF_REG_SPARC_O6,
+	PERF_REG_SPARC_O7,
+	PERF_REG_SPARC_TSTATE,
+	PERF_REG_SPARC_NPC,
+	PERF_REG_SPARC_Y,
+	PERF_REG_SPARC_MAX
+};
+
+#endif /* _UAPI_ASM_SPARC_PERF_REGS_H */
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index 497b5714fa8f..a3dd92247c3b 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -113,7 +113,7 @@ obj-$(CONFIG_AUDIT)     += audit.o
 audit--$(CONFIG_AUDIT)  := compat_audit.o
 obj-$(CONFIG_COMPAT)    += $(audit--y)
 
-pc--$(CONFIG_PERF_EVENTS) := perf_event.o
+pc--$(CONFIG_PERF_EVENTS) := perf_event.o perf_regs.o
 obj-$(CONFIG_SPARC64)	+= $(pc--y)
 
 obj-$(CONFIG_UPROBES)	+= uprobes.o
diff --git a/arch/sparc/kernel/perf_regs.c b/arch/sparc/kernel/perf_regs.c
new file mode 100644
index 000000000000..8bcc3421ec19
--- /dev/null
+++ b/arch/sparc/kernel/perf_regs.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/perf_event.h>
+#include <linux/perf_regs.h>
+#include <linux/sched/task_stack.h>
+#include <asm/cacheflush.h>
+#include <asm/ptrace.h>
+
+u64 perf_reg_value(struct pt_regs *regs, int idx)
+{
+	u64 val;
+
+	switch (idx) {
+	case PERF_REG_SPARC_PC:
+		val = regs->tpc;
+		break;
+	case PERF_REG_SPARC_G1 ... PERF_REG_SPARC_O7:
+		val = regs->u_regs[idx];
+		break;
+	case PERF_REG_SPARC_TSTATE:
+		return regs->tstate;
+	case PERF_REG_SPARC_NPC:
+		val = regs->tnpc;
+		break;
+	case PERF_REG_SPARC_Y:
+		return regs->y;
+	default:
+		WARN_ON_ONCE(1);
+		return 0;
+	}
+
+	if (user_mode(regs) && test_thread_flag(TIF_32BIT))
+		val = (u32)val;
+
+	return val;
+}
+
+#define REG_RESERVED (~((1ULL << PERF_REG_SPARC_MAX) - 1))
+
+int perf_reg_validate(u64 mask)
+{
+	if (!mask || mask & REG_RESERVED)
+		return -EINVAL;
+
+	return 0;
+}
+
+u64 perf_reg_abi(struct task_struct *task)
+{
+	if (test_tsk_thread_flag(task, TIF_32BIT))
+		return PERF_SAMPLE_REGS_ABI_32;
+
+	return PERF_SAMPLE_REGS_ABI_64;
+}
+
+void perf_get_regs_user(struct perf_regs *regs_user,
+			struct pt_regs *regs)
+{
+	regs_user->regs = task_pt_regs(current);
+	regs_user->abi = perf_reg_abi(current);
+}
+
+void perf_arch_prepare_ustack(void)
+{
+	flushw_user();
+}
+
+unsigned long perf_arch_user_stack_pointer(struct pt_regs *regs)
+{
+	unsigned long sp = user_stack_pointer(regs);
+
+	if (test_thread_64bit_stack(sp))
+		sp += STACK_BIAS;
+	return sp;
+}
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [RFC PATCH v3 3/3] perf tools: Support sparc user register samples and dwarf unwinding
  2026-09-23  9:04 [RFC PATCH v3 0/3] perf: sparc64 user regs and stack dump, with arch hooks Stian Halseth
  2026-09-23  9:04 ` [RFC PATCH v3 1/3] perf/core: Let an arch prepare and locate the user stack dump Stian Halseth
  2026-09-23  9:04 ` [RFC PATCH v3 2/3] sparc64: Support PERF_SAMPLE_REGS_USER and PERF_SAMPLE_STACK_USER Stian Halseth
@ 2026-09-23  9:04 ` Stian Halseth
  2026-09-23  9:14   ` sashiko-bot
  2026-09-23 20:38 ` [RFC PATCH v3 0/3] perf: sparc64 user regs and stack dump, with arch hooks Ian Rogers
  2026-09-23 23:10 ` Magnus Lindholm
  4 siblings, 1 reply; 18+ messages in thread
From: Stian Halseth @ 2026-09-23  9:04 UTC (permalink / raw)
  To: Peter Zijlstra, Ingo Molnar, Andreas Larsson, David S. Miller
  Cc: Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
	James Clark, Jonathan Corbet, Shuah Khan, Randy Dunlap,
	Magnus Lindholm, linux-perf-users, sparclinux, linux-doc,
	linux-kernel, Stian Halseth

Add the sparc perf_regs tables and the EM_SPARC/EM_SPARCV9 dispatch for
register names, masks, ip/sp and the perf-to-DWARF register mapping,
plus the uapi header copy.

For libdw unwinding, seed DWARF registers 16-31 (%l0-%l7, %i0-%i7) from
the register save area at the start of the stack dump: the kernel
flushes the sampled window there, and the CFI after `save` needs %i6
and %i7 to find the first caller. The dump of a 64-bit sparc stack
starts at %sp + 2047, so memory_read() takes its base from there.

Signed-off-by: Stian Halseth <stian@itx.no>
---
 tools/arch/sparc/include/uapi/asm/perf_regs.h | 34 ++++++++++
 tools/perf/arch/sparc/include/perf_regs.h     | 18 +++++
 tools/perf/check-headers.sh                   |  1 +
 tools/perf/util/dwarf-regs-arch/Build         |  1 +
 .../util/dwarf-regs-arch/dwarf-regs-sparc.c   | 12 ++++
 tools/perf/util/dwarf-regs.c                  |  4 ++
 tools/perf/util/include/dwarf-regs.h          |  1 +
 tools/perf/util/perf-regs-arch/Build          |  1 +
 .../util/perf-regs-arch/perf_regs_sparc.c     | 67 +++++++++++++++++++
 tools/perf/util/perf_regs.c                   | 18 +++++
 tools/perf/util/perf_regs.h                   |  5 ++
 tools/perf/util/unwind-libdw.c                | 37 ++++++++++
 12 files changed, 199 insertions(+)
 create mode 100644 tools/arch/sparc/include/uapi/asm/perf_regs.h
 create mode 100644 tools/perf/arch/sparc/include/perf_regs.h
 create mode 100644 tools/perf/util/dwarf-regs-arch/dwarf-regs-sparc.c
 create mode 100644 tools/perf/util/perf-regs-arch/perf_regs_sparc.c

diff --git a/tools/arch/sparc/include/uapi/asm/perf_regs.h b/tools/arch/sparc/include/uapi/asm/perf_regs.h
new file mode 100644
index 000000000000..0621ffbdafce
--- /dev/null
+++ b/tools/arch/sparc/include/uapi/asm/perf_regs.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_ASM_SPARC_PERF_REGS_H
+#define _UAPI_ASM_SPARC_PERF_REGS_H
+
+/*
+ * Mirrors struct pt_regs, with the PC in the slot of the hardwired-zero
+ * %g0.  O6 is %sp as held in the register: for a 64-bit stack (odd O6)
+ * it is biased by 2047, and the PERF_SAMPLE_STACK_USER dump starts at
+ * O6 + 2047.
+ */
+enum perf_event_sparc_regs {
+	PERF_REG_SPARC_PC,
+	PERF_REG_SPARC_G1,
+	PERF_REG_SPARC_G2,
+	PERF_REG_SPARC_G3,
+	PERF_REG_SPARC_G4,
+	PERF_REG_SPARC_G5,
+	PERF_REG_SPARC_G6,
+	PERF_REG_SPARC_G7,
+	PERF_REG_SPARC_O0,
+	PERF_REG_SPARC_O1,
+	PERF_REG_SPARC_O2,
+	PERF_REG_SPARC_O3,
+	PERF_REG_SPARC_O4,
+	PERF_REG_SPARC_O5,
+	PERF_REG_SPARC_O6,
+	PERF_REG_SPARC_O7,
+	PERF_REG_SPARC_TSTATE,
+	PERF_REG_SPARC_NPC,
+	PERF_REG_SPARC_Y,
+	PERF_REG_SPARC_MAX
+};
+
+#endif /* _UAPI_ASM_SPARC_PERF_REGS_H */
diff --git a/tools/perf/arch/sparc/include/perf_regs.h b/tools/perf/arch/sparc/include/perf_regs.h
new file mode 100644
index 000000000000..493fbff9ea16
--- /dev/null
+++ b/tools/perf/arch/sparc/include/perf_regs.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef ARCH_PERF_REGS_H
+#define ARCH_PERF_REGS_H
+
+#include <stdlib.h>
+#include <linux/types.h>
+#include "../../../../arch/sparc/include/uapi/asm/perf_regs.h"
+
+#define PERF_REGS_MASK	((1ULL << PERF_REG_SPARC_MAX) - 1)
+#define PERF_REGS_MAX	PERF_REG_SPARC_MAX
+
+#ifdef __arch64__
+#define PERF_SAMPLE_REGS_ABI	PERF_SAMPLE_REGS_ABI_64
+#else
+#define PERF_SAMPLE_REGS_ABI	PERF_SAMPLE_REGS_ABI_32
+#endif
+
+#endif /* ARCH_PERF_REGS_H */
diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh
index 531c0e0e84df..f144590f5082 100755
--- a/tools/perf/check-headers.sh
+++ b/tools/perf/check-headers.sh
@@ -42,6 +42,7 @@ declare -a FILES=(
   "arch/mips/include/uapi/asm/perf_regs.h"
   "arch/powerpc/include/uapi/asm/perf_regs.h"
   "arch/s390/include/uapi/asm/perf_regs.h"
+  "arch/sparc/include/uapi/asm/perf_regs.h"
   "arch/x86/include/uapi/asm/perf_regs.h"
   "arch/x86/include/uapi/asm/kvm.h"
   "arch/x86/include/uapi/asm/svm.h"
diff --git a/tools/perf/util/dwarf-regs-arch/Build b/tools/perf/util/dwarf-regs-arch/Build
index ceb68ae86fd8..bda944029046 100644
--- a/tools/perf/util/dwarf-regs-arch/Build
+++ b/tools/perf/util/dwarf-regs-arch/Build
@@ -6,4 +6,5 @@ perf-util-$(CONFIG_LIBDW) += dwarf-regs-mips.o
 perf-util-$(CONFIG_LIBDW) += dwarf-regs-powerpc.o
 perf-util-$(CONFIG_LIBDW) += dwarf-regs-riscv.o
 perf-util-$(CONFIG_LIBDW) += dwarf-regs-s390.o
+perf-util-$(CONFIG_LIBDW) += dwarf-regs-sparc.o
 perf-util-$(CONFIG_LIBDW) += dwarf-regs-x86.o
diff --git a/tools/perf/util/dwarf-regs-arch/dwarf-regs-sparc.c b/tools/perf/util/dwarf-regs-arch/dwarf-regs-sparc.c
new file mode 100644
index 000000000000..a5af1e1d8b8b
--- /dev/null
+++ b/tools/perf/util/dwarf-regs-arch/dwarf-regs-sparc.c
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <errno.h>
+#include <dwarf-regs.h>
+#include "../../../arch/sparc/include/uapi/asm/perf_regs.h"
+
+int __get_dwarf_regnum_for_perf_regnum_sparc(int perf_regnum)
+{
+	if (perf_regnum < PERF_REG_SPARC_G1 || perf_regnum > PERF_REG_SPARC_O7)
+		return -ENOENT;
+
+	return perf_regnum;
+}
diff --git a/tools/perf/util/dwarf-regs.c b/tools/perf/util/dwarf-regs.c
index 797f455eba0d..df9200c31aaa 100644
--- a/tools/perf/util/dwarf-regs.c
+++ b/tools/perf/util/dwarf-regs.c
@@ -217,6 +217,10 @@ int get_dwarf_regnum_for_perf_regnum(int perf_regnum, unsigned int machine,
 	case EM_S390:
 		reg = __get_dwarf_regnum_for_perf_regnum_s390(perf_regnum);
 		break;
+	case EM_SPARC:
+	case EM_SPARCV9:
+		reg = __get_dwarf_regnum_for_perf_regnum_sparc(perf_regnum);
+		break;
 	case EM_LOONGARCH:
 		reg = __get_dwarf_regnum_for_perf_regnum_loongarch(perf_regnum);
 		break;
diff --git a/tools/perf/util/include/dwarf-regs.h b/tools/perf/util/include/dwarf-regs.h
index 46a764cf322f..4a02f30c5604 100644
--- a/tools/perf/util/include/dwarf-regs.h
+++ b/tools/perf/util/include/dwarf-regs.h
@@ -113,6 +113,7 @@ int __get_dwarf_regnum_for_perf_regnum_loongarch(int perf_regnum);
 int __get_dwarf_regnum_for_perf_regnum_powerpc(int perf_regnum);
 int __get_dwarf_regnum_for_perf_regnum_riscv(int perf_regnum);
 int __get_dwarf_regnum_for_perf_regnum_s390(int perf_regnum);
+int __get_dwarf_regnum_for_perf_regnum_sparc(int perf_regnum);
 int __get_dwarf_regnum_for_perf_regnum_mips(int perf_regnum);
 
 /*
diff --git a/tools/perf/util/perf-regs-arch/Build b/tools/perf/util/perf-regs-arch/Build
index be95402aa540..47220a2f2dae 100644
--- a/tools/perf/util/perf-regs-arch/Build
+++ b/tools/perf/util/perf-regs-arch/Build
@@ -6,4 +6,5 @@ perf-util-y += perf_regs_mips.o
 perf-util-y += perf_regs_powerpc.o
 perf-util-y += perf_regs_riscv.o
 perf-util-y += perf_regs_s390.o
+perf-util-y += perf_regs_sparc.o
 perf-util-y += perf_regs_x86.o
diff --git a/tools/perf/util/perf-regs-arch/perf_regs_sparc.c b/tools/perf/util/perf-regs-arch/perf_regs_sparc.c
new file mode 100644
index 000000000000..9ee8e496ab8c
--- /dev/null
+++ b/tools/perf/util/perf-regs-arch/perf_regs_sparc.c
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "../perf_regs.h"
+#include "../../arch/sparc/include/perf_regs.h"
+
+uint64_t __perf_reg_mask_sparc(bool intr __maybe_unused)
+{
+	return PERF_REGS_MASK;
+}
+
+const char *__perf_reg_name_sparc(int id)
+{
+	switch (id) {
+	case PERF_REG_SPARC_PC:
+		return "pc";
+	case PERF_REG_SPARC_G1:
+		return "g1";
+	case PERF_REG_SPARC_G2:
+		return "g2";
+	case PERF_REG_SPARC_G3:
+		return "g3";
+	case PERF_REG_SPARC_G4:
+		return "g4";
+	case PERF_REG_SPARC_G5:
+		return "g5";
+	case PERF_REG_SPARC_G6:
+		return "g6";
+	case PERF_REG_SPARC_G7:
+		return "g7";
+	case PERF_REG_SPARC_O0:
+		return "o0";
+	case PERF_REG_SPARC_O1:
+		return "o1";
+	case PERF_REG_SPARC_O2:
+		return "o2";
+	case PERF_REG_SPARC_O3:
+		return "o3";
+	case PERF_REG_SPARC_O4:
+		return "o4";
+	case PERF_REG_SPARC_O5:
+		return "o5";
+	case PERF_REG_SPARC_O6:
+		return "sp";
+	case PERF_REG_SPARC_O7:
+		return "o7";
+	case PERF_REG_SPARC_TSTATE:
+		return "tstate";
+	case PERF_REG_SPARC_NPC:
+		return "npc";
+	case PERF_REG_SPARC_Y:
+		return "y";
+	default:
+		return NULL;
+	}
+
+	return NULL;
+}
+
+uint64_t __perf_reg_ip_sparc(void)
+{
+	return PERF_REG_SPARC_PC;
+}
+
+uint64_t __perf_reg_sp_sparc(void)
+{
+	return PERF_REG_SPARC_O6;
+}
diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c
index 558c143abbab..5880b54fd7dc 100644
--- a/tools/perf/util/perf_regs.c
+++ b/tools/perf/util/perf_regs.c
@@ -68,6 +68,10 @@ uint64_t perf_intr_reg_mask(uint16_t e_machine)
 	case EM_S390:
 		mask = __perf_reg_mask_s390(/*intr=*/true);
 		break;
+	case EM_SPARC:
+	case EM_SPARCV9:
+		mask = __perf_reg_mask_sparc(/*intr=*/true);
+		break;
 	case EM_386:
 	case EM_X86_64:
 		mask = __perf_reg_mask_x86(/*intr=*/true);
@@ -111,6 +115,10 @@ uint64_t perf_user_reg_mask(uint16_t e_machine)
 	case EM_S390:
 		mask = __perf_reg_mask_s390(/*intr=*/false);
 		break;
+	case EM_SPARC:
+	case EM_SPARCV9:
+		mask = __perf_reg_mask_sparc(/*intr=*/false);
+		break;
 	case EM_386:
 	case EM_X86_64:
 		mask = __perf_reg_mask_x86(/*intr=*/false);
@@ -154,6 +162,10 @@ const char *perf_reg_name(int id, uint16_t e_machine, uint32_t e_flags)
 	case EM_S390:
 		reg_name = __perf_reg_name_s390(id);
 		break;
+	case EM_SPARC:
+	case EM_SPARCV9:
+		reg_name = __perf_reg_name_sparc(id);
+		break;
 	case EM_386:
 	case EM_X86_64:
 		reg_name = __perf_reg_name_x86(id);
@@ -215,6 +227,9 @@ uint64_t perf_arch_reg_ip(uint16_t e_machine)
 		return __perf_reg_ip_riscv();
 	case EM_S390:
 		return __perf_reg_ip_s390();
+	case EM_SPARC:
+	case EM_SPARCV9:
+		return __perf_reg_ip_sparc();
 	case EM_386:
 	case EM_X86_64:
 		return __perf_reg_ip_x86();
@@ -244,6 +259,9 @@ uint64_t perf_arch_reg_sp(uint16_t e_machine)
 		return __perf_reg_sp_riscv();
 	case EM_S390:
 		return __perf_reg_sp_s390();
+	case EM_SPARC:
+	case EM_SPARCV9:
+		return __perf_reg_sp_sparc();
 	case EM_386:
 	case EM_X86_64:
 		return __perf_reg_sp_x86();
diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h
index 79be2b791509..3f453d910aa4 100644
--- a/tools/perf/util/perf_regs.h
+++ b/tools/perf/util/perf_regs.h
@@ -65,6 +65,11 @@ uint64_t __perf_reg_ip_s390(void);
 uint64_t __perf_reg_sp_s390(void);
 int __perf_sdt_arg_parse_op_s390(char *old_op, char **new_op);
 
+uint64_t __perf_reg_mask_sparc(bool intr);
+const char *__perf_reg_name_sparc(int id);
+uint64_t __perf_reg_ip_sparc(void);
+uint64_t __perf_reg_sp_sparc(void);
+
 int __perf_sdt_arg_parse_op_x86(char *old_op, char **new_op);
 uint64_t __perf_reg_mask_x86(bool intr);
 const char *__perf_reg_name_x86(int id);
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 63a5c2253174..d2adf7f2d8bb 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -4,7 +4,9 @@
 #include <elfutils/libdw.h>
 #include <elfutils/libdwfl.h>
 #include <inttypes.h>
+#include <elf.h>
 #include <errno.h>
+#include <string.h>
 #include "debug.h"
 #include "dso.h"
 #include <dwarf-regs.h>
@@ -225,6 +227,14 @@ static int access_dso_mem(struct unwind_info *ui, Dwarf_Addr addr,
 	return -1;
 }
 
+/* A 64-bit sparc stack (odd %sp) is biased; its dump starts past the bias. */
+static u64 stack_dump_start(uint16_t e_machine, u64 sp)
+{
+	if ((e_machine == EM_SPARC || e_machine == EM_SPARCV9) && (sp & 1))
+		return sp + 2047;
+	return sp;
+}
+
 static bool memory_read(Dwfl *dwfl __maybe_unused, Dwarf_Addr addr, Dwarf_Word *result,
 			void *arg)
 {
@@ -243,6 +253,7 @@ static bool memory_read(Dwfl *dwfl __maybe_unused, Dwarf_Addr addr, Dwarf_Word *
 	if (ret)
 		return false;
 
+	start = stack_dump_start(ui->e_machine, start);
 	end = start + stack->size;
 
 	/* Check overflow. */
@@ -267,6 +278,26 @@ static bool memory_read(Dwfl *dwfl __maybe_unused, Dwarf_Addr addr, Dwarf_Word *
 	return true;
 }
 
+/*
+ * The sampled window's %l and %i registers (DWARF 16-31) are not in the
+ * sample; the kernel flushed them to the register save area at the start
+ * of the dumped stack.
+ */
+static void libdw_set_sparc_window_registers(struct unwind_info *ui,
+					     struct regs_dump *user_regs,
+					     Dwarf_Word *dwarf_regs)
+{
+	struct stack_dump *stack = &ui->sample->user_stack;
+	u64 sp;
+
+	if (perf_reg_value(&sp, user_regs, perf_arch_reg_sp(ui->e_machine)))
+		return;
+	if (!(sp & 1) || 16 * sizeof(u64) > stack->size)
+		return;
+
+	memcpy(&dwarf_regs[16], stack->data, 16 * sizeof(u64));
+}
+
 static bool libdw_set_initial_registers(Dwfl_Thread *thread, void *arg)
 {
 	struct dwfl_ui_thread_info *dwfl_ui_ti = arg;
@@ -276,6 +307,7 @@ static bool libdw_set_initial_registers(Dwfl_Thread *thread, void *arg)
 	int max_dwarf_reg = 0;
 	bool ret;
 	uint16_t e_machine = ui->e_machine;
+	bool is_sparc = e_machine == EM_SPARC || e_machine == EM_SPARCV9;
 	int e_flags = ui->e_flags;
 	uint64_t ip_perf_reg = perf_arch_reg_ip(e_machine);
 	Dwarf_Word val = 0;
@@ -295,6 +327,9 @@ static bool libdw_set_initial_registers(Dwfl_Thread *thread, void *arg)
 				max_dwarf_reg = dwarf_reg;
 		}
 	}
+	/* libdw_set_sparc_window_registers() fills DWARF 16-31. */
+	if (is_sparc && max_dwarf_reg < 31)
+		max_dwarf_reg = 31;
 
 	dwarf_regs = calloc(max_dwarf_reg + 1, sizeof(*dwarf_regs));
 	if (!dwarf_regs)
@@ -313,6 +348,8 @@ static bool libdw_set_initial_registers(Dwfl_Thread *thread, void *arg)
 			}
 		}
 	}
+	if (is_sparc)
+		libdw_set_sparc_window_registers(ui, user_regs, dwarf_regs);
 	if (perf_reg_value(&val, user_regs, ip_perf_reg) == 0)
 		dwfl_thread_state_register_pc(thread, val);
 
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [RFC PATCH v3 2/3] sparc64: Support PERF_SAMPLE_REGS_USER and PERF_SAMPLE_STACK_USER
  2026-09-23  9:04 ` [RFC PATCH v3 2/3] sparc64: Support PERF_SAMPLE_REGS_USER and PERF_SAMPLE_STACK_USER Stian Halseth
@ 2026-09-23  9:14   ` sashiko-bot
  0 siblings, 0 replies; 18+ messages in thread
From: sashiko-bot @ 2026-09-23  9:14 UTC (permalink / raw)
  To: Stian Halseth; +Cc: linux-perf-users

> Select HAVE_PERF_REGS and HAVE_PERF_USER_STACK_DUMP and add the
> perf_regs implementation. The exposed registers mirror struct pt_regs:
> %g1-%g7, %o0-%o7 (named from the user's point of view; pt_regs calls
> them UREG_I*), %tstate, NPC and %y, with the PC in the slot of %g0, as
> mips and loongarch do for their hardwired-zero register. Trap entry
> does not save %g0, so its pt_regs slot holds stale stack contents for
> a trap taken in the kernel and must not be exposed.
> 
> %o6 is reported as held in the register, i.e. with the 2047 stack bias
> for a 64-bit stack, the same as ptrace and user_stack_pointer(). The
> stack dump starts at the stack's actual address instead, %o6 + 2047
> when test_thread_64bit_stack() says so, so that it begins at the
> sampled frame; the uapi header documents this for consumers.
> 
> User-mode values of a 32-bit task are truncated to 32 bits as
> genregs32_get() does, since the hardware does not zero-extend them.
> Kernel-mode registers, as seen by PERF_SAMPLE_REGS_INTR, are left
> alone.
> 
> perf_arch_prepare_ustack() flushes the user register windows so the
> sampled window's %l and %i registers are in the dumped stack, where a
> DWARF unwinder needs them: the CFI of a function after `save` defines
> the CFA in terms of %i6.
> 
> This makes perf record --call-graph dwarf and eu-stackprof usable on
> sparc64.
> 
> Signed-off-by: Stian Halseth <stian@itx.no>

Sashiko has reviewed this patch and found no issues. It looks great!

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260923090429.2026529-1-stian@itx.no?part=2


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC PATCH v3 3/3] perf tools: Support sparc user register samples and dwarf unwinding
  2026-09-23  9:04 ` [RFC PATCH v3 3/3] perf tools: Support sparc user register samples and dwarf unwinding Stian Halseth
@ 2026-09-23  9:14   ` sashiko-bot
  2026-09-23  9:42     ` Stian Halseth
  0 siblings, 1 reply; 18+ messages in thread
From: sashiko-bot @ 2026-09-23  9:14 UTC (permalink / raw)
  To: Stian Halseth; +Cc: linux-perf-users

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] perf/unwind: missing endian swap for sparc window registers
- [Low] perf/sparc: missing explicit stddef.h inclusion for NULL
--

commit 58ddb5306f26894ea36bdfc46ec5335a5abbcee6
Author: Stian Halseth <stian@itx.no>

perf tools: Support sparc user register samples and dwarf unwinding

Add the sparc perf_regs tables and the EM_SPARC/EM_SPARCV9 dispatch for
register names, masks, ip/sp and the perf-to-DWARF register mapping,
plus the uapi header copy.

> diff --git a/tools/perf/util/perf-regs-arch/perf_regs_sparc.c b/tools/perf/util/perf-regs-arch/perf_regs_sparc.c
> new file mode 100644
> index 0000000000000..9ee8e496ab8cc
> --- /dev/null
> +++ b/tools/perf/util/perf-regs-arch/perf_regs_sparc.c
> @@ -0,0 +1,67 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include "../perf_regs.h"
> +#include "../../arch/sparc/include/perf_regs.h"
> +
> +uint64_t __perf_reg_mask_sparc(bool intr __maybe_unused)
> +{
> +	return PERF_REGS_MASK;
> +}
> +
> +const char *__perf_reg_name_sparc(int id)
> +{
> +	switch (id) {

[ ... ]

> +	case PERF_REG_SPARC_Y:
> +		return "y";
> +	default:
> +		return NULL;
> +	}
> +
> +	return NULL;

[Severity: Low]
Does this rely on implicit header inclusion for NULL?

The NULL macro is used here, but neither <stddef.h> nor <stdlib.h> is
explicitly included in this file. It appears to rely on the implicit inclusion
of <stdlib.h> via the ../../arch/sparc/include/perf_regs.h header.

Should this explicitly include <stddef.h> or <stdlib.h>?

> +}

[ ... ]

> diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
> index 63a5c2253174f..d2adf7f2d8bb3 100644
> --- a/tools/perf/util/unwind-libdw.c
> +++ b/tools/perf/util/unwind-libdw.c

[ ... ]

> +/*
> + * The sampled window's %l and %i registers (DWARF 16-31) are not in the
> + * sample; the kernel flushed them to the register save area at the start
> + * of the dumped stack.
> + */
> +static void libdw_set_sparc_window_registers(struct unwind_info *ui,
> +					     struct regs_dump *user_regs,
> +					     Dwarf_Word *dwarf_regs)
> +{
> +	struct stack_dump *stack = &ui->sample->user_stack;
> +	u64 sp;
> +
> +	if (perf_reg_value(&sp, user_regs, perf_arch_reg_sp(ui->e_machine)))
> +		return;
> +	if (!(sp & 1) || 16 * sizeof(u64) > stack->size)
> +		return;
> +
> +	memcpy(&dwarf_regs[16], stack->data, 16 * sizeof(u64));

[Severity: Medium]
When analyzing a SPARC perf.data file on a little-endian host, will this
memcpy() write raw big-endian bytes into the little-endian host variables?

The dwarf_regs array is composed of Dwarf_Word (uint64_t) elements and expects
values in host endianness, while the stack dump (stack->data) retains the
target's original memory layout and endianness (SPARC is strictly big-endian).

This can cause the 64-bit integer values read by libdw to be byte-swapped,
breaking cross-architecture DWARF unwinding for SPARC as the stack unwinder
relies on %i6 and %i7 (DWARF registers 30 and 31) to find the caller's frame.

Should this code perform conditional byte-swapping when copying from the stack
dump?

> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260923090429.2026529-1-stian@itx.no?part=3

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC PATCH v3 1/3] perf/core: Let an arch prepare and locate the user stack dump
  2026-09-23  9:04 ` [RFC PATCH v3 1/3] perf/core: Let an arch prepare and locate the user stack dump Stian Halseth
@ 2026-09-23  9:16   ` sashiko-bot
  0 siblings, 0 replies; 18+ messages in thread
From: sashiko-bot @ 2026-09-23  9:16 UTC (permalink / raw)
  To: Stian Halseth; +Cc: linux-perf-users

> PERF_SAMPLE_STACK_USER copies the user stack as it is in memory,
> starting at the user stack pointer. Two things about sparc64 do not
> fit that.
> 
> The sampled window's %l and %i registers, including the frame pointer
> and return address an unwinder starts from, may still be in the
> register file: they only reach the stack when a window spills.
> perf_callchain_user() already handles this for the callchain by calling
> flushw_user() first; the user stack dump has no equivalent arch entry
> point.
> 
> And a 64-bit stack pointer is biased by 2047: the stack starts at
> %sp + 2047. Starting the dump at the register value spends a quarter of
> an 8K dump on memory below the frame, and gives no dump at all when that
> page has never been touched, as for a leaf frame at the deepest point a
> thread's stack has reached.
> 
> Add two hooks in the style of perf_arch_misc_flags():
> perf_arch_prepare_ustack(), a no-op by default, called from
> perf_prepare_sample() before the dump size is computed, and
> perf_arch_user_stack_pointer(), user_stack_pointer() by default, the
> address the dump starts at. Flushing in the arch PMU interrupt handler
> instead would not do: software events such as cpu-clock reach
> perf_event_overflow() without passing through it.
> 
> Signed-off-by: Stian Halseth <stian@itx.no>

Sashiko has reviewed this patch and found no issues. It looks great!

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260923090429.2026529-1-stian@itx.no?part=1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC PATCH v3 3/3] perf tools: Support sparc user register samples and dwarf unwinding
  2026-09-23  9:14   ` sashiko-bot
@ 2026-09-23  9:42     ` Stian Halseth
  2026-09-23 16:02       ` Ian Rogers
  0 siblings, 1 reply; 18+ messages in thread
From: Stian Halseth @ 2026-09-23  9:42 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: linux-perf-users

[-- Attachment #1: Type: text/plain, Size: 2589 bytes --]

On Wed, 2026-09-23 at 09:14 +0000, sashiko-bot@kernel.org wrote:
> 
> > +	case PERF_REG_SPARC_Y:
> > +		return "y";
> > +	default:
> > +		return NULL;
> > +	}
> > +
> > +	return NULL;
> 
> [Severity: Low]
> Does this rely on implicit header inclusion for NULL?
> 
> The NULL macro is used here, but neither <stddef.h> nor <stdlib.h> is
> explicitly included in this file. It appears to rely on the implicit
> inclusion
> of <stdlib.h> via the ../../arch/sparc/include/perf_regs.h header.
> 
> Should this explicitly include <stddef.h> or <stdlib.h>?

My take is: No.

perf_regs.h includes <stdlib.h>

It's done like this to maintain consistency with perf_regs_arm.c,
perf_regs_mips.c and perf_regs_loongarch.c.



> > +/*
> > + * The sampled window's %l and %i registers (DWARF 16-31) are not
> > in the
> > + * sample; the kernel flushed them to the register save area at
> > the start
> > + * of the dumped stack.
> > + */
> > +static void libdw_set_sparc_window_registers(struct unwind_info
> > *ui,
> > +					     struct regs_dump
> > *user_regs,
> > +					     Dwarf_Word
> > *dwarf_regs)
> > +{
> > +	struct stack_dump *stack = &ui->sample->user_stack;
> > +	u64 sp;
> > +
> > +	if (perf_reg_value(&sp, user_regs, perf_arch_reg_sp(ui-
> > >e_machine)))
> > +		return;
> > +	if (!(sp & 1) || 16 * sizeof(u64) > stack->size)
> > +		return;
> > +
> > +	memcpy(&dwarf_regs[16], stack->data, 16 * sizeof(u64));
> 
> [Severity: Medium]
> When analyzing a SPARC perf.data file on a little-endian host, will
> this
> memcpy() write raw big-endian bytes into the little-endian host
> variables?
> 
> The dwarf_regs array is composed of Dwarf_Word (uint64_t) elements
> and expects
> values in host endianness, while the stack dump (stack->data) retains
> the
> target's original memory layout and endianness (SPARC is strictly
> big-endian).
> 
> This can cause the 64-bit integer values read by libdw to be byte-
> swapped,
> breaking cross-architecture DWARF unwinding for SPARC as the stack
> unwinder
> relies on %i6 and %i7 (DWARF registers 30 and 31) to find the
> caller's frame.
> 
> Should this code perform conditional byte-swapping when copying from
> the stack
> dump?

No.

Checked by analyzing a sparc64 perf.data on x86 with this series.

unwinds leaf -> mid2 -> mid1 -> main -> __libc_start_main -> _start,
the same as on the SPARC T4.

The dump of a 64-bit sparc stack starts at %sp + 2047. It's 16-byte
aligned, so each saved register is one swap unit and is already in host
order.



[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC PATCH v3 3/3] perf tools: Support sparc user register samples and dwarf unwinding
  2026-09-23  9:42     ` Stian Halseth
@ 2026-09-23 16:02       ` Ian Rogers
  2026-09-23 19:36         ` Stian Halseth
  0 siblings, 1 reply; 18+ messages in thread
From: Ian Rogers @ 2026-09-23 16:02 UTC (permalink / raw)
  To: Stian Halseth; +Cc: sashiko-reviews, linux-perf-users

On Wed, Sep 23, 2026 at 2:57 AM Stian Halseth <stian@itx.no> wrote:
>
> On Wed, 2026-09-23 at 09:14 +0000, sashiko-bot@kernel.org wrote:
> >
> > > +   case PERF_REG_SPARC_Y:
> > > +           return "y";
> > > +   default:
> > > +           return NULL;
> > > +   }
> > > +
> > > +   return NULL;
> >
> > [Severity: Low]
> > Does this rely on implicit header inclusion for NULL?
> >
> > The NULL macro is used here, but neither <stddef.h> nor <stdlib.h> is
> > explicitly included in this file. It appears to rely on the implicit
> > inclusion
> > of <stdlib.h> via the ../../arch/sparc/include/perf_regs.h header.
> >
> > Should this explicitly include <stddef.h> or <stdlib.h>?
>
> My take is: No.
>
> perf_regs.h includes <stdlib.h>
>
> It's done like this to maintain consistency with perf_regs_arm.c,
> perf_regs_mips.c and perf_regs_loongarch.c.
>

This is a low priority item we're trying to keep cleaned up, so no
action is necessary. The issue is that musl libc doesn't transitively
include what glibc does and we frequently break the musl build. Let's
try to catch it at review time. It is also nice not to have transitive
dependencies. But yeah, there's nothing wrong with what you've done
and following the surrounding convention is the right thing to do.

>
> > > +/*
> > > + * The sampled window's %l and %i registers (DWARF 16-31) are not
> > > in the
> > > + * sample; the kernel flushed them to the register save area at
> > > the start
> > > + * of the dumped stack.
> > > + */
> > > +static void libdw_set_sparc_window_registers(struct unwind_info
> > > *ui,
> > > +                                        struct regs_dump
> > > *user_regs,
> > > +                                        Dwarf_Word
> > > *dwarf_regs)
> > > +{
> > > +   struct stack_dump *stack = &ui->sample->user_stack;
> > > +   u64 sp;
> > > +
> > > +   if (perf_reg_value(&sp, user_regs, perf_arch_reg_sp(ui-
> > > >e_machine)))
> > > +           return;
> > > +   if (!(sp & 1) || 16 * sizeof(u64) > stack->size)
> > > +           return;
> > > +
> > > +   memcpy(&dwarf_regs[16], stack->data, 16 * sizeof(u64));
> >
> > [Severity: Medium]
> > When analyzing a SPARC perf.data file on a little-endian host, will
> > this
> > memcpy() write raw big-endian bytes into the little-endian host
> > variables?
> >
> > The dwarf_regs array is composed of Dwarf_Word (uint64_t) elements
> > and expects
> > values in host endianness, while the stack dump (stack->data) retains
> > the
> > target's original memory layout and endianness (SPARC is strictly
> > big-endian).
> >
> > This can cause the 64-bit integer values read by libdw to be byte-
> > swapped,
> > breaking cross-architecture DWARF unwinding for SPARC as the stack
> > unwinder
> > relies on %i6 and %i7 (DWARF registers 30 and 31) to find the
> > caller's frame.
> >
> > Should this code perform conditional byte-swapping when copying from
> > the stack
> > dump?
>
> No.
>
> Checked by analyzing a sparc64 perf.data on x86 with this series.
>
> unwinds leaf -> mid2 -> mid1 -> main -> __libc_start_main -> _start,
> the same as on the SPARC T4.
>
> The dump of a 64-bit sparc stack starts at %sp + 2047. It's 16-byte
> aligned, so each saved register is one swap unit and is already in host
> order.

Thanks for testing! In session.c the functions like
perf_session__process_event will swap all 64-bit values by calling
event_swap, for a sample every 64-bit value is swapped by
perf_event__all64_swap:
https://web.git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git/tree/tools/perf/util/session.c?h=perf-tools-next#n1202

In libdw__get_entries the registers and then stack will find the
64-bit values swapped. I'm wondering if the case of 32-bit needs some
fix up like with PERF_SAMPLE_CPU in __evsel__parse_sample:
https://web.git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git/tree/tools/perf/util/evsel.c?h=perf-tools-next#n3527

The PERF_SAMPLE_REGS_USER always samples a 64-bit value, so I think
they are okay with a 64-bit bswap. For the PERF_SAMPLE_STACK_USER
accessed in memory_read in unwind-libdw.c, I wonder the byte swap 64
done in perf_event__all64_swap means we're off by 4 bytes with the
value being loaded from the stack. I wonder about the code:
```
 *result = *(Dwarf_Word *)&stack->data[offset];
```
should be something like this:
```
if (!ui->stack_is_32bit_differing_endian) {
 *result = *(Dwarf_Word *)&stack->data[offset];
} else {
  union u64_swap u;
  u.val64 = *(u64*)&stack->data[offset];
   /* undo swap of u64, then swap individual u32 */
  u.val64 = bswap_64(u.val64);
  *result = bswap_32(u.val32[0]);
}
```

Thanks,
Ian

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC PATCH v3 3/3] perf tools: Support sparc user register samples and dwarf unwinding
  2026-09-23 16:02       ` Ian Rogers
@ 2026-09-23 19:36         ` Stian Halseth
  0 siblings, 0 replies; 18+ messages in thread
From: Stian Halseth @ 2026-09-23 19:36 UTC (permalink / raw)
  To: Ian Rogers; +Cc: sashiko-reviews, linux-perf-users

[-- Attachment #1: Type: text/plain, Size: 3364 bytes --]

Hi Ian,

On Wed, 2026-09-23 at 09:02 -0700, Ian Rogers wrote:
> 
> 
> This is a low priority item we're trying to keep cleaned up, so no
> action is necessary. The issue is that musl libc doesn't transitively
> include what glibc does and we frequently break the musl build. Let's
> try to catch it at review time. It is also nice not to have
> transitive
> dependencies. But yeah, there's nothing wrong with what you've done
> and following the surrounding convention is the right thing to do.

Thanks for the explanation, makes sense.

> > 
> > 
> > No.
> > 
> > Checked by analyzing a sparc64 perf.data on x86 with this series.
> > 
> > unwinds leaf -> mid2 -> mid1 -> main -> __libc_start_main ->
> > _start,
> > the same as on the SPARC T4.
> > 
> > The dump of a 64-bit sparc stack starts at %sp + 2047. It's 16-byte
> > aligned, so each saved register is one swap unit and is already in
> > host
> > order.
> 
> Thanks for testing! In session.c the functions like
> perf_session__process_event will swap all 64-bit values by calling
> event_swap, for a sample every 64-bit value is swapped by
> perf_event__all64_swap:
> https://web.git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git/tree/tools/perf/util/session.c?h=perf-tools-next#n1202
> 
> In libdw__get_entries the registers and then stack will find the
> 64-bit values swapped. I'm wondering if the case of 32-bit needs some
> fix up like with PERF_SAMPLE_CPU in __evsel__parse_sample:
> https://web.git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git/tree/tools/perf/util/evsel.c?h=perf-tools-next#n3527
> 
> The PERF_SAMPLE_REGS_USER always samples a 64-bit value, so I think
> they are okay with a 64-bit bswap. For the PERF_SAMPLE_STACK_USER
> accessed in memory_read in unwind-libdw.c, I wonder the byte swap 64
> done in perf_event__all64_swap means we're off by 4 bytes with the
> value being loaded from the stack. I wonder about the code:

Yes, this is a real finding, and I ran into a related issue while doing
some 32-bit testing in a chroot on sparc64 earlier, even without a byte
swap.

memory_read() gives libdw 8 bytes, libdw keeps the low 32 bits for an
ELFCLASS32 target, and on big-endian that is the word at addr + 4. 

The chain stops at the first frame restored from the stack (and on
sparc an 8-byte load from an address that is only 4-byte aligned
traps).

I had parked the fix for that when I decided to focus on sparc64 only,
as there were already quite a few bits and pieces I wasn't sure about,
and I wanted some feedback before adding more.

But since you bring this up, I now have a patch for memory_read() that
handles both the native case and the cross-endian one, with the un-swap
you describe, picking the half that holds addr. 

It's tested with 32-bit sparc programs, natively on sparc64 and cross-
endian on x86. 

I sent it as a separate patch, since it's a generic fix, and would
appreciate it if you have time for a look:
[PATCH] perf unwind-libdw: Fix reading the stack of a 32-bit task
https://lore.kernel.org/all/20260923193432.2489729-1-stian@itx.no/

I did several tests on this series + the separate patch. Test details
in the patch.

No pending changes to v3 so far, everything in the separate patch.

Thanks for the review!

Best regards
Stian

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC PATCH v3 0/3] perf: sparc64 user regs and stack dump, with arch hooks
  2026-09-23  9:04 [RFC PATCH v3 0/3] perf: sparc64 user regs and stack dump, with arch hooks Stian Halseth
                   ` (2 preceding siblings ...)
  2026-09-23  9:04 ` [RFC PATCH v3 3/3] perf tools: Support sparc user register samples and dwarf unwinding Stian Halseth
@ 2026-09-23 20:38 ` Ian Rogers
  2026-09-23 20:56   ` Stian Halseth
  2026-09-23 23:10 ` Magnus Lindholm
  4 siblings, 1 reply; 18+ messages in thread
From: Ian Rogers @ 2026-09-23 20:38 UTC (permalink / raw)
  To: Stian Halseth
  Cc: Peter Zijlstra, Ingo Molnar, Andreas Larsson, David S. Miller,
	Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Adrian Hunter, James Clark,
	Jonathan Corbet, Shuah Khan, Randy Dunlap, Magnus Lindholm,
	linux-perf-users, sparclinux, linux-doc, linux-kernel

On Wed, Sep 23, 2026 at 2:04 AM Stian Halseth <stian@itx.no> wrote:
>
> This adds HAVE_PERF_REGS and HAVE_PERF_USER_STACK_DUMP to sparc64, so
> that perf record --call-graph dwarf and elfutils' eu-stackprof work
> there.
>
> Two things about the user stack dump do not fit in arch code. The
> sampled register window's %l/%i registers, which hold the frame pointer
> and return address the unwinder starts from, stay in the register file
> until a window spills. The kernel already flushes them wherever it
> exposes user stack memory (perf_callchain_user(), ptrace), but the stack
> dump has no arch entry point where that could happen. And a 64-bit
> sparc stack pointer is biased by 2047, so a dump that starts at the
> register value begins 2047 bytes below the frame, and is empty when that
> page has never been touched.
>
> Patch 1 therefore adds two hooks in the style of perf_arch_misc_flags(),
> both no-ops by default. Patch 2 is the sparc64 implementation and their
> user. Patch 3 teaches tools/perf the sparc registers and DWARF unwinding
> from the dump. The matching elfutils changes are attached to the
> tracking issue:
>
>   https://github.com/sparclinux/issues/issues/99
>
> Tested on an UltraSPARC T4-1 on 7.3-rc4: register values check out
> against known contents, --call-graph dwarf unwinds correctly for both
> cycles and cpu-clock, as does eu-stackprof, and perf stat/record/record
> -g are unchanged. Starting the dump at the stack's actual address
> matters in practice: with the dump at the biased register value, 94% of
> the user samples of xz -T4 had an empty stack dump; with this series,
> none do.
>
> Changes since v2:
> - Patch 1: add perf_arch_user_stack_pointer(), so an arch can start the
>   dump at the stack's actual address (sashiko review).
> - Patch 2: drop %g0 from the uapi, as trap entry does not save it; the
>   PC takes its slot, as on mips and loongarch (sashiko review).
> - Patch 2: start the dump at %sp + 2047 for a 64-bit stack (sashiko
>   review).
> - Patch 3: follow both, and comment the max_dwarf_reg adjustment (Ian).
>   Drop the memcpy() change to memory_read(), which the unbiased dump
>   start makes unnecessary.
>
> v2: https://lore.kernel.org/all/20260922201507.1719668-1-stian@itx.no/
> v1: https://lore.kernel.org/all/20260922135653.1622301-1-stian@itx.no/
>
> Stian Halseth (3):
>   perf/core: Let an arch prepare and locate the user stack dump
>   sparc64: Support PERF_SAMPLE_REGS_USER and PERF_SAMPLE_STACK_USER
>   perf tools: Support sparc user register samples and dwarf unwinding

For the series:

Reviewed-by: Ian Rogers <irogers@google.com>

Thanks!
Ian

>  .../features/perf/perf-regs/arch-support.txt  |  2 +-
>  .../perf/perf-stackdump/arch-support.txt      |  2 +-
>  arch/sparc/Kconfig                            |  2 +
>  arch/sparc/include/asm/perf_event.h           |  5 ++
>  arch/sparc/include/uapi/asm/perf_regs.h       | 34 +++++++++
>  arch/sparc/kernel/Makefile                    |  2 +-
>  arch/sparc/kernel/perf_regs.c                 | 74 +++++++++++++++++++
>  include/linux/perf_event.h                    | 11 +++
>  kernel/events/core.c                          |  2 +
>  kernel/events/internal.h                      |  2 +-
>  tools/arch/sparc/include/uapi/asm/perf_regs.h | 34 +++++++++
>  tools/perf/arch/sparc/include/perf_regs.h     | 18 +++++
>  tools/perf/check-headers.sh                   |  1 +
>  tools/perf/util/dwarf-regs-arch/Build         |  1 +
>  .../util/dwarf-regs-arch/dwarf-regs-sparc.c   | 12 +++
>  tools/perf/util/dwarf-regs.c                  |  4 +
>  tools/perf/util/include/dwarf-regs.h          |  1 +
>  tools/perf/util/perf-regs-arch/Build          |  1 +
>  .../util/perf-regs-arch/perf_regs_sparc.c     | 67 +++++++++++++++++
>  tools/perf/util/perf_regs.c                   | 18 +++++
>  tools/perf/util/perf_regs.h                   |  5 ++
>  tools/perf/util/unwind-libdw.c                | 37 ++++++++++
>  22 files changed, 331 insertions(+), 4 deletions(-)
>  create mode 100644 arch/sparc/include/uapi/asm/perf_regs.h
>  create mode 100644 arch/sparc/kernel/perf_regs.c
>  create mode 100644 tools/arch/sparc/include/uapi/asm/perf_regs.h
>  create mode 100644 tools/perf/arch/sparc/include/perf_regs.h
>  create mode 100644 tools/perf/util/dwarf-regs-arch/dwarf-regs-sparc.c
>  create mode 100644 tools/perf/util/perf-regs-arch/perf_regs_sparc.c
>
> --
> 2.55.0
>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC PATCH v3 0/3] perf: sparc64 user regs and stack dump, with arch hooks
  2026-09-23 20:38 ` [RFC PATCH v3 0/3] perf: sparc64 user regs and stack dump, with arch hooks Ian Rogers
@ 2026-09-23 20:56   ` Stian Halseth
  2026-09-23 21:16     ` Ian Rogers
  0 siblings, 1 reply; 18+ messages in thread
From: Stian Halseth @ 2026-09-23 20:56 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Peter Zijlstra, Ingo Molnar, Andreas Larsson, David S. Miller,
	Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Adrian Hunter, James Clark,
	Jonathan Corbet, Shuah Khan, Randy Dunlap, Magnus Lindholm,
	linux-perf-users, sparclinux, linux-doc, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 351 bytes --]

Hi Ian,

On Wed, 2026-09-23 at 13:38 -0700, Ian Rogers wrote:
> 
> 
> For the series:
> 
> Reviewed-by: Ian Rogers <irogers@google.com>
> 

Since this series is still marked RFC, should I resend it as a regular
PATCH v4 with your Reviewed-by, or wait for additional maintainer
feedback?

And thank you so much for the reviews!

Stian

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC PATCH v3 0/3] perf: sparc64 user regs and stack dump, with arch hooks
  2026-09-23 20:56   ` Stian Halseth
@ 2026-09-23 21:16     ` Ian Rogers
  2026-09-24 17:09       ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 18+ messages in thread
From: Ian Rogers @ 2026-09-23 21:16 UTC (permalink / raw)
  To: Stian Halseth, Peter Zijlstra, Ingo Molnar, Namhyung Kim,
	Arnaldo Carvalho de Melo
  Cc: Andreas Larsson, David S. Miller, Mark Rutland, Jiri Olsa,
	Alexander Shishkin, Adrian Hunter, James Clark, Jonathan Corbet,
	Shuah Khan, Randy Dunlap, Magnus Lindholm, linux-perf-users,
	sparclinux, linux-doc, linux-kernel

On Wed, Sep 23, 2026 at 1:57 PM Stian Halseth <stian@itx.no> wrote:
>
> Hi Ian,
>
> On Wed, 2026-09-23 at 13:38 -0700, Ian Rogers wrote:
> >
> >
> > For the series:
> >
> > Reviewed-by: Ian Rogers <irogers@google.com>
> >
>
> Since this series is still marked RFC, should I resend it as a regular
> PATCH v4 with your Reviewed-by, or wait for additional maintainer
> feedback?
>
> And thank you so much for the reviews!

I think we have everything we need but the kernel changes are really
up to Peter and Ingo, and the tool changes are up to Arnaldo and
Namhyung.

Thanks,
Ian

> Stian

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC PATCH v3 0/3] perf: sparc64 user regs and stack dump, with arch hooks
  2026-09-23  9:04 [RFC PATCH v3 0/3] perf: sparc64 user regs and stack dump, with arch hooks Stian Halseth
                   ` (3 preceding siblings ...)
  2026-09-23 20:38 ` [RFC PATCH v3 0/3] perf: sparc64 user regs and stack dump, with arch hooks Ian Rogers
@ 2026-09-23 23:10 ` Magnus Lindholm
  2026-09-24  8:20   ` Stian Halseth
  4 siblings, 1 reply; 18+ messages in thread
From: Magnus Lindholm @ 2026-09-23 23:10 UTC (permalink / raw)
  To: Stian Halseth
  Cc: Peter Zijlstra, Ingo Molnar, Andreas Larsson, David S. Miller,
	Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
	James Clark, Jonathan Corbet, Shuah Khan, Randy Dunlap,
	linux-perf-users, sparclinux, linux-doc, linux-kernel

Hi Stian,

On Wed, Sep 23, 2026 at 11:04 AM Stian Halseth <stian@itx.no> wrote:
>
> This adds HAVE_PERF_REGS and HAVE_PERF_USER_STACK_DUMP to sparc64, so
> that perf record --call-graph dwarf and elfutils' eu-stackprof work
> there.
>
> Two things about the user stack dump do not fit in arch code. The
> sampled register window's %l/%i registers, which hold the frame pointer
> and return address the unwinder starts from, stay in the register file
> until a window spills. The kernel already flushes them wherever it
> exposes user stack memory (perf_callchain_user(), ptrace), but the stack
> dump has no arch entry point where that could happen. And a 64-bit
> sparc stack pointer is biased by 2047, so a dump that starts at the
> register value begins 2047 bytes below the frame, and is empty when that
> page has never been touched.
>
> Patch 1 therefore adds two hooks in the style of perf_arch_misc_flags(),
> both no-ops by default. Patch 2 is the sparc64 implementation and their
> user. Patch 3 teaches tools/perf the sparc registers and DWARF unwinding
> from the dump. The matching elfutils changes are attached to the
> tracking issue:
>
>   https://github.com/sparclinux/issues/issues/99
>
> Tested on an UltraSPARC T4-1 on 7.3-rc4: register values check out
> against known contents, --call-graph dwarf unwinds correctly for both
> cycles and cpu-clock, as does eu-stackprof, and perf stat/record/record
> -g are unchanged. Starting the dump at the stack's actual address
> matters in practice: with the dump at the biased register value, 94% of
> the user samples of xz -T4 had an empty stack dump; with this series,
> none do.
>
> Changes since v2:
> - Patch 1: add perf_arch_user_stack_pointer(), so an arch can start the
>   dump at the stack's actual address (sashiko review).
> - Patch 2: drop %g0 from the uapi, as trap entry does not save it; the
>   PC takes its slot, as on mips and loongarch (sashiko review).
> - Patch 2: start the dump at %sp + 2047 for a 64-bit stack (sashiko
>   review).
> - Patch 3: follow both, and comment the max_dwarf_reg adjustment (Ian).
>   Drop the memcpy() change to memory_read(), which the unbiased dump
>   start makes unnecessary.
>
> v2: https://lore.kernel.org/all/20260922201507.1719668-1-stian@itx.no/
> v1: https://lore.kernel.org/all/20260922135653.1622301-1-stian@itx.no/
>
> Stian Halseth (3):
>   perf/core: Let an arch prepare and locate the user stack dump
>   sparc64: Support PERF_SAMPLE_REGS_USER and PERF_SAMPLE_STACK_USER
>   perf tools: Support sparc user register samples and dwarf unwinding
>
>  .../features/perf/perf-regs/arch-support.txt  |  2 +-
>  .../perf/perf-stackdump/arch-support.txt      |  2 +-
>  arch/sparc/Kconfig                            |  2 +
>  arch/sparc/include/asm/perf_event.h           |  5 ++
>  arch/sparc/include/uapi/asm/perf_regs.h       | 34 +++++++++
>  arch/sparc/kernel/Makefile                    |  2 +-
>  arch/sparc/kernel/perf_regs.c                 | 74 +++++++++++++++++++
>  include/linux/perf_event.h                    | 11 +++
>  kernel/events/core.c                          |  2 +
>  kernel/events/internal.h                      |  2 +-
>  tools/arch/sparc/include/uapi/asm/perf_regs.h | 34 +++++++++
>  tools/perf/arch/sparc/include/perf_regs.h     | 18 +++++
>  tools/perf/check-headers.sh                   |  1 +
>  tools/perf/util/dwarf-regs-arch/Build         |  1 +
>  .../util/dwarf-regs-arch/dwarf-regs-sparc.c   | 12 +++
>  tools/perf/util/dwarf-regs.c                  |  4 +
>  tools/perf/util/include/dwarf-regs.h          |  1 +
>  tools/perf/util/perf-regs-arch/Build          |  1 +
>  .../util/perf-regs-arch/perf_regs_sparc.c     | 67 +++++++++++++++++
>  tools/perf/util/perf_regs.c                   | 18 +++++
>  tools/perf/util/perf_regs.h                   |  5 ++
>  tools/perf/util/unwind-libdw.c                | 37 ++++++++++
>  22 files changed, 331 insertions(+), 4 deletions(-)
>  create mode 100644 arch/sparc/include/uapi/asm/perf_regs.h
>  create mode 100644 arch/sparc/kernel/perf_regs.c
>  create mode 100644 tools/arch/sparc/include/uapi/asm/perf_regs.h
>  create mode 100644 tools/perf/arch/sparc/include/perf_regs.h
>  create mode 100644 tools/perf/util/dwarf-regs-arch/dwarf-regs-sparc.c
>  create mode 100644 tools/perf/util/perf-regs-arch/perf_regs_sparc.c
>
> --
> 2.55.0
>

Hi Stian,

I tested v3 on real hardware. I haven't noticed any regressions.
I built tools/perf from this series and tested the new functionality
with software cpu-clock events.

Basic perf stat/record and the existing frame-pointer callchain mode
worked normally.

PERF_SAMPLE_REGS_USER also worked, with perf successfully recording
and decoding the SPARC register set.

I then tested:

  perf record -e '1:0:u' -F 99 --call-graph dwarf,8192 ...

This recorded 443 samples with PERF_SAMPLE_REGS_USER and
PERF_SAMPLE_STACK_USER, using the full 0x7ffff register mask and an
8192-byte stack dump. perf script and perf report were both able to
unwind the resulting callchains, and no samples were reported lost.

I haven't tested 32-bit compat tasks or hardware-cycle sampling.

Tested-by: Magnus Lindholm <linmag7@gmail.com>

Thanks,
Magnus

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC PATCH v3 0/3] perf: sparc64 user regs and stack dump, with arch hooks
  2026-09-23 23:10 ` Magnus Lindholm
@ 2026-09-24  8:20   ` Stian Halseth
  0 siblings, 0 replies; 18+ messages in thread
From: Stian Halseth @ 2026-09-24  8:20 UTC (permalink / raw)
  To: Magnus Lindholm
  Cc: Peter Zijlstra, Ingo Molnar, Andreas Larsson, David S. Miller,
	Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland,
	Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
	James Clark, Jonathan Corbet, Shuah Khan, Randy Dunlap,
	linux-perf-users, sparclinux, linux-doc, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1026 bytes --]

Hi Magnus,

On Thu, 2026-09-24 at 01:10 +0200, Magnus Lindholm wrote:
> 
> Hi Stian,
> 
> I tested v3 on real hardware. I haven't noticed any regressions.
> I built tools/perf from this series and tested the new functionality
> with software cpu-clock events.
> 
> Basic perf stat/record and the existing frame-pointer callchain mode
> worked normally.
> 
> PERF_SAMPLE_REGS_USER also worked, with perf successfully recording
> and decoding the SPARC register set.
> 
> I then tested:
> 
>   perf record -e '1:0:u' -F 99 --call-graph dwarf,8192 ...
> 
> This recorded 443 samples with PERF_SAMPLE_REGS_USER and
> PERF_SAMPLE_STACK_USER, using the full 0x7ffff register mask and an
> 8192-byte stack dump. perf script and perf report were both able to
> unwind the resulting callchains, and no samples were reported lost.
> 
> I haven't tested 32-bit compat tasks or hardware-cycle sampling.
> 
> Tested-by: Magnus Lindholm <linmag7@gmail.com>
> 
> Thanks,
> Magnus

Thanks for testing,
Stian

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC PATCH v3 0/3] perf: sparc64 user regs and stack dump, with arch hooks
  2026-09-23 21:16     ` Ian Rogers
@ 2026-09-24 17:09       ` Arnaldo Carvalho de Melo
  2026-09-24 17:11         ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 18+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-09-24 17:09 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Stian Halseth, Peter Zijlstra, Ingo Molnar, Namhyung Kim,
	Andreas Larsson, David S. Miller, Mark Rutland, Jiri Olsa,
	Alexander Shishkin, Adrian Hunter, James Clark, Jonathan Corbet,
	Shuah Khan, Randy Dunlap, Magnus Lindholm, linux-perf-users,
	sparclinux, linux-doc, linux-kernel

On Wed, Sep 23, 2026 at 02:16:49PM -0700, Ian Rogers wrote:
> On Wed, Sep 23, 2026 at 1:57 PM Stian Halseth <stian@itx.no> wrote:
> >
> > Hi Ian,
> >
> > On Wed, 2026-09-23 at 13:38 -0700, Ian Rogers wrote:
> > >
> > >
> > > For the series:
> > >
> > > Reviewed-by: Ian Rogers <irogers@google.com>
> > >
> >
> > Since this series is still marked RFC, should I resend it as a regular
> > PATCH v4 with your Reviewed-by, or wait for additional maintainer
> > feedback?
> >
> > And thank you so much for the reviews!
> 
> I think we have everything we need but the kernel changes are really
> up to Peter and Ingo, and the tool changes are up to Arnaldo and
> Namhyung.

Exactly, as soon as the kernel changes land in a path to upstream, I can
do the same for the tooling bits.

Cheers,

- Arnaldo

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC PATCH v3 0/3] perf: sparc64 user regs and stack dump, with arch hooks
  2026-09-24 17:09       ` Arnaldo Carvalho de Melo
@ 2026-09-24 17:11         ` Arnaldo Carvalho de Melo
  2026-09-25  7:33           ` Stian Halseth
  0 siblings, 1 reply; 18+ messages in thread
From: Arnaldo Carvalho de Melo @ 2026-09-24 17:11 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Stian Halseth, Peter Zijlstra, Ingo Molnar, Namhyung Kim,
	Andreas Larsson, David S. Miller, Mark Rutland, Jiri Olsa,
	Alexander Shishkin, Adrian Hunter, James Clark, Jonathan Corbet,
	Shuah Khan, Randy Dunlap, Magnus Lindholm, linux-perf-users,
	sparclinux, linux-doc, linux-kernel

On Thu, Sep 24, 2026 at 07:09:58PM +0200, Arnaldo Carvalho de Melo wrote:
> On Wed, Sep 23, 2026 at 02:16:49PM -0700, Ian Rogers wrote:
> > On Wed, Sep 23, 2026 at 1:57 PM Stian Halseth <stian@itx.no> wrote:
> > I think we have everything we need but the kernel changes are really
> > up to Peter and Ingo, and the tool changes are up to Arnaldo and
> > Namhyung.
 
> Exactly, as soon as the kernel changes land in a path to upstream, I can
> do the same for the tooling bits.

Once that happens, please resubmit just the tools patches without an RFC
in the subject line.

- Arnaldo

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [RFC PATCH v3 0/3] perf: sparc64 user regs and stack dump, with arch hooks
  2026-09-24 17:11         ` Arnaldo Carvalho de Melo
@ 2026-09-25  7:33           ` Stian Halseth
  0 siblings, 0 replies; 18+ messages in thread
From: Stian Halseth @ 2026-09-25  7:33 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Ian Rogers
  Cc: Peter Zijlstra, Ingo Molnar, Namhyung Kim, Andreas Larsson,
	David S. Miller, Mark Rutland, Jiri Olsa, Alexander Shishkin,
	Adrian Hunter, James Clark, Jonathan Corbet, Shuah Khan,
	Randy Dunlap, Magnus Lindholm, linux-perf-users, sparclinux,
	linux-doc, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 739 bytes --]

Hi Arnaldo,

On Thu, 2026-09-24 at 19:11 +0200, Arnaldo Carvalho de Melo wrote:
> On Thu, Sep 24, 2026 at 07:09:58PM +0200, Arnaldo Carvalho de Melo
> wrote:
> > On Wed, Sep 23, 2026 at 02:16:49PM -0700, Ian Rogers wrote:
> > > On Wed, Sep 23, 2026 at 1:57 PM Stian Halseth <stian@itx.no>
> > > wrote:
> > > I think we have everything we need but the kernel changes are
> > > really
> > > up to Peter and Ingo, and the tool changes are up to Arnaldo and
> > > Namhyung.
>  
> > Exactly, as soon as the kernel changes land in a path to upstream,
> > I can
> > do the same for the tooling bits.
> 
> Once that happens, please resubmit just the tools patches without an
> RFC
> in the subject line.

Will do, thanks!

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2026-09-25  7:33 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-23  9:04 [RFC PATCH v3 0/3] perf: sparc64 user regs and stack dump, with arch hooks Stian Halseth
2026-09-23  9:04 ` [RFC PATCH v3 1/3] perf/core: Let an arch prepare and locate the user stack dump Stian Halseth
2026-09-23  9:16   ` sashiko-bot
2026-09-23  9:04 ` [RFC PATCH v3 2/3] sparc64: Support PERF_SAMPLE_REGS_USER and PERF_SAMPLE_STACK_USER Stian Halseth
2026-09-23  9:14   ` sashiko-bot
2026-09-23  9:04 ` [RFC PATCH v3 3/3] perf tools: Support sparc user register samples and dwarf unwinding Stian Halseth
2026-09-23  9:14   ` sashiko-bot
2026-09-23  9:42     ` Stian Halseth
2026-09-23 16:02       ` Ian Rogers
2026-09-23 19:36         ` Stian Halseth
2026-09-23 20:38 ` [RFC PATCH v3 0/3] perf: sparc64 user regs and stack dump, with arch hooks Ian Rogers
2026-09-23 20:56   ` Stian Halseth
2026-09-23 21:16     ` Ian Rogers
2026-09-24 17:09       ` Arnaldo Carvalho de Melo
2026-09-24 17:11         ` Arnaldo Carvalho de Melo
2026-09-25  7:33           ` Stian Halseth
2026-09-23 23:10 ` Magnus Lindholm
2026-09-24  8:20   ` Stian Halseth

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox