gcc_personality_v0.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. //===-- gcc_personality_v0.c - Implement __gcc_personality_v0 -------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "int_lib.h"
  9. #include <stddef.h>
  10. #include <unwind.h>
  11. #if defined(__arm__) && !defined(__ARM_DWARF_EH__) && \
  12. !defined(__USING_SJLJ_EXCEPTIONS__)
  13. // When building with older compilers (e.g. clang <3.9), it is possible that we
  14. // have a version of unwind.h which does not provide the EHABI declarations
  15. // which are quired for the C personality to conform to the specification. In
  16. // order to provide forward compatibility for such compilers, we re-declare the
  17. // necessary interfaces in the helper to permit a standalone compilation of the
  18. // builtins (which contains the C unwinding personality for historical reasons).
  19. #include "unwind-ehabi-helpers.h"
  20. #endif
  21. #if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
  22. #include <windows.h>
  23. #include <winnt.h>
  24. EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void *, PCONTEXT,
  25. PDISPATCHER_CONTEXT,
  26. _Unwind_Personality_Fn);
  27. #endif
  28. // Pointer encodings documented at:
  29. // http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html
  30. #define DW_EH_PE_omit 0xff // no data follows
  31. #define DW_EH_PE_absptr 0x00
  32. #define DW_EH_PE_uleb128 0x01
  33. #define DW_EH_PE_udata2 0x02
  34. #define DW_EH_PE_udata4 0x03
  35. #define DW_EH_PE_udata8 0x04
  36. #define DW_EH_PE_sleb128 0x09
  37. #define DW_EH_PE_sdata2 0x0A
  38. #define DW_EH_PE_sdata4 0x0B
  39. #define DW_EH_PE_sdata8 0x0C
  40. #define DW_EH_PE_pcrel 0x10
  41. #define DW_EH_PE_textrel 0x20
  42. #define DW_EH_PE_datarel 0x30
  43. #define DW_EH_PE_funcrel 0x40
  44. #define DW_EH_PE_aligned 0x50
  45. #define DW_EH_PE_indirect 0x80 // gcc extension
  46. // read a uleb128 encoded value and advance pointer
  47. static size_t readULEB128(const uint8_t **data) {
  48. size_t result = 0;
  49. size_t shift = 0;
  50. unsigned char byte;
  51. const uint8_t *p = *data;
  52. do {
  53. byte = *p++;
  54. result |= (byte & 0x7f) << shift;
  55. shift += 7;
  56. } while (byte & 0x80);
  57. *data = p;
  58. return result;
  59. }
  60. // read a pointer encoded value and advance pointer
  61. static uintptr_t readEncodedPointer(const uint8_t **data, uint8_t encoding) {
  62. const uint8_t *p = *data;
  63. uintptr_t result = 0;
  64. if (encoding == DW_EH_PE_omit)
  65. return 0;
  66. // first get value
  67. switch (encoding & 0x0F) {
  68. case DW_EH_PE_absptr:
  69. result = *((const uintptr_t *)p);
  70. p += sizeof(uintptr_t);
  71. break;
  72. case DW_EH_PE_uleb128:
  73. result = readULEB128(&p);
  74. break;
  75. case DW_EH_PE_udata2:
  76. result = *((const uint16_t *)p);
  77. p += sizeof(uint16_t);
  78. break;
  79. case DW_EH_PE_udata4:
  80. result = *((const uint32_t *)p);
  81. p += sizeof(uint32_t);
  82. break;
  83. case DW_EH_PE_udata8:
  84. result = *((const uint64_t *)p);
  85. p += sizeof(uint64_t);
  86. break;
  87. case DW_EH_PE_sdata2:
  88. result = *((const int16_t *)p);
  89. p += sizeof(int16_t);
  90. break;
  91. case DW_EH_PE_sdata4:
  92. result = *((const int32_t *)p);
  93. p += sizeof(int32_t);
  94. break;
  95. case DW_EH_PE_sdata8:
  96. result = *((const int64_t *)p);
  97. p += sizeof(int64_t);
  98. break;
  99. case DW_EH_PE_sleb128:
  100. default:
  101. // not supported
  102. compilerrt_abort();
  103. break;
  104. }
  105. // then add relative offset
  106. switch (encoding & 0x70) {
  107. case DW_EH_PE_absptr:
  108. // do nothing
  109. break;
  110. case DW_EH_PE_pcrel:
  111. result += (uintptr_t)(*data);
  112. break;
  113. case DW_EH_PE_textrel:
  114. case DW_EH_PE_datarel:
  115. case DW_EH_PE_funcrel:
  116. case DW_EH_PE_aligned:
  117. default:
  118. // not supported
  119. compilerrt_abort();
  120. break;
  121. }
  122. // then apply indirection
  123. if (encoding & DW_EH_PE_indirect) {
  124. result = *((const uintptr_t *)result);
  125. }
  126. *data = p;
  127. return result;
  128. }
  129. #if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \
  130. !defined(__ARM_DWARF_EH__) && !defined(__SEH__)
  131. #define USING_ARM_EHABI 1
  132. _Unwind_Reason_Code __gnu_unwind_frame(struct _Unwind_Exception *,
  133. struct _Unwind_Context *);
  134. #endif
  135. static inline _Unwind_Reason_Code
  136. continueUnwind(struct _Unwind_Exception *exceptionObject,
  137. struct _Unwind_Context *context) {
  138. #if USING_ARM_EHABI
  139. // On ARM EHABI the personality routine is responsible for actually
  140. // unwinding a single stack frame before returning (ARM EHABI Sec. 6.1).
  141. if (__gnu_unwind_frame(exceptionObject, context) != _URC_OK)
  142. return _URC_FAILURE;
  143. #endif
  144. return _URC_CONTINUE_UNWIND;
  145. }
  146. // The C compiler makes references to __gcc_personality_v0 in
  147. // the dwarf unwind information for translation units that use
  148. // __attribute__((cleanup(xx))) on local variables.
  149. // This personality routine is called by the system unwinder
  150. // on each frame as the stack is unwound during a C++ exception
  151. // throw through a C function compiled with -fexceptions.
  152. #if __USING_SJLJ_EXCEPTIONS__
  153. // the setjump-longjump based exceptions personality routine has a
  154. // different name
  155. COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_sj0(
  156. int version, _Unwind_Action actions, uint64_t exceptionClass,
  157. struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context)
  158. #elif USING_ARM_EHABI
  159. // The ARM EHABI personality routine has a different signature.
  160. COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
  161. _Unwind_State state, struct _Unwind_Exception *exceptionObject,
  162. struct _Unwind_Context *context)
  163. #elif defined(__SEH__)
  164. static _Unwind_Reason_Code __gcc_personality_imp(
  165. int version, _Unwind_Action actions, uint64_t exceptionClass,
  166. struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context)
  167. #else
  168. COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
  169. int version, _Unwind_Action actions, uint64_t exceptionClass,
  170. struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context)
  171. #endif
  172. {
  173. // Since C does not have catch clauses, there is nothing to do during
  174. // phase 1 (the search phase).
  175. #if USING_ARM_EHABI
  176. // After resuming from a cleanup we should also continue on to the next
  177. // frame straight away.
  178. if ((state & _US_ACTION_MASK) != _US_UNWIND_FRAME_STARTING)
  179. #else
  180. if (actions & _UA_SEARCH_PHASE)
  181. #endif
  182. return continueUnwind(exceptionObject, context);
  183. // There is nothing to do if there is no LSDA for this frame.
  184. const uint8_t *lsda = (uint8_t *)_Unwind_GetLanguageSpecificData(context);
  185. if (lsda == (uint8_t *)0)
  186. return continueUnwind(exceptionObject, context);
  187. uintptr_t pc = (uintptr_t)_Unwind_GetIP(context) - 1;
  188. uintptr_t funcStart = (uintptr_t)_Unwind_GetRegionStart(context);
  189. uintptr_t pcOffset = pc - funcStart;
  190. // Parse LSDA header.
  191. uint8_t lpStartEncoding = *lsda++;
  192. if (lpStartEncoding != DW_EH_PE_omit) {
  193. readEncodedPointer(&lsda, lpStartEncoding);
  194. }
  195. uint8_t ttypeEncoding = *lsda++;
  196. if (ttypeEncoding != DW_EH_PE_omit) {
  197. readULEB128(&lsda);
  198. }
  199. // Walk call-site table looking for range that includes current PC.
  200. uint8_t callSiteEncoding = *lsda++;
  201. size_t callSiteTableLength = readULEB128(&lsda);
  202. const uint8_t *callSiteTableStart = lsda;
  203. const uint8_t *callSiteTableEnd = callSiteTableStart + callSiteTableLength;
  204. const uint8_t *p = callSiteTableStart;
  205. while (p < callSiteTableEnd) {
  206. uintptr_t start = readEncodedPointer(&p, callSiteEncoding);
  207. size_t length = readEncodedPointer(&p, callSiteEncoding);
  208. size_t landingPad = readEncodedPointer(&p, callSiteEncoding);
  209. readULEB128(&p); // action value not used for C code
  210. if (landingPad == 0)
  211. continue; // no landing pad for this entry
  212. if ((start <= pcOffset) && (pcOffset < (start + length))) {
  213. // Found landing pad for the PC.
  214. // Set Instruction Pointer to so we re-enter function
  215. // at landing pad. The landing pad is created by the compiler
  216. // to take two parameters in registers.
  217. _Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
  218. (uintptr_t)exceptionObject);
  219. _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
  220. _Unwind_SetIP(context, (funcStart + landingPad));
  221. return _URC_INSTALL_CONTEXT;
  222. }
  223. }
  224. // No landing pad found, continue unwinding.
  225. return continueUnwind(exceptionObject, context);
  226. }
  227. #if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
  228. COMPILER_RT_ABI EXCEPTION_DISPOSITION
  229. __gcc_personality_seh0(PEXCEPTION_RECORD ms_exc, void *this_frame,
  230. PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp) {
  231. return _GCC_specific_handler(ms_exc, this_frame, ms_orig_context, ms_disp,
  232. __gcc_personality_imp);
  233. }
  234. #endif