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