1 //===-- examples/ExceptionDemo/ExceptionDemo.cpp - 2 // An example use of the llvm Exception mechanism --===// 3 // 4 // The LLVM Compiler Infrastructure 5 // 6 // This file is distributed under the University of Illinois Open Source 7 // License. See LICENSE.TXT for details. 8 // 9 //===--------------------------------------------------------------------===// 10 // 11 // Demo program which implements an example LLVM exception implementation, and 12 // shows several test cases including the handling of foreign exceptions. 13 // It is run with type info types arguments to throw. A test will 14 // be run for each given type info type. While type info types with the value 15 // of -1 will trigger a foreign C++ exception to be thrown; type info types 16 // <= 6 and >= 1 will cause the associated generated exceptions to be thrown 17 // and caught by generated test functions; and type info types > 6 18 // will result in exceptions which pass through to the test harness. All other 19 // type info types are not supported and could cause a crash. In all cases, 20 // the "finally" blocks of every generated test functions will executed 21 // regardless of whether or not that test function ignores or catches the 22 // thrown exception. 23 // 24 // examples: 25 // 26 // ExceptionDemo 27 // 28 // causes a usage to be printed to stderr 29 // 30 // ExceptionDemo 2 3 7 -1 31 // 32 // results in the following cases: 33 // - Value 2 causes an exception with a type info type of 2 to be 34 // thrown and caught by an inner generated test function. 35 // - Value 3 causes an exception with a type info type of 3 to be 36 // thrown and caught by an outer generated test function. 37 // - Value 7 causes an exception with a type info type of 7 to be 38 // thrown and NOT be caught by any generated function. 39 // - Value -1 causes a foreign C++ exception to be thrown and not be 40 // caught by any generated function 41 // 42 // Cases -1 and 7 are caught by a C++ test harness where the validity of 43 // of a C++ catch(...) clause catching a generated exception with a 44 // type info type of 7 is questionable. 45 // 46 // This code uses code from the llvm compiler-rt project and the llvm 47 // Kaleidoscope project. 48 // 49 //===--------------------------------------------------------------------===// 50 51 52 #include "llvm/LLVMContext.h" 53 #include "llvm/DerivedTypes.h" 54 #include "llvm/ExecutionEngine/ExecutionEngine.h" 55 #include "llvm/ExecutionEngine/JIT.h" 56 #include "llvm/Module.h" 57 #include "llvm/PassManager.h" 58 #include "llvm/Intrinsics.h" 59 #include "llvm/Analysis/Verifier.h" 60 #include "llvm/Target/TargetData.h" 61 #include "llvm/Target/TargetSelect.h" 62 #include "llvm/Target/TargetOptions.h" 63 #include "llvm/Transforms/Scalar.h" 64 #include "llvm/Support/IRBuilder.h" 65 #include "llvm/Support/Dwarf.h" 66 67 #include <cstdio> 68 #include <string> 69 #include <sstream> 70 #include <map> 71 #include <vector> 72 #include <stdexcept> 73 74 75 #ifndef USE_GLOBAL_STR_CONSTS 76 #define USE_GLOBAL_STR_CONSTS true 77 #endif 78 79 // System C++ ABI unwind types from: 80 // http://refspecs.freestandards.org/abi-eh-1.21.html 81 82 extern "C" { 83 84 typedef enum { 85 _URC_NO_REASON = 0, 86 _URC_FOREIGN_EXCEPTION_CAUGHT = 1, 87 _URC_FATAL_PHASE2_ERROR = 2, 88 _URC_FATAL_PHASE1_ERROR = 3, 89 _URC_NORMAL_STOP = 4, 90 _URC_END_OF_STACK = 5, 91 _URC_HANDLER_FOUND = 6, 92 _URC_INSTALL_CONTEXT = 7, 93 _URC_CONTINUE_UNWIND = 8 94 } _Unwind_Reason_Code; 95 96 typedef enum { 97 _UA_SEARCH_PHASE = 1, 98 _UA_CLEANUP_PHASE = 2, 99 _UA_HANDLER_FRAME = 4, 100 _UA_FORCE_UNWIND = 8, 101 _UA_END_OF_STACK = 16 102 } _Unwind_Action; 103 104 struct _Unwind_Exception; 105 106 typedef void (*_Unwind_Exception_Cleanup_Fn) (_Unwind_Reason_Code, 107 struct _Unwind_Exception *); 108 109 struct _Unwind_Exception { 110 uint64_t exception_class; 111 _Unwind_Exception_Cleanup_Fn exception_cleanup; 112 113 uintptr_t private_1; 114 uintptr_t private_2; 115 116 // @@@ The IA-64 ABI says that this structure must be double-word aligned. 117 // Taking that literally does not make much sense generically. Instead 118 // we provide the maximum alignment required by any type for the machine. 119 } __attribute__((__aligned__)); 120 121 struct _Unwind_Context; 122 typedef struct _Unwind_Context* _Unwind_Context_t; 123 124 extern const uint8_t* _Unwind_GetLanguageSpecificData (_Unwind_Context_t c); 125 extern uintptr_t _Unwind_GetGR (_Unwind_Context_t c, int i); 126 extern void _Unwind_SetGR (_Unwind_Context_t c, int i, uintptr_t n); 127 extern void _Unwind_SetIP (_Unwind_Context_t, uintptr_t new_value); 128 extern uintptr_t _Unwind_GetIP (_Unwind_Context_t context); 129 extern uintptr_t _Unwind_GetRegionStart (_Unwind_Context_t context); 130 131 } // extern "C" 132 133 // 134 // Example types 135 // 136 137 /// This is our simplistic type info 138 struct OurExceptionType_t { 139 /// type info type 140 int type; 141 }; 142 143 144 /// This is our Exception class which relies on a negative offset to calculate 145 /// pointers to its instances from pointers to its unwindException member. 146 /// 147 /// Note: The above unwind.h defines struct _Unwind_Exception to be aligned 148 /// on a double word boundary. This is necessary to match the standard: 149 /// http://refspecs.freestandards.org/abi-eh-1.21.html 150 struct OurBaseException_t { 151 struct OurExceptionType_t type; 152 153 // Note: This is properly aligned in unwind.h 154 struct _Unwind_Exception unwindException; 155 }; 156 157 158 // Note: Not needed since we are C++ 159 typedef struct OurBaseException_t OurException; 160 typedef struct _Unwind_Exception OurUnwindException; 161 162 // 163 // Various globals used to support typeinfo and generatted exceptions in 164 // general 165 // 166 167 static std::map<std::string, llvm::Value*> namedValues; 168 169 int64_t ourBaseFromUnwindOffset; 170 171 const unsigned char ourBaseExcpClassChars[] = 172 {'o', 'b', 'j', '\0', 'b', 'a', 's', '\0'}; 173 174 175 static uint64_t ourBaseExceptionClass = 0; 176 177 static std::vector<std::string> ourTypeInfoNames; 178 static std::map<int, std::string> ourTypeInfoNamesIndex; 179 180 static llvm::StructType* ourTypeInfoType; 181 static llvm::StructType* ourExceptionType; 182 static llvm::StructType* ourUnwindExceptionType; 183 184 static llvm::ConstantInt* ourExceptionNotThrownState; 185 static llvm::ConstantInt* ourExceptionThrownState; 186 static llvm::ConstantInt* ourExceptionCaughtState; 187 188 typedef std::vector<std::string> ArgNames; 189 typedef std::vector<const llvm::Type*> ArgTypes; 190 191 // 192 // Code Generation Utilities 193 // 194 195 /// Utility used to create a function, both declarations and definitions 196 /// @param module for module instance 197 /// @param retType function return type 198 /// @param theArgTypes function's ordered argument types 199 /// @param theArgNames function's ordered arguments needed if use of this 200 /// function corresponds to a function definition. Use empty 201 /// aggregate for function declarations. 202 /// @param functName function name 203 /// @param linkage function linkage 204 /// @param declarationOnly for function declarations 205 /// @param isVarArg function uses vararg arguments 206 /// @returns function instance 207 llvm::Function *createFunction(llvm::Module& module, 208 const llvm::Type* retType, 209 const ArgTypes& theArgTypes, 210 const ArgNames& theArgNames, 211 const std::string& functName, 212 llvm::GlobalValue::LinkageTypes linkage, 213 bool declarationOnly, 214 bool isVarArg) { 215 llvm::FunctionType* functType = llvm::FunctionType::get(retType, 216 theArgTypes, 217 isVarArg); 218 llvm::Function* ret = llvm::Function::Create(functType, 219 linkage, 220 functName, 221 &module); 222 if (!ret || declarationOnly) 223 return(ret); 224 225 namedValues.clear(); 226 unsigned i = 0; 227 for (llvm::Function::arg_iterator argIndex = ret->arg_begin(); 228 i != theArgNames.size(); 229 ++argIndex, ++i) { 230 231 argIndex->setName(theArgNames[i]); 232 namedValues[theArgNames[i]] = argIndex; 233 } 234 235 return(ret); 236 } 237 238 239 /// Create an alloca instruction in the entry block of 240 /// the parent function. This is used for mutable variables etc. 241 /// @param function parent instance 242 /// @param varName stack variable name 243 /// @param type stack variable type 244 /// @param initWith optional constant initialization value 245 /// @returns AllocaInst instance 246 static llvm::AllocaInst *createEntryBlockAlloca(llvm::Function& function, 247 const std::string &varName, 248 const llvm::Type* type, 249 llvm::Constant* initWith = NULL) { 250 llvm::BasicBlock& block = function.getEntryBlock(); 251 llvm::IRBuilder<> tmp(&block, block.begin()); 252 llvm::AllocaInst* ret = tmp.CreateAlloca(type, 0, varName.c_str()); 253 254 if (initWith) 255 tmp.CreateStore(initWith, ret); 256 257 return(ret); 258 } 259 260 261 // 262 // Code Generation Utilities End 263 // 264 265 // 266 // Runtime C Library functions 267 // 268 269 // Note: using an extern "C" block so that static functions can be used 270 extern "C" { 271 272 // Note: Better ways to decide on bit width 273 // 274 /// Prints a 32 bit number, according to the format, to stderr. 275 /// @param intToPrint integer to print 276 /// @param format printf like format to use when printing 277 void print32Int(int intToPrint, const char* format) { 278 if (format) { 279 // Note: No NULL check 280 fprintf(stderr, format, intToPrint); 281 } 282 else { 283 // Note: No NULL check 284 fprintf(stderr, "::print32Int(...):NULL arg.\n"); 285 } 286 } 287 288 289 // Note: Better ways to decide on bit width 290 // 291 /// Prints a 64 bit number, according to the format, to stderr. 292 /// @param intToPrint integer to print 293 /// @param format printf like format to use when printing 294 void print64Int(long int intToPrint, const char* format) { 295 if (format) { 296 // Note: No NULL check 297 fprintf(stderr, format, intToPrint); 298 } 299 else { 300 // Note: No NULL check 301 fprintf(stderr, "::print64Int(...):NULL arg.\n"); 302 } 303 } 304 305 306 /// Prints a C string to stderr 307 /// @param toPrint string to print 308 void printStr(char* toPrint) { 309 if (toPrint) { 310 fprintf(stderr, "%s", toPrint); 311 } 312 else { 313 fprintf(stderr, "::printStr(...):NULL arg.\n"); 314 } 315 } 316 317 318 /// Deletes the true previosly allocated exception whose address 319 /// is calculated from the supplied OurBaseException_t::unwindException 320 /// member address. Handles (ignores), NULL pointers. 321 /// @param expToDelete exception to delete 322 void deleteOurException(OurUnwindException* expToDelete) { 323 #ifdef DEBUG 324 fprintf(stderr, 325 "deleteOurException(...).\n"); 326 #endif 327 328 if (expToDelete && 329 (expToDelete->exception_class == ourBaseExceptionClass)) { 330 331 free(((char*) expToDelete) + ourBaseFromUnwindOffset); 332 } 333 } 334 335 336 /// This function is the struct _Unwind_Exception API mandated delete function 337 /// used by foreign exception handlers when deleting our exception 338 /// (OurException), instances. 339 /// @param reason @link http://refspecs.freestandards.org/abi-eh-1.21.html 340 /// @unlink 341 /// @param expToDelete exception instance to delete 342 void deleteFromUnwindOurException(_Unwind_Reason_Code reason, 343 OurUnwindException* expToDelete) { 344 #ifdef DEBUG 345 fprintf(stderr, 346 "deleteFromUnwindOurException(...).\n"); 347 #endif 348 349 deleteOurException(expToDelete); 350 } 351 352 353 /// Creates (allocates on the heap), an exception (OurException instance), 354 /// of the supplied type info type. 355 /// @param type type info type 356 OurUnwindException* createOurException(int type) { 357 size_t size = sizeof(OurException); 358 OurException* ret = (OurException*) memset(malloc(size), 0, size); 359 (ret->type).type = type; 360 (ret->unwindException).exception_class = ourBaseExceptionClass; 361 (ret->unwindException).exception_cleanup = deleteFromUnwindOurException; 362 363 return(&(ret->unwindException)); 364 } 365 366 367 /// Read a uleb128 encoded value and advance pointer 368 /// See Variable Length Data in: 369 /// @link http://dwarfstd.org/Dwarf3.pdf @unlink 370 /// @param data reference variable holding memory pointer to decode from 371 /// @returns decoded value 372 static uintptr_t readULEB128(const uint8_t** data) { 373 uintptr_t result = 0; 374 uintptr_t shift = 0; 375 unsigned char byte; 376 const uint8_t* p = *data; 377 378 do { 379 byte = *p++; 380 result |= (byte & 0x7f) << shift; 381 shift += 7; 382 } 383 while (byte & 0x80); 384 385 *data = p; 386 387 return result; 388 } 389 390 391 /// Read a sleb128 encoded value and advance pointer 392 /// See Variable Length Data in: 393 /// @link http://dwarfstd.org/Dwarf3.pdf @unlink 394 /// @param data reference variable holding memory pointer to decode from 395 /// @returns decoded value 396 static uintptr_t readSLEB128(const uint8_t** data) { 397 uintptr_t result = 0; 398 uintptr_t shift = 0; 399 unsigned char byte; 400 const uint8_t* p = *data; 401 402 do { 403 byte = *p++; 404 result |= (byte & 0x7f) << shift; 405 shift += 7; 406 } 407 while (byte & 0x80); 408 409 *data = p; 410 411 if ((byte & 0x40) && (shift < (sizeof(result) << 3))) { 412 result |= (~0 << shift); 413 } 414 415 return result; 416 } 417 418 419 /// Read a pointer encoded value and advance pointer 420 /// See Variable Length Data in: 421 /// @link http://dwarfstd.org/Dwarf3.pdf @unlink 422 /// @param data reference variable holding memory pointer to decode from 423 /// @param encoding dwarf encoding type 424 /// @returns decoded value 425 static uintptr_t readEncodedPointer(const uint8_t** data, uint8_t encoding) { 426 uintptr_t result = 0; 427 const uint8_t* p = *data; 428 429 if (encoding == llvm::dwarf::DW_EH_PE_omit) 430 return(result); 431 432 // first get value 433 switch (encoding & 0x0F) { 434 case llvm::dwarf::DW_EH_PE_absptr: 435 result = *((uintptr_t*)p); 436 p += sizeof(uintptr_t); 437 break; 438 case llvm::dwarf::DW_EH_PE_uleb128: 439 result = readULEB128(&p); 440 break; 441 // Note: This case has not been tested 442 case llvm::dwarf::DW_EH_PE_sleb128: 443 result = readSLEB128(&p); 444 break; 445 case llvm::dwarf::DW_EH_PE_udata2: 446 result = *((uint16_t*)p); 447 p += sizeof(uint16_t); 448 break; 449 case llvm::dwarf::DW_EH_PE_udata4: 450 result = *((uint32_t*)p); 451 p += sizeof(uint32_t); 452 break; 453 case llvm::dwarf::DW_EH_PE_udata8: 454 result = *((uint64_t*)p); 455 p += sizeof(uint64_t); 456 break; 457 case llvm::dwarf::DW_EH_PE_sdata2: 458 result = *((int16_t*)p); 459 p += sizeof(int16_t); 460 break; 461 case llvm::dwarf::DW_EH_PE_sdata4: 462 result = *((int32_t*)p); 463 p += sizeof(int32_t); 464 break; 465 case llvm::dwarf::DW_EH_PE_sdata8: 466 result = *((int64_t*)p); 467 p += sizeof(int64_t); 468 break; 469 default: 470 // not supported 471 abort(); 472 break; 473 } 474 475 // then add relative offset 476 switch (encoding & 0x70) { 477 case llvm::dwarf::DW_EH_PE_absptr: 478 // do nothing 479 break; 480 case llvm::dwarf::DW_EH_PE_pcrel: 481 result += (uintptr_t)(*data); 482 break; 483 case llvm::dwarf::DW_EH_PE_textrel: 484 case llvm::dwarf::DW_EH_PE_datarel: 485 case llvm::dwarf::DW_EH_PE_funcrel: 486 case llvm::dwarf::DW_EH_PE_aligned: 487 default: 488 // not supported 489 abort(); 490 break; 491 } 492 493 // then apply indirection 494 if (encoding & llvm::dwarf::DW_EH_PE_indirect) { 495 result = *((uintptr_t*)result); 496 } 497 498 *data = p; 499 500 return result; 501 } 502 503 504 /// Deals with Dwarf actions matching our type infos 505 /// (OurExceptionType_t instances). Returns whether or not a dwarf emitted 506 /// action matches the supplied exception type. If such a match succeeds, 507 /// the resultAction argument will be set with > 0 index value. Only 508 /// corresponding llvm.eh.selector type info arguments, cleanup arguments 509 /// are supported. Filters are not supported. 510 /// See Variable Length Data in: 511 /// @link http://dwarfstd.org/Dwarf3.pdf @unlink 512 /// Also see @link http://refspecs.freestandards.org/abi-eh-1.21.html @unlink 513 /// @param resultAction reference variable which will be set with result 514 /// @param classInfo our array of type info pointers (to globals) 515 /// @param actionEntry index into above type info array or 0 (clean up). 516 /// We do not support filters. 517 /// @param exceptionClass exception class (_Unwind_Exception::exception_class) 518 /// of thrown exception. 519 /// @param exceptionObject thrown _Unwind_Exception instance. 520 /// @returns whether or not a type info was found. False is returned if only 521 /// a cleanup was found 522 static bool handleActionValue(int64_t *resultAction, 523 struct OurExceptionType_t **classInfo, 524 uintptr_t actionEntry, 525 uint64_t exceptionClass, 526 struct _Unwind_Exception *exceptionObject) { 527 bool ret = false; 528 529 if (!resultAction || 530 !exceptionObject || 531 (exceptionClass != ourBaseExceptionClass)) 532 return(ret); 533 534 struct OurBaseException_t* excp = (struct OurBaseException_t*) 535 (((char*) exceptionObject) + ourBaseFromUnwindOffset); 536 struct OurExceptionType_t *excpType = &(excp->type); 537 int type = excpType->type; 538 539 #ifdef DEBUG 540 fprintf(stderr, 541 "handleActionValue(...): exceptionObject = <%p>, " 542 "excp = <%p>.\n", 543 exceptionObject, 544 excp); 545 #endif 546 547 const uint8_t *actionPos = (uint8_t*) actionEntry, 548 *tempActionPos; 549 int64_t typeOffset = 0, 550 actionOffset; 551 552 for (int i = 0; true; ++i) { 553 // Each emitted dwarf action corresponds to a 2 tuple of 554 // type info address offset, and action offset to the next 555 // emitted action. 556 typeOffset = readSLEB128(&actionPos); 557 tempActionPos = actionPos; 558 actionOffset = readSLEB128(&tempActionPos); 559 560 #ifdef DEBUG 561 fprintf(stderr, 562 "handleActionValue(...):typeOffset: <%lld>, " 563 "actionOffset: <%lld>.\n", 564 typeOffset, 565 actionOffset); 566 #endif 567 assert((typeOffset >= 0) && 568 "handleActionValue(...):filters are not supported."); 569 570 // Note: A typeOffset == 0 implies that a cleanup llvm.eh.selector 571 // argument has been matched. 572 if ((typeOffset > 0) && 573 (type == (classInfo[-typeOffset])->type)) { 574 #ifdef DEBUG 575 fprintf(stderr, 576 "handleActionValue(...):actionValue <%d> found.\n", 577 i); 578 #endif 579 *resultAction = i + 1; 580 ret = true; 581 break; 582 } 583 584 #ifdef DEBUG 585 fprintf(stderr, 586 "handleActionValue(...):actionValue not found.\n"); 587 #endif 588 if (!actionOffset) 589 break; 590 591 actionPos += actionOffset; 592 } 593 594 return(ret); 595 } 596 597 598 /// Deals with the Language specific data portion of the emitted dwarf code. 599 /// See @link http://refspecs.freestandards.org/abi-eh-1.21.html @unlink 600 /// @param version unsupported (ignored), unwind version 601 /// @param lsda language specific data area 602 /// @param _Unwind_Action actions minimally supported unwind stage 603 /// (forced specifically not supported) 604 /// @param exceptionClass exception class (_Unwind_Exception::exception_class) 605 /// of thrown exception. 606 /// @param exceptionObject thrown _Unwind_Exception instance. 607 /// @param context unwind system context 608 /// @returns minimally supported unwinding control indicator 609 static _Unwind_Reason_Code handleLsda(int version, 610 const uint8_t* lsda, 611 _Unwind_Action actions, 612 uint64_t exceptionClass, 613 struct _Unwind_Exception* exceptionObject, 614 _Unwind_Context_t context) { 615 _Unwind_Reason_Code ret = _URC_CONTINUE_UNWIND; 616 617 if (!lsda) 618 return(ret); 619 620 #ifdef DEBUG 621 fprintf(stderr, 622 "handleLsda(...):lsda is non-zero.\n"); 623 #endif 624 625 // Get the current instruction pointer and offset it before next 626 // instruction in the current frame which threw the exception. 627 uintptr_t pc = _Unwind_GetIP(context)-1; 628 629 // Get beginning current frame's code (as defined by the 630 // emitted dwarf code) 631 uintptr_t funcStart = _Unwind_GetRegionStart(context); 632 uintptr_t pcOffset = pc - funcStart; 633 struct OurExceptionType_t** classInfo = NULL; 634 635 // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding 636 // dwarf emission 637 638 // Parse LSDA header. 639 uint8_t lpStartEncoding = *lsda++; 640 641 if (lpStartEncoding != llvm::dwarf::DW_EH_PE_omit) { 642 readEncodedPointer(&lsda, lpStartEncoding); 643 } 644 645 uint8_t ttypeEncoding = *lsda++; 646 uintptr_t classInfoOffset; 647 648 if (ttypeEncoding != llvm::dwarf::DW_EH_PE_omit) { 649 // Calculate type info locations in emitted dwarf code which 650 // were flagged by type info arguments to llvm.eh.selector 651 // intrinsic 652 classInfoOffset = readULEB128(&lsda); 653 classInfo = (struct OurExceptionType_t**) (lsda + classInfoOffset); 654 } 655 656 // Walk call-site table looking for range that 657 // includes current PC. 658 659 uint8_t callSiteEncoding = *lsda++; 660 uint32_t callSiteTableLength = readULEB128(&lsda); 661 const uint8_t* callSiteTableStart = lsda; 662 const uint8_t* callSiteTableEnd = callSiteTableStart + 663 callSiteTableLength; 664 const uint8_t* actionTableStart = callSiteTableEnd; 665 const uint8_t* callSitePtr = callSiteTableStart; 666 667 bool foreignException = false; 668 669 while (callSitePtr < callSiteTableEnd) { 670 uintptr_t start = readEncodedPointer(&callSitePtr, 671 callSiteEncoding); 672 uintptr_t length = readEncodedPointer(&callSitePtr, 673 callSiteEncoding); 674 uintptr_t landingPad = readEncodedPointer(&callSitePtr, 675 callSiteEncoding); 676 677 // Note: Action value 678 uintptr_t actionEntry = readULEB128(&callSitePtr); 679 680 if (exceptionClass != ourBaseExceptionClass) { 681 // We have been notified of a foreign exception being thrown, 682 // and we therefore need to execute cleanup landing pads 683 actionEntry = 0; 684 foreignException = true; 685 } 686 687 if (landingPad == 0) { 688 #ifdef DEBUG 689 fprintf(stderr, 690 "handleLsda(...): No landing pad found.\n"); 691 #endif 692 693 continue; // no landing pad for this entry 694 } 695 696 if (actionEntry) { 697 actionEntry += ((uintptr_t) actionTableStart) - 1; 698 } 699 else { 700 #ifdef DEBUG 701 fprintf(stderr, 702 "handleLsda(...):No action table found.\n"); 703 #endif 704 } 705 706 bool exceptionMatched = false; 707 708 if ((start <= pcOffset) && (pcOffset < (start + length))) { 709 #ifdef DEBUG 710 fprintf(stderr, 711 "handleLsda(...): Landing pad found.\n"); 712 #endif 713 int64_t actionValue = 0; 714 715 if (actionEntry) { 716 exceptionMatched = handleActionValue 717 ( 718 &actionValue, 719 classInfo, 720 actionEntry, 721 exceptionClass, 722 exceptionObject 723 ); 724 } 725 726 if (!(actions & _UA_SEARCH_PHASE)) { 727 #ifdef DEBUG 728 fprintf(stderr, 729 "handleLsda(...): installed landing pad " 730 "context.\n"); 731 #endif 732 733 // Found landing pad for the PC. 734 // Set Instruction Pointer to so we re-enter function 735 // at landing pad. The landing pad is created by the 736 // compiler to take two parameters in registers. 737 _Unwind_SetGR(context, 738 __builtin_eh_return_data_regno(0), 739 (uintptr_t)exceptionObject); 740 741 // Note: this virtual register directly corresponds 742 // to the return of the llvm.eh.selector intrinsic 743 if (!actionEntry || !exceptionMatched) { 744 // We indicate cleanup only 745 _Unwind_SetGR(context, 746 __builtin_eh_return_data_regno(1), 747 0); 748 } 749 else { 750 // Matched type info index of llvm.eh.selector intrinsic 751 // passed here. 752 _Unwind_SetGR(context, 753 __builtin_eh_return_data_regno(1), 754 actionValue); 755 } 756 757 // To execute landing pad set here 758 _Unwind_SetIP(context, funcStart + landingPad); 759 ret = _URC_INSTALL_CONTEXT; 760 } 761 else if (exceptionMatched) { 762 #ifdef DEBUG 763 fprintf(stderr, 764 "handleLsda(...): setting handler found.\n"); 765 #endif 766 ret = _URC_HANDLER_FOUND; 767 } 768 else { 769 // Note: Only non-clean up handlers are marked as 770 // found. Otherwise the clean up handlers will be 771 // re-found and executed during the clean up 772 // phase. 773 #ifdef DEBUG 774 fprintf(stderr, 775 "handleLsda(...): cleanup handler found.\n"); 776 #endif 777 } 778 779 break; 780 } 781 } 782 783 return(ret); 784 } 785 786 787 /// This is the personality function which is embedded (dwarf emitted), in the 788 /// dwarf unwind info block. Again see: JITDwarfEmitter.cpp. 789 /// See @link http://refspecs.freestandards.org/abi-eh-1.21.html @unlink 790 /// @param version unsupported (ignored), unwind version 791 /// @param _Unwind_Action actions minimally supported unwind stage 792 /// (forced specifically not supported) 793 /// @param exceptionClass exception class (_Unwind_Exception::exception_class) 794 /// of thrown exception. 795 /// @param exceptionObject thrown _Unwind_Exception instance. 796 /// @param context unwind system context 797 /// @returns minimally supported unwinding control indicator 798 _Unwind_Reason_Code ourPersonality(int version, 799 _Unwind_Action actions, 800 uint64_t exceptionClass, 801 struct _Unwind_Exception* exceptionObject, 802 _Unwind_Context_t context) { 803 #ifdef DEBUG 804 fprintf(stderr, 805 "We are in ourPersonality(...):actions is <%d>.\n", 806 actions); 807 808 if (actions & _UA_SEARCH_PHASE) { 809 fprintf(stderr, "ourPersonality(...):In search phase.\n"); 810 } 811 else { 812 fprintf(stderr, "ourPersonality(...):In non-search phase.\n"); 813 } 814 #endif 815 816 const uint8_t* lsda = _Unwind_GetLanguageSpecificData(context); 817 818 #ifdef DEBUG 819 fprintf(stderr, 820 "ourPersonality(...):lsda = <%p>.\n", 821 lsda); 822 #endif 823 824 // The real work of the personality function is captured here 825 return(handleLsda(version, 826 lsda, 827 actions, 828 exceptionClass, 829 exceptionObject, 830 context)); 831 } 832 833 834 /// Generates our _Unwind_Exception class from a given character array. 835 /// thereby handling arbitrary lengths (not in standard), and handling 836 /// embedded \0s. 837 /// See @link http://refspecs.freestandards.org/abi-eh-1.21.html @unlink 838 /// @param classChars char array to encode. NULL values not checkedf 839 /// @param classCharsSize number of chars in classChars. Value is not checked. 840 /// @returns class value 841 uint64_t genClass(const unsigned char classChars[], size_t classCharsSize) 842 { 843 uint64_t ret = classChars[0]; 844 845 for (unsigned i = 1; i < classCharsSize; ++i) { 846 ret <<= 8; 847 ret += classChars[i]; 848 } 849 850 return(ret); 851 } 852 853 } // extern "C" 854 855 // 856 // Runtime C Library functions End 857 // 858 859 // 860 // Code generation functions 861 // 862 863 /// Generates code to print given constant string 864 /// @param context llvm context 865 /// @param module code for module instance 866 /// @param builder builder instance 867 /// @param toPrint string to print 868 /// @param useGlobal A value of true (default) indicates a GlobalValue is 869 /// generated, and is used to hold the constant string. A value of 870 /// false indicates that the constant string will be stored on the 871 /// stack. 872 void generateStringPrint(llvm::LLVMContext& context, 873 llvm::Module& module, 874 llvm::IRBuilder<>& builder, 875 std::string toPrint, 876 bool useGlobal = true) { 877 llvm::Function *printFunct = module.getFunction("printStr"); 878 879 llvm::Value *stringVar; 880 llvm::Constant* stringConstant = 881 llvm::ConstantArray::get(context, toPrint); 882 883 if (useGlobal) { 884 // Note: Does not work without allocation 885 stringVar = 886 new llvm::GlobalVariable(module, 887 stringConstant->getType(), 888 true, 889 llvm::GlobalValue::LinkerPrivateLinkage, 890 stringConstant, 891 ""); 892 } 893 else { 894 stringVar = builder.CreateAlloca(stringConstant->getType()); 895 builder.CreateStore(stringConstant, stringVar); 896 } 897 898 llvm::Value* cast = 899 builder.CreatePointerCast(stringVar, 900 builder.getInt8Ty()->getPointerTo()); 901 builder.CreateCall(printFunct, cast); 902 } 903 904 905 /// Generates code to print given runtime integer according to constant 906 /// string format, and a given print function. 907 /// @param context llvm context 908 /// @param module code for module instance 909 /// @param builder builder instance 910 /// @param printFunct function used to "print" integer 911 /// @param toPrint string to print 912 /// @param format printf like formating string for print 913 /// @param useGlobal A value of true (default) indicates a GlobalValue is 914 /// generated, and is used to hold the constant string. A value of 915 /// false indicates that the constant string will be stored on the 916 /// stack. 917 void generateIntegerPrint(llvm::LLVMContext& context, 918 llvm::Module& module, 919 llvm::IRBuilder<>& builder, 920 llvm::Function& printFunct, 921 llvm::Value& toPrint, 922 std::string format, 923 bool useGlobal = true) { 924 llvm::Constant *stringConstant = llvm::ConstantArray::get(context, format); 925 llvm::Value *stringVar; 926 927 if (useGlobal) { 928 // Note: Does not seem to work without allocation 929 stringVar = 930 new llvm::GlobalVariable(module, 931 stringConstant->getType(), 932 true, 933 llvm::GlobalValue::LinkerPrivateLinkage, 934 stringConstant, 935 ""); 936 } 937 else { 938 stringVar = builder.CreateAlloca(stringConstant->getType()); 939 builder.CreateStore(stringConstant, stringVar); 940 } 941 942 llvm::Value* cast = 943 builder.CreateBitCast(stringVar, 944 builder.getInt8Ty()->getPointerTo()); 945 builder.CreateCall2(&printFunct, &toPrint, cast); 946 } 947 948 949 /// Generates code to handle finally block type semantics: always runs 950 /// regardless of whether a thrown exception is passing through or the 951 /// parent function is simply exiting. In addition to printing some state 952 /// to stderr, this code will resume the exception handling--runs the 953 /// unwind resume block, if the exception has not been previously caught 954 /// by a catch clause, and will otherwise execute the end block (terminator 955 /// block). In addition this function creates the corresponding function's 956 /// stack storage for the exception pointer and catch flag status. 957 /// @param context llvm context 958 /// @param module code for module instance 959 /// @param builder builder instance 960 /// @param toAddTo parent function to add block to 961 /// @param blockName block name of new "finally" block. 962 /// @param functionId output id used for printing 963 /// @param terminatorBlock terminator "end" block 964 /// @param unwindResumeBlock unwind resume block 965 /// @param exceptionCaughtFlag reference exception caught/thrown status storage 966 /// @param exceptionStorage reference to exception pointer storage 967 /// @returns newly created block 968 static llvm::BasicBlock* createFinallyBlock(llvm::LLVMContext& context, 969 llvm::Module& module, 970 llvm::IRBuilder<>& builder, 971 llvm::Function& toAddTo, 972 std::string& blockName, 973 std::string& functionId, 974 llvm::BasicBlock& terminatorBlock, 975 llvm::BasicBlock& unwindResumeBlock, 976 llvm::Value** exceptionCaughtFlag, 977 llvm::Value** exceptionStorage) { 978 assert(exceptionCaughtFlag && 979 "ExceptionDemo::createFinallyBlock(...):exceptionCaughtFlag " 980 "is NULL"); 981 assert(exceptionStorage && 982 "ExceptionDemo::createFinallyBlock(...):exceptionStorage " 983 "is NULL"); 984 985 *exceptionCaughtFlag = 986 createEntryBlockAlloca(toAddTo, 987 "exceptionCaught", 988 ourExceptionNotThrownState->getType(), 989 ourExceptionNotThrownState); 990 991 const llvm::PointerType* exceptionStorageType = 992 builder.getInt8Ty()->getPointerTo(); 993 *exceptionStorage = 994 createEntryBlockAlloca(toAddTo, 995 "exceptionStorage", 996 exceptionStorageType, 997 llvm::ConstantPointerNull::get( 998 exceptionStorageType)); 999 1000 llvm::BasicBlock *ret = llvm::BasicBlock::Create(context, 1001 blockName, 1002 &toAddTo); 1003 1004 builder.SetInsertPoint(ret); 1005 1006 std::ostringstream bufferToPrint; 1007 bufferToPrint << "Gen: Executing finally block " 1008 << blockName 1009 << " in " 1010 << functionId 1011 << std::endl; 1012 generateStringPrint(context, 1013 module, 1014 builder, 1015 bufferToPrint.str(), 1016 USE_GLOBAL_STR_CONSTS); 1017 1018 llvm::SwitchInst* theSwitch = 1019 builder.CreateSwitch(builder.CreateLoad(*exceptionCaughtFlag), 1020 &terminatorBlock, 1021 2); 1022 theSwitch->addCase(ourExceptionCaughtState, &terminatorBlock); 1023 theSwitch->addCase(ourExceptionThrownState, &unwindResumeBlock); 1024 1025 return(ret); 1026 } 1027 1028 1029 /// Generates catch block semantics which print a string to indicate type of 1030 /// catch executed, sets an exception caught flag, and executes passed in 1031 /// end block (terminator block). 1032 /// @param context llvm context 1033 /// @param module code for module instance 1034 /// @param builder builder instance 1035 /// @param toAddTo parent function to add block to 1036 /// @param blockName block name of new "catch" block. 1037 /// @param functionId output id used for printing 1038 /// @param terminatorBlock terminator "end" block 1039 /// @param exceptionCaughtFlag exception caught/thrown status 1040 /// @returns newly created block 1041 static llvm::BasicBlock* createCatchBlock(llvm::LLVMContext& context, 1042 llvm::Module& module, 1043 llvm::IRBuilder<>& builder, 1044 llvm::Function& toAddTo, 1045 std::string& blockName, 1046 std::string& functionId, 1047 llvm::BasicBlock& terminatorBlock, 1048 llvm::Value& exceptionCaughtFlag) { 1049 1050 llvm::BasicBlock *ret = llvm::BasicBlock::Create(context, 1051 blockName, 1052 &toAddTo); 1053 1054 builder.SetInsertPoint(ret); 1055 1056 std::ostringstream bufferToPrint; 1057 bufferToPrint << "Gen: Executing catch block " 1058 << blockName 1059 << " in " 1060 << functionId 1061 << std::endl; 1062 generateStringPrint(context, 1063 module, 1064 builder, 1065 bufferToPrint.str(), 1066 USE_GLOBAL_STR_CONSTS); 1067 builder.CreateStore(ourExceptionCaughtState, &exceptionCaughtFlag); 1068 builder.CreateBr(&terminatorBlock); 1069 1070 return(ret); 1071 } 1072 1073 1074 /// Generates a function which invokes a function (toInvoke) and, whose 1075 /// unwind block will "catch" the type info types correspondingly held in the 1076 /// exceptionTypesToCatch argument. If the toInvoke function throws an 1077 /// exception which does not match any type info types contained in 1078 /// exceptionTypesToCatch, the generated code will call _Unwind_Resume 1079 /// with the raised exception. On the other hand the generated code will 1080 /// normally exit if the toInvoke function does not throw an exception. 1081 /// The generated "finally" block is always run regardless of the cause of 1082 /// the generated function exit. 1083 /// The generated function is returned after being verified. 1084 /// @param module code for module instance 1085 /// @param builder builder instance 1086 /// @param fpm a function pass manager holding optional IR to IR 1087 /// transformations 1088 /// @param toInvoke inner function to invoke 1089 /// @param ourId id used to printing purposes 1090 /// @param numExceptionsToCatch length of exceptionTypesToCatch array 1091 /// @param exceptionTypesToCatch array of type info types to "catch" 1092 /// @returns generated function 1093 static 1094 llvm::Function* createCatchWrappedInvokeFunction(llvm::Module& module, 1095 llvm::IRBuilder<>& builder, 1096 llvm::FunctionPassManager& fpm, 1097 llvm::Function& toInvoke, 1098 std::string ourId, 1099 unsigned numExceptionsToCatch, 1100 unsigned exceptionTypesToCatch[]) { 1101 1102 llvm::LLVMContext& context = module.getContext(); 1103 llvm::Function *toPrint32Int = module.getFunction("print32Int"); 1104 1105 ArgTypes argTypes; 1106 argTypes.push_back(builder.getInt32Ty()); 1107 1108 ArgNames argNames; 1109 argNames.push_back("exceptTypeToThrow"); 1110 1111 llvm::Function* ret = createFunction(module, 1112 builder.getVoidTy(), 1113 argTypes, 1114 argNames, 1115 ourId, 1116 llvm::Function::ExternalLinkage, 1117 false, 1118 false); 1119 1120 // Block which calls invoke 1121 llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(context, 1122 "entry", 1123 ret); 1124 // Normal block for invoke 1125 llvm::BasicBlock *normalBlock = llvm::BasicBlock::Create(context, 1126 "normal", 1127 ret); 1128 // Unwind block for invoke 1129 llvm::BasicBlock *exceptionBlock = 1130 llvm::BasicBlock::Create(context, "exception", ret); 1131 1132 // Block which routes exception to correct catch handler block 1133 llvm::BasicBlock *exceptionRouteBlock = 1134 llvm::BasicBlock::Create(context, "exceptionRoute", ret); 1135 1136 // Foreign exception handler 1137 llvm::BasicBlock *externalExceptionBlock = 1138 llvm::BasicBlock::Create(context, "externalException", ret); 1139 1140 // Block which calls _Unwind_Resume 1141 llvm::BasicBlock *unwindResumeBlock = 1142 llvm::BasicBlock::Create(context, "unwindResume", ret); 1143 1144 // Clean up block which delete exception if needed 1145 llvm::BasicBlock *endBlock = 1146 llvm::BasicBlock::Create(context, "end", ret); 1147 1148 std::string nextName; 1149 std::vector<llvm::BasicBlock*> catchBlocks(numExceptionsToCatch); 1150 llvm::Value* exceptionCaughtFlag = NULL; 1151 llvm::Value* exceptionStorage = NULL; 1152 1153 // Finally block which will branch to unwindResumeBlock if 1154 // exception is not caught. Initializes/allocates stack locations. 1155 llvm::BasicBlock* finallyBlock = createFinallyBlock(context, 1156 module, 1157 builder, 1158 *ret, 1159 nextName = "finally", 1160 ourId, 1161 *endBlock, 1162 *unwindResumeBlock, 1163 &exceptionCaughtFlag, 1164 &exceptionStorage); 1165 1166 for (unsigned i = 0; i < numExceptionsToCatch; ++i) { 1167 nextName = ourTypeInfoNames[exceptionTypesToCatch[i]]; 1168 1169 // One catch block per type info to be caught 1170 catchBlocks[i] = createCatchBlock(context, 1171 module, 1172 builder, 1173 *ret, 1174 nextName, 1175 ourId, 1176 *finallyBlock, 1177 *exceptionCaughtFlag); 1178 } 1179 1180 // Entry Block 1181 1182 builder.SetInsertPoint(entryBlock); 1183 1184 std::vector<llvm::Value*> args; 1185 args.push_back(namedValues["exceptTypeToThrow"]); 1186 builder.CreateInvoke(&toInvoke, 1187 normalBlock, 1188 exceptionBlock, 1189 args.begin(), 1190 args.end()); 1191 1192 // End Block 1193 1194 builder.SetInsertPoint(endBlock); 1195 1196 generateStringPrint(context, 1197 module, 1198 builder, 1199 "Gen: In end block: exiting in " + ourId + ".\n", 1200 USE_GLOBAL_STR_CONSTS); 1201 llvm::Function *deleteOurException = 1202 module.getFunction("deleteOurException"); 1203 1204 // Note: function handles NULL exceptions 1205 builder.CreateCall(deleteOurException, 1206 builder.CreateLoad(exceptionStorage)); 1207 builder.CreateRetVoid(); 1208 1209 // Normal Block 1210 1211 builder.SetInsertPoint(normalBlock); 1212 1213 generateStringPrint(context, 1214 module, 1215 builder, 1216 "Gen: No exception in " + ourId + "!\n", 1217 USE_GLOBAL_STR_CONSTS); 1218 1219 // Finally block is always called 1220 builder.CreateBr(finallyBlock); 1221 1222 // Unwind Resume Block 1223 1224 builder.SetInsertPoint(unwindResumeBlock); 1225 1226 llvm::Function *resumeOurException = 1227 module.getFunction("_Unwind_Resume"); 1228 builder.CreateCall(resumeOurException, 1229 builder.CreateLoad(exceptionStorage)); 1230 builder.CreateUnreachable(); 1231 1232 // Exception Block 1233 1234 builder.SetInsertPoint(exceptionBlock); 1235 1236 llvm::Function *ehException = module.getFunction("llvm.eh.exception"); 1237 1238 // Retrieve thrown exception 1239 llvm::Value* unwindException = builder.CreateCall(ehException); 1240 1241 // Store exception and flag 1242 builder.CreateStore(unwindException, exceptionStorage); 1243 builder.CreateStore(ourExceptionThrownState, exceptionCaughtFlag); 1244 llvm::Function *personality = module.getFunction("ourPersonality"); 1245 llvm::Value* functPtr = 1246 builder.CreatePointerCast(personality, 1247 builder.getInt8Ty()->getPointerTo()); 1248 1249 args.clear(); 1250 args.push_back(unwindException); 1251 args.push_back(functPtr); 1252 1253 // Note: Skipping index 0 1254 for (unsigned i = 0; i < numExceptionsToCatch; ++i) { 1255 // Set up type infos to be caught 1256 args.push_back( 1257 module.getGlobalVariable( 1258 ourTypeInfoNames[exceptionTypesToCatch[i]])); 1259 } 1260 1261 args.push_back(llvm::ConstantInt::get(builder.getInt32Ty(), 0)); 1262 1263 llvm::Function *ehSelector = module.getFunction("llvm.eh.selector"); 1264 1265 // Set up this exeption block as the landing pad which will handle 1266 // given type infos. See case Intrinsic::eh_selector in 1267 // SelectionDAGBuilder::visitIntrinsicCall(...) and AddCatchInfo(...) 1268 // implemented in FunctionLoweringInfo.cpp to see how the implementation 1269 // handles this call. This landing pad (this exception block), will be 1270 // called either because it nees to cleanup (call finally) or a type 1271 // info was found which matched the thrown exception. 1272 llvm::Value* retTypeInfoIndex = builder.CreateCall(ehSelector, 1273 args.begin(), 1274 args.end()); 1275 1276 // Retrieve exception_class member from thrown exception 1277 // (_Unwind_Exception instance). This member tells us whether or not 1278 // the exception is foreign. 1279 llvm::Value* unwindExceptionClass = 1280 builder.CreateLoad( 1281 builder.CreateStructGEP( 1282 builder.CreatePointerCast( 1283 unwindException, 1284 ourUnwindExceptionType->getPointerTo()), 1285 0)); 1286 1287 // Branch to the externalExceptionBlock if the exception is foreign or 1288 // to a catch router if not. Either way the finally block will be run. 1289 builder.CreateCondBr( 1290 builder.CreateICmpEQ(unwindExceptionClass, 1291 llvm::ConstantInt::get(builder.getInt64Ty(), 1292 ourBaseExceptionClass)), 1293 exceptionRouteBlock, 1294 externalExceptionBlock); 1295 1296 // External Exception Block 1297 1298 builder.SetInsertPoint(externalExceptionBlock); 1299 1300 generateStringPrint(context, 1301 module, 1302 builder, 1303 "Gen: Foreign exception received.\n", 1304 USE_GLOBAL_STR_CONSTS); 1305 1306 // Branch to the finally block 1307 builder.CreateBr(finallyBlock); 1308 1309 // Exception Route Block 1310 1311 builder.SetInsertPoint(exceptionRouteBlock); 1312 1313 // Casts exception pointer (_Unwind_Exception instance) to parent 1314 // (OurException instance). 1315 // 1316 // Note: ourBaseFromUnwindOffset is usually negative 1317 llvm::Value* typeInfoThrown = 1318 builder.CreatePointerCast( 1319 builder.CreateConstGEP1_64(unwindException, 1320 ourBaseFromUnwindOffset), 1321 ourExceptionType->getPointerTo()); 1322 1323 // Retrieve thrown exception type info type 1324 // 1325 // Note: Index is not relative to pointer but instead to structure 1326 // unlike a true getelementptr (GEP) instruction 1327 typeInfoThrown = builder.CreateStructGEP(typeInfoThrown, 0); 1328 1329 llvm::Value* typeInfoThrownType = 1330 builder.CreateStructGEP(typeInfoThrown, 0); 1331 1332 generateIntegerPrint(context, 1333 module, 1334 builder, 1335 *toPrint32Int, 1336 *(builder.CreateLoad(typeInfoThrownType)), 1337 "Gen: Exception type <%d> received (stack unwound) " 1338 " in " + 1339 ourId + 1340 ".\n", 1341 USE_GLOBAL_STR_CONSTS); 1342 1343 // Route to matched type info catch block or run cleanup finally block 1344 llvm::SwitchInst* switchToCatchBlock = 1345 builder.CreateSwitch(retTypeInfoIndex, 1346 finallyBlock, 1347 numExceptionsToCatch); 1348 1349 unsigned nextTypeToCatch; 1350 1351 for (unsigned i = 1; i <= numExceptionsToCatch; ++i) { 1352 nextTypeToCatch = i - 1; 1353 switchToCatchBlock->addCase(llvm::ConstantInt::get( 1354 llvm::Type::getInt32Ty(context), 1355 i), 1356 catchBlocks[nextTypeToCatch]); 1357 } 1358 1359 llvm::verifyFunction(*ret); 1360 fpm.run(*ret); 1361 1362 return(ret); 1363 } 1364 1365 1366 /// Generates function which throws either an exception matched to a runtime 1367 /// determined type info type (argument to generated function), or if this 1368 /// runtime value matches nativeThrowType, throws a foreign exception by 1369 /// calling nativeThrowFunct. 1370 /// @param module code for module instance 1371 /// @param builder builder instance 1372 /// @param fpm a function pass manager holding optional IR to IR 1373 /// transformations 1374 /// @param ourId id used to printing purposes 1375 /// @param nativeThrowType a runtime argument of this value results in 1376 /// nativeThrowFunct being called to generate/throw exception. 1377 /// @param nativeThrowFunct function which will throw a foreign exception 1378 /// if the above nativeThrowType matches generated function's arg. 1379 /// @returns generated function 1380 static 1381 llvm::Function* createThrowExceptionFunction(llvm::Module& module, 1382 llvm::IRBuilder<>& builder, 1383 llvm::FunctionPassManager& fpm, 1384 std::string ourId, 1385 int32_t nativeThrowType, 1386 llvm::Function& nativeThrowFunct) { 1387 llvm::LLVMContext& context = module.getContext(); 1388 namedValues.clear(); 1389 ArgTypes unwindArgTypes; 1390 unwindArgTypes.push_back(builder.getInt32Ty()); 1391 ArgNames unwindArgNames; 1392 unwindArgNames.push_back("exceptTypeToThrow"); 1393 1394 llvm::Function *ret = createFunction(module, 1395 builder.getVoidTy(), 1396 unwindArgTypes, 1397 unwindArgNames, 1398 ourId, 1399 llvm::Function::ExternalLinkage, 1400 false, 1401 false); 1402 1403 // Throws either one of our exception or a native C++ exception depending 1404 // on a runtime argument value containing a type info type. 1405 llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(context, 1406 "entry", 1407 ret); 1408 // Throws a foreign exception 1409 llvm::BasicBlock *nativeThrowBlock = 1410 llvm::BasicBlock::Create(context, 1411 "nativeThrow", 1412 ret); 1413 // Throws one of our Exceptions 1414 llvm::BasicBlock *generatedThrowBlock = 1415 llvm::BasicBlock::Create(context, 1416 "generatedThrow", 1417 ret); 1418 // Retrieved runtime type info type to throw 1419 llvm::Value* exceptionType = namedValues["exceptTypeToThrow"]; 1420 1421 // nativeThrowBlock block 1422 1423 builder.SetInsertPoint(nativeThrowBlock); 1424 1425 // Throws foreign exception 1426 builder.CreateCall(&nativeThrowFunct, exceptionType); 1427 builder.CreateUnreachable(); 1428 1429 // entry block 1430 1431 builder.SetInsertPoint(entryBlock); 1432 1433 llvm::Function *toPrint32Int = module.getFunction("print32Int"); 1434 generateIntegerPrint(context, 1435 module, 1436 builder, 1437 *toPrint32Int, 1438 *exceptionType, 1439 "\nGen: About to throw exception type <%d> in " + 1440 ourId + 1441 ".\n", 1442 USE_GLOBAL_STR_CONSTS); 1443 1444 // Switches on runtime type info type value to determine whether or not 1445 // a foreign exception is thrown. Defaults to throwing one of our 1446 // generated exceptions. 1447 llvm::SwitchInst* theSwitch = builder.CreateSwitch(exceptionType, 1448 generatedThrowBlock, 1449 1); 1450 1451 theSwitch->addCase(llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), 1452 nativeThrowType), 1453 nativeThrowBlock); 1454 1455 // generatedThrow block 1456 1457 builder.SetInsertPoint(generatedThrowBlock); 1458 1459 llvm::Function *createOurException = 1460 module.getFunction("createOurException"); 1461 llvm::Function *raiseOurException = 1462 module.getFunction("_Unwind_RaiseException"); 1463 1464 // Creates exception to throw with runtime type info type. 1465 llvm::Value* exception = 1466 builder.CreateCall(createOurException, 1467 namedValues["exceptTypeToThrow"]); 1468 1469 // Throw generated Exception 1470 builder.CreateCall(raiseOurException, exception); 1471 builder.CreateUnreachable(); 1472 1473 llvm::verifyFunction(*ret); 1474 fpm.run(*ret); 1475 1476 return(ret); 1477 } 1478 1479 static void createStandardUtilityFunctions(unsigned numTypeInfos, 1480 llvm::Module& module, 1481 llvm::IRBuilder<>& builder); 1482 1483 /// Creates test code by generating and organizing these functions into the 1484 /// test case. The test case consists of an outer function setup to invoke 1485 /// an inner function within an environment having multiple catch and single 1486 /// finally blocks. This inner function is also setup to invoke a throw 1487 /// function within an evironment similar in nature to the outer function's 1488 /// catch and finally blocks. Each of these two functions catch mutually 1489 /// exclusive subsets (even or odd) of the type info types configured 1490 /// for this this. All generated functions have a runtime argument which 1491 /// holds a type info type to throw that each function takes and passes it 1492 /// to the inner one if such a inner function exists. This type info type is 1493 /// looked at by the generated throw function to see whether or not it should 1494 /// throw a generated exception with the same type info type, or instead call 1495 /// a supplied a function which in turn will throw a foreign exception. 1496 /// @param module code for module instance 1497 /// @param builder builder instance 1498 /// @param fpm a function pass manager holding optional IR to IR 1499 /// transformations 1500 /// @param nativeThrowFunctName name of external function which will throw 1501 /// a foreign exception 1502 /// @returns outermost generated test function. 1503 llvm::Function* createUnwindExceptionTest(llvm::Module& module, 1504 llvm::IRBuilder<>& builder, 1505 llvm::FunctionPassManager& fpm, 1506 std::string nativeThrowFunctName) { 1507 // Number of type infos to generate 1508 unsigned numTypeInfos = 6; 1509 1510 // Initialze intrisics and external functions to use along with exception 1511 // and type info globals. 1512 createStandardUtilityFunctions(numTypeInfos, 1513 module, 1514 builder); 1515 llvm::Function *nativeThrowFunct = 1516 module.getFunction(nativeThrowFunctName); 1517 1518 // Create exception throw function using the value ~0 to cause 1519 // foreign exceptions to be thrown. 1520 llvm::Function* throwFunct = 1521 createThrowExceptionFunction(module, 1522 builder, 1523 fpm, 1524 "throwFunct", 1525 ~0, 1526 *nativeThrowFunct); 1527 // Inner function will catch even type infos 1528 unsigned innerExceptionTypesToCatch[] = {6, 2, 4}; 1529 size_t numExceptionTypesToCatch = sizeof(innerExceptionTypesToCatch) / 1530 sizeof(unsigned); 1531 1532 // Generate inner function. 1533 llvm::Function* innerCatchFunct = 1534 createCatchWrappedInvokeFunction(module, 1535 builder, 1536 fpm, 1537 *throwFunct, 1538 "innerCatchFunct", 1539 numExceptionTypesToCatch, 1540 innerExceptionTypesToCatch); 1541 1542 // Outer function will catch odd type infos 1543 unsigned outerExceptionTypesToCatch[] = {3, 1, 5}; 1544 numExceptionTypesToCatch = sizeof(outerExceptionTypesToCatch) / 1545 sizeof(unsigned); 1546 1547 // Generate outer function 1548 llvm::Function* outerCatchFunct = 1549 createCatchWrappedInvokeFunction(module, 1550 builder, 1551 fpm, 1552 *innerCatchFunct, 1553 "outerCatchFunct", 1554 numExceptionTypesToCatch, 1555 outerExceptionTypesToCatch); 1556 1557 // Return outer function to run 1558 return(outerCatchFunct); 1559 } 1560 1561 1562 /// Represents our foreign exceptions 1563 class OurCppRunException : public std::runtime_error { 1564 public: 1565 OurCppRunException(const std::string reason) : 1566 std::runtime_error(reason) {} 1567 1568 OurCppRunException (const OurCppRunException& toCopy) : 1569 std::runtime_error(toCopy) {} 1570 1571 OurCppRunException& operator = (const OurCppRunException& toCopy) { 1572 return(reinterpret_cast<OurCppRunException&>( 1573 std::runtime_error::operator = (toCopy) 1574 )); 1575 } 1576 1577 ~OurCppRunException (void) throw () {}; 1578 }; 1579 1580 1581 /// Throws foreign C++ exception. 1582 /// @param ignoreIt unused parameter that allows function to match implied 1583 /// generated function contract. 1584 extern "C" 1585 void throwCppException (int32_t ignoreIt) { 1586 throw(OurCppRunException("thrown by throwCppException(...)")); 1587 } 1588 1589 typedef void (*OurExceptionThrowFunctType) (int32_t typeToThrow); 1590 1591 /// This is a test harness which runs test by executing generated 1592 /// function with a type info type to throw. Harness wraps the excecution 1593 /// of generated function in a C++ try catch clause. 1594 /// @param engine execution engine to use for executing generated function. 1595 /// This demo program expects this to be a JIT instance for demo 1596 /// purposes. 1597 /// @param function generated test function to run 1598 /// @param typeToThrow type info type of generated exception to throw, or 1599 /// indicator to cause foreign exception to be thrown. 1600 static 1601 void runExceptionThrow(llvm::ExecutionEngine* engine, 1602 llvm::Function* function, 1603 int32_t typeToThrow) { 1604 1605 // Find test's function pointer 1606 OurExceptionThrowFunctType functPtr = 1607 reinterpret_cast<OurExceptionThrowFunctType>( 1608 reinterpret_cast<intptr_t>( 1609 engine->getPointerToFunction(function) 1610 ) 1611 ); 1612 1613 try { 1614 // Run test 1615 (*functPtr)(typeToThrow); 1616 } 1617 catch (OurCppRunException exc) { 1618 // Catch foreign C++ exception 1619 fprintf(stderr, 1620 "\nrunExceptionThrow(...):In C++ catch OurCppRunException " 1621 "with reason: %s.\n", 1622 exc.what()); 1623 } 1624 catch (...) { 1625 // Catch all exceptions including our generated ones. I'm not sure 1626 // why this latter functionality should work, as it seems that 1627 // our exceptions should be foreign to C++ (the _Unwind_Exception:: 1628 // exception_class should be different from the one used by C++), and 1629 // therefore C++ should ignore the generated exceptions. 1630 1631 fprintf(stderr, 1632 "\nrunExceptionThrow(...):In C++ catch all.\n"); 1633 } 1634 } 1635 1636 // 1637 // End test functions 1638 // 1639 1640 /// This initialization routine creates type info globals and 1641 /// adds external function declarations to module. 1642 /// @param numTypeInfos number of linear type info associated type info types 1643 /// to create as GlobalVariable instances, starting with the value 1. 1644 /// @param module code for module instance 1645 /// @param builder builder instance 1646 static void createStandardUtilityFunctions(unsigned numTypeInfos, 1647 llvm::Module& module, 1648 llvm::IRBuilder<>& builder) { 1649 1650 llvm::LLVMContext& context = module.getContext(); 1651 1652 // Exception initializations 1653 1654 // Setup exception catch state 1655 ourExceptionNotThrownState = 1656 llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 0), 1657 ourExceptionThrownState = 1658 llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 1), 1659 ourExceptionCaughtState = 1660 llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 2), 1661 1662 1663 // Create our type info type 1664 ourTypeInfoType = llvm::StructType::get(context, 1665 builder.getInt32Ty(), 1666 NULL); 1667 1668 // Create OurException type 1669 ourExceptionType = llvm::StructType::get(context, 1670 ourTypeInfoType, 1671 NULL); 1672 1673 // Create portion of _Unwind_Exception type 1674 // 1675 // Note: Declaring only a portion of the _Unwind_Exception struct. 1676 // Does this cause problems? 1677 ourUnwindExceptionType = llvm::StructType::get(context, 1678 builder.getInt64Ty(), 1679 NULL); 1680 struct OurBaseException_t dummyException; 1681 1682 // Calculate offset of OurException::unwindException member. 1683 ourBaseFromUnwindOffset = ((uintptr_t) &dummyException) - 1684 ((uintptr_t) &(dummyException.unwindException)); 1685 1686 #ifdef DEBUG 1687 fprintf(stderr, 1688 "createStandardUtilityFunctions(...):ourBaseFromUnwindOffset " 1689 "= %lld, sizeof(struct OurBaseException_t) - " 1690 "sizeof(struct _Unwind_Exception) = %lu.\n", 1691 ourBaseFromUnwindOffset, 1692 sizeof(struct OurBaseException_t) - 1693 sizeof(struct _Unwind_Exception)); 1694 #endif 1695 1696 size_t numChars = sizeof(ourBaseExcpClassChars) / sizeof(char); 1697 1698 // Create our _Unwind_Exception::exception_class value 1699 ourBaseExceptionClass = genClass(ourBaseExcpClassChars, numChars); 1700 1701 // Type infos 1702 1703 std::string baseStr = "typeInfo", typeInfoName; 1704 std::ostringstream typeInfoNameBuilder; 1705 std::vector<llvm::Constant*> structVals; 1706 1707 llvm::Constant *nextStruct; 1708 llvm::GlobalVariable* nextGlobal = NULL; 1709 1710 // Generate each type info 1711 // 1712 // Note: First type info is not used. 1713 for (unsigned i = 0; i <= numTypeInfos; ++i) { 1714 structVals.clear(); 1715 structVals.push_back(llvm::ConstantInt::get(builder.getInt32Ty(), i)); 1716 nextStruct = llvm::ConstantStruct::get(ourTypeInfoType, structVals); 1717 1718 typeInfoNameBuilder.str(""); 1719 typeInfoNameBuilder << baseStr << i; 1720 typeInfoName = typeInfoNameBuilder.str(); 1721 1722 // Note: Does not seem to work without allocation 1723 nextGlobal = 1724 new llvm::GlobalVariable(module, 1725 ourTypeInfoType, 1726 true, 1727 llvm::GlobalValue::ExternalLinkage, 1728 nextStruct, 1729 typeInfoName); 1730 1731 ourTypeInfoNames.push_back(typeInfoName); 1732 ourTypeInfoNamesIndex[i] = typeInfoName; 1733 } 1734 1735 ArgNames argNames; 1736 ArgTypes argTypes; 1737 llvm::Function* funct = NULL; 1738 1739 // print32Int 1740 1741 const llvm::Type* retType = builder.getVoidTy(); 1742 1743 argTypes.clear(); 1744 argTypes.push_back(builder.getInt32Ty()); 1745 argTypes.push_back(builder.getInt8Ty()->getPointerTo()); 1746 1747 argNames.clear(); 1748 1749 createFunction(module, 1750 retType, 1751 argTypes, 1752 argNames, 1753 "print32Int", 1754 llvm::Function::ExternalLinkage, 1755 true, 1756 false); 1757 1758 // print64Int 1759 1760 retType = builder.getVoidTy(); 1761 1762 argTypes.clear(); 1763 argTypes.push_back(builder.getInt64Ty()); 1764 argTypes.push_back(builder.getInt8Ty()->getPointerTo()); 1765 1766 argNames.clear(); 1767 1768 createFunction(module, 1769 retType, 1770 argTypes, 1771 argNames, 1772 "print64Int", 1773 llvm::Function::ExternalLinkage, 1774 true, 1775 false); 1776 1777 // printStr 1778 1779 retType = builder.getVoidTy(); 1780 1781 argTypes.clear(); 1782 argTypes.push_back(builder.getInt8Ty()->getPointerTo()); 1783 1784 argNames.clear(); 1785 1786 createFunction(module, 1787 retType, 1788 argTypes, 1789 argNames, 1790 "printStr", 1791 llvm::Function::ExternalLinkage, 1792 true, 1793 false); 1794 1795 // throwCppException 1796 1797 retType = builder.getVoidTy(); 1798 1799 argTypes.clear(); 1800 argTypes.push_back(builder.getInt32Ty()); 1801 1802 argNames.clear(); 1803 1804 createFunction(module, 1805 retType, 1806 argTypes, 1807 argNames, 1808 "throwCppException", 1809 llvm::Function::ExternalLinkage, 1810 true, 1811 false); 1812 1813 // deleteOurException 1814 1815 retType = builder.getVoidTy(); 1816 1817 argTypes.clear(); 1818 argTypes.push_back(builder.getInt8Ty()->getPointerTo()); 1819 1820 argNames.clear(); 1821 1822 createFunction(module, 1823 retType, 1824 argTypes, 1825 argNames, 1826 "deleteOurException", 1827 llvm::Function::ExternalLinkage, 1828 true, 1829 false); 1830 1831 // createOurException 1832 1833 retType = builder.getInt8Ty()->getPointerTo(); 1834 1835 argTypes.clear(); 1836 argTypes.push_back(builder.getInt32Ty()); 1837 1838 argNames.clear(); 1839 1840 createFunction(module, 1841 retType, 1842 argTypes, 1843 argNames, 1844 "createOurException", 1845 llvm::Function::ExternalLinkage, 1846 true, 1847 false); 1848 1849 // _Unwind_RaiseException 1850 1851 retType = builder.getInt32Ty(); 1852 1853 argTypes.clear(); 1854 argTypes.push_back(builder.getInt8Ty()->getPointerTo()); 1855 1856 argNames.clear(); 1857 1858 funct = createFunction(module, 1859 retType, 1860 argTypes, 1861 argNames, 1862 "_Unwind_RaiseException", 1863 llvm::Function::ExternalLinkage, 1864 true, 1865 false); 1866 1867 funct->addFnAttr(llvm::Attribute::NoReturn); 1868 1869 // _Unwind_Resume 1870 1871 retType = builder.getInt32Ty(); 1872 1873 argTypes.clear(); 1874 argTypes.push_back(builder.getInt8Ty()->getPointerTo()); 1875 1876 argNames.clear(); 1877 1878 funct = createFunction(module, 1879 retType, 1880 argTypes, 1881 argNames, 1882 "_Unwind_Resume", 1883 llvm::Function::ExternalLinkage, 1884 true, 1885 false); 1886 1887 funct->addFnAttr(llvm::Attribute::NoReturn); 1888 1889 // ourPersonality 1890 1891 retType = builder.getInt32Ty(); 1892 1893 argTypes.clear(); 1894 argTypes.push_back(builder.getInt32Ty()); 1895 argTypes.push_back(builder.getInt32Ty()); 1896 argTypes.push_back(builder.getInt64Ty()); 1897 argTypes.push_back(builder.getInt8Ty()->getPointerTo()); 1898 argTypes.push_back(builder.getInt8Ty()->getPointerTo()); 1899 1900 argNames.clear(); 1901 1902 createFunction(module, 1903 retType, 1904 argTypes, 1905 argNames, 1906 "ourPersonality", 1907 llvm::Function::ExternalLinkage, 1908 true, 1909 false); 1910 1911 // llvm.eh.selector intrinsic 1912 1913 getDeclaration(&module, llvm::Intrinsic::eh_selector); 1914 1915 // llvm.eh.exception intrinsic 1916 1917 getDeclaration(&module, llvm::Intrinsic::eh_exception); 1918 1919 // llvm.eh.typeid.for intrinsic 1920 1921 getDeclaration(&module, llvm::Intrinsic::eh_typeid_for); 1922 } 1923 1924 1925 //===---------------------------------------------------------------------===// 1926 // Main test driver code. 1927 //===---------------------------------------------------------------------===// 1928 1929 /// Demo main routine which takes the type info types to throw. A test will 1930 /// be run for each given type info type. While type info types with the value 1931 /// of -1 will trigger a foreign C++ exception to be thrown; type info types 1932 /// <= 6 and >= 1 will be caught by test functions; and type info types > 6 1933 /// will result in exceptions which pass through to the test harness. All other 1934 /// type info types are not supported and could cause a crash. 1935 int main(int argc, char* argv[]) { 1936 if (argc == 1) { 1937 fprintf(stderr, 1938 "\nUsage: ExceptionDemo <exception type to throw> " 1939 "[<type 2>...<type n>].\n" 1940 " Each type must have the value of 1 - 6 for " 1941 "generated exceptions to be caught;\n" 1942 " the value -1 for foreign C++ exceptions to be " 1943 "generated and thrown;\n" 1944 " or the values > 6 for exceptions to be ignored.\n" 1945 "\nTry: ExceptionDemo 2 3 7 -1\n" 1946 " for a full test.\n\n"); 1947 return(0); 1948 } 1949 1950 // If not set, exception handling will not be turned on 1951 llvm::JITExceptionHandling = true; 1952 1953 llvm::InitializeNativeTarget(); 1954 llvm::LLVMContext& context = llvm::getGlobalContext(); 1955 llvm::IRBuilder<> theBuilder(context); 1956 1957 // Make the module, which holds all the code. 1958 llvm::Module* module = new llvm::Module("my cool jit", context); 1959 1960 // Build engine with JIT 1961 llvm::EngineBuilder factory(module); 1962 factory.setEngineKind(llvm::EngineKind::JIT); 1963 factory.setAllocateGVsWithCode(false); 1964 llvm::ExecutionEngine* executionEngine = factory.create(); 1965 1966 { 1967 llvm::FunctionPassManager fpm(module); 1968 1969 // Set up the optimizer pipeline. 1970 // Start with registering info about how the 1971 // target lays out data structures. 1972 fpm.add(new llvm::TargetData(*executionEngine->getTargetData())); 1973 1974 // Optimizations turned on 1975 #ifdef ADD_OPT_PASSES 1976 1977 // Promote allocas to registers. 1978 fpm.add(llvm::createPromoteMemoryToRegisterPass()); 1979 1980 // Do simple "peephole" optimizations and bit-twiddling optzns. 1981 fpm.add(llvm::createInstructionCombiningPass()); 1982 1983 // Reassociate expressions. 1984 fpm.add(llvm::createReassociatePass()); 1985 1986 // Eliminate Common SubExpressions. 1987 fpm.add(llvm::createGVNPass()); 1988 1989 // Simplify the control flow graph (deleting unreachable 1990 // blocks, etc). 1991 fpm.add(llvm::createCFGSimplificationPass()); 1992 #endif // ADD_OPT_PASSES 1993 1994 fpm.doInitialization(); 1995 1996 // Generate test code using function throwCppException(...) as 1997 // the function which throws foreign exceptions. 1998 llvm::Function* toRun = 1999 createUnwindExceptionTest(*module, 2000 theBuilder, 2001 fpm, 2002 "throwCppException"); 2003 2004 fprintf(stderr, "\nBegin module dump:\n\n"); 2005 2006 module->dump(); 2007 2008 fprintf(stderr, "\nEnd module dump:\n"); 2009 2010 fprintf(stderr, "\n\nBegin Test:\n"); 2011 2012 for (int i = 1; i < argc; ++i) { 2013 // Run test for each argument whose value is the exception 2014 // type to throw. 2015 runExceptionThrow(executionEngine, 2016 toRun, 2017 (unsigned) strtoul(argv[i], NULL, 10)); 2018 } 2019 2020 fprintf(stderr, "\nEnd Test:\n\n"); 2021 } 2022 2023 delete executionEngine; 2024 2025 return 0; 2026 } 2027 2028