stacktrace.c 1.9 KB

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