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