diff options
author | Lachlan McIlroy <lachlan@redback.melbourne.sgi.com> | 2009-01-08 13:22:55 +1100 |
---|---|---|
committer | Lachlan McIlroy <lachlan@redback.melbourne.sgi.com> | 2009-01-08 13:22:55 +1100 |
commit | 6206aa8b2b9a45b4cf3ee31b7209b014be349fd9 (patch) | |
tree | 72c4223a2cc21bf055948eadb3b314ed0568ae9d /arch/sparc/kernel/stacktrace.c | |
parent | 95f8e302c04c0b0c6de35ab399a5551605eeb006 (diff) | |
parent | 9e42d0cf5020aaf217433cad1a224745241d212a (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'arch/sparc/kernel/stacktrace.c')
-rw-r--r-- | arch/sparc/kernel/stacktrace.c | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/arch/sparc/kernel/stacktrace.c b/arch/sparc/kernel/stacktrace.c new file mode 100644 index 00000000000..acb12f67375 --- /dev/null +++ b/arch/sparc/kernel/stacktrace.c @@ -0,0 +1,64 @@ +#include <linux/sched.h> +#include <linux/stacktrace.h> +#include <linux/thread_info.h> +#include <linux/module.h> +#include <asm/ptrace.h> +#include <asm/stacktrace.h> + +#include "kstack.h" + +static void __save_stack_trace(struct thread_info *tp, + struct stack_trace *trace, + bool skip_sched) +{ + unsigned long ksp, fp; + + if (tp == current_thread_info()) { + stack_trace_flush(); + __asm__ __volatile__("mov %%fp, %0" : "=r" (ksp)); + } else { + ksp = tp->ksp; + } + + fp = ksp + STACK_BIAS; + do { + struct sparc_stackf *sf; + struct pt_regs *regs; + unsigned long pc; + + if (!kstack_valid(tp, fp)) + break; + + sf = (struct sparc_stackf *) fp; + regs = (struct pt_regs *) (sf + 1); + + if (kstack_is_trap_frame(tp, regs)) { + if (!(regs->tstate & TSTATE_PRIV)) + break; + pc = regs->tpc; + fp = regs->u_regs[UREG_I6] + STACK_BIAS; + } else { + pc = sf->callers_pc; + fp = (unsigned long)sf->fp + STACK_BIAS; + } + + if (trace->skip > 0) + trace->skip--; + else if (!skip_sched || !in_sched_functions(pc)) + trace->entries[trace->nr_entries++] = pc; + } while (trace->nr_entries < trace->max_entries); +} + +void save_stack_trace(struct stack_trace *trace) +{ + __save_stack_trace(current_thread_info(), trace, false); +} +EXPORT_SYMBOL_GPL(save_stack_trace); + +void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) +{ + struct thread_info *tp = task_thread_info(tsk); + + __save_stack_trace(tp, trace, true); +} +EXPORT_SYMBOL_GPL(save_stack_trace_tsk); |