Thomas Gleixner | 457c899 | 2019-05-19 13:08:55 +0100 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0-only |
Helge Deller | 548f117 | 2009-02-06 21:50:39 +0100 | [diff] [blame] | 2 | /* |
| 3 | * Stack trace management functions |
| 4 | * |
Helge Deller | aeb1e83 | 2021-05-04 14:49:14 +0200 | [diff] [blame] | 5 | * Copyright (C) 2009-2021 Helge Deller <deller@gmx.de> |
Helge Deller | 548f117 | 2009-02-06 21:50:39 +0100 | [diff] [blame] | 6 | * based on arch/x86/kernel/stacktrace.c by Ingo Molnar <mingo@redhat.com> |
| 7 | * and parisc unwind functions by Randolph Chung <tausq@debian.org> |
| 8 | * |
| 9 | * TODO: Userspace stacktrace (CONFIG_USER_STACKTRACE_SUPPORT) |
| 10 | */ |
Helge Deller | f0d1cfa | 2021-11-09 22:47:24 +0100 | [diff] [blame] | 11 | #include <linux/kernel.h> |
Helge Deller | 548f117 | 2009-02-06 21:50:39 +0100 | [diff] [blame] | 12 | #include <linux/stacktrace.h> |
| 13 | |
| 14 | #include <asm/unwind.h> |
| 15 | |
Helge Deller | aeb1e83 | 2021-05-04 14:49:14 +0200 | [diff] [blame] | 16 | static void notrace walk_stackframe(struct task_struct *task, |
| 17 | struct pt_regs *regs, bool (*fn)(void *, unsigned long), void *cookie) |
Helge Deller | 548f117 | 2009-02-06 21:50:39 +0100 | [diff] [blame] | 18 | { |
| 19 | struct unwind_frame_info info; |
| 20 | |
Helge Deller | 9e0d5c4 | 2018-08-17 17:00:08 +0200 | [diff] [blame] | 21 | unwind_frame_init_task(&info, task, NULL); |
Helge Deller | aeb1e83 | 2021-05-04 14:49:14 +0200 | [diff] [blame] | 22 | while (1) { |
Helge Deller | 548f117 | 2009-02-06 21:50:39 +0100 | [diff] [blame] | 23 | if (unwind_once(&info) < 0 || info.ip == 0) |
| 24 | break; |
| 25 | |
| 26 | if (__kernel_text_address(info.ip)) |
Helge Deller | aeb1e83 | 2021-05-04 14:49:14 +0200 | [diff] [blame] | 27 | if (!fn(cookie, info.ip)) |
| 28 | break; |
Helge Deller | 548f117 | 2009-02-06 21:50:39 +0100 | [diff] [blame] | 29 | } |
| 30 | } |
| 31 | |
Helge Deller | aeb1e83 | 2021-05-04 14:49:14 +0200 | [diff] [blame] | 32 | void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie, |
| 33 | struct task_struct *task, struct pt_regs *regs) |
Helge Deller | 548f117 | 2009-02-06 21:50:39 +0100 | [diff] [blame] | 34 | { |
Helge Deller | aeb1e83 | 2021-05-04 14:49:14 +0200 | [diff] [blame] | 35 | walk_stackframe(task, regs, consume_entry, cookie); |
Helge Deller | 548f117 | 2009-02-06 21:50:39 +0100 | [diff] [blame] | 36 | } |
Helge Deller | 548f117 | 2009-02-06 21:50:39 +0100 | [diff] [blame] | 37 | |
Helge Deller | aeb1e83 | 2021-05-04 14:49:14 +0200 | [diff] [blame] | 38 | int arch_stack_walk_reliable(stack_trace_consume_fn consume_entry, void *cookie, |
| 39 | struct task_struct *task) |
Helge Deller | 548f117 | 2009-02-06 21:50:39 +0100 | [diff] [blame] | 40 | { |
Helge Deller | aeb1e83 | 2021-05-04 14:49:14 +0200 | [diff] [blame] | 41 | walk_stackframe(task, NULL, consume_entry, cookie); |
| 42 | return 1; |
Helge Deller | 548f117 | 2009-02-06 21:50:39 +0100 | [diff] [blame] | 43 | } |