summaryrefslogtreecommitdiff
path: root/arch/s390/kernel/stacktrace.c
diff options
context:
space:
mode:
authorSven Schnelle <svens@linux.ibm.com>2024-04-26 12:02:15 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2024-06-12 11:39:23 +0200
commitfef7b77cdd0c6d5249982a9acbafb0d49598b80f (patch)
tree29d2fbe69e360f1555270b52ef41a57eccfa1c30 /arch/s390/kernel/stacktrace.c
parent2db561897743167d40f5902626b1ae01af3624e9 (diff)
s390/ftrace: Use unwinder instead of __builtin_return_address()
[ Upstream commit cae74ba8c295bc41bda749ef27a8f2b3ee957a41 ] Using __builtin_return_address(n) might return undefined values when used with values of n outside of the stack. This was noticed when __builtin_return_address() was called in ftrace on top level functions like the interrupt handlers. As this behaviour cannot be fixed, use the s390 stack unwinder and remove the ftrace compilation flags for unwind_bc.c and stacktrace.c to prevent the unwinding function polluting function traces. Another advantage is that this also works with clang. Reviewed-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Sven Schnelle <svens@linux.ibm.com> Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com> Stable-dep-of: ebd912ff9919 ("s390/stacktrace: Merge perf_callchain_user() and arch_stack_walk_user()") Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'arch/s390/kernel/stacktrace.c')
-rw-r--r--arch/s390/kernel/stacktrace.c19
1 files changed, 19 insertions, 0 deletions
diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c
index 94f440e38303..7c294da45bf5 100644
--- a/arch/s390/kernel/stacktrace.c
+++ b/arch/s390/kernel/stacktrace.c
@@ -101,3 +101,22 @@ void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie,
}
pagefault_enable();
}
+
+unsigned long return_address(unsigned int n)
+{
+ struct unwind_state state;
+ unsigned long addr;
+
+ /* Increment to skip current stack entry */
+ n++;
+
+ unwind_for_each_frame(&state, NULL, NULL, 0) {
+ addr = unwind_get_return_address(&state);
+ if (!addr)
+ break;
+ if (!n--)
+ return addr;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(return_address);