blob: 944e372e8ba89f7cfe84d931b1500b25c251fc49 [file] [log] [blame]
Howard Hinnant9027d252012-01-04 20:49:43 +00001//===------------------------- cxa_exception.cpp --------------------------===//
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// This file implements the "Exception Handling APIs"
10// http://www.codesourcery.com/public/cxx-abi/abi-eh.html
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +000011// http://www.intel.com/design/itanium/downloads/245358.htm
Howard Hinnant9027d252012-01-04 20:49:43 +000012//
13//===----------------------------------------------------------------------===//
14
15#include "unwind.h"
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +000016#include "cxa_exception.hpp"
Howard Hinnantebe8ed42012-01-22 21:47:40 +000017#include "private_typeinfo.h"
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +000018#include <typeinfo>
19#include <stdlib.h>
20#include <assert.h>
Howard Hinnant9027d252012-01-04 20:49:43 +000021
Howard Hinnant7f476b42012-01-22 19:14:27 +000022// +---------------------------+-----------------------------+---------------+
23// | __cxa_exception | _Unwind_Exception CLNGC++\0 | thrown object |
24// +---------------------------+-----------------------------+---------------+
25// ^
26// |
27// +-------------------------------------------------------+
28// |
29// +---------------------------+-----------------------------+
30// | __cxa_dependent_exception | _Unwind_Exception CLNGC++\1 |
31// +---------------------------+-----------------------------+
32
Howard Hinnant9027d252012-01-04 20:49:43 +000033namespace __cxxabiv1
34{
35
36extern "C"
37{
38
39// private API
40
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +000041// Heavily borrowed from llvm/examples/ExceptionDemo/ExceptionDemo.cpp
42
43// DWARF Constants
44enum
45{
46 DW_EH_PE_absptr = 0x00,
47 DW_EH_PE_uleb128 = 0x01,
48 DW_EH_PE_udata2 = 0x02,
49 DW_EH_PE_udata4 = 0x03,
50 DW_EH_PE_udata8 = 0x04,
51 DW_EH_PE_sleb128 = 0x09,
52 DW_EH_PE_sdata2 = 0x0A,
53 DW_EH_PE_sdata4 = 0x0B,
54 DW_EH_PE_sdata8 = 0x0C,
55 DW_EH_PE_pcrel = 0x10,
56 DW_EH_PE_textrel = 0x20,
57 DW_EH_PE_datarel = 0x30,
58 DW_EH_PE_funcrel = 0x40,
59 DW_EH_PE_aligned = 0x50,
60 DW_EH_PE_indirect = 0x80,
61 DW_EH_PE_omit = 0xFF
62};
63
64/// Read a uleb128 encoded value and advance pointer
65/// See Variable Length Data Appendix C in:
66/// @link http://dwarfstd.org/Dwarf4.pdf @unlink
67/// @param data reference variable holding memory pointer to decode from
68/// @returns decoded value
69static
70uintptr_t
71readULEB128(const uint8_t** data)
72{
73 uintptr_t result = 0;
74 uintptr_t shift = 0;
75 unsigned char byte;
76 const uint8_t *p = *data;
77 do
78 {
79 byte = *p++;
80 result |= static_cast<uintptr_t>(byte & 0x7F) << shift;
81 shift += 7;
82 } while (byte & 0x80);
83 *data = p;
84 return result;
85}
86
87/// Read a sleb128 encoded value and advance pointer
88/// See Variable Length Data Applendix C in:
89/// @link http://dwarfstd.org/Dwarf4.pdf @unlink
90/// @param data reference variable holding memory pointer to decode from
91/// @returns decoded value
92static
93uintptr_t
94readSLEB128(const uint8_t** data)
95{
96 uintptr_t result = 0;
97 uintptr_t shift = 0;
98 unsigned char byte;
99 const uint8_t *p = *data;
100 do
101 {
102 byte = *p++;
103 result |= static_cast<uintptr_t>(byte & 0x7F) << shift;
104 shift += 7;
105 } while (byte & 0x80);
106 *data = p;
107 if ((byte & 0x40) && (shift < (sizeof(result) << 3)))
108 result |= static_cast<uintptr_t>(~0) << shift;
109 return result;
110}
111
112/// Read a pointer encoded value and advance pointer
113/// See Variable Length Data in:
114/// @link http://dwarfstd.org/Dwarf3.pdf @unlink
115/// @param data reference variable holding memory pointer to decode from
116/// @param encoding dwarf encoding type
117/// @returns decoded value
118static
119uintptr_t
120readEncodedPointer(const uint8_t** data, uint8_t encoding)
121{
Howard Hinnantd8c44bd2012-01-08 23:50:46 +0000122// TODO: Not quite rgiht. This should be able to read a 0 from the TType table
123// and not dereference it. Pasted in temporayr workaround
124// TODO: Sometimes this is clearly not always reading an encoded pointer, for
125// example a length in the call site table. Needs new name?
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000126 uintptr_t result = 0;
127 const uint8_t* p = *data;
128 if (encoding == DW_EH_PE_omit)
129 return result;
130 // first get value
131 switch (encoding & 0x0F)
132 {
133 case DW_EH_PE_absptr:
134 result = *((uintptr_t*)p);
135 p += sizeof(uintptr_t);
136 break;
137 case DW_EH_PE_uleb128:
138 result = readULEB128(&p);
139 break;
140 case DW_EH_PE_sleb128:
141 result = readSLEB128(&p);
142 break;
143 case DW_EH_PE_udata2:
144 result = *((uint16_t*)p);
145 p += sizeof(uint16_t);
146 break;
147 case DW_EH_PE_udata4:
148 result = *((uint32_t*)p);
149 p += sizeof(uint32_t);
150 break;
151 case DW_EH_PE_udata8:
152 result = *((uint64_t*)p);
153 p += sizeof(uint64_t);
154 break;
155 case DW_EH_PE_sdata2:
156 result = *((int16_t*)p);
157 p += sizeof(int16_t);
158 break;
159 case DW_EH_PE_sdata4:
160 result = *((int32_t*)p);
161 p += sizeof(int32_t);
162 break;
163 case DW_EH_PE_sdata8:
164 result = *((int64_t*)p);
165 p += sizeof(int64_t);
166 break;
167 default:
168 // not supported
169 abort();
170 break;
171 }
172 // then add relative offset
173 switch (encoding & 0x70)
174 {
175 case DW_EH_PE_absptr:
176 // do nothing
177 break;
178 case DW_EH_PE_pcrel:
Howard Hinnantd8c44bd2012-01-08 23:50:46 +0000179 if (result)
180 result += (uintptr_t)(*data);
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000181 break;
182 case DW_EH_PE_textrel:
183 case DW_EH_PE_datarel:
184 case DW_EH_PE_funcrel:
185 case DW_EH_PE_aligned:
186 default:
187 // not supported
188 abort();
189 break;
190 }
191 // then apply indirection
Howard Hinnantd8c44bd2012-01-08 23:50:46 +0000192 if (result && (encoding & DW_EH_PE_indirect))
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000193 result = *((uintptr_t*)result);
194 *data = p;
195 return result;
196}
197
Howard Hinnantd8c44bd2012-01-08 23:50:46 +0000198static
199const uint8_t*
200getTTypeEntry(int64_t typeOffset, const uint8_t* classInfo, uint8_t ttypeEncoding)
201{
202 switch (ttypeEncoding & 0x0F)
203 {
204 case DW_EH_PE_absptr:
205 typeOffset *= sizeof(void*);
206 break;
207 case DW_EH_PE_udata2:
208 case DW_EH_PE_sdata2:
209 typeOffset *= 2;
210 break;
211 case DW_EH_PE_udata4:
212 case DW_EH_PE_sdata4:
213 typeOffset *= 4;
214 break;
215 case DW_EH_PE_udata8:
216 case DW_EH_PE_sdata8:
217 typeOffset *= 8;
218 break;
219 }
220 return classInfo - typeOffset;
221}
222
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000223/// Deals with Dwarf actions matching our type infos
224/// (OurExceptionType_t instances). Returns whether or not a dwarf emitted
225/// action matches the supplied exception type. If such a match succeeds,
226/// the handlerSwitchValue will be set with > 0 index value. Only
227/// corresponding llvm.eh.selector type info arguments, cleanup arguments
228/// are supported. Filters are not supported.
229/// See Variable Length Data in:
230/// @link http://dwarfstd.org/Dwarf3.pdf @unlink
231/// Also see @link http://refspecs.freestandards.org/abi-eh-1.21.html @unlink
232/// @param classInfo our array of type info pointers (to globals)
233/// @param actionEntry index into above type info array or 0 (clean up).
234/// We do not support filters.
Howard Hinnant7f476b42012-01-22 19:14:27 +0000235/// @param unwind_exception thrown _Unwind_Exception instance.
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000236/// @returns whether or not a type info was found. False is returned if only
237/// a cleanup was found
238static
239bool
Howard Hinnantd8c44bd2012-01-08 23:50:46 +0000240handleActionValue(const uint8_t* classInfo, uintptr_t actionEntry,
Howard Hinnant7f476b42012-01-22 19:14:27 +0000241 _Unwind_Exception* unwind_exception, uint8_t ttypeEncoding)
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000242{
Howard Hinnant7f476b42012-01-22 19:14:27 +0000243 __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
Howard Hinnantebe8ed42012-01-22 21:47:40 +0000244 void* thrown_object =
245 unwind_exception->exception_class == kOurDependentExceptionClass ?
246 ((__cxa_dependent_exception*)exception_header)->primaryException :
247 exception_header + 1;
248 const __shim_type_info* excpType =
249 static_cast<const __shim_type_info*>(exception_header->exceptionType);
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000250 const uint8_t* actionPos = (uint8_t*)actionEntry;
Howard Hinnantd8c44bd2012-01-08 23:50:46 +0000251 while (true)
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000252 {
253 // Each emitted dwarf action corresponds to a 2 tuple of
254 // type info address offset, and action offset to the next
255 // emitted action.
Howard Hinnantd8c44bd2012-01-08 23:50:46 +0000256 const uint8_t* SactionPos = actionPos;
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000257 int64_t typeOffset = readSLEB128(&actionPos);
258 const uint8_t* tempActionPos = actionPos;
259 int64_t actionOffset = readSLEB128(&tempActionPos);
Howard Hinnantd8c44bd2012-01-08 23:50:46 +0000260 if (typeOffset > 0) // a catch handler
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000261 {
Howard Hinnantd8c44bd2012-01-08 23:50:46 +0000262 const uint8_t* TTypeEntry = getTTypeEntry(typeOffset, classInfo,
263 ttypeEncoding);
Howard Hinnantebe8ed42012-01-22 21:47:40 +0000264 const __shim_type_info* catchType =
265 (const __shim_type_info*)readEncodedPointer(&TTypeEntry,
Howard Hinnantd8c44bd2012-01-08 23:50:46 +0000266 ttypeEncoding);
Howard Hinnantebe8ed42012-01-22 21:47:40 +0000267 void* adjustedPtr = thrown_object;
Howard Hinnantd8c44bd2012-01-08 23:50:46 +0000268 // catchType == 0 -> catch (...)
Howard Hinnantebe8ed42012-01-22 21:47:40 +0000269 if (catchType == 0 || catchType->can_catch(excpType, adjustedPtr))
Howard Hinnantd8c44bd2012-01-08 23:50:46 +0000270 {
Howard Hinnant7f476b42012-01-22 19:14:27 +0000271 exception_header->handlerSwitchValue = typeOffset;
Howard Hinnantebe8ed42012-01-22 21:47:40 +0000272 exception_header->actionRecord = SactionPos; // unnecessary?
273 // used by __cxa_get_exception_ptr and __cxa_begin_catch
274 exception_header->adjustedPtr = adjustedPtr;
Howard Hinnantd8c44bd2012-01-08 23:50:46 +0000275 return true;
276 }
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000277 }
Howard Hinnantd8c44bd2012-01-08 23:50:46 +0000278 else if (typeOffset < 0) // an exception spec
279 {
280 }
281 else // typeOffset == 0 // a clean up
282 {
283 }
284 if (actionOffset == 0)
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000285 break;
286 actionPos += actionOffset;
287 }
288 return false;
289}
290
Howard Hinnant9027d252012-01-04 20:49:43 +0000291// Return true if there is a handler and false otherwise
292// cache handlerSwitchValue, actionRecord, languageSpecificData,
293// catchTemp and adjustedPtr here.
294static
295bool
Howard Hinnant7f476b42012-01-22 19:14:27 +0000296contains_handler(_Unwind_Exception* unwind_exception, _Unwind_Context* context)
Howard Hinnant9027d252012-01-04 20:49:43 +0000297{
Howard Hinnant7f476b42012-01-22 19:14:27 +0000298 __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000299 const uint8_t* lsda = (const uint8_t*)_Unwind_GetLanguageSpecificData(context);
Howard Hinnant7f476b42012-01-22 19:14:27 +0000300 exception_header->languageSpecificData = lsda;
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000301 if (lsda)
302 {
303 // Get the current instruction pointer and offset it before next
304 // instruction in the current frame which threw the exception.
305 uintptr_t pc = _Unwind_GetIP(context) - 1;
306 // Get beginning current frame's code (as defined by the
307 // emitted dwarf code)
308 uintptr_t funcStart = _Unwind_GetRegionStart(context);
309 uintptr_t pcOffset = pc - funcStart;
Howard Hinnantd8c44bd2012-01-08 23:50:46 +0000310 const uint8_t* classInfo = NULL;
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000311 // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding
312 // dwarf emission
313 // Parse LSDA header.
314 uint8_t lpStartEncoding = *lsda++;
315 if (lpStartEncoding != DW_EH_PE_omit)
316 (void)readEncodedPointer(&lsda, lpStartEncoding);
317 uint8_t ttypeEncoding = *lsda++;
Howard Hinnantd8c44bd2012-01-08 23:50:46 +0000318 // TODO: preflight ttypeEncoding here and return error if there's a problem
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000319 if (ttypeEncoding != DW_EH_PE_omit)
320 {
321 // Calculate type info locations in emitted dwarf code which
322 // were flagged by type info arguments to llvm.eh.selector
323 // intrinsic
324 uintptr_t classInfoOffset = readULEB128(&lsda);
Howard Hinnantd8c44bd2012-01-08 23:50:46 +0000325 classInfo = lsda + classInfoOffset;
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000326 }
327 // Walk call-site table looking for range that
328 // includes current PC.
329 uint8_t callSiteEncoding = *lsda++;
330 uint32_t callSiteTableLength = readULEB128(&lsda);
331 const uint8_t* callSiteTableStart = lsda;
332 const uint8_t* callSiteTableEnd = callSiteTableStart + callSiteTableLength;
333 const uint8_t* actionTableStart = callSiteTableEnd;
334 const uint8_t* callSitePtr = callSiteTableStart;
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000335 while (callSitePtr < callSiteTableEnd)
336 {
337 uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding);
338 uintptr_t length = readEncodedPointer(&callSitePtr, callSiteEncoding);
339 uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding);
340 // Note: Action value
341 uintptr_t actionEntry = readULEB128(&callSitePtr);
342 if (landingPad == 0)
343 continue; // no landing pad for this entry
344 if (actionEntry)
345 actionEntry += ((uintptr_t)actionTableStart) - 1;
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000346 if ((start <= pcOffset) && (pcOffset < (start + length)))
347 {
Howard Hinnant7f476b42012-01-22 19:14:27 +0000348 exception_header->catchTemp = (void*)(funcStart + landingPad);
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000349 if (actionEntry)
350 return handleActionValue(classInfo,
351 actionEntry,
Howard Hinnant7f476b42012-01-22 19:14:27 +0000352 unwind_exception,
Howard Hinnantd8c44bd2012-01-08 23:50:46 +0000353 ttypeEncoding);
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000354 // Note: Only non-clean up handlers are marked as
355 // found. Otherwise the clean up handlers will be
356 // re-found and executed during the clean up
357 // phase.
Howard Hinnantd8c44bd2012-01-08 23:50:46 +0000358 return true; //?
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000359 }
360 }
Howard Hinnantd8c44bd2012-01-08 23:50:46 +0000361 // Not found, need to properly terminate
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000362 }
363 return false;
Howard Hinnant9027d252012-01-04 20:49:43 +0000364}
365
Howard Hinnant9027d252012-01-04 20:49:43 +0000366static
367_Unwind_Reason_Code
Howard Hinnant7f476b42012-01-22 19:14:27 +0000368transfer_control_to_landing_pad(_Unwind_Exception* unwind_exception,
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000369 _Unwind_Context* context)
Howard Hinnant9027d252012-01-04 20:49:43 +0000370{
Howard Hinnant7f476b42012-01-22 19:14:27 +0000371 __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
372 _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), (uintptr_t)unwind_exception);
373 _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), exception_header->handlerSwitchValue);
374 _Unwind_SetIP(context, (uintptr_t)exception_header->catchTemp);
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000375 return _URC_INSTALL_CONTEXT;
Howard Hinnant9027d252012-01-04 20:49:43 +0000376}
377
Howard Hinnant9027d252012-01-04 20:49:43 +0000378static
379_Unwind_Reason_Code
Howard Hinnant7f476b42012-01-22 19:14:27 +0000380perform_cleanup(_Unwind_Exception* unwind_exception, _Unwind_Context* context)
Howard Hinnant9027d252012-01-04 20:49:43 +0000381{
Howard Hinnant7f476b42012-01-22 19:14:27 +0000382 __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
383 _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), (uintptr_t)unwind_exception);
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000384 _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
Howard Hinnant7f476b42012-01-22 19:14:27 +0000385 _Unwind_SetIP(context, (uintptr_t)exception_header->catchTemp);
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000386 return _URC_INSTALL_CONTEXT;
Howard Hinnant9027d252012-01-04 20:49:43 +0000387}
388
389// public API
390
391// Requires: version == 1
392// actions == _UA_SEARCH_PHASE, or
393// == _UA_CLEANUP_PHASE, or
394// == _UA_CLEANUP_PHASE | _UA_HANDLER_FRAME, or
395// == _UA_CLEANUP_PHASE | _UA_FORCE_UNWIND
Howard Hinnant7f476b42012-01-22 19:14:27 +0000396// unwind_exception != nullptr
Howard Hinnant9027d252012-01-04 20:49:43 +0000397// context != nullptr
398_Unwind_Reason_Code
399__gxx_personality_v0(int version, _Unwind_Action actions, uint64_t exceptionClass,
Howard Hinnant7f476b42012-01-22 19:14:27 +0000400 _Unwind_Exception* unwind_exception, _Unwind_Context* context)
Howard Hinnant9027d252012-01-04 20:49:43 +0000401{
Howard Hinnant7f476b42012-01-22 19:14:27 +0000402 if (version == 1 && unwind_exception != 0 && context != 0)
Howard Hinnant9027d252012-01-04 20:49:43 +0000403 {
Howard Hinnantd8c44bd2012-01-08 23:50:46 +0000404 bool native_exception = (exceptionClass & 0xFFFFFF00) == 0x432B2B00;
Howard Hinnant9027d252012-01-04 20:49:43 +0000405 bool force_unwind = actions & _UA_FORCE_UNWIND;
406 if (native_exception && !force_unwind)
407 {
408 if (actions & _UA_SEARCH_PHASE)
409 {
410 if (actions & _UA_CLEANUP_PHASE)
411 return _URC_FATAL_PHASE1_ERROR;
Howard Hinnant7f476b42012-01-22 19:14:27 +0000412 if (contains_handler(unwind_exception, context))
Howard Hinnantf7bfc6f2012-01-06 20:39:47 +0000413 return _URC_HANDLER_FOUND;
Howard Hinnant9027d252012-01-04 20:49:43 +0000414 return _URC_CONTINUE_UNWIND;
415 }
416 if (actions & _UA_CLEANUP_PHASE)
417 {
418 if (actions & _UA_HANDLER_FRAME)
419 {
420 // return _URC_INSTALL_CONTEXT or _URC_FATAL_PHASE2_ERROR
Howard Hinnant7f476b42012-01-22 19:14:27 +0000421 return transfer_control_to_landing_pad(unwind_exception, context);
Howard Hinnant9027d252012-01-04 20:49:43 +0000422 }
423 // return _URC_CONTINUE_UNWIND or _URC_FATAL_PHASE2_ERROR
Howard Hinnant7f476b42012-01-22 19:14:27 +0000424 return perform_cleanup(unwind_exception, context);
Howard Hinnant9027d252012-01-04 20:49:43 +0000425 }
426 }
427 else // foreign exception or force_unwind
428 {
429 if (actions & _UA_SEARCH_PHASE)
430 {
431 if (actions & _UA_CLEANUP_PHASE)
432 return _URC_FATAL_PHASE1_ERROR;
433 return _URC_CONTINUE_UNWIND;
434 }
435 if (actions & _UA_CLEANUP_PHASE)
436 {
437 if (actions & _UA_HANDLER_FRAME)
438 return _URC_FATAL_PHASE2_ERROR;
439 // return _URC_CONTINUE_UNWIND or _URC_FATAL_PHASE2_ERROR
Howard Hinnant7f476b42012-01-22 19:14:27 +0000440 return perform_cleanup(unwind_exception, context);
Howard Hinnant9027d252012-01-04 20:49:43 +0000441 }
442 }
443 }
444 return _URC_FATAL_PHASE1_ERROR;
445}
446
447} // extern "C"
448
449} // __cxxabiv1