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