dumpstack.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /*
  2. * Copyright (C) 1991, 1992 Linus Torvalds
  3. * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
  4. * Copyright (C) 2009 Matt Fleming
  5. * Copyright (C) 2002 - 2012 Paul Mundt
  6. *
  7. * This file is subject to the terms and conditions of the GNU General Public
  8. * License. See the file "COPYING" in the main directory of this archive
  9. * for more details.
  10. */
  11. #include <linux/kallsyms.h>
  12. #include <linux/ftrace.h>
  13. #include <linux/debug_locks.h>
  14. #include <linux/sched/debug.h>
  15. #include <linux/sched/task_stack.h>
  16. #include <linux/kdebug.h>
  17. #include <linux/export.h>
  18. #include <linux/uaccess.h>
  19. #include <asm/unwinder.h>
  20. #include <asm/stacktrace.h>
  21. void dump_mem(const char *str, unsigned long bottom, unsigned long top)
  22. {
  23. unsigned long p;
  24. int i;
  25. printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
  26. for (p = bottom & ~31; p < top; ) {
  27. printk("%04lx: ", p & 0xffff);
  28. for (i = 0; i < 8; i++, p += 4) {
  29. unsigned int val;
  30. if (p < bottom || p >= top)
  31. printk(" ");
  32. else {
  33. if (__get_user(val, (unsigned int __user *)p)) {
  34. printk("\n");
  35. return;
  36. }
  37. printk("%08x ", val);
  38. }
  39. }
  40. printk("\n");
  41. }
  42. }
  43. void printk_address(unsigned long address, int reliable)
  44. {
  45. printk(" [<%p>] %s%pS\n", (void *) address,
  46. reliable ? "" : "? ", (void *) address);
  47. }
  48. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  49. static void
  50. print_ftrace_graph_addr(unsigned long addr, void *data,
  51. const struct stacktrace_ops *ops,
  52. struct thread_info *tinfo, int *graph)
  53. {
  54. struct task_struct *task = tinfo->task;
  55. unsigned long ret_addr;
  56. int index = task->curr_ret_stack;
  57. if (addr != (unsigned long)return_to_handler)
  58. return;
  59. if (!task->ret_stack || index < *graph)
  60. return;
  61. index -= *graph;
  62. ret_addr = task->ret_stack[index].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. static int print_trace_stack(void *data, char *name)
  92. {
  93. printk("%s <%s> ", (char *)data, name);
  94. return 0;
  95. }
  96. /*
  97. * Print one address/symbol entries per line.
  98. */
  99. static void print_trace_address(void *data, unsigned long addr, int reliable)
  100. {
  101. printk("%s", (char *)data);
  102. printk_address(addr, reliable);
  103. }
  104. static const struct stacktrace_ops print_trace_ops = {
  105. .stack = print_trace_stack,
  106. .address = print_trace_address,
  107. };
  108. void show_trace(struct task_struct *tsk, unsigned long *sp,
  109. struct pt_regs *regs)
  110. {
  111. if (regs && user_mode(regs))
  112. return;
  113. printk("\nCall trace:\n");
  114. unwind_stack(tsk, regs, sp, &print_trace_ops, "");
  115. printk("\n");
  116. if (!tsk)
  117. tsk = current;
  118. debug_show_held_locks(tsk);
  119. }
  120. void show_stack(struct task_struct *tsk, unsigned long *sp)
  121. {
  122. unsigned long stack;
  123. if (!tsk)
  124. tsk = current;
  125. if (tsk == current)
  126. sp = (unsigned long *)current_stack_pointer;
  127. else
  128. sp = (unsigned long *)tsk->thread.sp;
  129. stack = (unsigned long)sp;
  130. dump_mem("Stack: ", stack, THREAD_SIZE +
  131. (unsigned long)task_stack_page(tsk));
  132. show_trace(tsk, sp, NULL);
  133. }