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