dumpstack.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  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/kdebug.h>
  15. #include <linux/export.h>
  16. #include <linux/uaccess.h>
  17. #include <asm/unwinder.h>
  18. #include <asm/stacktrace.h>
  19. void dump_mem(const char *str, unsigned long bottom, unsigned long top)
  20. {
  21. unsigned long p;
  22. int i;
  23. printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
  24. for (p = bottom & ~31; p < top; ) {
  25. printk("%04lx: ", p & 0xffff);
  26. for (i = 0; i < 8; i++, p += 4) {
  27. unsigned int val;
  28. if (p < bottom || p >= top)
  29. printk(" ");
  30. else {
  31. if (__get_user(val, (unsigned int __user *)p)) {
  32. printk("\n");
  33. return;
  34. }
  35. printk("%08x ", val);
  36. }
  37. }
  38. printk("\n");
  39. }
  40. }
  41. void printk_address(unsigned long address, int reliable)
  42. {
  43. printk(" [<%p>] %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. unsigned long ret_addr;
  54. int index = task->curr_ret_stack;
  55. if (addr != (unsigned long)return_to_handler)
  56. return;
  57. if (!task->ret_stack || index < *graph)
  58. return;
  59. index -= *graph;
  60. ret_addr = task->ret_stack[index].ret;
  61. ops->address(data, ret_addr, 1);
  62. (*graph)++;
  63. }
  64. #else
  65. static inline void
  66. print_ftrace_graph_addr(unsigned long addr, void *data,
  67. const struct stacktrace_ops *ops,
  68. struct thread_info *tinfo, int *graph)
  69. { }
  70. #endif
  71. void
  72. stack_reader_dump(struct task_struct *task, struct pt_regs *regs,
  73. unsigned long *sp, const struct stacktrace_ops *ops,
  74. void *data)
  75. {
  76. struct thread_info *context;
  77. int graph = 0;
  78. context = (struct thread_info *)
  79. ((unsigned long)sp & (~(THREAD_SIZE - 1)));
  80. while (!kstack_end(sp)) {
  81. unsigned long addr = *sp++;
  82. if (__kernel_text_address(addr)) {
  83. ops->address(data, addr, 1);
  84. print_ftrace_graph_addr(addr, data, ops,
  85. context, &graph);
  86. }
  87. }
  88. }
  89. static int print_trace_stack(void *data, char *name)
  90. {
  91. printk("%s <%s> ", (char *)data, name);
  92. return 0;
  93. }
  94. /*
  95. * Print one address/symbol entries per line.
  96. */
  97. static void print_trace_address(void *data, unsigned long addr, int reliable)
  98. {
  99. printk("%s", (char *)data);
  100. printk_address(addr, reliable);
  101. }
  102. static const struct stacktrace_ops print_trace_ops = {
  103. .stack = print_trace_stack,
  104. .address = print_trace_address,
  105. };
  106. void show_trace(struct task_struct *tsk, unsigned long *sp,
  107. struct pt_regs *regs)
  108. {
  109. if (regs && user_mode(regs))
  110. return;
  111. printk("\nCall trace:\n");
  112. unwind_stack(tsk, regs, sp, &print_trace_ops, "");
  113. printk("\n");
  114. if (!tsk)
  115. tsk = current;
  116. debug_show_held_locks(tsk);
  117. }
  118. void show_stack(struct task_struct *tsk, unsigned long *sp)
  119. {
  120. unsigned long stack;
  121. if (!tsk)
  122. tsk = current;
  123. if (tsk == current)
  124. sp = (unsigned long *)current_stack_pointer;
  125. else
  126. sp = (unsigned long *)tsk->thread.sp;
  127. stack = (unsigned long)sp;
  128. dump_mem("Stack: ", stack, THREAD_SIZE +
  129. (unsigned long)task_stack_page(tsk));
  130. show_trace(tsk, sp, NULL);
  131. }