dumpstack.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 1991, 1992 Linus Torvalds
  4. * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
  5. * Copyright (C) 2009 Matt Fleming
  6. * Copyright (C) 2002 - 2012 Paul Mundt
  7. */
  8. #include <linux/kallsyms.h>
  9. #include <linux/ftrace.h>
  10. #include <linux/debug_locks.h>
  11. #include <linux/sched/debug.h>
  12. #include <linux/sched/task_stack.h>
  13. #include <linux/kdebug.h>
  14. #include <linux/export.h>
  15. #include <linux/uaccess.h>
  16. #include <asm/unwinder.h>
  17. #include <asm/stacktrace.h>
  18. void dump_mem(const char *str, const char *loglvl, unsigned long bottom,
  19. unsigned long top)
  20. {
  21. unsigned long p;
  22. int i;
  23. printk("%s%s(0x%08lx to 0x%08lx)\n", loglvl, str, bottom, top);
  24. for (p = bottom & ~31; p < top; ) {
  25. printk("%s%04lx: ", loglvl, p & 0xffff);
  26. for (i = 0; i < 8; i++, p += 4) {
  27. unsigned int val;
  28. if (p < bottom || p >= top)
  29. pr_cont(" ");
  30. else {
  31. if (__get_user(val, (unsigned int __user *)p)) {
  32. pr_cont("\n");
  33. return;
  34. }
  35. pr_cont("%08x ", val);
  36. }
  37. }
  38. pr_cont("\n");
  39. }
  40. }
  41. void printk_address(unsigned long address, int reliable)
  42. {
  43. pr_cont(" [<%px>] %s%pS\n", (void *) address,
  44. reliable ? "" : "? ", (void *) address);
  45. }
  46. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  47. static void
  48. print_ftrace_graph_addr(unsigned long addr, void *data,
  49. const struct stacktrace_ops *ops,
  50. struct thread_info *tinfo, int *graph)
  51. {
  52. struct task_struct *task = tinfo->task;
  53. struct ftrace_ret_stack *ret_stack;
  54. unsigned long ret_addr;
  55. if (addr != (unsigned long)return_to_handler)
  56. return;
  57. if (!task->ret_stack)
  58. return;
  59. ret_stack = ftrace_graph_get_ret_stack(task, *graph);
  60. if (!ret_stack)
  61. return;
  62. ret_addr = ret_stack->ret;
  63. ops->address(data, ret_addr, 1);
  64. (*graph)++;
  65. }
  66. #else
  67. static inline void
  68. print_ftrace_graph_addr(unsigned long addr, void *data,
  69. const struct stacktrace_ops *ops,
  70. struct thread_info *tinfo, int *graph)
  71. { }
  72. #endif
  73. void
  74. stack_reader_dump(struct task_struct *task, struct pt_regs *regs,
  75. unsigned long *sp, const struct stacktrace_ops *ops,
  76. void *data)
  77. {
  78. struct thread_info *context;
  79. int graph = 0;
  80. context = (struct thread_info *)
  81. ((unsigned long)sp & (~(THREAD_SIZE - 1)));
  82. while (!kstack_end(sp)) {
  83. unsigned long addr = *sp++;
  84. if (__kernel_text_address(addr)) {
  85. ops->address(data, addr, 1);
  86. print_ftrace_graph_addr(addr, data, ops,
  87. context, &graph);
  88. }
  89. }
  90. }
  91. /*
  92. * Print one address/symbol entries per line.
  93. */
  94. static void print_trace_address(void *data, unsigned long addr, int reliable)
  95. {
  96. printk("%s", (char *)data);
  97. printk_address(addr, reliable);
  98. }
  99. static const struct stacktrace_ops print_trace_ops = {
  100. .address = print_trace_address,
  101. };
  102. void show_trace(struct task_struct *tsk, unsigned long *sp,
  103. struct pt_regs *regs, const char *loglvl)
  104. {
  105. if (regs && user_mode(regs))
  106. return;
  107. printk("%s\nCall trace:\n", loglvl);
  108. unwind_stack(tsk, regs, sp, &print_trace_ops, (void *)loglvl);
  109. pr_cont("\n");
  110. if (!tsk)
  111. tsk = current;
  112. debug_show_held_locks(tsk);
  113. }
  114. void show_stack(struct task_struct *tsk, unsigned long *sp, const char *loglvl)
  115. {
  116. unsigned long stack;
  117. if (!tsk)
  118. tsk = current;
  119. if (tsk == current)
  120. sp = (unsigned long *)current_stack_pointer;
  121. else
  122. sp = (unsigned long *)tsk->thread.sp;
  123. stack = (unsigned long)sp;
  124. dump_mem("Stack: ", loglvl, stack, THREAD_SIZE +
  125. (unsigned long)task_stack_page(tsk));
  126. show_trace(tsk, sp, NULL, loglvl);
  127. }