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"))) 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 116 void terminate_helper(std::terminate_handler t_handler) { 117 try { 118 t_handler(); 119 abort(); 120 } catch (...) { 121 abort(); 122 } 123 } 124 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"))) 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 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"))) 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"))) 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