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