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