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