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 _GABIXX_NORETURN 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" _Unwind_Reason_Code __gnu_unwind_frame(_Unwind_Exception*, 346 _Unwind_Context*); 347 348 void setRegisters(_Unwind_Exception* unwind_exception, 349 _Unwind_Context* context, 350 const ScanResultInternal& results) { 351 _Unwind_SetGR(context, 0, reinterpret_cast<uintptr_t>(unwind_exception)); 352 _Unwind_SetGR(context, 1, static_cast<uintptr_t>(results.ttypeIndex)); 353 _Unwind_SetIP(context, results.landingPad); 354 } 355 356 _Unwind_Reason_Code continueUnwinding(_Unwind_Exception *ex, 357 _Unwind_Context *context) { 358 if (__gnu_unwind_frame(ex, context) != _URC_OK) { 359 return _URC_FAILURE; 360 } 361 return _URC_CONTINUE_UNWIND; 362 } 363 364 void saveDataToBarrierCache(_Unwind_Exception* exc, 365 _Unwind_Context* ctx, 366 const ScanResultInternal& results) { 367 exc->barrier_cache.sp = _Unwind_GetGR(ctx, UNWIND_STACK_REG); 368 exc->barrier_cache.bitpattern[0] = (uint32_t)results.adjustedPtr; 369 exc->barrier_cache.bitpattern[1] = (uint32_t)results.ttypeIndex; 370 exc->barrier_cache.bitpattern[3] = (uint32_t)results.landingPad; 371 } 372 373 void loadDataFromBarrierCache(_Unwind_Exception* exc, 374 ScanResultInternal& results) { 375 results.adjustedPtr = (void*) exc->barrier_cache.bitpattern[0]; 376 results.ttypeIndex = (int64_t) exc->barrier_cache.bitpattern[1]; 377 results.landingPad = (uintptr_t) exc->barrier_cache.bitpattern[3]; 378 } 379 380 void prepareBeginCleanup(_Unwind_Exception* exc) { 381 __cxa_begin_cleanup(exc); 382 } 383 384 void saveUnexpectedDataToBarrierCache(_Unwind_Exception* exc, 385 _Unwind_Context* ctx, 386 const ScanResultInternal& results) { 387 prepareBeginCleanup(exc); 388 389 const uint8_t* lsda = (const uint8_t*)_Unwind_GetLanguageSpecificData(ctx); 390 const uint8_t* classInfo = NULL; 391 uint8_t lpStartEncoding = *lsda++; 392 __attribute__((unused)) 393 const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding); 394 __attribute__((unused)) 395 uintptr_t funcStart = _Unwind_GetRegionStart(ctx); 396 uint8_t ttypeEncoding = *lsda++; 397 if (ttypeEncoding != DW_EH_PE_omit) { 398 uintptr_t classInfoOffset = readULEB128(&lsda); 399 classInfo = lsda + classInfoOffset; 400 } 401 402 const uint32_t* e = (const uint32_t*) classInfo - results.ttypeIndex - 1; 403 uint32_t n = 0; 404 while (e[n] != 0) { 405 ++n; 406 } 407 408 exc->barrier_cache.bitpattern[1] = n; 409 exc->barrier_cache.bitpattern[3] = 4; 410 exc->barrier_cache.bitpattern[4] = (uint32_t)e; 411 } 412 413 #else // ! __arm__ 414 415 const __shim_type_info* getTypePtr(uint64_t ttypeIndex, 416 const uint8_t* classInfo, 417 uint8_t ttypeEncoding, 418 _Unwind_Exception* unwind_exception) { 419 if (classInfo == 0) { // eh table corrupted! 420 call_terminate(unwind_exception); 421 } 422 423 switch (ttypeEncoding & 0x0F) { 424 case DW_EH_PE_absptr: 425 ttypeIndex *= sizeof(void*); 426 break; 427 case DW_EH_PE_udata2: 428 case DW_EH_PE_sdata2: 429 ttypeIndex *= 2; 430 break; 431 case DW_EH_PE_udata4: 432 case DW_EH_PE_sdata4: 433 ttypeIndex *= 4; 434 break; 435 case DW_EH_PE_udata8: 436 case DW_EH_PE_sdata8: 437 ttypeIndex *= 8; 438 break; 439 default: 440 // this should not happen. 441 call_terminate(unwind_exception); 442 } 443 classInfo -= ttypeIndex; 444 return (const __shim_type_info*)readEncodedPointer(&classInfo, ttypeEncoding); 445 } 446 447 bool canExceptionSpecCatch(int64_t specIndex, 448 const uint8_t* classInfo, 449 uint8_t ttypeEncoding, 450 const std::type_info* excpType, 451 void* adjustedPtr, 452 _Unwind_Exception* unwind_exception) { 453 if (classInfo == 0) { // eh table corrupted! 454 call_terminate(unwind_exception); 455 } 456 457 specIndex = -specIndex; 458 specIndex -= 1; 459 const uint8_t* temp = classInfo + specIndex; 460 461 while (true) { 462 uint64_t ttypeIndex = readULEB128(&temp); 463 if (ttypeIndex == 0) { 464 break; 465 } 466 const __shim_type_info* catchType = getTypePtr(ttypeIndex, 467 classInfo, 468 ttypeEncoding, 469 unwind_exception); 470 void* tempPtr = adjustedPtr; 471 if (catchType->can_catch( 472 static_cast<const __shim_type_info*>(excpType), tempPtr)) { 473 return false; 474 } 475 } // while 476 return true; 477 } 478 479 void setRegisters(_Unwind_Exception* unwind_exception, 480 _Unwind_Context* context, 481 const ScanResultInternal& results) { 482 _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), 483 reinterpret_cast<uintptr_t>(unwind_exception)); 484 _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 485 static_cast<uintptr_t>(results.ttypeIndex)); 486 _Unwind_SetIP(context, results.landingPad); 487 } 488 489 _Unwind_Reason_Code continueUnwinding(_Unwind_Exception *ex, 490 _Unwind_Context *context) { 491 return _URC_CONTINUE_UNWIND; 492 } 493 494 // Do nothing, only for API compatibility 495 // We don't use C++ polymorphism since we hope no virtual table cost. 496 void saveDataToBarrierCache(_Unwind_Exception* exc, 497 _Unwind_Context* ctx, 498 const ScanResultInternal& results) {} 499 500 void loadDataFromBarrierCache(_Unwind_Exception* exc, 501 ScanResultInternal& results) {} 502 503 void prepareBeginCleanup(_Unwind_Exception* exc) {} 504 505 void saveUnexpectedDataToBarrierCache(_Unwind_Exception* exc, 506 _Unwind_Context* ctx, 507 const ScanResultInternal& results) {} 508 509 #endif // __arm__ 510 511 } // namespace __cxxabiv1 512