diff options
author | Heiko Carstens | 2023-10-30 16:50:47 +0100 |
---|---|---|
committer | Vasily Gorbik | 2023-11-05 22:34:57 +0100 |
commit | aa44433ac4ee2ae59b4b11e01eddb6241ae24ef5 (patch) | |
tree | 75fec215f6dd53e54fa2116e6d0a9f3240b3b1fb /arch | |
parent | 504b73d00a55a68c0d1bb0e7c12e56e5f908e906 (diff) |
s390: add USER_STACKTRACE support
Use the perf_callchain_user() code as blueprint to also add support for
USER_STACKTRACE. To describe how to use this cite the commit message of the
LoongArch implementation which came with commit 4d7bf939df08 ("LoongArch:
Add USER_STACKTRACE support"), but replace -fno-omit-frame-pointer option
with the s390 specific -mbackchain option:
====================================================================== To
get the best stacktrace output, you can compile your userspace programs
with frame pointers (at least glibc + the app you are tracing).
1, export "CC = gcc -mbackchain";
2, compile your programs with "CC";
3, use uprobe to get stacktrace output.
...
echo 'p:malloc /usr/lib64/libc.so.6:0x0a4704 size=%r2:u64' > uprobe_events
echo 'p:free /usr/lib64/libc.so.6:0x0a4d50 ptr=%r2:u64' >> uprobe_events
echo 'comm == "demo"' > ./events/uprobes/malloc/filter
echo 'comm == "demo"' > ./events/uprobes/free/filter
echo 1 > ./options/userstacktrace
echo 1 > ./options/sym-userobj
...
======================================================================
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/s390/Kconfig | 1 | ||||
-rw-r--r-- | arch/s390/kernel/stacktrace.c | 43 |
2 files changed, 44 insertions, 0 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index b0d67ac8695f..3bec98d20283 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -236,6 +236,7 @@ config S390 select THREAD_INFO_IN_TASK select TRACE_IRQFLAGS_SUPPORT select TTY + select USER_STACKTRACE_SUPPORT select VIRT_CPU_ACCOUNTING select ZONE_DMA # Note: keep the above list sorted alphabetically diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c index 0787010139f7..94f440e38303 100644 --- a/arch/s390/kernel/stacktrace.c +++ b/arch/s390/kernel/stacktrace.c @@ -6,9 +6,12 @@ */ #include <linux/stacktrace.h> +#include <linux/uaccess.h> +#include <linux/compat.h> #include <asm/stacktrace.h> #include <asm/unwind.h> #include <asm/kprobes.h> +#include <asm/ptrace.h> void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie, struct task_struct *task, struct pt_regs *regs) @@ -58,3 +61,43 @@ int arch_stack_walk_reliable(stack_trace_consume_fn consume_entry, return -EINVAL; return 0; } + +void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie, + const struct pt_regs *regs) +{ + struct stack_frame_user __user *sf; + unsigned long ip, sp; + bool first = true; + + if (is_compat_task()) + return; + if (!consume_entry(cookie, instruction_pointer(regs))) + return; + sf = (void __user *)user_stack_pointer(regs); + pagefault_disable(); + while (1) { + if (__get_user(sp, &sf->back_chain)) + break; + if (__get_user(ip, &sf->gprs[8])) + break; + if (ip & 0x1) { + /* + * If the instruction address is invalid, and this + * is the first stack frame, assume r14 has not + * been written to the stack yet. Otherwise exit. + */ + if (first && !(regs->gprs[14] & 0x1)) + ip = regs->gprs[14]; + else + break; + } + if (!consume_entry(cookie, ip)) + break; + /* Sanity check: ABI requires SP to be aligned 8 bytes. */ + if (!sp || sp & 0x7) + break; + sf = (void __user *)sp; + first = false; + } + pagefault_enable(); +} |