aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/kernel/stacktrace.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-06 13:20:10 -0700
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-06 13:20:10 -0700
commitc6799ade4ae04b53a5f677e5289116155ff01574 (patch)
tree3601b5e2387e39d62c207e4268c6cc5c68f2a364 /arch/arm/kernel/stacktrace.c
parentb7405e16435f710edfae6ba32bef4ca20d3de145 (diff)
parent5cd47155155a32e5b944ac9fc3f3dc578e429aa0 (diff)
Merge branch 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm: (82 commits) [ARM] Add comments marking in-use ptrace numbers [ARM] Move syscall saving out of the way of utrace [ARM] 4360/1: S3C24XX: regs-udc.h remove unused macro [ARM] 4358/1: S3C24XX: mach-qt2410.c: remove linux/mmc/protocol.h header [ARM] mm 10: allow memory type to be specified with ioremap [ARM] mm 9: add additional device memory types [ARM] mm 8: define mem_types table L1 bit 4 to be for ARMv6 [ARM] iop: add missing parens in macro [ARM] mm 7: remove duplicated __ioremap() prototypes ARM: OMAP: fix OMAP1 mpuio suspend/resume oops ARM: OMAP: MPUIO wake updates ARM: OMAP: speed up gpio irq handling ARM: OMAP: plat-omap changes for 2430 SDP ARM: OMAP: gpio object shrinkage, cleanup ARM: OMAP: /sys/kernel/debug/omap_gpio ARM: OMAP: Implement workaround for GPIO wakeup bug in OMAP2420 silicon ARM: OMAP: Enable 24xx GPIO autoidling [ARM] 4318/2: DSM-G600 Board Support [ARM] 4227/1: minor head.S fixups [ARM] 4328/1: Move i.MX UART regs to driver ...
Diffstat (limited to 'arch/arm/kernel/stacktrace.c')
-rw-r--r--arch/arm/kernel/stacktrace.c73
1 files changed, 73 insertions, 0 deletions
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 <linux/sched.h>
+#include <linux/stacktrace.h>
+
+#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