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