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>
This commit is contained in:
Rabin Vincent 2015-05-14 18:19:03 +02:00 committed by Jesper Nilsson
parent 3fffa23ee0
commit aa6f4d2b65
4 changed files with 88 additions and 0 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 */