stacktrace.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Stack trace management functions
  4. *
  5. * Copyright (C) 2006 Atsushi Nemoto <[email protected]>
  6. */
  7. #include <linux/sched.h>
  8. #include <linux/sched/debug.h>
  9. #include <linux/sched/task_stack.h>
  10. #include <linux/stacktrace.h>
  11. #include <linux/export.h>
  12. #include <asm/stacktrace.h>
  13. /*
  14. * Save stack-backtrace addresses into a stack_trace buffer:
  15. */
  16. static void save_raw_context_stack(struct stack_trace *trace,
  17. unsigned long reg29, int savesched)
  18. {
  19. unsigned long *sp = (unsigned long *)reg29;
  20. unsigned long addr;
  21. while (!kstack_end(sp)) {
  22. addr = *sp++;
  23. if (__kernel_text_address(addr) &&
  24. (savesched || !in_sched_functions(addr))) {
  25. if (trace->skip > 0)
  26. trace->skip--;
  27. else
  28. trace->entries[trace->nr_entries++] = addr;
  29. if (trace->nr_entries >= trace->max_entries)
  30. break;
  31. }
  32. }
  33. }
  34. static void save_context_stack(struct stack_trace *trace,
  35. struct task_struct *tsk, struct pt_regs *regs, int savesched)
  36. {
  37. unsigned long sp = regs->regs[29];
  38. #ifdef CONFIG_KALLSYMS
  39. unsigned long ra = regs->regs[31];
  40. unsigned long pc = regs->cp0_epc;
  41. if (raw_show_trace || !__kernel_text_address(pc)) {
  42. unsigned long stack_page =
  43. (unsigned long)task_stack_page(tsk);
  44. if (stack_page && sp >= stack_page &&
  45. sp <= stack_page + THREAD_SIZE - 32)
  46. save_raw_context_stack(trace, sp, savesched);
  47. return;
  48. }
  49. do {
  50. if (savesched || !in_sched_functions(pc)) {
  51. if (trace->skip > 0)
  52. trace->skip--;
  53. else
  54. trace->entries[trace->nr_entries++] = pc;
  55. if (trace->nr_entries >= trace->max_entries)
  56. break;
  57. }
  58. pc = unwind_stack(tsk, &sp, pc, &ra);
  59. } while (pc);
  60. #else
  61. save_raw_context_stack(trace, sp, savesched);
  62. #endif
  63. }
  64. /*
  65. * Save stack-backtrace addresses into a stack_trace buffer.
  66. */
  67. void save_stack_trace(struct stack_trace *trace)
  68. {
  69. save_stack_trace_tsk(current, trace);
  70. }
  71. EXPORT_SYMBOL_GPL(save_stack_trace);
  72. void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
  73. {
  74. struct pt_regs dummyregs;
  75. struct pt_regs *regs = &dummyregs;
  76. WARN_ON(trace->nr_entries || !trace->max_entries);
  77. if (tsk != current) {
  78. regs->regs[29] = tsk->thread.reg29;
  79. regs->regs[31] = 0;
  80. regs->cp0_epc = tsk->thread.reg31;
  81. } else
  82. prepare_frametrace(regs);
  83. save_context_stack(trace, tsk, regs, tsk == current);
  84. }
  85. EXPORT_SYMBOL_GPL(save_stack_trace_tsk);