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 <unwind.h>
68
69 #include "cxxabi_defines.h"
70 #include "dwarf_helper.h"
71 #include "helper_func_internal.h"
72
73 namespace __cxxabiv1 {
74
75 #ifdef __arm__
76 extern "C" enum type_match_result {
77 ctm_failed = 0,
78 ctm_succeeded = 1,
79 ctm_succeeded_with_ptr_to_base = 2
80 };
81
82
83 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)84 __cxa_type_match(_Unwind_Exception* ucbp,
85 const __shim_type_info* rttip,
86 bool is_reference_type,
87 void** matched_object) {
88
89 __cxa_exception* header = reinterpret_cast<__cxa_exception*>(ucbp+1)-1;
90 type_match_result result = ctm_succeeded;
91
92 void* adjustedPtr = header+1;
93 if (dynamic_cast<const __pointer_type_info*>(header->exceptionType)) {
94 adjustedPtr = *reinterpret_cast<void**>(adjustedPtr);
95 result = ctm_succeeded_with_ptr_to_base;
96 }
97
98 const __shim_type_info* catch_type = rttip;
99 const __shim_type_info* thrown_type =
100 static_cast<const __shim_type_info*>(header->exceptionType);
101 if (!catch_type || !thrown_type) {
102 return ctm_failed;
103 }
104
105 if (catch_type->can_catch(thrown_type, adjustedPtr)) {
106 *matched_object = adjustedPtr;
107 return result;
108 }
109
110 return ctm_failed;
111 }
112 #endif // __arm__
113
114 namespace {
115
terminate_helper(std::terminate_handler t_handler)116 void terminate_helper(std::terminate_handler t_handler) {
117 try {
118 t_handler();
119 abort();
120 } catch (...) {
121 abort();
122 }
123 }
124
unexpected_helper(std::unexpected_handler u_handler)125 void unexpected_helper(std::unexpected_handler u_handler) {
126 u_handler();
127 std::terminate();
128 }
129
130 } // namespace
131
132 #ifdef __arm__
133 extern "C" bool __attribute__((visibility("default")))
__cxa_begin_cleanup(_Unwind_Exception * exc)134 __cxa_begin_cleanup(_Unwind_Exception* exc) {
135 __cxa_eh_globals *globals = __cxa_get_globals();
136 __cxa_exception *header = reinterpret_cast<__cxa_exception*>(exc+1)-1;
137 bool native = header->unwindHeader.exception_class == __gxx_exception_class;
138
139 if (native) {
140 header->cleanupCount += 1;
141 if (header->cleanupCount == 1) { // First time
142 header->nextCleanup = globals->cleanupExceptions;
143 globals->cleanupExceptions = header;
144 }
145 } else {
146 globals->cleanupExceptions = header;
147 }
148
149 return true;
150 }
151
helper_end_cleanup()152 extern "C" _Unwind_Exception * helper_end_cleanup() {
153 __cxa_eh_globals *globals = __cxa_get_globals();
154 __cxa_exception* header = globals->cleanupExceptions;
155
156 if (!header) {
157 std::terminate();
158 }
159
160 if (header->unwindHeader.exception_class == __gxx_exception_class) {
161 header->cleanupCount -= 1;
162 if (header->cleanupCount == 0) { // Last one
163 globals->cleanupExceptions = header->nextCleanup;
164 header->nextCleanup = NULL;
165 }
166 } else {
167 globals->cleanupExceptions = NULL;
168 }
169
170 return &header->unwindHeader;
171 }
172
173 asm (
174 ".pushsection .text.__cxa_end_cleanup \n"
175 ".global __cxa_end_cleanup \n"
176 ".type __cxa_end_cleanup, \"function\" \n"
177 "__cxa_end_cleanup: \n"
178 " push\t{r1, r2, r3, r4} \n"
179 " bl helper_end_cleanup \n"
180 " pop\t{r1, r2, r3, r4} \n"
181 " bl _Unwind_Resume \n"
182 " bl abort \n"
183 ".popsection \n"
184 );
185
186 extern "C" void __attribute__((visibility("default")))
__cxa_call_unexpected(void * arg)187 __cxa_call_unexpected(void* arg) {
188 _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(arg);
189 __cxa_exception* header = reinterpret_cast<__cxa_exception*>(unwind_exception+1)-1;
190 bool native_exception = unwind_exception->exception_class == __gxx_exception_class;
191
192 if (!native_exception) {
193 __cxa_begin_catch(unwind_exception); // unexpected is also a handler
194 try {
195 std::unexpected();
196 } catch (...) {
197 std::terminate();
198 }
199
200 return;
201 }
202
203 // Cache previous data first since we will change contents below.
204 uint32_t count = unwind_exception->barrier_cache.bitpattern[1];
205 uint32_t stride = unwind_exception->barrier_cache.bitpattern[3];
206 uint32_t* list = reinterpret_cast<uint32_t*>(
207 unwind_exception->barrier_cache.bitpattern[4]);
208
209 __cxa_begin_catch(unwind_exception); // unexpected is also a handler
210 try {
211 unexpected_helper(header->unexpectedHandler);
212 } catch (...) {
213 // A new exception thrown when calling unexpected.
214 bool allow_bad_exception = false;
215
216 for (uint32_t i = 0; i != count; ++i) {
217 uint32_t offset = reinterpret_cast<uint32_t>(&list[i * (stride >> 2)]);
218 offset = decodeRelocTarget2(offset);
219 const __shim_type_info* catch_type = reinterpret_cast<const __shim_type_info*>(offset);
220
221 __cxa_exception* new_header = __cxa_get_globals()->caughtExceptions;
222 void* adjustedPtr = new_header + 1;
223 if (__cxa_type_match(&new_header->unwindHeader,
224 catch_type,
225 false/* is_ref_type */,
226 &adjustedPtr) != ctm_failed) {
227 throw;
228 }
229
230 void* null_adjustedPtr = NULL;
231 const __shim_type_info* bad_excp =
232 static_cast<const __shim_type_info*>(&typeid(std::bad_exception));
233 if (catch_type->can_catch(bad_excp, null_adjustedPtr)) {
234 allow_bad_exception = true;
235 }
236 }
237
238 // If no other ones match, throw bad_exception.
239 if (allow_bad_exception) {
240 __cxa_end_catch();
241 __cxa_end_catch();
242 throw std::bad_exception();
243 }
244
245 terminate_helper(header->terminateHandler);
246 }
247 }
248 #else // ! __arm__
249 extern "C" void __attribute__((visibility("default")))
__cxa_call_unexpected(void * arg)250 __cxa_call_unexpected(void* arg) {
251 _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(arg);
252 if (unwind_exception == 0) {
253 call_terminate(unwind_exception);
254 }
255 __cxa_begin_catch(unwind_exception); // unexpected is also a handler
256
257 bool native_old_exception = unwind_exception->exception_class == __gxx_exception_class;
258 std::unexpected_handler u_handler;
259 std::terminate_handler t_handler;
260 __cxa_exception* old_exception_header = 0;
261 int64_t ttypeIndex;
262 const uint8_t* lsda;
263 if (native_old_exception) {
264 old_exception_header = reinterpret_cast<__cxa_exception*>(unwind_exception+1)-1;
265 t_handler = old_exception_header->terminateHandler;
266 u_handler = old_exception_header->unexpectedHandler;
267 // If unexpected_helper(u_handler) rethrows the same exception,
268 // these values get overwritten by the rethrow. So save them now:
269 ttypeIndex = old_exception_header->handlerSwitchValue;
270 lsda = old_exception_header->languageSpecificData;
271 } else {
272 t_handler = std::get_terminate();
273 u_handler = std::get_unexpected();
274 }
275
276 try {
277 unexpected_helper(u_handler);
278 } catch (...) {
279 // A new exception thrown when calling unexpected.
280
281 if (!native_old_exception) {
282 std::terminate();
283 }
284 uint8_t lpStartEncoding = *lsda++;
285 readEncodedPointer(&lsda, lpStartEncoding);
286 uint8_t ttypeEncoding = *lsda++;
287 if (ttypeEncoding == DW_EH_PE_omit) {
288 terminate_helper(t_handler);
289 }
290 uintptr_t classInfoOffset = readULEB128(&lsda);
291 const uint8_t* classInfo = lsda + classInfoOffset;
292 __cxa_eh_globals* globals = __cxa_get_globals_fast();
293 __cxa_exception* new_exception_header = globals->caughtExceptions;
294 if (new_exception_header == 0) { // This shouldn't be able to happen!
295 terminate_helper(t_handler);
296 }
297 bool native_new_exception =
298 new_exception_header->unwindHeader.exception_class == __gxx_exception_class;
299
300 if (native_new_exception && (new_exception_header != old_exception_header)) {
301 const std::type_info* excpType = new_exception_header->exceptionType;
302 if (!canExceptionSpecCatch(ttypeIndex, classInfo, ttypeEncoding,
303 excpType, new_exception_header+1, unwind_exception)) {
304 // We need to __cxa_end_catch, but for the old exception,
305 // not the new one. This is a little tricky ...
306 // Disguise new_exception_header as a rethrown exception, but
307 // don't actually rethrow it. This means you can temporarily
308 // end the catch clause enclosing new_exception_header without
309 // __cxa_end_catch destroying new_exception_header.
310 new_exception_header->handlerCount = -new_exception_header->handlerCount;
311 globals->uncaughtExceptions += 1;
312 __cxa_end_catch();
313 __cxa_end_catch();
314 __cxa_begin_catch(&new_exception_header->unwindHeader);
315 throw;
316 }
317 }
318
319 const std::type_info* excpType = &typeid(std::bad_exception);
320 if (!canExceptionSpecCatch(ttypeIndex, classInfo, ttypeEncoding,
321 excpType, NULL, unwind_exception)) {
322 __cxa_end_catch();
323 __cxa_end_catch();
324 throw std::bad_exception();
325 }
326 } // catch (...)
327
328 // Call terminate after unexpected normally done
329 terminate_helper(t_handler);
330 }
331 #endif // __arm__
332
333 } // namespace __cxxabiv1
334