stacktrace.c 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. #include <linux/sched.h>
  2. #include <linux/stacktrace.h>
  3. #include <linux/thread_info.h>
  4. #include <linux/module.h>
  5. #include <asm/ptrace.h>
  6. #include <asm/stacktrace.h>
  7. #include "kstack.h"
  8. static void __save_stack_trace(struct thread_info *tp,
  9. struct stack_trace *trace,
  10. bool skip_sched)
  11. {
  12. unsigned long ksp, fp;
  13. if (tp == current_thread_info()) {
  14. stack_trace_flush();
  15. __asm__ __volatile__("mov %%fp, %0" : "=r" (ksp));
  16. } else {
  17. ksp = tp->ksp;
  18. }
  19. fp = ksp + STACK_BIAS;
  20. do {
  21. struct sparc_stackf *sf;
  22. struct pt_regs *regs;
  23. unsigned long pc;
  24. if (!kstack_valid(tp, fp))
  25. break;
  26. sf = (struct sparc_stackf *) fp;
  27. regs = (struct pt_regs *) (sf + 1);
  28. if (kstack_is_trap_frame(tp, regs)) {
  29. if (!(regs->tstate & TSTATE_PRIV))
  30. break;
  31. pc = regs->tpc;
  32. fp = regs->u_regs[UREG_I6] + STACK_BIAS;
  33. } else {
  34. pc = sf->callers_pc;
  35. fp = (unsigned long)sf->fp + STACK_BIAS;
  36. }
  37. if (trace->skip > 0)
  38. trace->skip--;
  39. else if (!skip_sched || !in_sched_functions(pc))
  40. trace->entries[trace->nr_entries++] = pc;
  41. } while (trace->nr_entries < trace->max_entries);
  42. }
  43. void save_stack_trace(struct stack_trace *trace)
  44. {
  45. __save_stack_trace(current_thread_info(), trace, false);
  46. }
  47. EXPORT_SYMBOL_GPL(save_stack_trace);
  48. void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
  49. {
  50. struct thread_info *tp = task_thread_info(tsk);
  51. __save_stack_trace(tp, trace, true);
  52. }
  53. EXPORT_SYMBOL_GPL(save_stack_trace_tsk);