stacktrace.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /*
  2. * arch/x86_64/kernel/stacktrace.c
  3. *
  4. * Stack trace management functions
  5. *
  6. * Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
  7. */
  8. #include <linux/sched.h>
  9. #include <linux/stacktrace.h>
  10. #include <asm/smp.h>
  11. static inline int
  12. in_range(unsigned long start, unsigned long addr, unsigned long end)
  13. {
  14. return addr >= start && addr <= end;
  15. }
  16. static unsigned long
  17. get_stack_end(struct task_struct *task, unsigned long stack)
  18. {
  19. unsigned long stack_start, stack_end, flags;
  20. int i, cpu;
  21. /*
  22. * The most common case is that we are in the task stack:
  23. */
  24. stack_start = (unsigned long)task->thread_info;
  25. stack_end = stack_start + THREAD_SIZE;
  26. if (in_range(stack_start, stack, stack_end))
  27. return stack_end;
  28. /*
  29. * We are in an interrupt if irqstackptr is set:
  30. */
  31. raw_local_irq_save(flags);
  32. cpu = safe_smp_processor_id();
  33. stack_end = (unsigned long)cpu_pda(cpu)->irqstackptr;
  34. if (stack_end) {
  35. stack_start = stack_end & ~(IRQSTACKSIZE-1);
  36. if (in_range(stack_start, stack, stack_end))
  37. goto out_restore;
  38. /*
  39. * We get here if we are in an IRQ context but we
  40. * are also in an exception stack.
  41. */
  42. }
  43. /*
  44. * Iterate over all exception stacks, and figure out whether
  45. * 'stack' is in one of them:
  46. */
  47. for (i = 0; i < N_EXCEPTION_STACKS; i++) {
  48. /*
  49. * set 'end' to the end of the exception stack.
  50. */
  51. stack_end = per_cpu(init_tss, cpu).ist[i];
  52. stack_start = stack_end - EXCEPTION_STKSZ;
  53. /*
  54. * Is 'stack' above this exception frame's end?
  55. * If yes then skip to the next frame.
  56. */
  57. if (stack >= stack_end)
  58. continue;
  59. /*
  60. * Is 'stack' above this exception frame's start address?
  61. * If yes then we found the right frame.
  62. */
  63. if (stack >= stack_start)
  64. goto out_restore;
  65. /*
  66. * If this is a debug stack, and if it has a larger size than
  67. * the usual exception stacks, then 'stack' might still
  68. * be within the lower portion of the debug stack:
  69. */
  70. #if DEBUG_STKSZ > EXCEPTION_STKSZ
  71. if (i == DEBUG_STACK - 1 && stack >= stack_end - DEBUG_STKSZ) {
  72. /*
  73. * Black magic. A large debug stack is composed of
  74. * multiple exception stack entries, which we
  75. * iterate through now. Dont look:
  76. */
  77. do {
  78. stack_end -= EXCEPTION_STKSZ;
  79. stack_start -= EXCEPTION_STKSZ;
  80. } while (stack < stack_start);
  81. goto out_restore;
  82. }
  83. #endif
  84. }
  85. /*
  86. * Ok, 'stack' is not pointing to any of the system stacks.
  87. */
  88. stack_end = 0;
  89. out_restore:
  90. raw_local_irq_restore(flags);
  91. return stack_end;
  92. }
  93. /*
  94. * Save stack-backtrace addresses into a stack_trace buffer:
  95. */
  96. static inline unsigned long
  97. save_context_stack(struct stack_trace *trace, unsigned int skip,
  98. unsigned long stack, unsigned long stack_end)
  99. {
  100. unsigned long addr;
  101. #ifdef CONFIG_FRAME_POINTER
  102. unsigned long prev_stack = 0;
  103. while (in_range(prev_stack, stack, stack_end)) {
  104. pr_debug("stack: %p\n", (void *)stack);
  105. addr = (unsigned long)(((unsigned long *)stack)[1]);
  106. pr_debug("addr: %p\n", (void *)addr);
  107. if (!skip)
  108. trace->entries[trace->nr_entries++] = addr-1;
  109. else
  110. skip--;
  111. if (trace->nr_entries >= trace->max_entries)
  112. break;
  113. if (!addr)
  114. return 0;
  115. /*
  116. * Stack frames must go forwards (otherwise a loop could
  117. * happen if the stackframe is corrupted), so we move
  118. * prev_stack forwards:
  119. */
  120. prev_stack = stack;
  121. stack = (unsigned long)(((unsigned long *)stack)[0]);
  122. }
  123. pr_debug("invalid: %p\n", (void *)stack);
  124. #else
  125. while (stack < stack_end) {
  126. addr = ((unsigned long *)stack)[0];
  127. stack += sizeof(long);
  128. if (__kernel_text_address(addr)) {
  129. if (!skip)
  130. trace->entries[trace->nr_entries++] = addr-1;
  131. else
  132. skip--;
  133. if (trace->nr_entries >= trace->max_entries)
  134. break;
  135. }
  136. }
  137. #endif
  138. return stack;
  139. }
  140. #define MAX_STACKS 10
  141. /*
  142. * Save stack-backtrace addresses into a stack_trace buffer.
  143. * If all_contexts is set, all contexts (hardirq, softirq and process)
  144. * are saved. If not set then only the current context is saved.
  145. */
  146. void save_stack_trace(struct stack_trace *trace,
  147. struct task_struct *task, int all_contexts,
  148. unsigned int skip)
  149. {
  150. unsigned long stack = (unsigned long)&stack;
  151. int i, nr_stacks = 0, stacks_done[MAX_STACKS];
  152. WARN_ON(trace->nr_entries || !trace->max_entries);
  153. if (!task)
  154. task = current;
  155. pr_debug("task: %p, ti: %p\n", task, task->thread_info);
  156. if (!task || task == current) {
  157. /* Grab rbp right from our regs: */
  158. asm ("mov %%rbp, %0" : "=r" (stack));
  159. pr_debug("rbp: %p\n", (void *)stack);
  160. } else {
  161. /* rbp is the last reg pushed by switch_to(): */
  162. stack = task->thread.rsp;
  163. pr_debug("other task rsp: %p\n", (void *)stack);
  164. stack = (unsigned long)(((unsigned long *)stack)[0]);
  165. pr_debug("other task rbp: %p\n", (void *)stack);
  166. }
  167. while (1) {
  168. unsigned long stack_end = get_stack_end(task, stack);
  169. pr_debug("stack: %p\n", (void *)stack);
  170. pr_debug("stack end: %p\n", (void *)stack_end);
  171. /*
  172. * Invalid stack addres?
  173. */
  174. if (!stack_end)
  175. return;
  176. /*
  177. * Were we in this stack already? (recursion)
  178. */
  179. for (i = 0; i < nr_stacks; i++)
  180. if (stacks_done[i] == stack_end)
  181. return;
  182. stacks_done[nr_stacks] = stack_end;
  183. stack = save_context_stack(trace, skip, stack, stack_end);
  184. if (!all_contexts || !stack ||
  185. trace->nr_entries >= trace->max_entries)
  186. return;
  187. trace->entries[trace->nr_entries++] = ULONG_MAX;
  188. if (trace->nr_entries >= trace->max_entries)
  189. return;
  190. if (++nr_stacks >= MAX_STACKS)
  191. return;
  192. }
  193. }