blob: 2fcac5f643a84fad7f9014239c987178287db49d [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 Hinnantad048712012-01-28 00:28:31 +000022/*
23Exception Header Layout:
24
25+---------------------------+-----------------------------+---------------+
26| __cxa_exception | _Unwind_Exception CLNGC++\0 | thrown object |
27+---------------------------+-----------------------------+---------------+
28 ^
29 |
30 +-------------------------------------------------------+
31 |
32+---------------------------+-----------------------------+
33| __cxa_dependent_exception | _Unwind_Exception CLNGC++\1 |
34+---------------------------+-----------------------------+
35
36 Exception Handling Table Layout:
37
38+-----------------+--------+
39| lpStartEncoding | (char) |
40+---------+-------+--------+---------------+-----------------------+
41| lpStart | (encoded wtih lpStartEncoding) | defaults to funcStart |
42+---------+-----+--------+-----------------+---------------+-------+
43| ttypeEncoding | (char) | Encoding of the type_info table |
44+---------------+-+------+----+----------------------------+----------------+
45| classInfoOffset | (ULEB128) | Offset to type_info table, defaults to null |
46+-----------------++--------+-+----------------------------+----------------+
47| callSiteEncoding | (char) | Encoding for Call Site Table |
48+------------------+--+-----+-----+------------------------+--------------------------+
49| callSiteTableLength | (ULEB128) | Call Site Table length, used to find Action table |
50+---------------------+-----------+--------------------------------------------------++
51| Beginning of Call Site Table If the current ip lies within the |
52| ... (start, length) range of one of these |
53| call sites, there may be action needed. |
54| +-------------+-----------------------------------+------------------------------+ |
55| | start | (encoded with Call Site Encoding) | offset relative to funcStart | |
56| | length | (encoded with Call Site Encoding) | lenght of code fragment | |
57| | landingPad | (encoded with Call Site Encoding) | offset relative to lpStart | |
58| | actionEntry | (ULEB128) | Action Table Index 1-based | |
59| | | | actionEntry == 0 -> clean up | |
60| +-------------+-----------------------------------+------------------------------+ |
61| ... |
62+---------------------------------------------------------------------+--------------+
63| Beginning of Action Table ttypeIndex == 0 : cleanup |
64| ... ttypeIndex > 0 : catch |
65| ttypeIndex < 0 : exception spec |
66| +--------------+-----------+--------------------------------------+ |
67| | ttypeIndex | (SLEB128) | Index into type_info Table (1-based) | |
68| | actionOffset | (SLEB128) | Offset into next Action Table entry | |
69| +--------------+-----------+--------------------------------------+ |
70| ... |
71+---------------------------------------------------------------------+-----------------+
72| type_info Table, but classInfoOffset does *not* point here! |
73| +----------------+------------------------------------------------+-----------------+ |
74| | Nth type_info* | Encoded with ttypeEncoding, 0 means every type | ttypeIndex == N | |
75| +----------------+------------------------------------------------+-----------------+ |
76| ... |
77| +----------------+------------------------------------------------+-----------------+ |
78| | 1st type_info* | Encoded with ttypeEncoding, 0 means every type | ttypeIndex == 1 | |
79| +----------------+------------------------------------------------+-----------------+ |
80| +---------------------------------------+-----------+------------------------------+ |
81| | 1st ttypeIndex for 1st exception spec | (ULEB128) | classInfoOffset points here! | |
82| | 2nd ttypeIndex for 1st exception spec | (ULEB128) | | |
83| | 3rd ttypeIndex for 1st exception spec | (ULEB128) | | |
84| | 0 | (ULEB128) | | |
85| +---------------------------------------+------------------------------------------+ |
86| ... |
87| +---------------------------------------+------------------------------------------+ |
88| | 1st ttypeIndex for Nth exception spec | (ULEB128) | | |
89| | 2nd ttypeIndex for Nth exception spec | (ULEB128) | | |
90| | 3rd ttypeIndex for Nth exception spec | (ULEB128) | | |
91| | 0 | (ULEB128) | | |
92| +---------------------------------------+------------------------------------------+ |
93+---------------------------------------------------------------------------------------+
94*/
Howard Hinnantafcf7ac2012-01-22 19:14:27 +000095
Howard Hinnant66d93272012-01-04 20:49:43 +000096namespace __cxxabiv1
97{
98
99extern "C"
100{
101
102// private API
103
Howard Hinnantd3dba312012-01-06 20:39:47 +0000104// Heavily borrowed from llvm/examples/ExceptionDemo/ExceptionDemo.cpp
105
106// DWARF Constants
107enum
108{
109 DW_EH_PE_absptr = 0x00,
110 DW_EH_PE_uleb128 = 0x01,
111 DW_EH_PE_udata2 = 0x02,
112 DW_EH_PE_udata4 = 0x03,
113 DW_EH_PE_udata8 = 0x04,
114 DW_EH_PE_sleb128 = 0x09,
115 DW_EH_PE_sdata2 = 0x0A,
116 DW_EH_PE_sdata4 = 0x0B,
117 DW_EH_PE_sdata8 = 0x0C,
118 DW_EH_PE_pcrel = 0x10,
119 DW_EH_PE_textrel = 0x20,
120 DW_EH_PE_datarel = 0x30,
121 DW_EH_PE_funcrel = 0x40,
122 DW_EH_PE_aligned = 0x50,
123 DW_EH_PE_indirect = 0x80,
124 DW_EH_PE_omit = 0xFF
125};
126
127/// Read a uleb128 encoded value and advance pointer
128/// See Variable Length Data Appendix C in:
129/// @link http://dwarfstd.org/Dwarf4.pdf @unlink
130/// @param data reference variable holding memory pointer to decode from
131/// @returns decoded value
132static
133uintptr_t
134readULEB128(const uint8_t** data)
135{
136 uintptr_t result = 0;
137 uintptr_t shift = 0;
138 unsigned char byte;
139 const uint8_t *p = *data;
140 do
141 {
142 byte = *p++;
143 result |= static_cast<uintptr_t>(byte & 0x7F) << shift;
144 shift += 7;
145 } while (byte & 0x80);
146 *data = p;
147 return result;
148}
149
150/// Read a sleb128 encoded value and advance pointer
151/// See Variable Length Data Applendix C in:
152/// @link http://dwarfstd.org/Dwarf4.pdf @unlink
153/// @param data reference variable holding memory pointer to decode from
154/// @returns decoded value
155static
156uintptr_t
157readSLEB128(const uint8_t** data)
158{
159 uintptr_t result = 0;
160 uintptr_t shift = 0;
161 unsigned char byte;
162 const uint8_t *p = *data;
163 do
164 {
165 byte = *p++;
166 result |= static_cast<uintptr_t>(byte & 0x7F) << shift;
167 shift += 7;
168 } while (byte & 0x80);
169 *data = p;
170 if ((byte & 0x40) && (shift < (sizeof(result) << 3)))
171 result |= static_cast<uintptr_t>(~0) << shift;
172 return result;
173}
174
175/// Read a pointer encoded value and advance pointer
176/// See Variable Length Data in:
177/// @link http://dwarfstd.org/Dwarf3.pdf @unlink
178/// @param data reference variable holding memory pointer to decode from
179/// @param encoding dwarf encoding type
180/// @returns decoded value
181static
182uintptr_t
183readEncodedPointer(const uint8_t** data, uint8_t encoding)
184{
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000185// TODO: Not quite rgiht. This should be able to read a 0 from the TType table
186// and not dereference it. Pasted in temporayr workaround
187// TODO: Sometimes this is clearly not always reading an encoded pointer, for
188// example a length in the call site table. Needs new name?
Howard Hinnantd3dba312012-01-06 20:39:47 +0000189 uintptr_t result = 0;
190 const uint8_t* p = *data;
191 if (encoding == DW_EH_PE_omit)
192 return result;
193 // first get value
194 switch (encoding & 0x0F)
195 {
196 case DW_EH_PE_absptr:
197 result = *((uintptr_t*)p);
198 p += sizeof(uintptr_t);
199 break;
200 case DW_EH_PE_uleb128:
201 result = readULEB128(&p);
202 break;
203 case DW_EH_PE_sleb128:
204 result = readSLEB128(&p);
205 break;
206 case DW_EH_PE_udata2:
207 result = *((uint16_t*)p);
208 p += sizeof(uint16_t);
209 break;
210 case DW_EH_PE_udata4:
211 result = *((uint32_t*)p);
212 p += sizeof(uint32_t);
213 break;
214 case DW_EH_PE_udata8:
215 result = *((uint64_t*)p);
216 p += sizeof(uint64_t);
217 break;
218 case DW_EH_PE_sdata2:
219 result = *((int16_t*)p);
220 p += sizeof(int16_t);
221 break;
222 case DW_EH_PE_sdata4:
223 result = *((int32_t*)p);
224 p += sizeof(int32_t);
225 break;
226 case DW_EH_PE_sdata8:
227 result = *((int64_t*)p);
228 p += sizeof(int64_t);
229 break;
230 default:
231 // not supported
232 abort();
233 break;
234 }
235 // then add relative offset
236 switch (encoding & 0x70)
237 {
238 case DW_EH_PE_absptr:
239 // do nothing
240 break;
241 case DW_EH_PE_pcrel:
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000242 if (result)
243 result += (uintptr_t)(*data);
Howard Hinnantd3dba312012-01-06 20:39:47 +0000244 break;
245 case DW_EH_PE_textrel:
246 case DW_EH_PE_datarel:
247 case DW_EH_PE_funcrel:
248 case DW_EH_PE_aligned:
249 default:
250 // not supported
251 abort();
252 break;
253 }
254 // then apply indirection
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000255 if (result && (encoding & DW_EH_PE_indirect))
Howard Hinnantd3dba312012-01-06 20:39:47 +0000256 result = *((uintptr_t*)result);
257 *data = p;
258 return result;
259}
260
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000261static
262const uint8_t*
Howard Hinnantad048712012-01-28 00:28:31 +0000263getTTypeEntry(int64_t ttypeIndex, const uint8_t* classInfo, uint8_t ttypeEncoding)
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000264{
265 switch (ttypeEncoding & 0x0F)
266 {
267 case DW_EH_PE_absptr:
Howard Hinnantad048712012-01-28 00:28:31 +0000268 ttypeIndex *= sizeof(void*);
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000269 break;
270 case DW_EH_PE_udata2:
271 case DW_EH_PE_sdata2:
Howard Hinnantad048712012-01-28 00:28:31 +0000272 ttypeIndex *= 2;
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000273 break;
274 case DW_EH_PE_udata4:
275 case DW_EH_PE_sdata4:
Howard Hinnantad048712012-01-28 00:28:31 +0000276 ttypeIndex *= 4;
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000277 break;
278 case DW_EH_PE_udata8:
279 case DW_EH_PE_sdata8:
Howard Hinnantad048712012-01-28 00:28:31 +0000280 ttypeIndex *= 8;
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000281 break;
282 }
Howard Hinnantad048712012-01-28 00:28:31 +0000283 return classInfo - ttypeIndex;
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000284}
285
Howard Hinnantd3dba312012-01-06 20:39:47 +0000286/// Deals with Dwarf actions matching our type infos
287/// (OurExceptionType_t instances). Returns whether or not a dwarf emitted
288/// action matches the supplied exception type. If such a match succeeds,
289/// the handlerSwitchValue will be set with > 0 index value. Only
290/// corresponding llvm.eh.selector type info arguments, cleanup arguments
291/// are supported. Filters are not supported.
292/// See Variable Length Data in:
293/// @link http://dwarfstd.org/Dwarf3.pdf @unlink
294/// Also see @link http://refspecs.freestandards.org/abi-eh-1.21.html @unlink
295/// @param classInfo our array of type info pointers (to globals)
296/// @param actionEntry index into above type info array or 0 (clean up).
297/// We do not support filters.
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000298/// @param unwind_exception thrown _Unwind_Exception instance.
Howard Hinnantd3dba312012-01-06 20:39:47 +0000299/// @returns whether or not a type info was found. False is returned if only
300/// a cleanup was found
301static
302bool
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000303handleActionValue(const uint8_t* classInfo, uintptr_t actionEntry,
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000304 _Unwind_Exception* unwind_exception, uint8_t ttypeEncoding)
Howard Hinnantd3dba312012-01-06 20:39:47 +0000305{
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000306 __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
Howard Hinnant699692a2012-01-22 21:47:40 +0000307 void* thrown_object =
308 unwind_exception->exception_class == kOurDependentExceptionClass ?
309 ((__cxa_dependent_exception*)exception_header)->primaryException :
310 exception_header + 1;
311 const __shim_type_info* excpType =
312 static_cast<const __shim_type_info*>(exception_header->exceptionType);
Howard Hinnantd3dba312012-01-06 20:39:47 +0000313 const uint8_t* actionPos = (uint8_t*)actionEntry;
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000314 while (true)
Howard Hinnantd3dba312012-01-06 20:39:47 +0000315 {
316 // Each emitted dwarf action corresponds to a 2 tuple of
317 // type info address offset, and action offset to the next
318 // emitted action.
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000319 const uint8_t* SactionPos = actionPos;
Howard Hinnantad048712012-01-28 00:28:31 +0000320 int64_t ttypeIndex = readSLEB128(&actionPos);
Howard Hinnantd3dba312012-01-06 20:39:47 +0000321 const uint8_t* tempActionPos = actionPos;
322 int64_t actionOffset = readSLEB128(&tempActionPos);
Howard Hinnantad048712012-01-28 00:28:31 +0000323 if (ttypeIndex > 0) // a catch handler
Howard Hinnantd3dba312012-01-06 20:39:47 +0000324 {
Howard Hinnantad048712012-01-28 00:28:31 +0000325 const uint8_t* TTypeEntry = getTTypeEntry(ttypeIndex, classInfo,
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000326 ttypeEncoding);
Howard Hinnant699692a2012-01-22 21:47:40 +0000327 const __shim_type_info* catchType =
328 (const __shim_type_info*)readEncodedPointer(&TTypeEntry,
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000329 ttypeEncoding);
Howard Hinnant699692a2012-01-22 21:47:40 +0000330 void* adjustedPtr = thrown_object;
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000331 // catchType == 0 -> catch (...)
Howard Hinnant699692a2012-01-22 21:47:40 +0000332 if (catchType == 0 || catchType->can_catch(excpType, adjustedPtr))
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000333 {
Howard Hinnantad048712012-01-28 00:28:31 +0000334 exception_header->handlerSwitchValue = ttypeIndex;
Howard Hinnant699692a2012-01-22 21:47:40 +0000335 exception_header->actionRecord = SactionPos; // unnecessary?
336 // used by __cxa_get_exception_ptr and __cxa_begin_catch
337 exception_header->adjustedPtr = adjustedPtr;
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000338 return true;
339 }
Howard Hinnantd3dba312012-01-06 20:39:47 +0000340 }
Howard Hinnantad048712012-01-28 00:28:31 +0000341 else if (ttypeIndex < 0) // an exception spec
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000342 {
343 }
Howard Hinnantad048712012-01-28 00:28:31 +0000344 else // ttypeIndex == 0 // a clean up
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000345 {
346 }
347 if (actionOffset == 0)
Howard Hinnantd3dba312012-01-06 20:39:47 +0000348 break;
349 actionPos += actionOffset;
350 }
351 return false;
352}
353
Howard Hinnant66d93272012-01-04 20:49:43 +0000354// Return true if there is a handler and false otherwise
355// cache handlerSwitchValue, actionRecord, languageSpecificData,
356// catchTemp and adjustedPtr here.
357static
358bool
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000359contains_handler(_Unwind_Exception* unwind_exception, _Unwind_Context* context)
Howard Hinnant66d93272012-01-04 20:49:43 +0000360{
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000361 __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
Howard Hinnantd3dba312012-01-06 20:39:47 +0000362 const uint8_t* lsda = (const uint8_t*)_Unwind_GetLanguageSpecificData(context);
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000363 exception_header->languageSpecificData = lsda;
Howard Hinnantd3dba312012-01-06 20:39:47 +0000364 if (lsda)
365 {
366 // Get the current instruction pointer and offset it before next
367 // instruction in the current frame which threw the exception.
Howard Hinnantad048712012-01-28 00:28:31 +0000368 uintptr_t ip = _Unwind_GetIP(context) - 1;
Howard Hinnantd3dba312012-01-06 20:39:47 +0000369 // Get beginning current frame's code (as defined by the
370 // emitted dwarf code)
371 uintptr_t funcStart = _Unwind_GetRegionStart(context);
Howard Hinnantad048712012-01-28 00:28:31 +0000372 uintptr_t ipOffset = ip - funcStart;
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000373 const uint8_t* classInfo = NULL;
Howard Hinnantd3dba312012-01-06 20:39:47 +0000374 // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding
375 // dwarf emission
376 // Parse LSDA header.
377 uint8_t lpStartEncoding = *lsda++;
Howard Hinnantad048712012-01-28 00:28:31 +0000378 const uint8_t* lpStart = (const unit8_t*)readEncodedPointer(&lsda, lpStartEncoding);
379 if (lpStart == 0)
380 lpStart = funcStart;
Howard Hinnantd3dba312012-01-06 20:39:47 +0000381 uint8_t ttypeEncoding = *lsda++;
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000382 // TODO: preflight ttypeEncoding here and return error if there's a problem
Howard Hinnantd3dba312012-01-06 20:39:47 +0000383 if (ttypeEncoding != DW_EH_PE_omit)
384 {
385 // Calculate type info locations in emitted dwarf code which
386 // were flagged by type info arguments to llvm.eh.selector
387 // intrinsic
388 uintptr_t classInfoOffset = readULEB128(&lsda);
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000389 classInfo = lsda + classInfoOffset;
Howard Hinnantd3dba312012-01-06 20:39:47 +0000390 }
391 // Walk call-site table looking for range that
392 // includes current PC.
393 uint8_t callSiteEncoding = *lsda++;
394 uint32_t callSiteTableLength = readULEB128(&lsda);
395 const uint8_t* callSiteTableStart = lsda;
396 const uint8_t* callSiteTableEnd = callSiteTableStart + callSiteTableLength;
397 const uint8_t* actionTableStart = callSiteTableEnd;
398 const uint8_t* callSitePtr = callSiteTableStart;
Howard Hinnantd3dba312012-01-06 20:39:47 +0000399 while (callSitePtr < callSiteTableEnd)
400 {
401 uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding);
402 uintptr_t length = readEncodedPointer(&callSitePtr, callSiteEncoding);
403 uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding);
404 // Note: Action value
405 uintptr_t actionEntry = readULEB128(&callSitePtr);
406 if (landingPad == 0)
407 continue; // no landing pad for this entry
408 if (actionEntry)
409 actionEntry += ((uintptr_t)actionTableStart) - 1;
Howard Hinnantad048712012-01-28 00:28:31 +0000410 if ((start <= ipOffset) && (ipOffset < (start + length)))
Howard Hinnantd3dba312012-01-06 20:39:47 +0000411 {
Howard Hinnantad048712012-01-28 00:28:31 +0000412 exception_header->catchTemp = (void*)(lpStart + landingPad);
Howard Hinnantd3dba312012-01-06 20:39:47 +0000413 if (actionEntry)
414 return handleActionValue(classInfo,
415 actionEntry,
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000416 unwind_exception,
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000417 ttypeEncoding);
Howard Hinnantd3dba312012-01-06 20:39:47 +0000418 // Note: Only non-clean up handlers are marked as
419 // found. Otherwise the clean up handlers will be
420 // re-found and executed during the clean up
421 // phase.
Howard Hinnantad048712012-01-28 00:28:31 +0000422 return false; // Won't find another call site in range of ipOffset
Howard Hinnantd3dba312012-01-06 20:39:47 +0000423 }
424 }
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000425 // Not found, need to properly terminate
Howard Hinnantd3dba312012-01-06 20:39:47 +0000426 }
427 return false;
Howard Hinnant66d93272012-01-04 20:49:43 +0000428}
429
Howard Hinnant66d93272012-01-04 20:49:43 +0000430static
431_Unwind_Reason_Code
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000432transfer_control_to_landing_pad(_Unwind_Exception* unwind_exception,
Howard Hinnantd3dba312012-01-06 20:39:47 +0000433 _Unwind_Context* context)
Howard Hinnant66d93272012-01-04 20:49:43 +0000434{
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000435 __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
436 _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), (uintptr_t)unwind_exception);
437 _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), exception_header->handlerSwitchValue);
438 _Unwind_SetIP(context, (uintptr_t)exception_header->catchTemp);
Howard Hinnantd3dba312012-01-06 20:39:47 +0000439 return _URC_INSTALL_CONTEXT;
Howard Hinnant66d93272012-01-04 20:49:43 +0000440}
441
Howard Hinnant66d93272012-01-04 20:49:43 +0000442static
443_Unwind_Reason_Code
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000444perform_cleanup(_Unwind_Exception* unwind_exception, _Unwind_Context* context)
Howard Hinnant66d93272012-01-04 20:49:43 +0000445{
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000446 __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
447 _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), (uintptr_t)unwind_exception);
Howard Hinnantd3dba312012-01-06 20:39:47 +0000448 _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000449 _Unwind_SetIP(context, (uintptr_t)exception_header->catchTemp);
Howard Hinnantd3dba312012-01-06 20:39:47 +0000450 return _URC_INSTALL_CONTEXT;
Howard Hinnant66d93272012-01-04 20:49:43 +0000451}
452
453// public API
454
Howard Hinnantad048712012-01-28 00:28:31 +0000455/*
456A foreign exception is defined by by one with an exceptionClass that doesn't
457have 'C++' in the 3 low order bytes 3 - 1:
458
459 big end | | ... | C | + | + |1/0| little end
460
461The lowest order byte may be 0 or 1.
462
463The personality function branches on actions like so:
464
465_UA_SEARCH_PHASE
466
467 If _UA_CLEANUP_PHASE or _UA_HANDLER_FRAME or _UA_FORCE_UNWIND there's
468 an error from above, return _URC_FATAL_PHASE1_ERROR.
469
470 Scan for anything that could stop unwinding:
471
472 1. A catch clause that will catch this exception
473 (will never catch foreign).
474 2. A catch (...) (will always catch foreign).
475 3. An exception spec that will catch this exception
476 (will always catch foreign).
477 If a handler is found
478 If not foreign
479 Save state in header
480 return _URC_HANDLER_FOUND
481 Else a handler not found
482 return _URC_CONTINUE_UNWIND
483
484_UA_CLEANUP_PHASE
485
486 If _UA_HANDLER_FRAME
487 If _UA_FORCE_UNWIND
488 How did this happen? return _URC_FATAL_PHASE2_ERROR
489 If foreign
490 Do _UA_SEARCH_PHASE to recover state
491 else
492 Recover state from header
493 Transfer control to landing pad. return _URC_INSTALL_CONTEXT
494
495 Else
496
497 Scan for anything that can not stop unwinding:
498
499 1. A clean up.
500
501 If a clean up is found
502 transfer control to it. return _URC_INSTALL_CONTEXT
503
504 Else a clean up is not found: return _URC_CONTINUE_UNWIND
505*/
Howard Hinnant66d93272012-01-04 20:49:43 +0000506_Unwind_Reason_Code
507__gxx_personality_v0(int version, _Unwind_Action actions, uint64_t exceptionClass,
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000508 _Unwind_Exception* unwind_exception, _Unwind_Context* context)
Howard Hinnant66d93272012-01-04 20:49:43 +0000509{
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000510 if (version == 1 && unwind_exception != 0 && context != 0)
Howard Hinnant66d93272012-01-04 20:49:43 +0000511 {
Howard Hinnant86b4dfa2012-01-08 23:50:46 +0000512 bool native_exception = (exceptionClass & 0xFFFFFF00) == 0x432B2B00;
Howard Hinnant66d93272012-01-04 20:49:43 +0000513 bool force_unwind = actions & _UA_FORCE_UNWIND;
514 if (native_exception && !force_unwind)
515 {
516 if (actions & _UA_SEARCH_PHASE)
517 {
518 if (actions & _UA_CLEANUP_PHASE)
519 return _URC_FATAL_PHASE1_ERROR;
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000520 if (contains_handler(unwind_exception, context))
Howard Hinnantd3dba312012-01-06 20:39:47 +0000521 return _URC_HANDLER_FOUND;
Howard Hinnant66d93272012-01-04 20:49:43 +0000522 return _URC_CONTINUE_UNWIND;
523 }
524 if (actions & _UA_CLEANUP_PHASE)
525 {
526 if (actions & _UA_HANDLER_FRAME)
527 {
528 // return _URC_INSTALL_CONTEXT or _URC_FATAL_PHASE2_ERROR
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000529 return transfer_control_to_landing_pad(unwind_exception, context);
Howard Hinnant66d93272012-01-04 20:49:43 +0000530 }
531 // return _URC_CONTINUE_UNWIND or _URC_FATAL_PHASE2_ERROR
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000532 return perform_cleanup(unwind_exception, context);
Howard Hinnant66d93272012-01-04 20:49:43 +0000533 }
534 }
535 else // foreign exception or force_unwind
536 {
537 if (actions & _UA_SEARCH_PHASE)
538 {
539 if (actions & _UA_CLEANUP_PHASE)
540 return _URC_FATAL_PHASE1_ERROR;
541 return _URC_CONTINUE_UNWIND;
542 }
543 if (actions & _UA_CLEANUP_PHASE)
544 {
545 if (actions & _UA_HANDLER_FRAME)
546 return _URC_FATAL_PHASE2_ERROR;
547 // return _URC_CONTINUE_UNWIND or _URC_FATAL_PHASE2_ERROR
Howard Hinnantafcf7ac2012-01-22 19:14:27 +0000548 return perform_cleanup(unwind_exception, context);
Howard Hinnant66d93272012-01-04 20:49:43 +0000549 }
550 }
551 }
552 return _URC_FATAL_PHASE1_ERROR;
553}
554
555} // extern "C"
556
557} // __cxxabiv1