postProcessingDataMemory.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. /*
  2. * arch/arm/kernel/unwind.c
  3. *
  4. * Copyright (C) 2008 ARM Limited
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. *
  19. *
  20. * Stack unwinding support for ARM
  21. *
  22. * An ARM EABI version of gcc is required to generate the unwind
  23. * tables. For information about the structure of the unwind tables,
  24. * see "Exception Handling ABI for the ARM Architecture" at:
  25. *
  26. * http://infocenter.arm.com/help/topic/com.arm.doc.subset.swdev.abi/index.html
  27. */
  28. #ifndef __CHECKER__
  29. #if !defined (__ARM_EABI__)
  30. #warning Your compiler does not have EABI support.
  31. #warning ARM unwind is known to compile only with EABI compilers.
  32. #warning Change compiler or disable ARM_UNWIND option.
  33. #elif (__GNUC__ == 4 && __GNUC_MINOR__ <= 2)
  34. #warning Your compiler is too buggy; it is known to not compile ARM unwind support.
  35. #warning Change compiler or disable ARM_UNWIND option.
  36. #endif
  37. #endif /* __CHECKER__ */
  38. #include <linux/kernel.h>
  39. #include <linux/init.h>
  40. #include <linux/export.h>
  41. #include <linux/sched.h>
  42. #include <linux/slab.h>
  43. #include <linux/spinlock.h>
  44. #include <linux/list.h>
  45. #include <asm/stacktrace.h>
  46. #include <asm/traps.h>
  47. #include <asm/unwind.h>
  48. /* Dummy functions to avoid linker complaints */
  49. void __aeabi_unwind_cpp_pr0(void)
  50. {
  51. };
  52. EXPORT_SYMBOL(__aeabi_unwind_cpp_pr0);
  53. void __aeabi_unwind_cpp_pr1(void)
  54. {
  55. };
  56. EXPORT_SYMBOL(__aeabi_unwind_cpp_pr1);
  57. void __aeabi_unwind_cpp_pr2(void)
  58. {
  59. };
  60. EXPORT_SYMBOL(__aeabi_unwind_cpp_pr2);
  61. struct unwind_ctrl_block {
  62. unsigned long vrs[16]; /* virtual register set */
  63. const unsigned long *insn; /* pointer to the current instructions word */
  64. int entries; /* number of entries left to interpret */
  65. int byte; /* current byte number in the instructions word */
  66. };
  67. enum regs {
  68. #ifdef CONFIG_THUMB2_KERNEL
  69. FP = 7,
  70. #else
  71. FP = 11,
  72. #endif
  73. SP = 13,
  74. LR = 14,
  75. PC = 15
  76. };
  77. extern const struct unwind_idx __start_unwind_idx[];
  78. static const struct unwind_idx *__origin_unwind_idx;
  79. extern const struct unwind_idx __stop_unwind_idx[];
  80. static DEFINE_SPINLOCK(unwind_lock);
  81. static LIST_HEAD(unwind_tables);
  82. /* Convert a prel31 symbol to an absolute address */
  83. #define prel31_to_addr(ptr) \
  84. ({ \
  85. /* sign-extend to 32 bits */ \
  86. long offset = (((long)*(ptr)) << 1) >> 1; \
  87. (unsigned long)(ptr) + offset; \
  88. })
  89. /*
  90. * Binary search in the unwind index. The entries are
  91. * guaranteed to be sorted in ascending order by the linker.
  92. *
  93. * start = first entry
  94. * origin = first entry with positive offset (or stop if there is no such entry)
  95. * stop - 1 = last entry
  96. */
  97. static const struct unwind_idx *search_index(unsigned long addr,
  98. const struct unwind_idx *start,
  99. const struct unwind_idx *origin,
  100. const struct unwind_idx *stop)
  101. {
  102. unsigned long addr_prel31;
  103. pr_debug("%s(%08lx, %p, %p, %p)\n",
  104. __func__, addr, start, origin, stop);
  105. /*
  106. * only search in the section with the matching sign. This way the
  107. * prel31 numbers can be compared as unsigned longs.
  108. */
  109. if (addr < (unsigned long)start)
  110. /* negative offsets: [start; origin) */
  111. stop = origin;
  112. else
  113. /* positive offsets: [origin; stop) */
  114. start = origin;
  115. /* prel31 for address relavive to start */
  116. addr_prel31 = (addr - (unsigned long)start) & 0x7fffffff;
  117. while (start < stop - 1) {
  118. const struct unwind_idx *mid = start + ((stop - start) >> 1);
  119. /*
  120. * As addr_prel31 is relative to start an offset is needed to
  121. * make it relative to mid.
  122. */
  123. if (addr_prel31 - ((unsigned long)mid - (unsigned long)start) <
  124. mid->addr_offset)
  125. stop = mid;
  126. else {
  127. /* keep addr_prel31 relative to start */
  128. addr_prel31 -= ((unsigned long)mid -
  129. (unsigned long)start);
  130. start = mid;
  131. }
  132. }