summaryrefslogtreecommitdiff
path: root/arch/cris/kernel/stacktrace.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2015-10-14 16:05:18 +0200
committerIngo Molnar <mingo@kernel.org>2015-10-14 16:05:18 +0200
commitc7d77a7980e434c3af17de19e3348157f9b9ccce (patch)
treeb32c5988ce8239b80c83e94c22d68f5eb0fb84da /arch/cris/kernel/stacktrace.c
parent0ce423b6492a02be11662bfaa837dd16945aad3e (diff)
parent8a53554e12e98d1759205afd7b8e9e2ea0936f48 (diff)
Merge branch 'x86/urgent' into core/efi, to pick up a pending EFI fix
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/cris/kernel/stacktrace.c')
-rw-r--r--arch/cris/kernel/stacktrace.c76
1 files changed, 76 insertions, 0 deletions
diff --git a/arch/cris/kernel/stacktrace.c b/arch/cris/kernel/stacktrace.c
new file mode 100644
index 000000000000..99838c74456d
--- /dev/null
+++ b/arch/cris/kernel/stacktrace.c
@@ -0,0 +1,76 @@
+#include <linux/sched.h>
+#include <linux/stacktrace.h>
+#include <linux/stacktrace.h>
+#include <asm/stacktrace.h>
+
+void walk_stackframe(unsigned long sp,
+ int (*fn)(unsigned long addr, void *data),
+ void *data)
+{
+ unsigned long high = ALIGN(sp, THREAD_SIZE);
+
+ for (; sp <= high - 4; sp += 4) {
+ unsigned long addr = *(unsigned long *) sp;
+
+ if (!kernel_text_address(addr))
+ continue;
+
+ if (fn(addr, data))
+ break;
+ }
+}
+
+struct stack_trace_data {
+ struct stack_trace *trace;
+ unsigned int no_sched_functions;
+ unsigned int skip;
+};
+
+#ifdef CONFIG_STACKTRACE
+
+static int save_trace(unsigned long addr, void *d)
+{
+ struct stack_trace_data *data = d;
+ struct stack_trace *trace = data->trace;
+
+ if (data->no_sched_functions && in_sched_functions(addr))
+ return 0;
+
+ if (data->skip) {
+ data->skip--;
+ return 0;
+ }
+
+ trace->entries[trace->nr_entries++] = addr;
+
+ return trace->nr_entries >= trace->max_entries;
+}
+
+void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
+{
+ struct stack_trace_data data;
+ unsigned long sp;
+
+ data.trace = trace;
+ data.skip = trace->skip;
+
+ if (tsk != current) {
+ data.no_sched_functions = 1;
+ sp = tsk->thread.ksp;
+ } else {
+ data.no_sched_functions = 0;
+ sp = rdsp();
+ }
+
+ walk_stackframe(sp, save_trace, &data);
+ if (trace->nr_entries < trace->max_entries)
+ trace->entries[trace->nr_entries++] = ULONG_MAX;
+}
+
+void save_stack_trace(struct stack_trace *trace)
+{
+ save_stack_trace_tsk(current, trace);
+}
+EXPORT_SYMBOL_GPL(save_stack_trace);
+
+#endif /* CONFIG_STACKTRACE */