1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * arch/sh/kernel/stacktrace.c |
4 | * |
5 | * Stack trace management functions |
6 | * |
7 | * Copyright (C) 2006 - 2008 Paul Mundt |
8 | */ |
9 | #include <linux/sched.h> |
10 | #include <linux/sched/debug.h> |
11 | #include <linux/stacktrace.h> |
12 | #include <linux/thread_info.h> |
13 | #include <linux/module.h> |
14 | #include <asm/unwinder.h> |
15 | #include <asm/ptrace.h> |
16 | #include <asm/stacktrace.h> |
17 | |
18 | /* |
19 | * Save stack-backtrace addresses into a stack_trace buffer. |
20 | */ |
21 | static void save_stack_address(void *data, unsigned long addr, int reliable) |
22 | { |
23 | struct stack_trace *trace = data; |
24 | |
25 | if (!reliable) |
26 | return; |
27 | |
28 | if (trace->skip > 0) { |
29 | trace->skip--; |
30 | return; |
31 | } |
32 | |
33 | if (trace->nr_entries < trace->max_entries) |
34 | trace->entries[trace->nr_entries++] = addr; |
35 | } |
36 | |
37 | static const struct stacktrace_ops save_stack_ops = { |
38 | .address = save_stack_address, |
39 | }; |
40 | |
41 | void save_stack_trace(struct stack_trace *trace) |
42 | { |
43 | unsigned long *sp = (unsigned long *)current_stack_pointer; |
44 | |
45 | unwind_stack(current, NULL, sp, &save_stack_ops, trace); |
46 | } |
47 | EXPORT_SYMBOL_GPL(save_stack_trace); |
48 | |
49 | static void |
50 | save_stack_address_nosched(void *data, unsigned long addr, int reliable) |
51 | { |
52 | struct stack_trace *trace = (struct stack_trace *)data; |
53 | |
54 | if (!reliable) |
55 | return; |
56 | |
57 | if (in_sched_functions(addr)) |
58 | return; |
59 | |
60 | if (trace->skip > 0) { |
61 | trace->skip--; |
62 | return; |
63 | } |
64 | |
65 | if (trace->nr_entries < trace->max_entries) |
66 | trace->entries[trace->nr_entries++] = addr; |
67 | } |
68 | |
69 | static const struct stacktrace_ops save_stack_ops_nosched = { |
70 | .address = save_stack_address_nosched, |
71 | }; |
72 | |
73 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) |
74 | { |
75 | unsigned long *sp = (unsigned long *)tsk->thread.sp; |
76 | |
77 | unwind_stack(current, NULL, sp, &save_stack_ops_nosched, trace); |
78 | } |
79 | EXPORT_SYMBOL_GPL(save_stack_trace_tsk); |
80 | |