stacktrace.c 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. /*
  2. * Stack trace management functions
  3. *
  4. * Copyright IBM Corp. 2006
  5. * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
  6. */
  7. #include <linux/sched.h>
  8. #include <linux/stacktrace.h>
  9. #include <linux/kallsyms.h>
  10. #include <linux/module.h>
  11. static unsigned long save_context_stack(struct stack_trace *trace,
  12. unsigned long sp,
  13. unsigned long low,
  14. unsigned long high,
  15. int savesched)
  16. {
  17. struct stack_frame *sf;
  18. struct pt_regs *regs;
  19. unsigned long addr;
  20. while(1) {
  21. if (sp < low || sp > high)
  22. return sp;
  23. sf = (struct stack_frame *)sp;
  24. while(1) {
  25. addr = sf->gprs[8];
  26. if (!trace->skip)
  27. trace->entries[trace->nr_entries++] = addr;
  28. else
  29. trace->skip--;
  30. if (trace->nr_entries >= trace->max_entries)
  31. return sp;
  32. low = sp;
  33. sp = sf->back_chain;
  34. if (!sp)
  35. break;
  36. if (sp <= low || sp > high - sizeof(*sf))
  37. return sp;
  38. sf = (struct stack_frame *)sp;
  39. }
  40. /* Zero backchain detected, check for interrupt frame. */
  41. sp = (unsigned long)(sf + 1);
  42. if (sp <= low || sp > high - sizeof(*regs))
  43. return sp;
  44. regs = (struct pt_regs *)sp;
  45. addr = regs->psw.addr;
  46. if (savesched || !in_sched_functions(addr)) {
  47. if (!trace->skip)
  48. trace->entries[trace->nr_entries++] = addr;
  49. else
  50. trace->skip--;
  51. }
  52. if (trace->nr_entries >= trace->max_entries)
  53. return sp;
  54. low = sp;
  55. sp = regs->gprs[15];
  56. }
  57. }
  58. void save_stack_trace(struct stack_trace *trace)
  59. {
  60. register unsigned long sp asm ("15");
  61. unsigned long orig_sp, new_sp;
  62. orig_sp = sp;
  63. new_sp = save_context_stack(trace, orig_sp,
  64. S390_lowcore.panic_stack - PAGE_SIZE,
  65. S390_lowcore.panic_stack, 1);
  66. if (new_sp != orig_sp)
  67. return;
  68. new_sp = save_context_stack(trace, new_sp,
  69. S390_lowcore.async_stack - ASYNC_SIZE,
  70. S390_lowcore.async_stack, 1);
  71. if (new_sp != orig_sp)
  72. return;
  73. save_context_stack(trace, new_sp,
  74. S390_lowcore.thread_info,
  75. S390_lowcore.thread_info + THREAD_SIZE, 1);
  76. }
  77. EXPORT_SYMBOL_GPL(save_stack_trace);
  78. void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
  79. {
  80. unsigned long sp, low, high;
  81. sp = tsk->thread.ksp;
  82. low = (unsigned long) task_stack_page(tsk);
  83. high = (unsigned long) task_pt_regs(tsk);
  84. save_context_stack(trace, sp, low, high, 0);
  85. if (trace->nr_entries < trace->max_entries)
  86. trace->entries[trace->nr_entries++] = ULONG_MAX;
  87. }
  88. EXPORT_SYMBOL_GPL(save_stack_trace_tsk);