postProcessingDataMemory.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  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. }
  133. if (likely(start->addr_offset <= addr_prel31))
  134. return start;
  135. else {
  136. pr_warning("unwind: Unknown symbol address %08lx\n", addr);
  137. return NULL;
  138. }
  139. }
  140. static const struct unwind_idx *unwind_find_origin(
  141. const struct unwind_idx *start, const struct unwind_idx *stop)
  142. {
  143. pr_debug("%s(%p, %p)\n", __func__, start, stop);
  144. while (start < stop) {
  145. const struct unwind_idx *mid = start + ((stop - start) >> 1);
  146. if (mid->addr_offset >= 0x40000000)
  147. /* negative offset */
  148. start = mid + 1;
  149. else
  150. /* positive offset */
  151. stop = mid;
  152. }
  153. pr_debug("%s -> %p\n", __func__, stop);
  154. return stop;
  155. }
  156. static const struct unwind_idx *unwind_find_idx(unsigned long addr)
  157. {
  158. const struct unwind_idx *idx = NULL;
  159. unsigned long flags;
  160. pr_debug("%s(%08lx)\n", __func__, addr);
  161. if (core_kernel_text(addr)) {
  162. if (unlikely(!__origin_unwind_idx))
  163. __origin_unwind_idx =
  164. unwind_find_origin(__start_unwind_idx,
  165. __stop_unwind_idx);
  166. /* main unwind table */
  167. idx = search_index(addr, __start_unwind_idx,
  168. __origin_unwind_idx,
  169. __stop_unwind_idx);
  170. } else {
  171. /* module unwind tables */
  172. struct unwind_table *table;
  173. spin_lock_irqsave(&unwind_lock, flags);
  174. list_for_each_entry(table, &unwind_tables, list) {
  175. if (addr >= table->begin_addr &&
  176. addr < table->end_addr) {
  177. idx = search_index(addr, table->start,
  178. table->origin,
  179. table->stop);
  180. /* Move-to-front to exploit common traces */
  181. list_move(&table->list, &unwind_tables);
  182. break;
  183. }
  184. }
  185. spin_unlock_irqrestore(&unwind_lock, flags);
  186. }
  187. pr_debug("%s: idx = %p\n", __func__, idx);
  188. return idx;
  189. }
  190. static unsigned long unwind_get_byte(struct unwind_ctrl_block *ctrl)