unwinder.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. /*
  2. * OpenRISC unwinder.c
  3. *
  4. * Reusable arch specific api for unwinding stacks.
  5. *
  6. * Copyright (C) 2017 Stafford Horne <shorne@gmail.com>
  7. *
  8. * This file is licensed under the terms of the GNU General Public License
  9. * version 2. This program is licensed "as is" without any warranty of any
  10. * kind, whether express or implied.
  11. */
  12. #include <linux/sched/task_stack.h>
  13. #include <linux/kernel.h>
  14. #include <asm/unwinder.h>
  15. #ifdef CONFIG_FRAME_POINTER
  16. struct or1k_frameinfo {
  17. unsigned long *fp;
  18. unsigned long ra;
  19. unsigned long top;
  20. };
  21. /*
  22. * Verify a frameinfo structure. The return address should be a valid text
  23. * address. The frame pointer may be null if its the last frame, otherwise
  24. * the frame pointer should point to a location in the stack after the the
  25. * top of the next frame up.
  26. */
  27. static inline int or1k_frameinfo_valid(struct or1k_frameinfo *frameinfo)
  28. {
  29. return (frameinfo->fp == NULL ||
  30. (!kstack_end(frameinfo->fp) &&
  31. frameinfo->fp > &frameinfo->top)) &&
  32. __kernel_text_address(frameinfo->ra);
  33. }
  34. /*
  35. * Create a stack trace doing scanning which is frame pointer aware. We can
  36. * get reliable stack traces by matching the previously found frame
  37. * pointer with the top of the stack address every time we find a valid
  38. * or1k_frameinfo.
  39. *
  40. * Ideally the stack parameter will be passed as FP, but it can not be
  41. * guaranteed. Therefore we scan each address looking for the first sign
  42. * of a return address.
  43. *
  44. * The OpenRISC stack frame looks something like the following. The
  45. * location SP is held in r1 and location FP is held in r2 when frame pointers
  46. * enabled.
  47. *
  48. * SP -> (top of stack)
  49. * - (callee saved registers)
  50. * - (local variables)
  51. * FP-8 -> previous FP \
  52. * FP-4 -> return address |- or1k_frameinfo
  53. * FP -> (previous top of stack) /
  54. */
  55. void unwind_stack(void *data, unsigned long *stack,
  56. void (*trace)(void *data, unsigned long addr, int reliable))
  57. {
  58. unsigned long *next_fp = NULL;
  59. struct or1k_frameinfo *frameinfo = NULL;
  60. int reliable = 0;
  61. while (!kstack_end(stack)) {
  62. frameinfo = container_of(stack,
  63. struct or1k_frameinfo,
  64. top);
  65. if (__kernel_text_address(frameinfo->ra)) {
  66. if (or1k_frameinfo_valid(frameinfo) &&
  67. (next_fp == NULL ||
  68. next_fp == &frameinfo->top)) {
  69. reliable = 1;
  70. next_fp = frameinfo->fp;
  71. } else
  72. reliable = 0;
  73. trace(data, frameinfo->ra, reliable);
  74. }
  75. stack++;
  76. }
  77. }
  78. #else /* CONFIG_FRAME_POINTER */
  79. /*
  80. * Create a stack trace by doing a simple scan treating all text addresses
  81. * as return addresses.
  82. */
  83. void unwind_stack(void *data, unsigned long *stack,
  84. void (*trace)(void *data, unsigned long addr, int reliable))
  85. {
  86. unsigned long addr;
  87. while (!kstack_end(stack)) {
  88. addr = *stack++;
  89. if (__kernel_text_address(addr))
  90. trace(data, addr, 0);
  91. }
  92. }
  93. #endif /* CONFIG_FRAME_POINTER */