diff options
Diffstat (limited to 'arch/sh/kernel/stacktrace.c')
-rw-r--r-- | arch/sh/kernel/stacktrace.c | 98 |
1 files changed, 72 insertions, 26 deletions
diff --git a/arch/sh/kernel/stacktrace.c b/arch/sh/kernel/stacktrace.c index 1a2a5eb76e41..c2e45c48409c 100644 --- a/arch/sh/kernel/stacktrace.c +++ b/arch/sh/kernel/stacktrace.c | |||
@@ -13,47 +13,93 @@ | |||
13 | #include <linux/stacktrace.h> | 13 | #include <linux/stacktrace.h> |
14 | #include <linux/thread_info.h> | 14 | #include <linux/thread_info.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <asm/unwinder.h> | ||
16 | #include <asm/ptrace.h> | 17 | #include <asm/ptrace.h> |
18 | #include <asm/stacktrace.h> | ||
19 | |||
20 | static void save_stack_warning(void *data, char *msg) | ||
21 | { | ||
22 | } | ||
23 | |||
24 | static void | ||
25 | save_stack_warning_symbol(void *data, char *msg, unsigned long symbol) | ||
26 | { | ||
27 | } | ||
28 | |||
29 | static int save_stack_stack(void *data, char *name) | ||
30 | { | ||
31 | return 0; | ||
32 | } | ||
17 | 33 | ||
18 | /* | 34 | /* |
19 | * Save stack-backtrace addresses into a stack_trace buffer. | 35 | * Save stack-backtrace addresses into a stack_trace buffer. |
20 | */ | 36 | */ |
37 | static void save_stack_address(void *data, unsigned long addr, int reliable) | ||
38 | { | ||
39 | struct stack_trace *trace = data; | ||
40 | |||
41 | if (!reliable) | ||
42 | return; | ||
43 | |||
44 | if (trace->skip > 0) { | ||
45 | trace->skip--; | ||
46 | return; | ||
47 | } | ||
48 | |||
49 | if (trace->nr_entries < trace->max_entries) | ||
50 | trace->entries[trace->nr_entries++] = addr; | ||
51 | } | ||
52 | |||
53 | static const struct stacktrace_ops save_stack_ops = { | ||
54 | .warning = save_stack_warning, | ||
55 | .warning_symbol = save_stack_warning_symbol, | ||
56 | .stack = save_stack_stack, | ||
57 | .address = save_stack_address, | ||
58 | }; | ||
59 | |||
21 | void save_stack_trace(struct stack_trace *trace) | 60 | void save_stack_trace(struct stack_trace *trace) |
22 | { | 61 | { |
23 | unsigned long *sp = (unsigned long *)current_stack_pointer; | 62 | unsigned long *sp = (unsigned long *)current_stack_pointer; |
24 | 63 | ||
25 | while (!kstack_end(sp)) { | 64 | unwind_stack(current, NULL, sp, &save_stack_ops, trace); |
26 | unsigned long addr = *sp++; | 65 | if (trace->nr_entries < trace->max_entries) |
27 | 66 | trace->entries[trace->nr_entries++] = ULONG_MAX; | |
28 | if (__kernel_text_address(addr)) { | ||
29 | if (trace->skip > 0) | ||
30 | trace->skip--; | ||
31 | else | ||
32 | trace->entries[trace->nr_entries++] = addr; | ||
33 | if (trace->nr_entries >= trace->max_entries) | ||
34 | break; | ||
35 | } | ||
36 | } | ||
37 | } | 67 | } |
38 | EXPORT_SYMBOL_GPL(save_stack_trace); | 68 | EXPORT_SYMBOL_GPL(save_stack_trace); |
39 | 69 | ||
70 | static void | ||
71 | save_stack_address_nosched(void *data, unsigned long addr, int reliable) | ||
72 | { | ||
73 | struct stack_trace *trace = (struct stack_trace *)data; | ||
74 | |||
75 | if (!reliable) | ||
76 | return; | ||
77 | |||
78 | if (in_sched_functions(addr)) | ||
79 | return; | ||
80 | |||
81 | if (trace->skip > 0) { | ||
82 | trace->skip--; | ||
83 | return; | ||
84 | } | ||
85 | |||
86 | if (trace->nr_entries < trace->max_entries) | ||
87 | trace->entries[trace->nr_entries++] = addr; | ||
88 | } | ||
89 | |||
90 | static const struct stacktrace_ops save_stack_ops_nosched = { | ||
91 | .warning = save_stack_warning, | ||
92 | .warning_symbol = save_stack_warning_symbol, | ||
93 | .stack = save_stack_stack, | ||
94 | .address = save_stack_address_nosched, | ||
95 | }; | ||
96 | |||
40 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) | 97 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) |
41 | { | 98 | { |
42 | unsigned long *sp = (unsigned long *)tsk->thread.sp; | 99 | unsigned long *sp = (unsigned long *)tsk->thread.sp; |
43 | 100 | ||
44 | while (!kstack_end(sp)) { | 101 | unwind_stack(current, NULL, sp, &save_stack_ops_nosched, trace); |
45 | unsigned long addr = *sp++; | 102 | if (trace->nr_entries < trace->max_entries) |
46 | 103 | trace->entries[trace->nr_entries++] = ULONG_MAX; | |
47 | if (__kernel_text_address(addr)) { | ||
48 | if (in_sched_functions(addr)) | ||
49 | break; | ||
50 | if (trace->skip > 0) | ||
51 | trace->skip--; | ||
52 | else | ||
53 | trace->entries[trace->nr_entries++] = addr; | ||
54 | if (trace->nr_entries >= trace->max_entries) | ||
55 | break; | ||
56 | } | ||
57 | } | ||
58 | } | 104 | } |
59 | EXPORT_SYMBOL_GPL(save_stack_trace_tsk); | 105 | EXPORT_SYMBOL_GPL(save_stack_trace_tsk); |