stacktrace.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #include <linux/export.h>
  2. #include <linux/sched.h>
  3. #include <linux/stacktrace.h>
  4. #include <asm/stacktrace.h>
  5. #if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND)
  6. /*
  7. * Unwind the current stack frame and store the new register values in the
  8. * structure passed as argument. Unwinding is equivalent to a function return,
  9. * hence the new PC value rather than LR should be used for backtrace.
  10. *
  11. * With framepointer enabled, a simple function prologue looks like this:
  12. * mov ip, sp
  13. * stmdb sp!, {fp, ip, lr, pc}
  14. * sub fp, ip, #4
  15. *
  16. * A simple function epilogue looks like this:
  17. * ldm sp, {fp, sp, pc}
  18. *
  19. * Note that with framepointer enabled, even the leaf functions have the same
  20. * prologue and epilogue, therefore we can ignore the LR value in this case.
  21. */
  22. int notrace unwind_frame(struct stackframe *frame)
  23. {
  24. unsigned long high, low;
  25. unsigned long fp = frame->fp;
  26. /* only go to a higher address on the stack */
  27. low = frame->sp;
  28. high = ALIGN(low, THREAD_SIZE);
  29. /* check current frame pointer is within bounds */
  30. if (fp < low + 12 || fp > high - 4)
  31. return -EINVAL;
  32. /* restore the registers from the stack frame */
  33. frame->fp = *(unsigned long *)(fp - 12);
  34. frame->sp = *(unsigned long *)(fp - 8);
  35. frame->pc = *(unsigned long *)(fp - 4);
  36. return 0;
  37. }
  38. #endif
  39. void notrace walk_stackframe(struct stackframe *frame,
  40. int (*fn)(struct stackframe *, void *), void *data)
  41. {
  42. while (1) {
  43. int ret;
  44. if (fn(frame, data))
  45. break;
  46. ret = unwind_frame(frame);
  47. if (ret < 0)
  48. break;
  49. }
  50. }
  51. EXPORT_SYMBOL(walk_stackframe);
  52. #ifdef CONFIG_STACKTRACE
  53. struct stack_trace_data {
  54. struct stack_trace *trace;
  55. unsigned int no_sched_functions;
  56. unsigned int skip;
  57. };
  58. static int save_trace(struct stackframe *frame, void *d)
  59. {
  60. struct stack_trace_data *data = d;
  61. struct stack_trace *trace = data->trace;
  62. unsigned long addr = frame->pc;
  63. if (data->no_sched_functions && in_sched_functions(addr))
  64. return 0;
  65. if (data->skip) {
  66. data->skip--;
  67. return 0;
  68. }
  69. trace->entries[trace->nr_entries++] = addr;
  70. return trace->nr_entries >= trace->max_entries;
  71. }
  72. /* This must be noinline to so that our skip calculation works correctly */
  73. static noinline void __save_stack_trace(struct task_struct *tsk,
  74. struct stack_trace *trace, unsigned int nosched)
  75. {
  76. struct stack_trace_data data;
  77. struct stackframe frame;
  78. data.trace = trace;
  79. data.skip = trace->skip;
  80. data.no_sched_functions = nosched;
  81. if (tsk != current) {
  82. #ifdef CONFIG_SMP
  83. /*
  84. * What guarantees do we have here that 'tsk' is not
  85. * running on another CPU? For now, ignore it as we
  86. * can't guarantee we won't explode.
  87. */
  88. if (trace->nr_entries < trace->max_entries)
  89. trace->entries[trace->nr_entries++] = ULONG_MAX;
  90. return;
  91. #else
  92. frame.fp = thread_saved_fp(tsk);
  93. frame.sp = thread_saved_sp(tsk);
  94. frame.lr = 0; /* recovered from the stack */
  95. frame.pc = thread_saved_pc(tsk);
  96. #endif
  97. } else {
  98. /* We don't want this function nor the caller */
  99. data.skip += 2;
  100. frame.fp = (unsigned long)__builtin_frame_address(0);
  101. frame.sp = current_stack_pointer;
  102. frame.lr = (unsigned long)__builtin_return_address(0);
  103. frame.pc = (unsigned long)__save_stack_trace;
  104. }
  105. walk_stackframe(&frame, save_trace, &data);
  106. if (trace->nr_entries < trace->max_entries)
  107. trace->entries[trace->nr_entries++] = ULONG_MAX;
  108. }
  109. void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
  110. {
  111. __save_stack_trace(tsk, trace, 1);
  112. }
  113. void save_stack_trace(struct stack_trace *trace)
  114. {
  115. __save_stack_trace(current, trace, 0);
  116. }
  117. EXPORT_SYMBOL_GPL(save_stack_trace);
  118. #endif