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