1 // Copyright (C) 2012 The Android Open Source Project
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 // 1. Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // 2. Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // 3. Neither the name of the project nor the names of its contributors
13 // may be used to endorse or promote products derived from this software
14 // without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 // ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 // SUCH DAMAGE.
27 //===----------------------------------------------------------------------===//
28 // The LLVM Compiler Infrastructure
29 //
30 // This file is dual licensed under the MIT and the University of Illinois Open
31 // Source Licenses. See LICENSE.TXT for details.
32 //
33 //
34 // This file implements the "Exception Handling APIs"
35 // http://www.codesourcery.com/public/cxx-abi/abi-eh.html
36 // http://www.intel.com/design/itanium/downloads/245358.htm
37 //
38 //===----------------------------------------------------------------------===//
39 /*
40 * Copyright 2010-2011 PathScale, Inc. All rights reserved.
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions are met:
44 *
45 * 1. Redistributions of source code must retain the above copyright notice,
46 * this list of conditions and the following disclaimer.
47 *
48 * 2. Redistributions in binary form must reproduce the above copyright notice,
49 * this list of conditions and the following disclaimer in the documentation
50 * and/or other materials provided with the distribution.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
53 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
54 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
55 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
56 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
57 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
58 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
59 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
60 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
61 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
62 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
63 */
64
65
66 #include <cstdlib>
67 #include <cxxabi.h>
68 #include <unwind.h>
69 #include "dwarf_helper.h"
70 #include "helper_func_internal.h"
71
72 namespace __cxxabiv1 {
73
74 #ifdef __arm__
75 extern "C" enum type_match_result {
76 ctm_failed = 0,
77 ctm_succeeded = 1,
78 ctm_succeeded_with_ptr_to_base = 2
79 };
80
81
82 extern "C" type_match_result __attribute__((visibility("default")))
__cxa_type_match(_Unwind_Exception * ucbp,const __shim_type_info * rttip,bool is_reference_type,void ** matched_object)83 __cxa_type_match(_Unwind_Exception* ucbp,
84 const __shim_type_info* rttip,
85 bool is_reference_type,
86 void** matched_object) {
87
88 __cxa_exception* header = reinterpret_cast<__cxa_exception*>(ucbp+1)-1;
89 type_match_result result = ctm_succeeded;
90
91 void* adjustedPtr = header+1;
92 if (dynamic_cast<const __pointer_type_info*>(header->exceptionType)) {
93 adjustedPtr = *reinterpret_cast<void**>(adjustedPtr);
94 result = ctm_succeeded_with_ptr_to_base;
95 }
96
97 const __shim_type_info* catch_type = rttip;
98 const __shim_type_info* thrown_type =
99 static_cast<const __shim_type_info*>(header->exceptionType);
100 if (!catch_type || !thrown_type) {
101 return ctm_failed;
102 }
103
104 if (catch_type->can_catch(thrown_type, adjustedPtr)) {
105 *matched_object = adjustedPtr;
106 return result;
107 }
108
109 return ctm_failed;
110 }
111 #endif // __arm__
112
113 namespace {
114
terminate_helper(std::terminate_handler t_handler)115 void terminate_helper(std::terminate_handler t_handler) {
116 try {
117 t_handler();
118 abort();
119 } catch (...) {
120 abort();
121 }
122 }
123
unexpected_helper(std::unexpected_handler u_handler)124 void unexpected_helper(std::unexpected_handler u_handler) {
125 u_handler();
126 std::terminate();
127 }
128
129 } // namespace
130
131 #ifdef __arm__
132 extern "C" bool __attribute__((visibility("default")))
__cxa_begin_cleanup(_Unwind_Exception * exc)133 __cxa_begin_cleanup(_Unwind_Exception* exc) {
134 __cxa_eh_globals *globals = __cxa_get_globals();
135 __cxa_exception *header = reinterpret_cast<__cxa_exception*>(exc+1)-1;
136 bool native = header->unwindHeader.exception_class == __gxx_exception_class;
137
138 if (native) {
139 header->cleanupCount += 1;
140 if (header->cleanupCount == 1) { // First time
141 header->nextCleanup = globals->cleanupExceptions;
142 globals->cleanupExceptions = header;
143 }
144 } else {
145 globals->cleanupExceptions = header;
146 }
147
148 return true;
149 }
150
helper_end_cleanup()151 extern "C" _Unwind_Exception * helper_end_cleanup() {
152 __cxa_eh_globals *globals = __cxa_get_globals();
153 __cxa_exception* header = globals->cleanupExceptions;
154
155 if (!header) {
156 std::terminate();
157 }
158
159 if (header->unwindHeader.exception_class == __gxx_exception_class) {
160 header->cleanupCount -= 1;
161 if (header->cleanupCount == 0) { // Last one
162 globals->cleanupExceptions = header->nextCleanup;
163 header->nextCleanup = NULL;
164 }
165 } else {
166 globals->cleanupExceptions = NULL;
167 }
168
169 return &header->unwindHeader;
170 }
171
172 asm (
173 ".pushsection .text.__cxa_end_cleanup \n"
174 ".global __cxa_end_cleanup \n"
175 ".type __cxa_end_cleanup, \"function\" \n"
176 "__cxa_end_cleanup: \n"
177 " push\t{r1, r2, r3, r4} \n"
178 " bl helper_end_cleanup \n"
179 " pop\t{r1, r2, r3, r4} \n"
180 " bl _Unwind_Resume \n"
181 " bl abort \n"
182 ".popsection \n"
183 );
184
185 extern "C" void __attribute__((visibility("default")))
__cxa_call_unexpected(void * arg)186 __cxa_call_unexpected(void* arg) {
187 _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(arg);
188 __cxa_exception* header = reinterpret_cast<__cxa_exception*>(unwind_exception+1)-1;
189 bool native_exception = unwind_exception->exception_class == __gxx_exception_class;
190
191 if (!native_exception) {
192 __cxa_begin_catch(unwind_exception); // unexpected is also a handler
193 try {
194 std::unexpected();
195 } catch (...) {
196 std::terminate();
197 }
198
199 return;
200 }
201
202 // Cache previous data first since we will change contents below.
203 uint32_t count = unwind_exception->barrier_cache.bitpattern[1];
204 uint32_t stride = unwind_exception->barrier_cache.bitpattern[3];
205 uint32_t* list = reinterpret_cast<uint32_t*>(
206 unwind_exception->barrier_cache.bitpattern[4]);
207
208 __cxa_begin_catch(unwind_exception); // unexpected is also a handler
209 try {
210 unexpected_helper(header->unexpectedHandler);
211 } catch (...) {
212 // A new exception thrown when calling unexpected.
213 bool allow_bad_exception = false;
214
215 for (uint32_t i = 0; i != count; ++i) {
216 uint32_t offset = reinterpret_cast<uint32_t>(&list[i * (stride >> 2)]);
217 offset = decodeRelocTarget2(offset);
218 const __shim_type_info* catch_type = reinterpret_cast<const __shim_type_info*>(offset);
219
220 __cxa_exception* new_header = __cxa_get_globals()->caughtExceptions;
221 void* adjustedPtr = new_header + 1;
222 if (__cxa_type_match(&new_header->unwindHeader,
223 catch_type,
224 false/* is_ref_type */,
225 &adjustedPtr) != ctm_failed) {
226 throw;
227 }
228
229 void* null_adjustedPtr = NULL;
230 const __shim_type_info* bad_excp =
231 static_cast<const __shim_type_info*>(&typeid(std::bad_exception));
232 if (catch_type->can_catch(bad_excp, null_adjustedPtr)) {
233 allow_bad_exception = true;
234 }
235 }
236
237 // If no other ones match, throw bad_exception.
238 if (allow_bad_exception) {
239 __cxa_end_catch();
240 __cxa_end_catch();
241 throw std::bad_exception();
242 }
243
244 terminate_helper(header->terminateHandler);
245 }
246 }
247 #else // ! __arm__
248 extern "C" void __attribute__((visibility("default")))
__cxa_call_unexpected(void * arg)249 __cxa_call_unexpected(void* arg) {
250 _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(arg);
251 if (unwind_exception == 0) {
252 call_terminate(unwind_exception);
253 }
254 __cxa_begin_catch(unwind_exception); // unexpected is also a handler
255
256 bool native_old_exception = unwind_exception->exception_class == __gxx_exception_class;
257 std::unexpected_handler u_handler;
258 std::terminate_handler t_handler;
259 __cxa_exception* old_exception_header = 0;
260 int64_t ttypeIndex;
261 const uint8_t* lsda;
262 if (native_old_exception) {
263 old_exception_header = reinterpret_cast<__cxa_exception*>(unwind_exception+1)-1;
264 t_handler = old_exception_header->terminateHandler;
265 u_handler = old_exception_header->unexpectedHandler;
266 // If unexpected_helper(u_handler) rethrows the same exception,
267 // these values get overwritten by the rethrow. So save them now:
268 ttypeIndex = old_exception_header->handlerSwitchValue;
269 lsda = old_exception_header->languageSpecificData;
270 } else {
271 t_handler = std::get_terminate();
272 u_handler = std::get_unexpected();
273 }
274
275 try {
276 unexpected_helper(u_handler);
277 } catch (...) {
278 // A new exception thrown when calling unexpected.
279
280 if (!native_old_exception) {
281 std::terminate();
282 }
283 uint8_t lpStartEncoding = *lsda++;
284 const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding);
285 uint8_t ttypeEncoding = *lsda++;
286 if (ttypeEncoding == DW_EH_PE_omit) {
287 terminate_helper(t_handler);
288 }
289 uintptr_t classInfoOffset = readULEB128(&lsda);
290 const uint8_t* classInfo = lsda + classInfoOffset;
291 __cxa_eh_globals* globals = __cxa_get_globals_fast();
292 __cxa_exception* new_exception_header = globals->caughtExceptions;
293 if (new_exception_header == 0) { // This shouldn't be able to happen!
294 terminate_helper(t_handler);
295 }
296 bool native_new_exception =
297 new_exception_header->unwindHeader.exception_class == __gxx_exception_class;
298
299 if (native_new_exception && (new_exception_header != old_exception_header)) {
300 const std::type_info* excpType = new_exception_header->exceptionType;
301 if (!canExceptionSpecCatch(ttypeIndex, classInfo, ttypeEncoding,
302 excpType, new_exception_header+1, unwind_exception)) {
303 // We need to __cxa_end_catch, but for the old exception,
304 // not the new one. This is a little tricky ...
305 // Disguise new_exception_header as a rethrown exception, but
306 // don't actually rethrow it. This means you can temporarily
307 // end the catch clause enclosing new_exception_header without
308 // __cxa_end_catch destroying new_exception_header.
309 new_exception_header->handlerCount = -new_exception_header->handlerCount;
310 globals->uncaughtExceptions += 1;
311 __cxa_end_catch();
312 __cxa_end_catch();
313 __cxa_begin_catch(&new_exception_header->unwindHeader);
314 throw;
315 }
316 }
317
318 const std::type_info* excpType = &typeid(std::bad_exception);
319 if (!canExceptionSpecCatch(ttypeIndex, classInfo, ttypeEncoding,
320 excpType, NULL, unwind_exception)) {
321 __cxa_end_catch();
322 __cxa_end_catch();
323 throw std::bad_exception();
324 }
325 } // catch (...)
326
327 // Call terminate after unexpected normally done
328 terminate_helper(t_handler);
329 }
330 #endif // __arm__
331
332 } // namespace __cxxabiv1
333