stacktrace.c 2.0 KB

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