stacktrace.c 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. #include <linux/sched.h>
  2. #include <linux/stacktrace.h>
  3. #include <linux/thread_info.h>
  4. #include <linux/ftrace.h>
  5. #include <linux/export.h>
  6. #include <asm/ptrace.h>
  7. #include <asm/stacktrace.h>
  8. #include "kstack.h"
  9. static void __save_stack_trace(struct thread_info *tp,
  10. struct stack_trace *trace,
  11. bool skip_sched)
  12. {
  13. unsigned long ksp, fp;
  14. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  15. struct task_struct *t;
  16. int graph = 0;
  17. #endif
  18. if (tp == current_thread_info()) {
  19. stack_trace_flush();
  20. __asm__ __volatile__("mov %%fp, %0" : "=r" (ksp));
  21. } else {
  22. ksp = tp->ksp;
  23. }
  24. fp = ksp + STACK_BIAS;
  25. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  26. t = tp->task;
  27. #endif
  28. do {
  29. struct sparc_stackf *sf;
  30. struct pt_regs *regs;
  31. unsigned long pc;
  32. if (!kstack_valid(tp, fp))
  33. break;
  34. sf = (struct sparc_stackf *) fp;
  35. regs = (struct pt_regs *) (sf + 1);
  36. if (kstack_is_trap_frame(tp, regs)) {
  37. if (!(regs->tstate & TSTATE_PRIV))
  38. break;
  39. pc = regs->tpc;
  40. fp = regs->u_regs[UREG_I6] + STACK_BIAS;
  41. } else {
  42. pc = sf->callers_pc;
  43. fp = (unsigned long)sf->fp + STACK_BIAS;
  44. }
  45. if (trace->skip > 0)
  46. trace->skip--;
  47. else if (!skip_sched || !in_sched_functions(pc)) {
  48. trace->entries[trace->nr_entries++] = pc;
  49. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  50. if ((pc + 8UL) == (unsigned long) &return_to_handler) {
  51. int index = t->curr_ret_stack;
  52. if (t->ret_stack && index >= graph) {
  53. pc = t->ret_stack[index - graph].ret;
  54. if (trace->nr_entries <
  55. trace->max_entries)
  56. trace->entries[trace->nr_entries++] = pc;
  57. graph++;
  58. }
  59. }
  60. #endif
  61. }
  62. } while (trace->nr_entries < trace->max_entries);
  63. }
  64. void save_stack_trace(struct stack_trace *trace)
  65. {
  66. __save_stack_trace(current_thread_info(), trace, false);
  67. }
  68. EXPORT_SYMBOL_GPL(save_stack_trace);
  69. void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
  70. {
  71. struct thread_info *tp = task_thread_info(tsk);
  72. __save_stack_trace(tp, trace, true);
  73. }
  74. EXPORT_SYMBOL_GPL(save_stack_trace_tsk);