backtrace.c 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. /*
  2. * S390 Version
  3. * Copyright IBM Corp. 2005
  4. * Author(s): Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
  5. */
  6. #include <linux/oprofile.h>
  7. #include <asm/processor.h> /* for struct stack_frame */
  8. static unsigned long
  9. __show_trace(unsigned int *depth, unsigned long sp,
  10. unsigned long low, unsigned long high)
  11. {
  12. struct stack_frame *sf;
  13. struct pt_regs *regs;
  14. while (*depth) {
  15. sp = sp & PSW_ADDR_INSN;
  16. if (sp < low || sp > high - sizeof(*sf))
  17. return sp;
  18. sf = (struct stack_frame *) sp;
  19. (*depth)--;
  20. oprofile_add_trace(sf->gprs[8] & PSW_ADDR_INSN);
  21. /* Follow the backchain. */
  22. while (*depth) {
  23. low = sp;
  24. sp = sf->back_chain & PSW_ADDR_INSN;
  25. if (!sp)
  26. break;
  27. if (sp <= low || sp > high - sizeof(*sf))
  28. return sp;
  29. sf = (struct stack_frame *) sp;
  30. (*depth)--;
  31. oprofile_add_trace(sf->gprs[8] & PSW_ADDR_INSN);
  32. }
  33. if (*depth == 0)
  34. break;
  35. /* Zero backchain detected, check for interrupt frame. */
  36. sp = (unsigned long) (sf + 1);
  37. if (sp <= low || sp > high - sizeof(*regs))
  38. return sp;
  39. regs = (struct pt_regs *) sp;
  40. (*depth)--;
  41. oprofile_add_trace(sf->gprs[8] & PSW_ADDR_INSN);
  42. low = sp;
  43. sp = regs->gprs[15];
  44. }
  45. return sp;
  46. }
  47. void s390_backtrace(struct pt_regs * const regs, unsigned int depth)
  48. {
  49. unsigned long head;
  50. struct stack_frame* head_sf;
  51. if (user_mode(regs))
  52. return;
  53. head = regs->gprs[15];
  54. head_sf = (struct stack_frame*)head;
  55. if (!head_sf->back_chain)
  56. return;
  57. head = head_sf->back_chain;
  58. head = __show_trace(&depth, head, S390_lowcore.async_stack - ASYNC_SIZE,
  59. S390_lowcore.async_stack);
  60. __show_trace(&depth, head, S390_lowcore.thread_info,
  61. S390_lowcore.thread_info + THREAD_SIZE);
  62. }