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/Analysis/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/Module.h" 60 #include "llvm/PassManager.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::LinkerPrivateLinkage, 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::LinkerPrivateLinkage, 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 1126 llvm::Function *createCatchWrappedInvokeFunction(llvm::Module &module, 1127 llvm::IRBuilder<> &builder, 1128 llvm::FunctionPassManager &fpm, 1129 llvm::Function &toInvoke, 1130 std::string ourId, 1131 unsigned numExceptionsToCatch, 1132 unsigned exceptionTypesToCatch[]) { 1133 1134 llvm::LLVMContext &context = module.getContext(); 1135 llvm::Function *toPrint32Int = module.getFunction("print32Int"); 1136 1137 ArgTypes argTypes; 1138 argTypes.push_back(builder.getInt32Ty()); 1139 1140 ArgNames argNames; 1141 argNames.push_back("exceptTypeToThrow"); 1142 1143 llvm::Function *ret = createFunction(module, 1144 builder.getVoidTy(), 1145 argTypes, 1146 argNames, 1147 ourId, 1148 llvm::Function::ExternalLinkage, 1149 false, 1150 false); 1151 1152 // Block which calls invoke 1153 llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(context, 1154 "entry", 1155 ret); 1156 // Normal block for invoke 1157 llvm::BasicBlock *normalBlock = llvm::BasicBlock::Create(context, 1158 "normal", 1159 ret); 1160 // Unwind block for invoke 1161 llvm::BasicBlock *exceptionBlock = llvm::BasicBlock::Create(context, 1162 "exception", 1163 ret); 1164 1165 // Block which routes exception to correct catch handler block 1166 llvm::BasicBlock *exceptionRouteBlock = llvm::BasicBlock::Create(context, 1167 "exceptionRoute", 1168 ret); 1169 1170 // Foreign exception handler 1171 llvm::BasicBlock *externalExceptionBlock = llvm::BasicBlock::Create(context, 1172 "externalException", 1173 ret); 1174 1175 // Block which calls _Unwind_Resume 1176 llvm::BasicBlock *unwindResumeBlock = llvm::BasicBlock::Create(context, 1177 "unwindResume", 1178 ret); 1179 1180 // Clean up block which delete exception if needed 1181 llvm::BasicBlock *endBlock = llvm::BasicBlock::Create(context, "end", ret); 1182 1183 std::string nextName; 1184 std::vector<llvm::BasicBlock*> catchBlocks(numExceptionsToCatch); 1185 llvm::Value *exceptionCaughtFlag = NULL; 1186 llvm::Value *exceptionStorage = NULL; 1187 llvm::Value *caughtResultStorage = NULL; 1188 1189 // Finally block which will branch to unwindResumeBlock if 1190 // exception is not caught. Initializes/allocates stack locations. 1191 llvm::BasicBlock *finallyBlock = createFinallyBlock(context, 1192 module, 1193 builder, 1194 *ret, 1195 nextName = "finally", 1196 ourId, 1197 *endBlock, 1198 *unwindResumeBlock, 1199 &exceptionCaughtFlag, 1200 &exceptionStorage, 1201 &caughtResultStorage 1202 ); 1203 1204 for (unsigned i = 0; i < numExceptionsToCatch; ++i) { 1205 nextName = ourTypeInfoNames[exceptionTypesToCatch[i]]; 1206 1207 // One catch block per type info to be caught 1208 catchBlocks[i] = createCatchBlock(context, 1209 module, 1210 builder, 1211 *ret, 1212 nextName, 1213 ourId, 1214 *finallyBlock, 1215 *exceptionCaughtFlag); 1216 } 1217 1218 // Entry Block 1219 1220 builder.SetInsertPoint(entryBlock); 1221 1222 std::vector<llvm::Value*> args; 1223 args.push_back(namedValues["exceptTypeToThrow"]); 1224 builder.CreateInvoke(&toInvoke, 1225 normalBlock, 1226 exceptionBlock, 1227 args); 1228 1229 // End Block 1230 1231 builder.SetInsertPoint(endBlock); 1232 1233 generateStringPrint(context, 1234 module, 1235 builder, 1236 "Gen: In end block: exiting in " + ourId + ".\n", 1237 USE_GLOBAL_STR_CONSTS); 1238 llvm::Function *deleteOurException = module.getFunction("deleteOurException"); 1239 1240 // Note: function handles NULL exceptions 1241 builder.CreateCall(deleteOurException, 1242 builder.CreateLoad(exceptionStorage)); 1243 builder.CreateRetVoid(); 1244 1245 // Normal Block 1246 1247 builder.SetInsertPoint(normalBlock); 1248 1249 generateStringPrint(context, 1250 module, 1251 builder, 1252 "Gen: No exception in " + ourId + "!\n", 1253 USE_GLOBAL_STR_CONSTS); 1254 1255 // Finally block is always called 1256 builder.CreateBr(finallyBlock); 1257 1258 // Unwind Resume Block 1259 1260 builder.SetInsertPoint(unwindResumeBlock); 1261 1262 builder.CreateResume(builder.CreateLoad(caughtResultStorage)); 1263 1264 // Exception Block 1265 1266 builder.SetInsertPoint(exceptionBlock); 1267 1268 llvm::Function *personality = module.getFunction("ourPersonality"); 1269 1270 llvm::LandingPadInst *caughtResult = 1271 builder.CreateLandingPad(ourCaughtResultType, 1272 personality, 1273 numExceptionsToCatch, 1274 "landingPad"); 1275 1276 caughtResult->setCleanup(true); 1277 1278 for (unsigned i = 0; i < numExceptionsToCatch; ++i) { 1279 // Set up type infos to be caught 1280 caughtResult->addClause(module.getGlobalVariable( 1281 ourTypeInfoNames[exceptionTypesToCatch[i]])); 1282 } 1283 1284 llvm::Value *unwindException = builder.CreateExtractValue(caughtResult, 0); 1285 llvm::Value *retTypeInfoIndex = builder.CreateExtractValue(caughtResult, 1); 1286 1287 // FIXME: Redundant storage which, beyond utilizing value of 1288 // caughtResultStore for unwindException storage, may be alleviated 1289 // altogether with a block rearrangement 1290 builder.CreateStore(caughtResult, caughtResultStorage); 1291 builder.CreateStore(unwindException, exceptionStorage); 1292 builder.CreateStore(ourExceptionThrownState, exceptionCaughtFlag); 1293 1294 // Retrieve exception_class member from thrown exception 1295 // (_Unwind_Exception instance). This member tells us whether or not 1296 // the exception is foreign. 1297 llvm::Value *unwindExceptionClass = 1298 builder.CreateLoad(builder.CreateStructGEP( 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(typeInfoThrown, 0); 1342 1343 llvm::Value *typeInfoThrownType = 1344 builder.CreateStructGEP(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 1393 llvm::Function *createThrowExceptionFunction(llvm::Module &module, 1394 llvm::IRBuilder<> &builder, 1395 llvm::FunctionPassManager &fpm, 1396 std::string ourId, 1397 int32_t nativeThrowType, 1398 llvm::Function &nativeThrowFunct) { 1399 llvm::LLVMContext &context = module.getContext(); 1400 namedValues.clear(); 1401 ArgTypes unwindArgTypes; 1402 unwindArgTypes.push_back(builder.getInt32Ty()); 1403 ArgNames unwindArgNames; 1404 unwindArgNames.push_back("exceptTypeToThrow"); 1405 1406 llvm::Function *ret = createFunction(module, 1407 builder.getVoidTy(), 1408 unwindArgTypes, 1409 unwindArgNames, 1410 ourId, 1411 llvm::Function::ExternalLinkage, 1412 false, 1413 false); 1414 1415 // Throws either one of our exception or a native C++ exception depending 1416 // on a runtime argument value containing a type info type. 1417 llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(context, 1418 "entry", 1419 ret); 1420 // Throws a foreign exception 1421 llvm::BasicBlock *nativeThrowBlock = llvm::BasicBlock::Create(context, 1422 "nativeThrow", 1423 ret); 1424 // Throws one of our Exceptions 1425 llvm::BasicBlock *generatedThrowBlock = llvm::BasicBlock::Create(context, 1426 "generatedThrow", 1427 ret); 1428 // Retrieved runtime type info type to throw 1429 llvm::Value *exceptionType = namedValues["exceptTypeToThrow"]; 1430 1431 // nativeThrowBlock block 1432 1433 builder.SetInsertPoint(nativeThrowBlock); 1434 1435 // Throws foreign exception 1436 builder.CreateCall(&nativeThrowFunct, exceptionType); 1437 builder.CreateUnreachable(); 1438 1439 // entry block 1440 1441 builder.SetInsertPoint(entryBlock); 1442 1443 llvm::Function *toPrint32Int = module.getFunction("print32Int"); 1444 generateIntegerPrint(context, 1445 module, 1446 builder, 1447 *toPrint32Int, 1448 *exceptionType, 1449 "\nGen: About to throw exception type <%d> in " + 1450 ourId + 1451 ".\n", 1452 USE_GLOBAL_STR_CONSTS); 1453 1454 // Switches on runtime type info type value to determine whether or not 1455 // a foreign exception is thrown. Defaults to throwing one of our 1456 // generated exceptions. 1457 llvm::SwitchInst *theSwitch = builder.CreateSwitch(exceptionType, 1458 generatedThrowBlock, 1459 1); 1460 1461 theSwitch->addCase(llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), 1462 nativeThrowType), 1463 nativeThrowBlock); 1464 1465 // generatedThrow block 1466 1467 builder.SetInsertPoint(generatedThrowBlock); 1468 1469 llvm::Function *createOurException = module.getFunction("createOurException"); 1470 llvm::Function *raiseOurException = module.getFunction( 1471 "_Unwind_RaiseException"); 1472 1473 // Creates exception to throw with runtime type info type. 1474 llvm::Value *exception = builder.CreateCall(createOurException, 1475 namedValues["exceptTypeToThrow"]); 1476 1477 // Throw generated Exception 1478 builder.CreateCall(raiseOurException, exception); 1479 builder.CreateUnreachable(); 1480 1481 llvm::verifyFunction(*ret); 1482 fpm.run(*ret); 1483 1484 return(ret); 1485 } 1486 1487 static void createStandardUtilityFunctions(unsigned numTypeInfos, 1488 llvm::Module &module, 1489 llvm::IRBuilder<> &builder); 1490 1491 /// Creates test code by generating and organizing these functions into the 1492 /// test case. The test case consists of an outer function setup to invoke 1493 /// an inner function within an environment having multiple catch and single 1494 /// finally blocks. This inner function is also setup to invoke a throw 1495 /// function within an evironment similar in nature to the outer function's 1496 /// catch and finally blocks. Each of these two functions catch mutually 1497 /// exclusive subsets (even or odd) of the type info types configured 1498 /// for this this. All generated functions have a runtime argument which 1499 /// holds a type info type to throw that each function takes and passes it 1500 /// to the inner one if such a inner function exists. This type info type is 1501 /// looked at by the generated throw function to see whether or not it should 1502 /// throw a generated exception with the same type info type, or instead call 1503 /// a supplied a function which in turn will throw a foreign exception. 1504 /// @param module code for module instance 1505 /// @param builder builder instance 1506 /// @param fpm a function pass manager holding optional IR to IR 1507 /// transformations 1508 /// @param nativeThrowFunctName name of external function which will throw 1509 /// a foreign exception 1510 /// @returns outermost generated test function. 1511 llvm::Function *createUnwindExceptionTest(llvm::Module &module, 1512 llvm::IRBuilder<> &builder, 1513 llvm::FunctionPassManager &fpm, 1514 std::string nativeThrowFunctName) { 1515 // Number of type infos to generate 1516 unsigned numTypeInfos = 6; 1517 1518 // Initialze intrisics and external functions to use along with exception 1519 // and type info globals. 1520 createStandardUtilityFunctions(numTypeInfos, 1521 module, 1522 builder); 1523 llvm::Function *nativeThrowFunct = module.getFunction(nativeThrowFunctName); 1524 1525 // Create exception throw function using the value ~0 to cause 1526 // foreign exceptions to be thrown. 1527 llvm::Function *throwFunct = createThrowExceptionFunction(module, 1528 builder, 1529 fpm, 1530 "throwFunct", 1531 ~0, 1532 *nativeThrowFunct); 1533 // Inner function will catch even type infos 1534 unsigned innerExceptionTypesToCatch[] = {6, 2, 4}; 1535 size_t numExceptionTypesToCatch = sizeof(innerExceptionTypesToCatch) / 1536 sizeof(unsigned); 1537 1538 // Generate inner function. 1539 llvm::Function *innerCatchFunct = createCatchWrappedInvokeFunction(module, 1540 builder, 1541 fpm, 1542 *throwFunct, 1543 "innerCatchFunct", 1544 numExceptionTypesToCatch, 1545 innerExceptionTypesToCatch); 1546 1547 // Outer function will catch odd type infos 1548 unsigned outerExceptionTypesToCatch[] = {3, 1, 5}; 1549 numExceptionTypesToCatch = sizeof(outerExceptionTypesToCatch) / 1550 sizeof(unsigned); 1551 1552 // Generate outer function 1553 llvm::Function *outerCatchFunct = createCatchWrappedInvokeFunction(module, 1554 builder, 1555 fpm, 1556 *innerCatchFunct, 1557 "outerCatchFunct", 1558 numExceptionTypesToCatch, 1559 outerExceptionTypesToCatch); 1560 1561 // Return outer function to run 1562 return(outerCatchFunct); 1563 } 1564 1565 1566 /// Represents our foreign exceptions 1567 class OurCppRunException : public std::runtime_error { 1568 public: 1569 OurCppRunException(const std::string reason) : 1570 std::runtime_error(reason) {} 1571 1572 OurCppRunException (const OurCppRunException &toCopy) : 1573 std::runtime_error(toCopy) {} 1574 1575 OurCppRunException &operator = (const OurCppRunException &toCopy) { 1576 return(reinterpret_cast<OurCppRunException&>( 1577 std::runtime_error::operator=(toCopy))); 1578 } 1579 1580 ~OurCppRunException (void) throw () {} 1581 }; 1582 1583 1584 /// Throws foreign C++ exception. 1585 /// @param ignoreIt unused parameter that allows function to match implied 1586 /// generated function contract. 1587 extern "C" 1588 void throwCppException (int32_t ignoreIt) { 1589 throw(OurCppRunException("thrown by throwCppException(...)")); 1590 } 1591 1592 typedef void (*OurExceptionThrowFunctType) (int32_t typeToThrow); 1593 1594 /// This is a test harness which runs test by executing generated 1595 /// function with a type info type to throw. Harness wraps the execution 1596 /// of generated function in a C++ try catch clause. 1597 /// @param engine execution engine to use for executing generated function. 1598 /// This demo program expects this to be a JIT instance for demo 1599 /// purposes. 1600 /// @param function generated test function to run 1601 /// @param typeToThrow type info type of generated exception to throw, or 1602 /// indicator to cause foreign exception to be thrown. 1603 static 1604 void runExceptionThrow(llvm::ExecutionEngine *engine, 1605 llvm::Function *function, 1606 int32_t typeToThrow) { 1607 1608 // Find test's function pointer 1609 OurExceptionThrowFunctType functPtr = 1610 reinterpret_cast<OurExceptionThrowFunctType>( 1611 reinterpret_cast<intptr_t>(engine->getPointerToFunction(function))); 1612 1613 try { 1614 // Run test 1615 (*functPtr)(typeToThrow); 1616 } 1617 catch (OurCppRunException exc) { 1618 // Catch foreign C++ exception 1619 fprintf(stderr, 1620 "\nrunExceptionThrow(...):In C++ catch OurCppRunException " 1621 "with reason: %s.\n", 1622 exc.what()); 1623 } 1624 catch (...) { 1625 // Catch all exceptions including our generated ones. This latter 1626 // functionality works according to the example in rules 1.6.4 of 1627 // http://mentorembedded.github.com/cxx-abi/abi-eh.html (v1.22), 1628 // given that these will be exceptions foreign to C++ 1629 // (the _Unwind_Exception::exception_class should be different from 1630 // the one used by C++). 1631 fprintf(stderr, 1632 "\nrunExceptionThrow(...):In C++ catch all.\n"); 1633 } 1634 } 1635 1636 // 1637 // End test functions 1638 // 1639 1640 typedef llvm::ArrayRef<llvm::Type*> TypeArray; 1641 1642 /// This initialization routine creates type info globals and 1643 /// adds external function declarations to module. 1644 /// @param numTypeInfos number of linear type info associated type info types 1645 /// to create as GlobalVariable instances, starting with the value 1. 1646 /// @param module code for module instance 1647 /// @param builder builder instance 1648 static void createStandardUtilityFunctions(unsigned numTypeInfos, 1649 llvm::Module &module, 1650 llvm::IRBuilder<> &builder) { 1651 1652 llvm::LLVMContext &context = module.getContext(); 1653 1654 // Exception initializations 1655 1656 // Setup exception catch state 1657 ourExceptionNotThrownState = 1658 llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 0), 1659 ourExceptionThrownState = 1660 llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 1), 1661 ourExceptionCaughtState = 1662 llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 2), 1663 1664 1665 1666 // Create our type info type 1667 ourTypeInfoType = llvm::StructType::get(context, 1668 TypeArray(builder.getInt32Ty())); 1669 1670 llvm::Type *caughtResultFieldTypes[] = { 1671 builder.getInt8PtrTy(), 1672 builder.getInt32Ty() 1673 }; 1674 1675 // Create our landingpad result type 1676 ourCaughtResultType = llvm::StructType::get(context, 1677 TypeArray(caughtResultFieldTypes)); 1678 1679 // Create OurException type 1680 ourExceptionType = llvm::StructType::get(context, 1681 TypeArray(ourTypeInfoType)); 1682 1683 // Create portion of _Unwind_Exception type 1684 // 1685 // Note: Declaring only a portion of the _Unwind_Exception struct. 1686 // Does this cause problems? 1687 ourUnwindExceptionType = 1688 llvm::StructType::get(context, 1689 TypeArray(builder.getInt64Ty())); 1690 1691 struct OurBaseException_t dummyException; 1692 1693 // Calculate offset of OurException::unwindException member. 1694 ourBaseFromUnwindOffset = ((uintptr_t) &dummyException) - 1695 ((uintptr_t) &(dummyException.unwindException)); 1696 1697 #ifdef DEBUG 1698 fprintf(stderr, 1699 "createStandardUtilityFunctions(...):ourBaseFromUnwindOffset " 1700 "= %lld, sizeof(struct OurBaseException_t) - " 1701 "sizeof(struct _Unwind_Exception) = %lu.\n", 1702 ourBaseFromUnwindOffset, 1703 sizeof(struct OurBaseException_t) - 1704 sizeof(struct _Unwind_Exception)); 1705 #endif 1706 1707 size_t numChars = sizeof(ourBaseExcpClassChars) / sizeof(char); 1708 1709 // Create our _Unwind_Exception::exception_class value 1710 ourBaseExceptionClass = genClass(ourBaseExcpClassChars, numChars); 1711 1712 // Type infos 1713 1714 std::string baseStr = "typeInfo", typeInfoName; 1715 std::ostringstream typeInfoNameBuilder; 1716 std::vector<llvm::Constant*> structVals; 1717 1718 llvm::Constant *nextStruct; 1719 1720 // Generate each type info 1721 // 1722 // Note: First type info is not used. 1723 for (unsigned i = 0; i <= numTypeInfos; ++i) { 1724 structVals.clear(); 1725 structVals.push_back(llvm::ConstantInt::get(builder.getInt32Ty(), i)); 1726 nextStruct = llvm::ConstantStruct::get(ourTypeInfoType, structVals); 1727 1728 typeInfoNameBuilder.str(""); 1729 typeInfoNameBuilder << baseStr << i; 1730 typeInfoName = typeInfoNameBuilder.str(); 1731 1732 // Note: Does not seem to work without allocation 1733 new llvm::GlobalVariable(module, 1734 ourTypeInfoType, 1735 true, 1736 llvm::GlobalValue::ExternalLinkage, 1737 nextStruct, 1738 typeInfoName); 1739 1740 ourTypeInfoNames.push_back(typeInfoName); 1741 ourTypeInfoNamesIndex[i] = typeInfoName; 1742 } 1743 1744 ArgNames argNames; 1745 ArgTypes argTypes; 1746 llvm::Function *funct = NULL; 1747 1748 // print32Int 1749 1750 llvm::Type *retType = builder.getVoidTy(); 1751 1752 argTypes.clear(); 1753 argTypes.push_back(builder.getInt32Ty()); 1754 argTypes.push_back(builder.getInt8PtrTy()); 1755 1756 argNames.clear(); 1757 1758 createFunction(module, 1759 retType, 1760 argTypes, 1761 argNames, 1762 "print32Int", 1763 llvm::Function::ExternalLinkage, 1764 true, 1765 false); 1766 1767 // print64Int 1768 1769 retType = builder.getVoidTy(); 1770 1771 argTypes.clear(); 1772 argTypes.push_back(builder.getInt64Ty()); 1773 argTypes.push_back(builder.getInt8PtrTy()); 1774 1775 argNames.clear(); 1776 1777 createFunction(module, 1778 retType, 1779 argTypes, 1780 argNames, 1781 "print64Int", 1782 llvm::Function::ExternalLinkage, 1783 true, 1784 false); 1785 1786 // printStr 1787 1788 retType = builder.getVoidTy(); 1789 1790 argTypes.clear(); 1791 argTypes.push_back(builder.getInt8PtrTy()); 1792 1793 argNames.clear(); 1794 1795 createFunction(module, 1796 retType, 1797 argTypes, 1798 argNames, 1799 "printStr", 1800 llvm::Function::ExternalLinkage, 1801 true, 1802 false); 1803 1804 // throwCppException 1805 1806 retType = builder.getVoidTy(); 1807 1808 argTypes.clear(); 1809 argTypes.push_back(builder.getInt32Ty()); 1810 1811 argNames.clear(); 1812 1813 createFunction(module, 1814 retType, 1815 argTypes, 1816 argNames, 1817 "throwCppException", 1818 llvm::Function::ExternalLinkage, 1819 true, 1820 false); 1821 1822 // deleteOurException 1823 1824 retType = builder.getVoidTy(); 1825 1826 argTypes.clear(); 1827 argTypes.push_back(builder.getInt8PtrTy()); 1828 1829 argNames.clear(); 1830 1831 createFunction(module, 1832 retType, 1833 argTypes, 1834 argNames, 1835 "deleteOurException", 1836 llvm::Function::ExternalLinkage, 1837 true, 1838 false); 1839 1840 // createOurException 1841 1842 retType = builder.getInt8PtrTy(); 1843 1844 argTypes.clear(); 1845 argTypes.push_back(builder.getInt32Ty()); 1846 1847 argNames.clear(); 1848 1849 createFunction(module, 1850 retType, 1851 argTypes, 1852 argNames, 1853 "createOurException", 1854 llvm::Function::ExternalLinkage, 1855 true, 1856 false); 1857 1858 // _Unwind_RaiseException 1859 1860 retType = builder.getInt32Ty(); 1861 1862 argTypes.clear(); 1863 argTypes.push_back(builder.getInt8PtrTy()); 1864 1865 argNames.clear(); 1866 1867 funct = createFunction(module, 1868 retType, 1869 argTypes, 1870 argNames, 1871 "_Unwind_RaiseException", 1872 llvm::Function::ExternalLinkage, 1873 true, 1874 false); 1875 1876 funct->setDoesNotReturn(); 1877 1878 // _Unwind_Resume 1879 1880 retType = builder.getInt32Ty(); 1881 1882 argTypes.clear(); 1883 argTypes.push_back(builder.getInt8PtrTy()); 1884 1885 argNames.clear(); 1886 1887 funct = createFunction(module, 1888 retType, 1889 argTypes, 1890 argNames, 1891 "_Unwind_Resume", 1892 llvm::Function::ExternalLinkage, 1893 true, 1894 false); 1895 1896 funct->setDoesNotReturn(); 1897 1898 // ourPersonality 1899 1900 retType = builder.getInt32Ty(); 1901 1902 argTypes.clear(); 1903 argTypes.push_back(builder.getInt32Ty()); 1904 argTypes.push_back(builder.getInt32Ty()); 1905 argTypes.push_back(builder.getInt64Ty()); 1906 argTypes.push_back(builder.getInt8PtrTy()); 1907 argTypes.push_back(builder.getInt8PtrTy()); 1908 1909 argNames.clear(); 1910 1911 createFunction(module, 1912 retType, 1913 argTypes, 1914 argNames, 1915 "ourPersonality", 1916 llvm::Function::ExternalLinkage, 1917 true, 1918 false); 1919 1920 // llvm.eh.typeid.for intrinsic 1921 1922 getDeclaration(&module, llvm::Intrinsic::eh_typeid_for); 1923 } 1924 1925 1926 //===----------------------------------------------------------------------===// 1927 // Main test driver code. 1928 //===----------------------------------------------------------------------===// 1929 1930 /// Demo main routine which takes the type info types to throw. A test will 1931 /// be run for each given type info type. While type info types with the value 1932 /// of -1 will trigger a foreign C++ exception to be thrown; type info types 1933 /// <= 6 and >= 1 will be caught by test functions; and type info types > 6 1934 /// will result in exceptions which pass through to the test harness. All other 1935 /// type info types are not supported and could cause a crash. 1936 int main(int argc, char *argv[]) { 1937 if (argc == 1) { 1938 fprintf(stderr, 1939 "\nUsage: ExceptionDemo <exception type to throw> " 1940 "[<type 2>...<type n>].\n" 1941 " Each type must have the value of 1 - 6 for " 1942 "generated exceptions to be caught;\n" 1943 " the value -1 for foreign C++ exceptions to be " 1944 "generated and thrown;\n" 1945 " or the values > 6 for exceptions to be ignored.\n" 1946 "\nTry: ExceptionDemo 2 3 7 -1\n" 1947 " for a full test.\n\n"); 1948 return(0); 1949 } 1950 1951 // If not set, exception handling will not be turned on 1952 llvm::TargetOptions Opts; 1953 1954 llvm::InitializeNativeTarget(); 1955 llvm::InitializeNativeTargetAsmPrinter(); 1956 llvm::LLVMContext &context = llvm::getGlobalContext(); 1957 llvm::IRBuilder<> theBuilder(context); 1958 1959 // Make the module, which holds all the code. 1960 llvm::Module *module = new llvm::Module("my cool jit", context); 1961 1962 llvm::RTDyldMemoryManager *MemMgr = new llvm::SectionMemoryManager(); 1963 1964 // Build engine with JIT 1965 llvm::EngineBuilder factory(module); 1966 factory.setEngineKind(llvm::EngineKind::JIT); 1967 factory.setAllocateGVsWithCode(false); 1968 factory.setTargetOptions(Opts); 1969 factory.setMCJITMemoryManager(MemMgr); 1970 factory.setUseMCJIT(true); 1971 llvm::ExecutionEngine *executionEngine = factory.create(); 1972 1973 { 1974 llvm::FunctionPassManager fpm(module); 1975 1976 // Set up the optimizer pipeline. 1977 // Start with registering info about how the 1978 // target lays out data structures. 1979 fpm.add(new llvm::DataLayout(*executionEngine->getDataLayout())); 1980 1981 // Optimizations turned on 1982 #ifdef ADD_OPT_PASSES 1983 1984 // Basic AliasAnslysis support for GVN. 1985 fpm.add(llvm::createBasicAliasAnalysisPass()); 1986 1987 // Promote allocas to registers. 1988 fpm.add(llvm::createPromoteMemoryToRegisterPass()); 1989 1990 // Do simple "peephole" optimizations and bit-twiddling optzns. 1991 fpm.add(llvm::createInstructionCombiningPass()); 1992 1993 // Reassociate expressions. 1994 fpm.add(llvm::createReassociatePass()); 1995 1996 // Eliminate Common SubExpressions. 1997 fpm.add(llvm::createGVNPass()); 1998 1999 // Simplify the control flow graph (deleting unreachable 2000 // blocks, etc). 2001 fpm.add(llvm::createCFGSimplificationPass()); 2002 #endif // ADD_OPT_PASSES 2003 2004 fpm.doInitialization(); 2005 2006 // Generate test code using function throwCppException(...) as 2007 // the function which throws foreign exceptions. 2008 llvm::Function *toRun = 2009 createUnwindExceptionTest(*module, 2010 theBuilder, 2011 fpm, 2012 "throwCppException"); 2013 2014 executionEngine->finalizeObject(); 2015 2016 fprintf(stderr, "\nBegin module dump:\n\n"); 2017 2018 module->dump(); 2019 2020 fprintf(stderr, "\nEnd module dump:\n"); 2021 2022 fprintf(stderr, "\n\nBegin Test:\n"); 2023 2024 for (int i = 1; i < argc; ++i) { 2025 // Run test for each argument whose value is the exception 2026 // type to throw. 2027 runExceptionThrow(executionEngine, 2028 toRun, 2029 (unsigned) strtoul(argv[i], NULL, 10)); 2030 } 2031 2032 fprintf(stderr, "\nEnd Test:\n\n"); 2033 } 2034 2035 delete executionEngine; 2036 2037 return 0; 2038 } 2039