ExceptionDemo.cpp revision 5a364c5561ec04e33a6f5d52c14f1bac6f247ea0
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 87extern "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 143struct 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 155struct 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++ 164typedef struct OurBaseException_t OurException; 165typedef struct _Unwind_Exception OurUnwindException; 166 167// 168// Various globals used to support typeinfo and generatted exceptions in 169// general 170// 171 172static std::map<std::string, llvm::Value*> namedValues; 173 174int64_t ourBaseFromUnwindOffset; 175 176const unsigned char ourBaseExcpClassChars[] = 177{'o', 'b', 'j', '\0', 'b', 'a', 's', '\0'}; 178 179 180static uint64_t ourBaseExceptionClass = 0; 181 182static std::vector<std::string> ourTypeInfoNames; 183static std::map<int, std::string> ourTypeInfoNamesIndex; 184 185static llvm::StructType *ourTypeInfoType; 186static llvm::StructType *ourCaughtResultType; 187static llvm::StructType *ourExceptionType; 188static llvm::StructType *ourUnwindExceptionType; 189 190static llvm::ConstantInt *ourExceptionNotThrownState; 191static llvm::ConstantInt *ourExceptionThrownState; 192static llvm::ConstantInt *ourExceptionCaughtState; 193 194typedef std::vector<std::string> ArgNames; 195typedef 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 213llvm::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 249static 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 273extern "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 280void 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 297void 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 311void 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 325void 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 345void 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 359OurUnwindException *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 375static 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 399static 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 421unsigned 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 452static 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 549static 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 643static _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 870uint64_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. 901void 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. 945void 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 997static 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 1073static 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 1125static 1126llvm::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 1392static 1393llvm::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 1487static 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. 1511llvm::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 1567class OurCppRunException : public std::runtime_error { 1568public: 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 1583OurCppRunException::~OurCppRunException() throw () {} 1584 1585 1586/// Throws foreign C++ exception. 1587/// @param ignoreIt unused parameter that allows function to match implied 1588/// generated function contract. 1589extern "C" 1590void throwCppException (int32_t ignoreIt) { 1591 throw(OurCppRunException("thrown by throwCppException(...)")); 1592} 1593 1594typedef void (*OurExceptionThrowFunctType) (int32_t typeToThrow); 1595 1596/// This is a test harness which runs test by executing generated 1597/// function with a type info type to throw. Harness wraps the execution 1598/// of generated function in a C++ try catch clause. 1599/// @param engine execution engine to use for executing generated function. 1600/// This demo program expects this to be a JIT instance for demo 1601/// purposes. 1602/// @param function generated test function to run 1603/// @param typeToThrow type info type of generated exception to throw, or 1604/// indicator to cause foreign exception to be thrown. 1605static 1606void runExceptionThrow(llvm::ExecutionEngine *engine, 1607 llvm::Function *function, 1608 int32_t typeToThrow) { 1609 1610 // Find test's function pointer 1611 OurExceptionThrowFunctType functPtr = 1612 reinterpret_cast<OurExceptionThrowFunctType>( 1613 reinterpret_cast<intptr_t>(engine->getPointerToFunction(function))); 1614 1615 try { 1616 // Run test 1617 (*functPtr)(typeToThrow); 1618 } 1619 catch (OurCppRunException exc) { 1620 // Catch foreign C++ exception 1621 fprintf(stderr, 1622 "\nrunExceptionThrow(...):In C++ catch OurCppRunException " 1623 "with reason: %s.\n", 1624 exc.what()); 1625 } 1626 catch (...) { 1627 // Catch all exceptions including our generated ones. This latter 1628 // functionality works according to the example in rules 1.6.4 of 1629 // http://mentorembedded.github.com/cxx-abi/abi-eh.html (v1.22), 1630 // given that these will be exceptions foreign to C++ 1631 // (the _Unwind_Exception::exception_class should be different from 1632 // the one used by C++). 1633 fprintf(stderr, 1634 "\nrunExceptionThrow(...):In C++ catch all.\n"); 1635 } 1636} 1637 1638// 1639// End test functions 1640// 1641 1642typedef llvm::ArrayRef<llvm::Type*> TypeArray; 1643 1644/// This initialization routine creates type info globals and 1645/// adds external function declarations to module. 1646/// @param numTypeInfos number of linear type info associated type info types 1647/// to create as GlobalVariable instances, starting with the value 1. 1648/// @param module code for module instance 1649/// @param builder builder instance 1650static void createStandardUtilityFunctions(unsigned numTypeInfos, 1651 llvm::Module &module, 1652 llvm::IRBuilder<> &builder) { 1653 1654 llvm::LLVMContext &context = module.getContext(); 1655 1656 // Exception initializations 1657 1658 // Setup exception catch state 1659 ourExceptionNotThrownState = 1660 llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 0), 1661 ourExceptionThrownState = 1662 llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 1), 1663 ourExceptionCaughtState = 1664 llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 2), 1665 1666 1667 1668 // Create our type info type 1669 ourTypeInfoType = llvm::StructType::get(context, 1670 TypeArray(builder.getInt32Ty())); 1671 1672 llvm::Type *caughtResultFieldTypes[] = { 1673 builder.getInt8PtrTy(), 1674 builder.getInt32Ty() 1675 }; 1676 1677 // Create our landingpad result type 1678 ourCaughtResultType = llvm::StructType::get(context, 1679 TypeArray(caughtResultFieldTypes)); 1680 1681 // Create OurException type 1682 ourExceptionType = llvm::StructType::get(context, 1683 TypeArray(ourTypeInfoType)); 1684 1685 // Create portion of _Unwind_Exception type 1686 // 1687 // Note: Declaring only a portion of the _Unwind_Exception struct. 1688 // Does this cause problems? 1689 ourUnwindExceptionType = 1690 llvm::StructType::get(context, 1691 TypeArray(builder.getInt64Ty())); 1692 1693 struct OurBaseException_t dummyException; 1694 1695 // Calculate offset of OurException::unwindException member. 1696 ourBaseFromUnwindOffset = ((uintptr_t) &dummyException) - 1697 ((uintptr_t) &(dummyException.unwindException)); 1698 1699#ifdef DEBUG 1700 fprintf(stderr, 1701 "createStandardUtilityFunctions(...):ourBaseFromUnwindOffset " 1702 "= %lld, sizeof(struct OurBaseException_t) - " 1703 "sizeof(struct _Unwind_Exception) = %lu.\n", 1704 ourBaseFromUnwindOffset, 1705 sizeof(struct OurBaseException_t) - 1706 sizeof(struct _Unwind_Exception)); 1707#endif 1708 1709 size_t numChars = sizeof(ourBaseExcpClassChars) / sizeof(char); 1710 1711 // Create our _Unwind_Exception::exception_class value 1712 ourBaseExceptionClass = genClass(ourBaseExcpClassChars, numChars); 1713 1714 // Type infos 1715 1716 std::string baseStr = "typeInfo", typeInfoName; 1717 std::ostringstream typeInfoNameBuilder; 1718 std::vector<llvm::Constant*> structVals; 1719 1720 llvm::Constant *nextStruct; 1721 1722 // Generate each type info 1723 // 1724 // Note: First type info is not used. 1725 for (unsigned i = 0; i <= numTypeInfos; ++i) { 1726 structVals.clear(); 1727 structVals.push_back(llvm::ConstantInt::get(builder.getInt32Ty(), i)); 1728 nextStruct = llvm::ConstantStruct::get(ourTypeInfoType, structVals); 1729 1730 typeInfoNameBuilder.str(""); 1731 typeInfoNameBuilder << baseStr << i; 1732 typeInfoName = typeInfoNameBuilder.str(); 1733 1734 // Note: Does not seem to work without allocation 1735 new llvm::GlobalVariable(module, 1736 ourTypeInfoType, 1737 true, 1738 llvm::GlobalValue::ExternalLinkage, 1739 nextStruct, 1740 typeInfoName); 1741 1742 ourTypeInfoNames.push_back(typeInfoName); 1743 ourTypeInfoNamesIndex[i] = typeInfoName; 1744 } 1745 1746 ArgNames argNames; 1747 ArgTypes argTypes; 1748 llvm::Function *funct = NULL; 1749 1750 // print32Int 1751 1752 llvm::Type *retType = builder.getVoidTy(); 1753 1754 argTypes.clear(); 1755 argTypes.push_back(builder.getInt32Ty()); 1756 argTypes.push_back(builder.getInt8PtrTy()); 1757 1758 argNames.clear(); 1759 1760 createFunction(module, 1761 retType, 1762 argTypes, 1763 argNames, 1764 "print32Int", 1765 llvm::Function::ExternalLinkage, 1766 true, 1767 false); 1768 1769 // print64Int 1770 1771 retType = builder.getVoidTy(); 1772 1773 argTypes.clear(); 1774 argTypes.push_back(builder.getInt64Ty()); 1775 argTypes.push_back(builder.getInt8PtrTy()); 1776 1777 argNames.clear(); 1778 1779 createFunction(module, 1780 retType, 1781 argTypes, 1782 argNames, 1783 "print64Int", 1784 llvm::Function::ExternalLinkage, 1785 true, 1786 false); 1787 1788 // printStr 1789 1790 retType = builder.getVoidTy(); 1791 1792 argTypes.clear(); 1793 argTypes.push_back(builder.getInt8PtrTy()); 1794 1795 argNames.clear(); 1796 1797 createFunction(module, 1798 retType, 1799 argTypes, 1800 argNames, 1801 "printStr", 1802 llvm::Function::ExternalLinkage, 1803 true, 1804 false); 1805 1806 // throwCppException 1807 1808 retType = builder.getVoidTy(); 1809 1810 argTypes.clear(); 1811 argTypes.push_back(builder.getInt32Ty()); 1812 1813 argNames.clear(); 1814 1815 createFunction(module, 1816 retType, 1817 argTypes, 1818 argNames, 1819 "throwCppException", 1820 llvm::Function::ExternalLinkage, 1821 true, 1822 false); 1823 1824 // deleteOurException 1825 1826 retType = builder.getVoidTy(); 1827 1828 argTypes.clear(); 1829 argTypes.push_back(builder.getInt8PtrTy()); 1830 1831 argNames.clear(); 1832 1833 createFunction(module, 1834 retType, 1835 argTypes, 1836 argNames, 1837 "deleteOurException", 1838 llvm::Function::ExternalLinkage, 1839 true, 1840 false); 1841 1842 // createOurException 1843 1844 retType = builder.getInt8PtrTy(); 1845 1846 argTypes.clear(); 1847 argTypes.push_back(builder.getInt32Ty()); 1848 1849 argNames.clear(); 1850 1851 createFunction(module, 1852 retType, 1853 argTypes, 1854 argNames, 1855 "createOurException", 1856 llvm::Function::ExternalLinkage, 1857 true, 1858 false); 1859 1860 // _Unwind_RaiseException 1861 1862 retType = builder.getInt32Ty(); 1863 1864 argTypes.clear(); 1865 argTypes.push_back(builder.getInt8PtrTy()); 1866 1867 argNames.clear(); 1868 1869 funct = createFunction(module, 1870 retType, 1871 argTypes, 1872 argNames, 1873 "_Unwind_RaiseException", 1874 llvm::Function::ExternalLinkage, 1875 true, 1876 false); 1877 1878 funct->setDoesNotReturn(); 1879 1880 // _Unwind_Resume 1881 1882 retType = builder.getInt32Ty(); 1883 1884 argTypes.clear(); 1885 argTypes.push_back(builder.getInt8PtrTy()); 1886 1887 argNames.clear(); 1888 1889 funct = createFunction(module, 1890 retType, 1891 argTypes, 1892 argNames, 1893 "_Unwind_Resume", 1894 llvm::Function::ExternalLinkage, 1895 true, 1896 false); 1897 1898 funct->setDoesNotReturn(); 1899 1900 // ourPersonality 1901 1902 retType = builder.getInt32Ty(); 1903 1904 argTypes.clear(); 1905 argTypes.push_back(builder.getInt32Ty()); 1906 argTypes.push_back(builder.getInt32Ty()); 1907 argTypes.push_back(builder.getInt64Ty()); 1908 argTypes.push_back(builder.getInt8PtrTy()); 1909 argTypes.push_back(builder.getInt8PtrTy()); 1910 1911 argNames.clear(); 1912 1913 createFunction(module, 1914 retType, 1915 argTypes, 1916 argNames, 1917 "ourPersonality", 1918 llvm::Function::ExternalLinkage, 1919 true, 1920 false); 1921 1922 // llvm.eh.typeid.for intrinsic 1923 1924 getDeclaration(&module, llvm::Intrinsic::eh_typeid_for); 1925} 1926 1927 1928//===----------------------------------------------------------------------===// 1929// Main test driver code. 1930//===----------------------------------------------------------------------===// 1931 1932/// Demo main routine which takes the type info types to throw. A test will 1933/// be run for each given type info type. While type info types with the value 1934/// of -1 will trigger a foreign C++ exception to be thrown; type info types 1935/// <= 6 and >= 1 will be caught by test functions; and type info types > 6 1936/// will result in exceptions which pass through to the test harness. All other 1937/// type info types are not supported and could cause a crash. 1938int main(int argc, char *argv[]) { 1939 if (argc == 1) { 1940 fprintf(stderr, 1941 "\nUsage: ExceptionDemo <exception type to throw> " 1942 "[<type 2>...<type n>].\n" 1943 " Each type must have the value of 1 - 6 for " 1944 "generated exceptions to be caught;\n" 1945 " the value -1 for foreign C++ exceptions to be " 1946 "generated and thrown;\n" 1947 " or the values > 6 for exceptions to be ignored.\n" 1948 "\nTry: ExceptionDemo 2 3 7 -1\n" 1949 " for a full test.\n\n"); 1950 return(0); 1951 } 1952 1953 // If not set, exception handling will not be turned on 1954 llvm::TargetOptions Opts; 1955 1956 llvm::InitializeNativeTarget(); 1957 llvm::InitializeNativeTargetAsmPrinter(); 1958 llvm::LLVMContext &context = llvm::getGlobalContext(); 1959 llvm::IRBuilder<> theBuilder(context); 1960 1961 // Make the module, which holds all the code. 1962 llvm::Module *module = new llvm::Module("my cool jit", context); 1963 1964 llvm::RTDyldMemoryManager *MemMgr = new llvm::SectionMemoryManager(); 1965 1966 // Build engine with JIT 1967 llvm::EngineBuilder factory(module); 1968 factory.setEngineKind(llvm::EngineKind::JIT); 1969 factory.setAllocateGVsWithCode(false); 1970 factory.setTargetOptions(Opts); 1971 factory.setMCJITMemoryManager(MemMgr); 1972 factory.setUseMCJIT(true); 1973 llvm::ExecutionEngine *executionEngine = factory.create(); 1974 1975 { 1976 llvm::FunctionPassManager fpm(module); 1977 1978 // Set up the optimizer pipeline. 1979 // Start with registering info about how the 1980 // target lays out data structures. 1981 fpm.add(new llvm::DataLayout(*executionEngine->getDataLayout())); 1982 1983 // Optimizations turned on 1984#ifdef ADD_OPT_PASSES 1985 1986 // Basic AliasAnslysis support for GVN. 1987 fpm.add(llvm::createBasicAliasAnalysisPass()); 1988 1989 // Promote allocas to registers. 1990 fpm.add(llvm::createPromoteMemoryToRegisterPass()); 1991 1992 // Do simple "peephole" optimizations and bit-twiddling optzns. 1993 fpm.add(llvm::createInstructionCombiningPass()); 1994 1995 // Reassociate expressions. 1996 fpm.add(llvm::createReassociatePass()); 1997 1998 // Eliminate Common SubExpressions. 1999 fpm.add(llvm::createGVNPass()); 2000 2001 // Simplify the control flow graph (deleting unreachable 2002 // blocks, etc). 2003 fpm.add(llvm::createCFGSimplificationPass()); 2004#endif // ADD_OPT_PASSES 2005 2006 fpm.doInitialization(); 2007 2008 // Generate test code using function throwCppException(...) as 2009 // the function which throws foreign exceptions. 2010 llvm::Function *toRun = 2011 createUnwindExceptionTest(*module, 2012 theBuilder, 2013 fpm, 2014 "throwCppException"); 2015 2016 executionEngine->finalizeObject(); 2017 2018 fprintf(stderr, "\nBegin module dump:\n\n"); 2019 2020 module->dump(); 2021 2022 fprintf(stderr, "\nEnd module dump:\n"); 2023 2024 fprintf(stderr, "\n\nBegin Test:\n"); 2025 2026 for (int i = 1; i < argc; ++i) { 2027 // Run test for each argument whose value is the exception 2028 // type to throw. 2029 runExceptionThrow(executionEngine, 2030 toRun, 2031 (unsigned) strtoul(argv[i], NULL, 10)); 2032 } 2033 2034 fprintf(stderr, "\nEnd Test:\n\n"); 2035 } 2036 2037 delete executionEngine; 2038 2039 return 0; 2040} 2041