From f16fb1ecc5a1cb2f7cc595179d1fe55e711e599f Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 28 Apr 2007 09:59:37 +0100 Subject: [ARM] Add stacktrace support and make oprofile use it Add support for stacktrace. Use the new stacktrace code with oprofile instead of it's version; there's no point having multiple versions of stacktracing in the kernel. Signed-off-by: Russell King --- arch/arm/kernel/Makefile | 4 +-- arch/arm/kernel/stacktrace.c | 73 ++++++++++++++++++++++++++++++++++++++++++++ arch/arm/kernel/stacktrace.h | 9 ++++++ 3 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 arch/arm/kernel/stacktrace.c create mode 100644 arch/arm/kernel/stacktrace.h (limited to 'arch/arm/kernel') diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index bb28087bf81..593b56509f4 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -7,8 +7,8 @@ AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) # Object file lists. obj-y := compat.o entry-armv.o entry-common.o irq.o \ - process.o ptrace.o semaphore.o setup.o signal.o sys_arm.o \ - time.o traps.o + process.o ptrace.o semaphore.o setup.o signal.o \ + sys_arm.o stacktrace.o time.o traps.o obj-$(CONFIG_ISA_DMA_API) += dma.o obj-$(CONFIG_ARCH_ACORN) += ecard.o diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c new file mode 100644 index 00000000000..77ef35efaa8 --- /dev/null +++ b/arch/arm/kernel/stacktrace.c @@ -0,0 +1,73 @@ +#include +#include + +#include "stacktrace.h" + +int walk_stackframe(unsigned long fp, unsigned long low, unsigned long high, + int (*fn)(struct stackframe *, void *), void *data) +{ + struct stackframe *frame; + + do { + /* + * Check current frame pointer is within bounds + */ + if ((fp - 12) < low || fp + 4 >= high) + break; + + frame = (struct stackframe *)(fp - 12); + + if (fn(frame, data)) + break; + + /* + * Update the low bound - the next frame must always + * be at a higher address than the current frame. + */ + low = fp + 4; + fp = frame->fp; + } while (fp); + + return 0; +} + +#ifdef CONFIG_STACKTRACE +struct stack_trace_data { + struct stack_trace *trace; + unsigned int skip; +}; + +static int save_trace(struct stackframe *frame, void *d) +{ + struct stack_trace_data *data = d; + struct stack_trace *trace = data->trace; + + if (data->skip) { + data->skip--; + return 0; + } + + trace->entries[trace->nr_entries++] = frame->lr; + + return trace->nr_entries >= trace->max_entries; +} + +void save_stack_trace(struct stack_trace *trace, struct task_struct *task) +{ + struct stack_trace_data data; + unsigned long fp, base; + + data.trace = trace; + data.skip = trace->skip; + + if (task) { + base = (unsigned long)task_stack_page(task); + fp = 0; /* FIXME */ + } else { + base = (unsigned long)task_stack_page(current); + asm("mov %0, fp" : "=r" (fp)); + } + + walk_stackframe(fp, base, base + THREAD_SIZE, save_trace, &data); +} +#endif diff --git a/arch/arm/kernel/stacktrace.h b/arch/arm/kernel/stacktrace.h new file mode 100644 index 00000000000..e9fd20cb566 --- /dev/null +++ b/arch/arm/kernel/stacktrace.h @@ -0,0 +1,9 @@ +struct stackframe { + unsigned long fp; + unsigned long sp; + unsigned long lr; + unsigned long pc; +}; + +int walk_stackframe(unsigned long fp, unsigned long low, unsigned long high, + int (*fn)(struct stackframe *, void *), void *data); -- cgit v1.2.3