Home | History | Annotate | Download | only in src
      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