#include <linux/stacktrace.h>
 
 #include <asm/stacktrace.h>
+#include <asm/traps.h>
 
 #if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND)
 /*
 #ifdef CONFIG_STACKTRACE
 struct stack_trace_data {
        struct stack_trace *trace;
+       unsigned long last_pc;
        unsigned int no_sched_functions;
        unsigned int skip;
 };
 {
        struct stack_trace_data *data = d;
        struct stack_trace *trace = data->trace;
+       struct pt_regs *regs;
        unsigned long addr = frame->pc;
 
        if (data->no_sched_functions && in_sched_functions(addr))
 
        trace->entries[trace->nr_entries++] = addr;
 
+       if (trace->nr_entries >= trace->max_entries)
+               return 1;
+
+       /*
+        * in_exception_text() is designed to test if the PC is one of
+        * the functions which has an exception stack above it, but
+        * unfortunately what is in frame->pc is the return LR value,
+        * not the saved PC value.  So, we need to track the previous
+        * frame PC value when doing this.
+        */
+       addr = data->last_pc;
+       data->last_pc = frame->pc;
+       if (!in_exception_text(addr))
+               return 0;
+
+       regs = (struct pt_regs *)frame->sp;
+
+       trace->entries[trace->nr_entries++] = regs->ARM_pc;
+
        return trace->nr_entries >= trace->max_entries;
 }
 
        struct stackframe frame;
 
        data.trace = trace;
+       data.last_pc = ULONG_MAX;
        data.skip = trace->skip;
        data.no_sched_functions = nosched;