gcc_personality_v0.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. /* ===-- gcc_personality_v0.c - Implement __gcc_personality_v0 -------------===
  2. *
  3. * The LLVM Compiler Infrastructure
  4. *
  5. * This file is dual licensed under the MIT and the University of Illinois Open
  6. * Source Licenses. See LICENSE.TXT for details.
  7. *
  8. * ===----------------------------------------------------------------------===
  9. *
  10. */
  11. #include <stdint.h>
  12. #include <stdlib.h>
  13. #include "se_cdefs.h"
  14. #define compilerrt_abort abort
  15. SGX_ACCESS_VERSION(tstdcxx, 2)
  16. /*
  17. * _Unwind_* stuff based on C++ ABI public documentation
  18. * http://refspecs.freestandards.org/abi-eh-1.21.html
  19. */
  20. typedef enum {
  21. _URC_NO_REASON = 0,
  22. _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
  23. _URC_FATAL_PHASE2_ERROR = 2,
  24. _URC_FATAL_PHASE1_ERROR = 3,
  25. _URC_NORMAL_STOP = 4,
  26. _URC_END_OF_STACK = 5,
  27. _URC_HANDLER_FOUND = 6,
  28. _URC_INSTALL_CONTEXT = 7,
  29. _URC_CONTINUE_UNWIND = 8
  30. } _Unwind_Reason_Code;
  31. typedef enum {
  32. _UA_SEARCH_PHASE = 1,
  33. _UA_CLEANUP_PHASE = 2,
  34. _UA_HANDLER_FRAME = 4,
  35. _UA_FORCE_UNWIND = 8,
  36. _UA_END_OF_STACK = 16
  37. } _Unwind_Action;
  38. typedef struct _Unwind_Context* _Unwind_Context_t;
  39. struct _Unwind_Exception {
  40. uint64_t exception_class;
  41. void (*exception_cleanup)(_Unwind_Reason_Code reason,
  42. struct _Unwind_Exception* exc);
  43. uintptr_t private_1;
  44. uintptr_t private_2;
  45. };
  46. extern const uint8_t* _Unwind_GetLanguageSpecificData(_Unwind_Context_t c);
  47. extern void _Unwind_SetGR(_Unwind_Context_t c, int i, uintptr_t n);
  48. extern void _Unwind_SetIP(_Unwind_Context_t, uintptr_t new_value);
  49. extern uintptr_t _Unwind_GetIP(_Unwind_Context_t context);
  50. extern uintptr_t _Unwind_GetRegionStart(_Unwind_Context_t context);
  51. /*
  52. * Pointer encodings documented at:
  53. * http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html
  54. */
  55. #define DW_EH_PE_omit 0xff /* no data follows */
  56. #define DW_EH_PE_absptr 0x00
  57. #define DW_EH_PE_uleb128 0x01
  58. #define DW_EH_PE_udata2 0x02
  59. #define DW_EH_PE_udata4 0x03
  60. #define DW_EH_PE_udata8 0x04
  61. #define DW_EH_PE_sleb128 0x09
  62. #define DW_EH_PE_sdata2 0x0A
  63. #define DW_EH_PE_sdata4 0x0B
  64. #define DW_EH_PE_sdata8 0x0C
  65. #define DW_EH_PE_pcrel 0x10
  66. #define DW_EH_PE_textrel 0x20
  67. #define DW_EH_PE_datarel 0x30
  68. #define DW_EH_PE_funcrel 0x40
  69. #define DW_EH_PE_aligned 0x50
  70. #define DW_EH_PE_indirect 0x80 /* gcc extension */
  71. /* read a uleb128 encoded value and advance pointer */
  72. static uintptr_t readULEB128(const uint8_t** data)
  73. {
  74. uintptr_t result = 0;
  75. uintptr_t shift = 0;
  76. unsigned char byte;
  77. const uint8_t* p = *data;
  78. do {
  79. byte = *p++;
  80. result |= (byte & 0x7f) << shift;
  81. shift += 7;
  82. } while (byte & 0x80);
  83. *data = p;
  84. return result;
  85. }
  86. /* read a pointer encoded value and advance pointer */
  87. static uint64_t readEncodedPointer(const uint8_t** data, uint8_t encoding)
  88. {
  89. const uint8_t* p = *data;
  90. uint64_t result = 0;
  91. if ( encoding == DW_EH_PE_omit )
  92. return 0;
  93. /* first get value */
  94. switch (encoding & 0x0F) {
  95. case DW_EH_PE_absptr:
  96. result = *((uintptr_t*)p);
  97. p += sizeof(uintptr_t);
  98. break;
  99. case DW_EH_PE_uleb128:
  100. result = readULEB128(&p);
  101. break;
  102. case DW_EH_PE_udata2:
  103. result = *((uint16_t*)p);
  104. p += sizeof(uint16_t);
  105. break;
  106. case DW_EH_PE_udata4:
  107. result = *((uint32_t*)p);
  108. p += sizeof(uint32_t);
  109. break;
  110. case DW_EH_PE_udata8:
  111. result = *((uint64_t*)p);
  112. p += sizeof(uint64_t);
  113. break;
  114. case DW_EH_PE_sdata2:
  115. result = *((int16_t*)p);
  116. p += sizeof(int16_t);
  117. break;
  118. case DW_EH_PE_sdata4:
  119. result = *((int32_t*)p);
  120. p += sizeof(int32_t);
  121. break;
  122. case DW_EH_PE_sdata8:
  123. result = *((int64_t*)p);
  124. p += sizeof(int64_t);
  125. break;
  126. case DW_EH_PE_sleb128:
  127. default:
  128. /* not supported */
  129. compilerrt_abort();
  130. break;
  131. }
  132. /* then add relative offset */
  133. switch ( encoding & 0x70 ) {
  134. case DW_EH_PE_absptr:
  135. /* do nothing */
  136. break;
  137. case DW_EH_PE_pcrel:
  138. result += (uintptr_t)(*data);
  139. break;
  140. case DW_EH_PE_textrel:
  141. case DW_EH_PE_datarel:
  142. case DW_EH_PE_funcrel:
  143. case DW_EH_PE_aligned:
  144. default:
  145. /* not supported */
  146. compilerrt_abort();
  147. break;
  148. }
  149. /* then apply indirection */
  150. if (encoding & DW_EH_PE_indirect) {
  151. result = *((uintptr_t*)result);
  152. }
  153. *data = p;
  154. return result;
  155. }
  156. /*
  157. * The C compiler makes references to __gcc_personality_v0 in
  158. * the dwarf unwind information for translation units that use
  159. * __attribute__((cleanup(xx))) on local variables.
  160. * This personality routine is called by the system unwinder
  161. * on each frame as the stack is unwound during a C++ exception
  162. * throw through a C function compiled with -fexceptions.
  163. */
  164. #if __arm__
  165. // the setjump-longjump based exceptions personality routine has a different name
  166. _Unwind_Reason_Code __gcc_personality_sj0(int version, _Unwind_Action actions,
  167. uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
  168. _Unwind_Context_t context)
  169. #else
  170. _Unwind_Reason_Code __gcc_personality_v0(int version, _Unwind_Action actions,
  171. uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
  172. _Unwind_Context_t context)
  173. #endif
  174. {
  175. /* Since C does not have catch clauses, there is nothing to do during */
  176. /* phase 1 (the search phase). */
  177. if ( actions & _UA_SEARCH_PHASE )
  178. return _URC_CONTINUE_UNWIND;
  179. /* There is nothing to do if there is no LSDA for this frame. */
  180. const uint8_t* lsda = _Unwind_GetLanguageSpecificData(context);
  181. if ( lsda == (uint8_t*) 0 )
  182. return _URC_CONTINUE_UNWIND;
  183. uintptr_t pc = _Unwind_GetIP(context)-1;
  184. uintptr_t funcStart = _Unwind_GetRegionStart(context);
  185. uintptr_t pcOffset = pc - funcStart;
  186. /* Parse LSDA header. */
  187. uint8_t lpStartEncoding = *lsda++;
  188. if (lpStartEncoding != DW_EH_PE_omit) {
  189. readEncodedPointer(&lsda, lpStartEncoding);
  190. }
  191. uint8_t ttypeEncoding = *lsda++;
  192. if (ttypeEncoding != DW_EH_PE_omit) {
  193. readULEB128(&lsda);
  194. }
  195. /* Walk call-site table looking for range that includes current PC. */
  196. uint8_t callSiteEncoding = *lsda++;
  197. uint32_t callSiteTableLength = readULEB128(&lsda);
  198. const uint8_t* callSiteTableStart = lsda;
  199. const uint8_t* callSiteTableEnd = callSiteTableStart + callSiteTableLength;
  200. const uint8_t* p=callSiteTableStart;
  201. while (p < callSiteTableEnd) {
  202. uint64_t start = readEncodedPointer(&p, callSiteEncoding);
  203. uint64_t length = readEncodedPointer(&p, callSiteEncoding);
  204. uint64_t landingPad = readEncodedPointer(&p, callSiteEncoding);
  205. readULEB128(&p); /* action value not used for C code */
  206. if ( landingPad == 0 )
  207. continue; /* no landing pad for this entry */
  208. if ( (start <= pcOffset) && (pcOffset < (start+length)) ) {
  209. /* Found landing pad for the PC.
  210. * Set Instruction Pointer to so we re-enter function
  211. * at landing pad. The landing pad is created by the compiler
  212. * to take two parameters in registers.
  213. */
  214. _Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
  215. (uintptr_t)exceptionObject);
  216. _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
  217. _Unwind_SetIP(context, funcStart+landingPad);
  218. return _URC_INSTALL_CONTEXT;
  219. }
  220. }
  221. /* No landing pad found, continue unwinding. */
  222. return _URC_CONTINUE_UNWIND;
  223. }