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 #include <exception>
     41 #include <unwind.h>
     42 #include "cxxabi_defines.h"
     43 #include "helper_func_internal.h"
     44 
     45 namespace __cxxabiv1 {
     46 
     47   const __shim_type_info* getTypePtr(uint64_t ttypeIndex,
     48                                      const uint8_t* classInfo,
     49                                      uint8_t ttypeEncoding,
     50                                      _Unwind_Exception* unwind_exception);
     51 
     52   void call_terminate(_Unwind_Exception* unwind_exception) {
     53     __cxa_begin_catch(unwind_exception);  // terminate is also a handler
     54     std::terminate();
     55   }
     56 
     57   // Boring stuff which has lots of encode/decode details
     58   void scanEHTable(ScanResultInternal& results,
     59                    _Unwind_Action actions,
     60                    bool native_exception,
     61                    _Unwind_Exception* unwind_exception,
     62                    _Unwind_Context* context) {
     63     // Initialize results to found nothing but an error
     64     results.ttypeIndex = 0;
     65     results.actionRecord = 0;
     66     results.languageSpecificData = 0;
     67     results.landingPad = 0;
     68     results.adjustedPtr = 0;
     69     results.reason = _URC_FATAL_PHASE1_ERROR;
     70 
     71     // Check for consistent actions
     72     if (actions & _UA_SEARCH_PHASE) {
     73       if (actions & (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME | _UA_FORCE_UNWIND)) {
     74         results.reason = _URC_FATAL_PHASE1_ERROR;
     75         return;
     76       }
     77     } else if (actions & _UA_CLEANUP_PHASE) {
     78       if ((actions & _UA_HANDLER_FRAME) && (actions & _UA_FORCE_UNWIND)) {
     79         results.reason = _URC_FATAL_PHASE2_ERROR;
     80         return;
     81       }
     82     } else {
     83       results.reason = _URC_FATAL_PHASE1_ERROR;
     84       return;
     85     }
     86 
     87 
     88     // Start scan by getting exception table address
     89     const uint8_t* lsda = (const uint8_t*)_Unwind_GetLanguageSpecificData(context);
     90     if (lsda == 0) {
     91       // No exception table
     92       results.reason = _URC_CONTINUE_UNWIND;
     93       return;
     94     }
     95     results.languageSpecificData = lsda;
     96     uintptr_t ip = _Unwind_GetIP(context) - 1;
     97     uintptr_t funcStart = _Unwind_GetRegionStart(context);
     98     uintptr_t ipOffset = ip - funcStart;
     99     const uint8_t* classInfo = NULL;
    100     uint8_t lpStartEncoding = *lsda++;
    101     const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding);
    102     if (lpStart == 0) {
    103       lpStart = (const uint8_t*)funcStart;
    104     }
    105     uint8_t ttypeEncoding = *lsda++;
    106     if (ttypeEncoding != DW_EH_PE_omit) {
    107       uintptr_t classInfoOffset = readULEB128(&lsda);
    108       classInfo = lsda + classInfoOffset;
    109     }
    110     uint8_t callSiteEncoding = *lsda++;
    111     uint32_t callSiteTableLength = static_cast<uint32_t>(readULEB128(&lsda));
    112     const uint8_t* callSiteTableStart = lsda;
    113     const uint8_t* callSiteTableEnd = callSiteTableStart + callSiteTableLength;
    114     const uint8_t* actionTableStart = callSiteTableEnd;
    115     const uint8_t* callSitePtr = callSiteTableStart;
    116 
    117 
    118     while (callSitePtr < callSiteTableEnd) {
    119       uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding);
    120       uintptr_t length = readEncodedPointer(&callSitePtr, callSiteEncoding);
    121       uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding);
    122       uintptr_t actionEntry = readULEB128(&callSitePtr);
    123       if ((start <= ipOffset) && (ipOffset < (start + length))) {
    124         if (landingPad == 0) {
    125           // No handler here
    126           results.reason = _URC_CONTINUE_UNWIND;
    127           return;
    128         }
    129 
    130         landingPad = (uintptr_t)lpStart + landingPad;
    131         if (actionEntry == 0) {
    132           if ((actions & _UA_CLEANUP_PHASE) && !(actions & _UA_HANDLER_FRAME))
    133           {
    134             results.ttypeIndex = 0;
    135             results.landingPad = landingPad;
    136             results.reason = _URC_HANDLER_FOUND;
    137             return;
    138           }
    139           // No handler here
    140           results.reason = _URC_CONTINUE_UNWIND;
    141           return;
    142         }
    143 
    144         const uint8_t* action = actionTableStart + (actionEntry - 1);
    145         while (true) {
    146           const uint8_t* actionRecord = action;
    147           int64_t ttypeIndex = readSLEB128(&action);
    148           if (ttypeIndex > 0) {
    149             // Found a catch, does it actually catch?
    150             // First check for catch (...)
    151             const __shim_type_info* catchType =
    152               getTypePtr(static_cast<uint64_t>(ttypeIndex),
    153                          classInfo, ttypeEncoding, unwind_exception);
    154             if (catchType == 0) {
    155               // Found catch (...) catches everything, including foreign exceptions
    156               if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME))
    157               {
    158                 // Save state and return _URC_HANDLER_FOUND
    159                 results.ttypeIndex = ttypeIndex;
    160                 results.actionRecord = actionRecord;
    161                 results.landingPad = landingPad;
    162                 results.adjustedPtr = unwind_exception+1;
    163                 results.reason = _URC_HANDLER_FOUND;
    164                 return;
    165               }
    166               else if (!(actions & _UA_FORCE_UNWIND))
    167               {
    168                 // It looks like the exception table has changed
    169                 //    on us.  Likely stack corruption!
    170                 call_terminate(unwind_exception);
    171               }
    172             } else if (native_exception) {
    173               __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
    174               void* adjustedPtr = unwind_exception+1;
    175               const __shim_type_info* excpType =
    176                   static_cast<const __shim_type_info*>(exception_header->exceptionType);
    177               if (adjustedPtr == 0 || excpType == 0) {
    178                 // Such a disaster! What's wrong?
    179                 call_terminate(unwind_exception);
    180               }
    181 
    182               // Only derefence once, so put ouside the recursive search below
    183               if (dynamic_cast<const __pointer_type_info*>(excpType)) {
    184                 adjustedPtr = *static_cast<void**>(adjustedPtr);
    185               }
    186 
    187               // Let's play!
    188               if (catchType->can_catch(excpType, adjustedPtr)) {
    189                 if (actions & _UA_SEARCH_PHASE) {
    190                   // Cache it.
    191                   results.ttypeIndex = ttypeIndex;
    192                   results.actionRecord = actionRecord;
    193                   results.landingPad = landingPad;
    194                   results.adjustedPtr = adjustedPtr;
    195                   results.reason = _URC_HANDLER_FOUND;
    196                   return;
    197                 } else if (!(actions & _UA_FORCE_UNWIND)) {
    198                   // It looks like the exception table has changed
    199                   //    on us.  Likely stack corruption!
    200                   call_terminate(unwind_exception);
    201                 }
    202               } // catchType->can_catch
    203             } // if (catchType == 0)
    204           } else if (ttypeIndex < 0) {
    205             // Found an exception spec.
    206             if (native_exception) {
    207               __cxa_exception* header = reinterpret_cast<__cxa_exception*>(unwind_exception+1)-1;
    208               void* adjustedPtr = unwind_exception+1;
    209               const std::type_info* excpType = header->exceptionType;
    210               if (adjustedPtr == 0 || excpType == 0) {
    211                 // Such a disaster! What's wrong?
    212                 call_terminate(unwind_exception);
    213               }
    214 
    215               // Let's play!
    216               if (canExceptionSpecCatch(ttypeIndex, classInfo,
    217                                         ttypeEncoding, excpType,
    218                                         adjustedPtr, unwind_exception)) {
    219                 if (actions & _UA_SEARCH_PHASE) {
    220                   // Cache it.
    221                   results.ttypeIndex = ttypeIndex;
    222                   results.actionRecord = actionRecord;
    223                   results.landingPad = landingPad;
    224                   results.adjustedPtr = adjustedPtr;
    225                   results.reason = _URC_HANDLER_FOUND;
    226                   return;
    227                 } else if (!(actions & _UA_FORCE_UNWIND)) {
    228                   // It looks like the exception table has changed
    229                   //    on us.  Likely stack corruption!
    230                   call_terminate(unwind_exception);
    231                 }
    232               }
    233             } else {  // ! native_exception
    234               // foreign exception must be caught by exception spec
    235               if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME)) {
    236                 results.ttypeIndex = ttypeIndex;
    237                 results.actionRecord = actionRecord;
    238                 results.landingPad = landingPad;
    239                 results.adjustedPtr = unwind_exception+1;
    240                 results.reason = _URC_HANDLER_FOUND;
    241                 return;
    242               }
    243               else if (!(actions & _UA_FORCE_UNWIND)) {
    244                 // It looks like the exception table has changed
    245                 //    on us.  Likely stack corruption!
    246                 call_terminate(unwind_exception);
    247               }
    248             }
    249           } else {  // ttypeIndex == 0
    250             // Found a cleanup, or nothing
    251             if ((actions & _UA_CLEANUP_PHASE) && !(actions & _UA_HANDLER_FRAME)) {
    252               results.ttypeIndex = ttypeIndex;
    253               results.actionRecord = actionRecord;
    254               results.landingPad = landingPad;
    255               results.adjustedPtr = unwind_exception+1;
    256               results.reason = _URC_HANDLER_FOUND;
    257               return;
    258             }
    259           }
    260 
    261 
    262           const uint8_t* temp = action;
    263           int64_t actionOffset = readSLEB128(&temp);
    264           if (actionOffset == 0) {
    265             // End of action list, no matching handler or cleanup found
    266             results.reason = _URC_CONTINUE_UNWIND;
    267             return;
    268           }
    269 
    270           // Go to next action
    271           action += actionOffset;
    272         }
    273       } else if (ipOffset < start) {
    274         // There is no call site for this ip
    275         call_terminate(unwind_exception);
    276       }
    277     } // while (callSitePtr < callSiteTableEnd)
    278 
    279     call_terminate(unwind_exception);
    280   }
    281 
    282   /*
    283    * Below is target-dependent part
    284    */
    285 
    286 #ifdef __arm__
    287 
    288   /* Decode an R_ARM_TARGET2 relocation.  */
    289   uint32_t decodeRelocTarget2 (uint32_t ptr) {
    290     uint32_t tmp;
    291 
    292     tmp = *reinterpret_cast<uint32_t*>(ptr);
    293     if (!tmp) {
    294       return 0;
    295     }
    296 
    297     tmp += ptr;
    298     tmp = *reinterpret_cast<uint32_t*>(tmp);
    299     return tmp;
    300   }
    301 
    302   const __shim_type_info* getTypePtr(uint64_t ttypeIndex,
    303                                      const uint8_t* classInfo,
    304                                      uint8_t ttypeEncoding,
    305                                      _Unwind_Exception* unwind_exception) {
    306     if (classInfo == 0) { // eh table corrupted!
    307       call_terminate(unwind_exception);
    308     }
    309     const uint8_t* ptr = classInfo - ttypeIndex * 4;
    310     return (const __shim_type_info*)decodeRelocTarget2((uint32_t)ptr);
    311   }
    312 
    313   bool canExceptionSpecCatch(int64_t specIndex,
    314                              const uint8_t* classInfo,
    315                              uint8_t ttypeEncoding,
    316                              const std::type_info* excpType,
    317                              void* adjustedPtr,
    318                              _Unwind_Exception* unwind_exception) {
    319     if (classInfo == 0) { // eh table corrupted!
    320       call_terminate(unwind_exception);
    321     }
    322 
    323     specIndex = -specIndex;
    324     specIndex -= 1;
    325     const uint32_t* temp = reinterpret_cast<const uint32_t*>(classInfo) + specIndex;
    326 
    327     while (true) {
    328       uint32_t ttypeIndex = *temp;
    329       if (ttypeIndex == 0) {
    330         break;
    331       }
    332       ttypeIndex = decodeRelocTarget2((uint32_t)temp);
    333       temp += 1;
    334       const __shim_type_info* catchType = (const __shim_type_info*) ttypeIndex;
    335       void* tempPtr = adjustedPtr;
    336       if (catchType->can_catch(
    337               static_cast<const __shim_type_info*>(excpType), tempPtr)) {
    338         return false;
    339       }
    340     } // while
    341     return true;
    342   }
    343 
    344   // lower-level runtime library API function that unwinds the frame
    345   extern "C" bool __gnu_unwind_frame(_Unwind_Exception*, _Unwind_Context*);
    346 
    347   void setRegisters(_Unwind_Exception* unwind_exception,
    348                     _Unwind_Context* context,
    349                     const ScanResultInternal& results) {
    350     _Unwind_SetGR(context, 0, reinterpret_cast<uintptr_t>(unwind_exception));
    351     _Unwind_SetGR(context, 1, static_cast<uintptr_t>(results.ttypeIndex));
    352     _Unwind_SetIP(context, results.landingPad);
    353   }
    354 
    355   _Unwind_Reason_Code continueUnwinding(_Unwind_Exception *ex,
    356                                         _Unwind_Context *context) {
    357     if (__gnu_unwind_frame(ex, context) != _URC_OK) {
    358       return _URC_FAILURE;
    359     }
    360     return _URC_CONTINUE_UNWIND;
    361   }
    362 
    363   void saveDataToBarrierCache(_Unwind_Exception* exc,
    364                               _Unwind_Context* ctx,
    365                               const ScanResultInternal& results) {
    366     exc->barrier_cache.sp = _Unwind_GetGR(ctx, UNWIND_STACK_REG);
    367     exc->barrier_cache.bitpattern[0] = (uint32_t)results.adjustedPtr;
    368     exc->barrier_cache.bitpattern[1] = (uint32_t)results.ttypeIndex;
    369     exc->barrier_cache.bitpattern[3] = (uint32_t)results.landingPad;
    370   }
    371 
    372   void loadDataFromBarrierCache(_Unwind_Exception* exc,
    373                                 ScanResultInternal& results) {
    374     results.adjustedPtr = (void*) exc->barrier_cache.bitpattern[0];
    375     results.ttypeIndex = (int64_t) exc->barrier_cache.bitpattern[1];
    376     results.landingPad = (uintptr_t) exc->barrier_cache.bitpattern[3];
    377   }
    378 
    379   void prepareBeginCleanup(_Unwind_Exception* exc) {
    380     __cxa_begin_cleanup(exc);
    381   }
    382 
    383   void saveUnexpectedDataToBarrierCache(_Unwind_Exception* exc,
    384                                         _Unwind_Context* ctx,
    385                                         const ScanResultInternal& results) {
    386     prepareBeginCleanup(exc);
    387 
    388     const uint8_t* lsda = (const uint8_t*)_Unwind_GetLanguageSpecificData(ctx);
    389     const uint8_t* classInfo = NULL;
    390     uint8_t lpStartEncoding = *lsda++;
    391     __attribute__((unused))
    392     const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding);
    393     __attribute__((unused))
    394     uintptr_t funcStart = _Unwind_GetRegionStart(ctx);
    395     uint8_t ttypeEncoding = *lsda++;
    396     if (ttypeEncoding != DW_EH_PE_omit) {
    397       uintptr_t classInfoOffset = readULEB128(&lsda);
    398       classInfo = lsda + classInfoOffset;
    399     }
    400 
    401     const uint32_t* e = (const uint32_t*) classInfo - results.ttypeIndex - 1;
    402     uint32_t n = 0;
    403     while (e[n] != 0) {
    404       ++n;
    405     }
    406 
    407     exc->barrier_cache.bitpattern[1] = n;
    408     exc->barrier_cache.bitpattern[3] = 4;
    409     exc->barrier_cache.bitpattern[4] = (uint32_t)e;
    410   }
    411 
    412 #else // ! __arm__
    413 
    414   const __shim_type_info* getTypePtr(uint64_t ttypeIndex,
    415                                      const uint8_t* classInfo,
    416                                      uint8_t ttypeEncoding,
    417                                      _Unwind_Exception* unwind_exception) {
    418     if (classInfo == 0) { // eh table corrupted!
    419       call_terminate(unwind_exception);
    420     }
    421 
    422     switch (ttypeEncoding & 0x0F) {
    423     case DW_EH_PE_absptr:
    424       ttypeIndex *= sizeof(void*);
    425       break;
    426     case DW_EH_PE_udata2:
    427     case DW_EH_PE_sdata2:
    428       ttypeIndex *= 2;
    429       break;
    430     case DW_EH_PE_udata4:
    431     case DW_EH_PE_sdata4:
    432       ttypeIndex *= 4;
    433       break;
    434     case DW_EH_PE_udata8:
    435     case DW_EH_PE_sdata8:
    436       ttypeIndex *= 8;
    437       break;
    438     default:
    439       // this should not happen.
    440       call_terminate(unwind_exception);
    441     }
    442     classInfo -= ttypeIndex;
    443     return (const __shim_type_info*)readEncodedPointer(&classInfo, ttypeEncoding);
    444   }
    445 
    446   bool canExceptionSpecCatch(int64_t specIndex,
    447                              const uint8_t* classInfo,
    448                              uint8_t ttypeEncoding,
    449                              const std::type_info* excpType,
    450                              void* adjustedPtr,
    451                              _Unwind_Exception* unwind_exception) {
    452     if (classInfo == 0) { // eh table corrupted!
    453       call_terminate(unwind_exception);
    454     }
    455 
    456     specIndex = -specIndex;
    457     specIndex -= 1;
    458     const uint8_t* temp = classInfo + specIndex;
    459 
    460     while (true) {
    461       uint64_t ttypeIndex = readULEB128(&temp);
    462       if (ttypeIndex == 0) {
    463         break;
    464       }
    465       const __shim_type_info* catchType = getTypePtr(ttypeIndex,
    466                                                      classInfo,
    467                                                      ttypeEncoding,
    468                                                      unwind_exception);
    469       void* tempPtr = adjustedPtr;
    470       if (catchType->can_catch(
    471               static_cast<const __shim_type_info*>(excpType), tempPtr)) {
    472         return false;
    473       }
    474     } // while
    475     return true;
    476   }
    477 
    478   void setRegisters(_Unwind_Exception* unwind_exception,
    479                     _Unwind_Context* context,
    480                     const ScanResultInternal& results) {
    481     _Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
    482                   reinterpret_cast<uintptr_t>(unwind_exception));
    483     _Unwind_SetGR(context, __builtin_eh_return_data_regno(1),
    484                   static_cast<uintptr_t>(results.ttypeIndex));
    485     _Unwind_SetIP(context, results.landingPad);
    486   }
    487 
    488   _Unwind_Reason_Code continueUnwinding(_Unwind_Exception *ex,
    489                                         _Unwind_Context *context) {
    490     return _URC_CONTINUE_UNWIND;
    491   }
    492 
    493   // Do nothing, only for API compatibility
    494   // We don't use C++ polymorphism since we hope no virtual table cost.
    495   void saveDataToBarrierCache(_Unwind_Exception* exc,
    496                               _Unwind_Context* ctx,
    497                               const ScanResultInternal& results) {}
    498 
    499   void loadDataFromBarrierCache(_Unwind_Exception* exc,
    500                                 ScanResultInternal& results) {}
    501 
    502   void prepareBeginCleanup(_Unwind_Exception* exc) {}
    503 
    504   void saveUnexpectedDataToBarrierCache(_Unwind_Exception* exc,
    505                                         _Unwind_Context* ctx,
    506                                         const ScanResultInternal& results) {}
    507 
    508 #endif // __arm__
    509 
    510 } // namespace __cxxabiv1
    511