]>
Commit | Line | Data |
---|---|---|
afbfb52e PM |
1 | /* |
2 | * arch/sh/kernel/stacktrace.c | |
3 | * | |
4 | * Stack trace management functions | |
5 | * | |
5a89f1ad | 6 | * Copyright (C) 2006 - 2008 Paul Mundt |
afbfb52e PM |
7 | * |
8 | * This file is subject to the terms and conditions of the GNU General Public | |
9 | * License. See the file "COPYING" in the main directory of this archive | |
10 | * for more details. | |
11 | */ | |
12 | #include <linux/sched.h> | |
b17b0153 | 13 | #include <linux/sched/debug.h> |
afbfb52e PM |
14 | #include <linux/stacktrace.h> |
15 | #include <linux/thread_info.h> | |
8b95d917 | 16 | #include <linux/module.h> |
0eff9f66 | 17 | #include <asm/unwinder.h> |
afbfb52e | 18 | #include <asm/ptrace.h> |
4e14dfc7 MF |
19 | #include <asm/stacktrace.h> |
20 | ||
4e14dfc7 MF |
21 | static int save_stack_stack(void *data, char *name) |
22 | { | |
23 | return 0; | |
24 | } | |
afbfb52e PM |
25 | |
26 | /* | |
27 | * Save stack-backtrace addresses into a stack_trace buffer. | |
28 | */ | |
4e14dfc7 MF |
29 | static void save_stack_address(void *data, unsigned long addr, int reliable) |
30 | { | |
31 | struct stack_trace *trace = data; | |
32 | ||
48e4d460 PM |
33 | if (!reliable) |
34 | return; | |
35 | ||
4e14dfc7 MF |
36 | if (trace->skip > 0) { |
37 | trace->skip--; | |
38 | return; | |
39 | } | |
40 | ||
41 | if (trace->nr_entries < trace->max_entries) | |
42 | trace->entries[trace->nr_entries++] = addr; | |
43 | } | |
44 | ||
45 | static const struct stacktrace_ops save_stack_ops = { | |
4e14dfc7 MF |
46 | .stack = save_stack_stack, |
47 | .address = save_stack_address, | |
48 | }; | |
49 | ||
a3cf4ea8 | 50 | void save_stack_trace(struct stack_trace *trace) |
afbfb52e | 51 | { |
ab1b6f03 | 52 | unsigned long *sp = (unsigned long *)current_stack_pointer; |
afbfb52e | 53 | |
0eff9f66 | 54 | unwind_stack(current, NULL, sp, &save_stack_ops, trace); |
606b4c99 PM |
55 | if (trace->nr_entries < trace->max_entries) |
56 | trace->entries[trace->nr_entries++] = ULONG_MAX; | |
afbfb52e | 57 | } |
7b4c9505 | 58 | EXPORT_SYMBOL_GPL(save_stack_trace); |
5a89f1ad | 59 | |
4e14dfc7 MF |
60 | static void |
61 | save_stack_address_nosched(void *data, unsigned long addr, int reliable) | |
62 | { | |
63 | struct stack_trace *trace = (struct stack_trace *)data; | |
64 | ||
48e4d460 PM |
65 | if (!reliable) |
66 | return; | |
67 | ||
4e14dfc7 MF |
68 | if (in_sched_functions(addr)) |
69 | return; | |
70 | ||
71 | if (trace->skip > 0) { | |
72 | trace->skip--; | |
73 | return; | |
74 | } | |
75 | ||
76 | if (trace->nr_entries < trace->max_entries) | |
77 | trace->entries[trace->nr_entries++] = addr; | |
78 | } | |
79 | ||
80 | static const struct stacktrace_ops save_stack_ops_nosched = { | |
4e14dfc7 MF |
81 | .stack = save_stack_stack, |
82 | .address = save_stack_address_nosched, | |
83 | }; | |
84 | ||
5a89f1ad PM |
85 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) |
86 | { | |
87 | unsigned long *sp = (unsigned long *)tsk->thread.sp; | |
88 | ||
0eff9f66 | 89 | unwind_stack(current, NULL, sp, &save_stack_ops_nosched, trace); |
606b4c99 PM |
90 | if (trace->nr_entries < trace->max_entries) |
91 | trace->entries[trace->nr_entries++] = ULONG_MAX; | |
5a89f1ad PM |
92 | } |
93 | EXPORT_SYMBOL_GPL(save_stack_trace_tsk); |