Browse Source

CRIS: add STACKTRACE_SUPPORT

Add stacktrace support, which is required for lockdep and tracing.  The
stack tracing simply looks at all kernel text symbols found on the
stack, similar to the trap stack dumping code, which can also be
converted to use this.

Signed-off-by: Rabin Vincent <rabin@rab.in>
Signed-off-by: Jesper Nilsson <jesper.nilsson@axis.com>
Rabin Vincent 10 years ago
parent
commit
aa6f4d2b65

+ 3 - 0
arch/cris/Kconfig

@@ -40,6 +40,9 @@ config TRACE_IRQFLAGS_SUPPORT
 	depends on ETRAX_ARCH_V32
 	def_bool y
 
+config STACKTRACE_SUPPORT
+	def_bool y
+
 config CRIS
 	bool
 	default y

+ 8 - 0
arch/cris/include/asm/stacktrace.h

@@ -0,0 +1,8 @@
+#ifndef __CRIS_STACKTRACE_H
+#define __CRIS_STACKTRACE_H
+
+void walk_stackframe(unsigned long sp,
+		     int (*fn)(unsigned long addr, void *data),
+		     void *data);
+
+#endif

+ 1 - 0
arch/cris/kernel/Makefile

@@ -8,6 +8,7 @@ extra-y	:= vmlinux.lds
 
 obj-y   := process.o traps.o irq.o ptrace.o setup.o time.o sys_cris.o
 obj-y += devicetree.o
+obj-y += stacktrace.o
 
 obj-$(CONFIG_MODULES)    += crisksyms.o
 obj-$(CONFIG_MODULES)	 += module.o

+ 76 - 0
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 */