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