blob: ccad2bcd9581ac61f009ed209beaf36ad1a5433a [file] [log] [blame]
Howard Hinnant66d93272012-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 Hinnantd3dba312012-01-06 20:39:47 +000011// http://www.intel.com/design/itanium/downloads/245358.htm
Howard Hinnant66d93272012-01-04 20:49:43 +000012//
13//===----------------------------------------------------------------------===//
14
15#include "unwind.h"
Howard Hinnantd3dba312012-01-06 20:39:47 +000016#include "cxa_exception.hpp"
Howard Hinnant699692a2012-01-22 21:47:40 +000017#include "private_typeinfo.h"
Howard Hinnantd3dba312012-01-06 20:39:47 +000018#include <typeinfo>
19#include <stdlib.h>
20#include <assert.h>
Howard Hinnant66d93272012-01-04 20:49:43 +000021
Howard Hinnantafcf7ac2012-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 Hinnant66d93272012-01-04 20:49:43 +000033namespace __cxxabiv1
34{
35
36extern "C"
37{
38
39// private API
40
Howard Hinnantd3dba312012-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 Hinnant86b4dfa2012-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 Hinnantd3dba312012-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 Hinnant86b4dfa2012-01-08 23:50:46 +0000179 if (result)
180 result += (uintptr_t)(*data);
Howard Hinnantd3dba312012-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 Hinnant86b4dfa2012-01-08 23:50:46 +0000192 if (result && (encoding & DW_EH_PE_indirect))
Howard Hinnantd3dba312012-01-06 20:39:47 +0000193 result = *((uintptr_t*)result);
194 *data = p;
195 return result;
196}
197
Howard Hinnant86b4dfa2012-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 Hinnant699692a2012-01-22 21:47:40 +0000223static const uint64_t kOurDependentExceptionClass = 0x434C4E47432B2B01; // CLNGC++\1
224
Howard Hinnantd3dba312012-01-06 20:39:47 +0000225/// Deals with Dwarf actions matching our type infos
226/// (OurExceptionType_t instances). Returns whether or not a dwarf emitted
227/// action matches the supplied exception type. If such a match succeeds,
228/// the handlerSwitchValue will be set with > 0 index value. Only
229/// corresponding llvm.eh.selector type info arguments, cleanup arguments
230/// are supported. Filters are not supported.
231/// See Variable Length Data in:
232/// @link http://dwarfstd.org/Dwarf3.pdf @unlink
233/// Also see @link http://refspecs.freestandards.org/abi-eh-1.21.html @unlink
234/// @param classInfo our array of type info pointers (to globals)
235/// @param actionEntry index into above type info array or 0 (clean up).
236/// We do not support filters.
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000237/// @param unwind_exception thrown _Unwind_Exception instance.
Howard Hinnantd3dba312012-01-06 20:39:47 +0000238/// @returns whether or not a type info was found. False is returned if only
239/// a cleanup was found
240static
241bool
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000242handleActionValue(const uint8_t* classInfo, uintptr_t actionEntry,
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000243 _Unwind_Exception* unwind_exception, uint8_t ttypeEncoding)
Howard Hinnantd3dba312012-01-06 20:39:47 +0000244{
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000245 __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
Howard Hinnant699692a2012-01-22 21:47:40 +0000246 void* thrown_object =
247 unwind_exception->exception_class == kOurDependentExceptionClass ?
248 ((__cxa_dependent_exception*)exception_header)->primaryException :
249 exception_header + 1;
250 const __shim_type_info* excpType =
251 static_cast<const __shim_type_info*>(exception_header->exceptionType);
Howard Hinnantd3dba312012-01-06 20:39:47 +0000252 const uint8_t* actionPos = (uint8_t*)actionEntry;
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000253 while (true)
Howard Hinnantd3dba312012-01-06 20:39:47 +0000254 {
255 // Each emitted dwarf action corresponds to a 2 tuple of
256 // type info address offset, and action offset to the next
257 // emitted action.
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000258 const uint8_t* SactionPos = actionPos;
Howard Hinnantd3dba312012-01-06 20:39:47 +0000259 int64_t typeOffset = readSLEB128(&actionPos);
260 const uint8_t* tempActionPos = actionPos;
261 int64_t actionOffset = readSLEB128(&tempActionPos);
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000262 if (typeOffset > 0) // a catch handler
Howard Hinnantd3dba312012-01-06 20:39:47 +0000263 {
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000264 const uint8_t* TTypeEntry = getTTypeEntry(typeOffset, classInfo,
265 ttypeEncoding);
Howard Hinnant699692a2012-01-22 21:47:40 +0000266 const __shim_type_info* catchType =
267 (const __shim_type_info*)readEncodedPointer(&TTypeEntry,
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000268 ttypeEncoding);
Howard Hinnant699692a2012-01-22 21:47:40 +0000269 void* adjustedPtr = thrown_object;
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000270 // catchType == 0 -> catch (...)
Howard Hinnant699692a2012-01-22 21:47:40 +0000271 if (catchType == 0 || catchType->can_catch(excpType, adjustedPtr))
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000272 {
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000273 exception_header->handlerSwitchValue = typeOffset;
Howard Hinnant699692a2012-01-22 21:47:40 +0000274 exception_header->actionRecord = SactionPos; // unnecessary?
275 // used by __cxa_get_exception_ptr and __cxa_begin_catch
276 exception_header->adjustedPtr = adjustedPtr;
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000277 return true;
278 }
Howard Hinnantd3dba312012-01-06 20:39:47 +0000279 }
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000280 else if (typeOffset < 0) // an exception spec
281 {
282 }
283 else // typeOffset == 0 // a clean up
284 {
285 }
286 if (actionOffset == 0)
Howard Hinnantd3dba312012-01-06 20:39:47 +0000287 break;
288 actionPos += actionOffset;
289 }
290 return false;
291}
292
Howard Hinnant66d93272012-01-04 20:49:43 +0000293// Return true if there is a handler and false otherwise
294// cache handlerSwitchValue, actionRecord, languageSpecificData,
295// catchTemp and adjustedPtr here.
296static
297bool
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000298contains_handler(_Unwind_Exception* unwind_exception, _Unwind_Context* context)
Howard Hinnant66d93272012-01-04 20:49:43 +0000299{
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000300 __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
Howard Hinnantd3dba312012-01-06 20:39:47 +0000301 const uint8_t* lsda = (const uint8_t*)_Unwind_GetLanguageSpecificData(context);
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000302 exception_header->languageSpecificData = lsda;
Howard Hinnantd3dba312012-01-06 20:39:47 +0000303 if (lsda)
304 {
305 // Get the current instruction pointer and offset it before next
306 // instruction in the current frame which threw the exception.
307 uintptr_t pc = _Unwind_GetIP(context) - 1;
308 // Get beginning current frame's code (as defined by the
309 // emitted dwarf code)
310 uintptr_t funcStart = _Unwind_GetRegionStart(context);
311 uintptr_t pcOffset = pc - funcStart;
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000312 const uint8_t* classInfo = NULL;
Howard Hinnantd3dba312012-01-06 20:39:47 +0000313 // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding
314 // dwarf emission
315 // Parse LSDA header.
316 uint8_t lpStartEncoding = *lsda++;
317 if (lpStartEncoding != DW_EH_PE_omit)
318 (void)readEncodedPointer(&lsda, lpStartEncoding);
319 uint8_t ttypeEncoding = *lsda++;
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000320 // TODO: preflight ttypeEncoding here and return error if there's a problem
Howard Hinnantd3dba312012-01-06 20:39:47 +0000321 if (ttypeEncoding != DW_EH_PE_omit)
322 {
323 // Calculate type info locations in emitted dwarf code which
324 // were flagged by type info arguments to llvm.eh.selector
325 // intrinsic
326 uintptr_t classInfoOffset = readULEB128(&lsda);
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000327 classInfo = lsda + classInfoOffset;
Howard Hinnantd3dba312012-01-06 20:39:47 +0000328 }
329 // Walk call-site table looking for range that
330 // includes current PC.
331 uint8_t callSiteEncoding = *lsda++;
332 uint32_t callSiteTableLength = readULEB128(&lsda);
333 const uint8_t* callSiteTableStart = lsda;
334 const uint8_t* callSiteTableEnd = callSiteTableStart + callSiteTableLength;
335 const uint8_t* actionTableStart = callSiteTableEnd;
336 const uint8_t* callSitePtr = callSiteTableStart;
Howard Hinnantd3dba312012-01-06 20:39:47 +0000337 while (callSitePtr < callSiteTableEnd)
338 {
339 uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding);
340 uintptr_t length = readEncodedPointer(&callSitePtr, callSiteEncoding);
341 uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding);
342 // Note: Action value
343 uintptr_t actionEntry = readULEB128(&callSitePtr);
344 if (landingPad == 0)
345 continue; // no landing pad for this entry
346 if (actionEntry)
347 actionEntry += ((uintptr_t)actionTableStart) - 1;
Howard Hinnantd3dba312012-01-06 20:39:47 +0000348 if ((start <= pcOffset) && (pcOffset < (start + length)))
349 {
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000350 exception_header->catchTemp = (void*)(funcStart + landingPad);
Howard Hinnantd3dba312012-01-06 20:39:47 +0000351 if (actionEntry)
352 return handleActionValue(classInfo,
353 actionEntry,
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000354 unwind_exception,
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000355 ttypeEncoding);
Howard Hinnantd3dba312012-01-06 20:39:47 +0000356 // Note: Only non-clean up handlers are marked as
357 // found. Otherwise the clean up handlers will be
358 // re-found and executed during the clean up
359 // phase.
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000360 return true; //?
Howard Hinnantd3dba312012-01-06 20:39:47 +0000361 }
362 }
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000363 // Not found, need to properly terminate
Howard Hinnantd3dba312012-01-06 20:39:47 +0000364 }
365 return false;
Howard Hinnant66d93272012-01-04 20:49:43 +0000366}
367
Howard Hinnant66d93272012-01-04 20:49:43 +0000368static
369_Unwind_Reason_Code
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000370transfer_control_to_landing_pad(_Unwind_Exception* unwind_exception,
Howard Hinnantd3dba312012-01-06 20:39:47 +0000371 _Unwind_Context* context)
Howard Hinnant66d93272012-01-04 20:49:43 +0000372{
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000373 __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
374 _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), (uintptr_t)unwind_exception);
375 _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), exception_header->handlerSwitchValue);
376 _Unwind_SetIP(context, (uintptr_t)exception_header->catchTemp);
Howard Hinnantd3dba312012-01-06 20:39:47 +0000377 return _URC_INSTALL_CONTEXT;
Howard Hinnant66d93272012-01-04 20:49:43 +0000378}
379
Howard Hinnant66d93272012-01-04 20:49:43 +0000380static
381_Unwind_Reason_Code
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000382perform_cleanup(_Unwind_Exception* unwind_exception, _Unwind_Context* context)
Howard Hinnant66d93272012-01-04 20:49:43 +0000383{
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000384 __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
385 _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), (uintptr_t)unwind_exception);
Howard Hinnantd3dba312012-01-06 20:39:47 +0000386 _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000387 _Unwind_SetIP(context, (uintptr_t)exception_header->catchTemp);
Howard Hinnantd3dba312012-01-06 20:39:47 +0000388 return _URC_INSTALL_CONTEXT;
Howard Hinnant66d93272012-01-04 20:49:43 +0000389}
390
391// public API
392
393// Requires: version == 1
394// actions == _UA_SEARCH_PHASE, or
395// == _UA_CLEANUP_PHASE, or
396// == _UA_CLEANUP_PHASE | _UA_HANDLER_FRAME, or
397// == _UA_CLEANUP_PHASE | _UA_FORCE_UNWIND
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000398// unwind_exception != nullptr
Howard Hinnant66d93272012-01-04 20:49:43 +0000399// context != nullptr
400_Unwind_Reason_Code
401__gxx_personality_v0(int version, _Unwind_Action actions, uint64_t exceptionClass,
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000402 _Unwind_Exception* unwind_exception, _Unwind_Context* context)
Howard Hinnant66d93272012-01-04 20:49:43 +0000403{
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000404 if (version == 1 && unwind_exception != 0 && context != 0)
Howard Hinnant66d93272012-01-04 20:49:43 +0000405 {
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000406 bool native_exception = (exceptionClass & 0xFFFFFF00) == 0x432B2B00;
Howard Hinnant66d93272012-01-04 20:49:43 +0000407 bool force_unwind = actions & _UA_FORCE_UNWIND;
408 if (native_exception && !force_unwind)
409 {
410 if (actions & _UA_SEARCH_PHASE)
411 {
412 if (actions & _UA_CLEANUP_PHASE)
413 return _URC_FATAL_PHASE1_ERROR;
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000414 if (contains_handler(unwind_exception, context))
Howard Hinnantd3dba312012-01-06 20:39:47 +0000415 return _URC_HANDLER_FOUND;
Howard Hinnant66d93272012-01-04 20:49:43 +0000416 return _URC_CONTINUE_UNWIND;
417 }
418 if (actions & _UA_CLEANUP_PHASE)
419 {
420 if (actions & _UA_HANDLER_FRAME)
421 {
422 // return _URC_INSTALL_CONTEXT or _URC_FATAL_PHASE2_ERROR
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000423 return transfer_control_to_landing_pad(unwind_exception, context);
Howard Hinnant66d93272012-01-04 20:49:43 +0000424 }
425 // return _URC_CONTINUE_UNWIND or _URC_FATAL_PHASE2_ERROR
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000426 return perform_cleanup(unwind_exception, context);
Howard Hinnant66d93272012-01-04 20:49:43 +0000427 }
428 }
429 else // foreign exception or force_unwind
430 {
431 if (actions & _UA_SEARCH_PHASE)
432 {
433 if (actions & _UA_CLEANUP_PHASE)
434 return _URC_FATAL_PHASE1_ERROR;
435 return _URC_CONTINUE_UNWIND;
436 }
437 if (actions & _UA_CLEANUP_PHASE)
438 {
439 if (actions & _UA_HANDLER_FRAME)
440 return _URC_FATAL_PHASE2_ERROR;
441 // return _URC_CONTINUE_UNWIND or _URC_FATAL_PHASE2_ERROR
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000442 return perform_cleanup(unwind_exception, context);
Howard Hinnant66d93272012-01-04 20:49:43 +0000443 }
444 }
445 }
446 return _URC_FATAL_PHASE1_ERROR;
447}
448
449} // extern "C"
450
451} // __cxxabiv1