s390/ftrace: Use unwinder instead of __builtin_return_address()
authorSven Schnelle <svens@linux.ibm.com>
Fri, 26 Apr 2024 10:02:15 +0000 (12:02 +0200)
committerAlexander Gordeev <agordeev@linux.ibm.com>
Mon, 29 Apr 2024 15:33:30 +0000 (17:33 +0200)
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>
arch/s390/include/asm/ftrace.h
arch/s390/kernel/Makefile
arch/s390/kernel/stacktrace.c

index 621f23d5ae30a6a05e39e3bf54df1a3b80011f68..77e479d44f1e375d3244ea6e526de2670d36d9d2 100644 (file)
@@ -8,12 +8,8 @@
 
 #ifndef __ASSEMBLY__
 
-#ifdef CONFIG_CC_IS_CLANG
-/* https://llvm.org/pr41424 */
-#define ftrace_return_address(n) 0UL
-#else
-#define ftrace_return_address(n) __builtin_return_address(n)
-#endif
+unsigned long return_address(unsigned int n);
+#define ftrace_return_address(n) return_address(n)
 
 void ftrace_caller(void);
 
index fa029d0dc28ff90567a47ec2ff264198c1342890..db2d9ba5a86d229a91a9ff375c70a2edc0b9ed26 100644 (file)
@@ -11,6 +11,8 @@ CFLAGS_REMOVE_ftrace.o                = $(CC_FLAGS_FTRACE)
 # Do not trace early setup code
 CFLAGS_REMOVE_early.o          = $(CC_FLAGS_FTRACE)
 CFLAGS_REMOVE_rethook.o                = $(CC_FLAGS_FTRACE)
+CFLAGS_REMOVE_stacktrace.o     = $(CC_FLAGS_FTRACE)
+CFLAGS_REMOVE_unwind_bc.o      = $(CC_FLAGS_FTRACE)
 
 endif
 
index 94f440e38303191d64097f12a274cb46e5a10e2e..7c294da45bf524e9891d8c3e83ab71f9b0115e50 100644 (file)
@@ -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);