gcc_personality_v0.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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 "int_lib.h"
  12. #include <unwind.h>
  13. /*
  14. * Pointer encodings documented at:
  15. * http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html
  16. */
  17. #define DW_EH_PE_omit 0xff /* no data follows */
  18. #define DW_EH_PE_absptr 0x00
  19. #define DW_EH_PE_uleb128 0x01
  20. #define DW_EH_PE_udata2 0x02
  21. #define DW_EH_PE_udata4 0x03
  22. #define DW_EH_PE_udata8 0x04
  23. #define DW_EH_PE_sleb128 0x09
  24. #define DW_EH_PE_sdata2 0x0A
  25. #define DW_EH_PE_sdata4 0x0B
  26. #define DW_EH_PE_sdata8 0x0C
  27. #define DW_EH_PE_pcrel 0x10
  28. #define DW_EH_PE_textrel 0x20
  29. #define DW_EH_PE_datarel 0x30
  30. #define DW_EH_PE_funcrel 0x40
  31. #define DW_EH_PE_aligned 0x50
  32. #define DW_EH_PE_indirect 0x80 /* gcc extension */
  33. /* read a uleb128 encoded value and advance pointer */
  34. static uintptr_t readULEB128(const uint8_t** data)
  35. {
  36. uintptr_t result = 0;
  37. uintptr_t shift = 0;
  38. unsigned char byte;
  39. const uint8_t* p = *data;
  40. do {
  41. byte = *p++;
  42. result |= (byte & 0x7f) << shift;
  43. shift += 7;
  44. } while (byte & 0x80);
  45. *data = p;
  46. return result;
  47. }
  48. /* read a pointer encoded value and advance pointer */
  49. static uintptr_t readEncodedPointer(const uint8_t** data, uint8_t encoding)
  50. {
  51. const uint8_t* p = *data;
  52. uintptr_t result = 0;
  53. if ( encoding == DW_EH_PE_omit )
  54. return 0;
  55. /* first get value */
  56. switch (encoding & 0x0F) {
  57. case DW_EH_PE_absptr:
  58. result = *((const uintptr_t*)p);
  59. p += sizeof(uintptr_t);
  60. break;
  61. case DW_EH_PE_uleb128:
  62. result = readULEB128(&p);
  63. break;
  64. case DW_EH_PE_udata2:
  65. result = *((const uint16_t*)p);
  66. p += sizeof(uint16_t);
  67. break;
  68. case DW_EH_PE_udata4:
  69. result = *((const uint32_t*)p);
  70. p += sizeof(uint32_t);
  71. break;
  72. case DW_EH_PE_udata8:
  73. result = *((const uint64_t*)p);
  74. p += sizeof(uint64_t);
  75. break;
  76. case DW_EH_PE_sdata2:
  77. result = *((const int16_t*)p);
  78. p += sizeof(int16_t);
  79. break;
  80. case DW_EH_PE_sdata4:
  81. result = *((const int32_t*)p);
  82. p += sizeof(int32_t);
  83. break;
  84. case DW_EH_PE_sdata8:
  85. result = *((const int64_t*)p);
  86. p += sizeof(int64_t);
  87. break;
  88. case DW_EH_PE_sleb128:
  89. default:
  90. /* not supported */
  91. compilerrt_abort();
  92. break;
  93. }
  94. /* then add relative offset */
  95. switch ( encoding & 0x70 ) {
  96. case DW_EH_PE_absptr:
  97. /* do nothing */
  98. break;
  99. case DW_EH_PE_pcrel:
  100. result += (uintptr_t)(*data);
  101. break;
  102. case DW_EH_PE_textrel:
  103. case DW_EH_PE_datarel:
  104. case DW_EH_PE_funcrel:
  105. case DW_EH_PE_aligned:
  106. default:
  107. /* not supported */
  108. compilerrt_abort();
  109. break;
  110. }
  111. /* then apply indirection */
  112. if (encoding & DW_EH_PE_indirect) {
  113. result = *((const uintptr_t*)result);
  114. }
  115. *data = p;
  116. return result;
  117. }
  118. /*
  119. * The C compiler makes references to __gcc_personality_v0 in
  120. * the dwarf unwind information for translation units that use
  121. * __attribute__((cleanup(xx))) on local variables.
  122. * This personality routine is called by the system unwinder
  123. * on each frame as the stack is unwound during a C++ exception
  124. * throw through a C function compiled with -fexceptions.
  125. */
  126. #if __USING_SJLJ_EXCEPTIONS__
  127. // the setjump-longjump based exceptions personality routine has a different name
  128. COMPILER_RT_ABI _Unwind_Reason_Code
  129. __gcc_personality_sj0(int version, _Unwind_Action actions,
  130. uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
  131. struct _Unwind_Context *context)
  132. #else
  133. COMPILER_RT_ABI _Unwind_Reason_Code
  134. __gcc_personality_v0(int version, _Unwind_Action actions,
  135. uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
  136. struct _Unwind_Context *context)
  137. #endif
  138. {
  139. /* Since C does not have catch clauses, there is nothing to do during */
  140. /* phase 1 (the search phase). */
  141. if ( actions & _UA_SEARCH_PHASE )
  142. return _URC_CONTINUE_UNWIND;
  143. /* There is nothing to do if there is no LSDA for this frame. */
  144. const uint8_t* lsda = (uint8_t*)_Unwind_GetLanguageSpecificData(context);
  145. if ( lsda == (uint8_t*) 0 )
  146. return _URC_CONTINUE_UNWIND;
  147. uintptr_t pc = _Unwind_GetIP(context)-1;
  148. uintptr_t funcStart = _Unwind_GetRegionStart(context);
  149. uintptr_t pcOffset = pc - funcStart;
  150. /* Parse LSDA header. */
  151. uint8_t lpStartEncoding = *lsda++;
  152. if (lpStartEncoding != DW_EH_PE_omit) {
  153. readEncodedPointer(&lsda, lpStartEncoding);
  154. }
  155. uint8_t ttypeEncoding = *lsda++;
  156. if (ttypeEncoding != DW_EH_PE_omit) {
  157. readULEB128(&lsda);
  158. }
  159. /* Walk call-site table looking for range that includes current PC. */
  160. uint8_t callSiteEncoding = *lsda++;
  161. uint32_t callSiteTableLength = readULEB128(&lsda);
  162. const uint8_t* callSiteTableStart = lsda;
  163. const uint8_t* callSiteTableEnd = callSiteTableStart + callSiteTableLength;
  164. const uint8_t* p=callSiteTableStart;
  165. while (p < callSiteTableEnd) {
  166. uintptr_t start = readEncodedPointer(&p, callSiteEncoding);
  167. uintptr_t length = readEncodedPointer(&p, callSiteEncoding);
  168. uintptr_t landingPad = readEncodedPointer(&p, callSiteEncoding);
  169. readULEB128(&p); /* action value not used for C code */
  170. if ( landingPad == 0 )
  171. continue; /* no landing pad for this entry */
  172. if ( (start <= pcOffset) && (pcOffset < (start+length)) ) {
  173. /* Found landing pad for the PC.
  174. * Set Instruction Pointer to so we re-enter function
  175. * at landing pad. The landing pad is created by the compiler
  176. * to take two parameters in registers.
  177. */
  178. _Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
  179. (uintptr_t)exceptionObject);
  180. _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
  181. _Unwind_SetIP(context, (funcStart + landingPad));
  182. return _URC_INSTALL_CONTEXT;
  183. }
  184. }
  185. /* No landing pad found, continue unwinding. */
  186. return _URC_CONTINUE_UNWIND;
  187. }