Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aa6f4d2b authored by Rabin Vincent's avatar Rabin Vincent Committed by Jesper Nilsson
Browse files

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: default avatarRabin Vincent <rabin@rab.in>
Signed-off-by: default avatarJesper Nilsson <jesper.nilsson@axis.com>
parent 3fffa23e
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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
Original line number Diff line number Diff line
#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
Original line number Diff line number Diff line
@@ -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
Original line number Diff line number Diff line
#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 */