[llvm-readobj] - Repair the test case.
[llvm-complete.git] / examples / ExceptionDemo / ExceptionDemo.cpp
blob91c8617f26d206bab1db693d7f31525207aa8cbd
1 //===-- ExceptionDemo.cpp - An example using llvm Exceptions --------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Demo program which implements an example LLVM exception implementation, and
10 // shows several test cases including the handling of foreign exceptions.
11 // It is run with type info types arguments to throw. A test will
12 // be run for each given type info type. While type info types with the value
13 // of -1 will trigger a foreign C++ exception to be thrown; type info types
14 // <= 6 and >= 1 will cause the associated generated exceptions to be thrown
15 // and caught by generated test functions; and type info types > 6
16 // will result in exceptions which pass through to the test harness. All other
17 // type info types are not supported and could cause a crash. In all cases,
18 // the "finally" blocks of every generated test functions will executed
19 // regardless of whether or not that test function ignores or catches the
20 // thrown exception.
22 // examples:
24 // ExceptionDemo
26 // causes a usage to be printed to stderr
28 // ExceptionDemo 2 3 7 -1
30 // results in the following cases:
31 // - Value 2 causes an exception with a type info type of 2 to be
32 // thrown and caught by an inner generated test function.
33 // - Value 3 causes an exception with a type info type of 3 to be
34 // thrown and caught by an outer generated test function.
35 // - Value 7 causes an exception with a type info type of 7 to be
36 // thrown and NOT be caught by any generated function.
37 // - Value -1 causes a foreign C++ exception to be thrown and not be
38 // caught by any generated function
40 // Cases -1 and 7 are caught by a C++ test harness where the validity of
41 // of a C++ catch(...) clause catching a generated exception with a
42 // type info type of 7 is explained by: example in rules 1.6.4 in
43 // http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html (v1.22)
45 // This code uses code from the llvm compiler-rt project and the llvm
46 // Kaleidoscope project.
48 //===----------------------------------------------------------------------===//
50 #include "llvm/ADT/STLExtras.h"
51 #include "llvm/BinaryFormat/Dwarf.h"
52 #include "llvm/ExecutionEngine/MCJIT.h"
53 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
54 #include "llvm/IR/DataLayout.h"
55 #include "llvm/IR/DerivedTypes.h"
56 #include "llvm/IR/IRBuilder.h"
57 #include "llvm/IR/Intrinsics.h"
58 #include "llvm/IR/LLVMContext.h"
59 #include "llvm/IR/LegacyPassManager.h"
60 #include "llvm/IR/Module.h"
61 #include "llvm/IR/Verifier.h"
62 #include "llvm/Support/TargetSelect.h"
63 #include "llvm/Target/TargetOptions.h"
64 #include "llvm/Transforms/Scalar.h"
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>
76 #include <sstream>
77 #include <stdexcept>
79 #include <inttypes.h>
81 #include <unwind.h>
83 #ifndef USE_GLOBAL_STR_CONSTS
84 #define USE_GLOBAL_STR_CONSTS true
85 #endif
88 // Example types
91 /// This is our simplistic type info
92 struct OurExceptionType_t {
93 /// type info type
94 int type;
98 /// This is our Exception class which relies on a negative offset to calculate
99 /// pointers to its instances from pointers to its unwindException member.
101 /// Note: The above unwind.h defines struct _Unwind_Exception to be aligned
102 /// on a double word boundary. This is necessary to match the standard:
103 /// http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
104 struct OurBaseException_t {
105 struct OurExceptionType_t type;
107 // Note: This is properly aligned in unwind.h
108 struct _Unwind_Exception unwindException;
112 // Note: Not needed since we are C++
113 typedef struct OurBaseException_t OurException;
114 typedef struct _Unwind_Exception OurUnwindException;
117 // Various globals used to support typeinfo and generatted exceptions in
118 // general
121 static std::map<std::string, llvm::Value*> namedValues;
123 int64_t ourBaseFromUnwindOffset;
125 const unsigned char ourBaseExcpClassChars[] =
126 {'o', 'b', 'j', '\0', 'b', 'a', 's', '\0'};
129 static uint64_t ourBaseExceptionClass = 0;
131 static std::vector<std::string> ourTypeInfoNames;
132 static std::map<int, std::string> ourTypeInfoNamesIndex;
134 static llvm::StructType *ourTypeInfoType;
135 static llvm::StructType *ourCaughtResultType;
136 static llvm::StructType *ourExceptionType;
137 static llvm::StructType *ourUnwindExceptionType;
139 static llvm::ConstantInt *ourExceptionNotThrownState;
140 static llvm::ConstantInt *ourExceptionThrownState;
141 static llvm::ConstantInt *ourExceptionCaughtState;
143 typedef std::vector<std::string> ArgNames;
144 typedef std::vector<llvm::Type*> ArgTypes;
147 // Code Generation Utilities
150 /// Utility used to create a function, both declarations and definitions
151 /// @param module for module instance
152 /// @param retType function return type
153 /// @param theArgTypes function's ordered argument types
154 /// @param theArgNames function's ordered arguments needed if use of this
155 /// function corresponds to a function definition. Use empty
156 /// aggregate for function declarations.
157 /// @param functName function name
158 /// @param linkage function linkage
159 /// @param declarationOnly for function declarations
160 /// @param isVarArg function uses vararg arguments
161 /// @returns function instance
162 llvm::Function *createFunction(llvm::Module &module,
163 llvm::Type *retType,
164 const ArgTypes &theArgTypes,
165 const ArgNames &theArgNames,
166 const std::string &functName,
167 llvm::GlobalValue::LinkageTypes linkage,
168 bool declarationOnly,
169 bool isVarArg) {
170 llvm::FunctionType *functType =
171 llvm::FunctionType::get(retType, theArgTypes, isVarArg);
172 llvm::Function *ret =
173 llvm::Function::Create(functType, linkage, functName, &module);
174 if (!ret || declarationOnly)
175 return(ret);
177 namedValues.clear();
178 unsigned i = 0;
179 for (llvm::Function::arg_iterator argIndex = ret->arg_begin();
180 i != theArgNames.size();
181 ++argIndex, ++i) {
183 argIndex->setName(theArgNames[i]);
184 namedValues[theArgNames[i]] = argIndex;
187 return(ret);
191 /// Create an alloca instruction in the entry block of
192 /// the parent function. This is used for mutable variables etc.
193 /// @param function parent instance
194 /// @param varName stack variable name
195 /// @param type stack variable type
196 /// @param initWith optional constant initialization value
197 /// @returns AllocaInst instance
198 static llvm::AllocaInst *createEntryBlockAlloca(llvm::Function &function,
199 const std::string &varName,
200 llvm::Type *type,
201 llvm::Constant *initWith = 0) {
202 llvm::BasicBlock &block = function.getEntryBlock();
203 llvm::IRBuilder<> tmp(&block, block.begin());
204 llvm::AllocaInst *ret = tmp.CreateAlloca(type, 0, varName);
206 if (initWith)
207 tmp.CreateStore(initWith, ret);
209 return(ret);
214 // Code Generation Utilities End
218 // Runtime C Library functions
221 namespace {
222 template <typename Type_>
223 uintptr_t ReadType(const uint8_t *&p) {
224 Type_ value;
225 memcpy(&value, p, sizeof(Type_));
226 p += sizeof(Type_);
227 return static_cast<uintptr_t>(value);
231 // Note: using an extern "C" block so that static functions can be used
232 extern "C" {
234 // Note: Better ways to decide on bit width
236 /// Prints a 32 bit number, according to the format, to stderr.
237 /// @param intToPrint integer to print
238 /// @param format printf like format to use when printing
239 void print32Int(int intToPrint, const char *format) {
240 if (format) {
241 // Note: No NULL check
242 fprintf(stderr, format, intToPrint);
244 else {
245 // Note: No NULL check
246 fprintf(stderr, "::print32Int(...):NULL arg.\n");
251 // Note: Better ways to decide on bit width
253 /// Prints a 64 bit number, according to the format, to stderr.
254 /// @param intToPrint integer to print
255 /// @param format printf like format to use when printing
256 void print64Int(long int intToPrint, const char *format) {
257 if (format) {
258 // Note: No NULL check
259 fprintf(stderr, format, intToPrint);
261 else {
262 // Note: No NULL check
263 fprintf(stderr, "::print64Int(...):NULL arg.\n");
268 /// Prints a C string to stderr
269 /// @param toPrint string to print
270 void printStr(char *toPrint) {
271 if (toPrint) {
272 fprintf(stderr, "%s", toPrint);
274 else {
275 fprintf(stderr, "::printStr(...):NULL arg.\n");
280 /// Deletes the true previously allocated exception whose address
281 /// is calculated from the supplied OurBaseException_t::unwindException
282 /// member address. Handles (ignores), NULL pointers.
283 /// @param expToDelete exception to delete
284 void deleteOurException(OurUnwindException *expToDelete) {
285 #ifdef DEBUG
286 fprintf(stderr,
287 "deleteOurException(...).\n");
288 #endif
290 if (expToDelete &&
291 (expToDelete->exception_class == ourBaseExceptionClass)) {
293 free(((char*) expToDelete) + ourBaseFromUnwindOffset);
298 /// This function is the struct _Unwind_Exception API mandated delete function
299 /// used by foreign exception handlers when deleting our exception
300 /// (OurException), instances.
301 /// @param reason See @link http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
302 /// @unlink
303 /// @param expToDelete exception instance to delete
304 void deleteFromUnwindOurException(_Unwind_Reason_Code reason,
305 OurUnwindException *expToDelete) {
306 #ifdef DEBUG
307 fprintf(stderr,
308 "deleteFromUnwindOurException(...).\n");
309 #endif
311 deleteOurException(expToDelete);
315 /// Creates (allocates on the heap), an exception (OurException instance),
316 /// of the supplied type info type.
317 /// @param type type info type
318 OurUnwindException *createOurException(int type) {
319 size_t size = sizeof(OurException);
320 OurException *ret = (OurException*) memset(malloc(size), 0, size);
321 (ret->type).type = type;
322 (ret->unwindException).exception_class = ourBaseExceptionClass;
323 (ret->unwindException).exception_cleanup = deleteFromUnwindOurException;
325 return(&(ret->unwindException));
329 /// Read a uleb128 encoded value and advance pointer
330 /// See Variable Length Data in:
331 /// @link http://dwarfstd.org/Dwarf3.pdf @unlink
332 /// @param data reference variable holding memory pointer to decode from
333 /// @returns decoded value
334 static uintptr_t readULEB128(const uint8_t **data) {
335 uintptr_t result = 0;
336 uintptr_t shift = 0;
337 unsigned char byte;
338 const uint8_t *p = *data;
340 do {
341 byte = *p++;
342 result |= (byte & 0x7f) << shift;
343 shift += 7;
345 while (byte & 0x80);
347 *data = p;
349 return result;
353 /// Read a sleb128 encoded value and advance pointer
354 /// See Variable Length Data in:
355 /// @link http://dwarfstd.org/Dwarf3.pdf @unlink
356 /// @param data reference variable holding memory pointer to decode from
357 /// @returns decoded value
358 static uintptr_t readSLEB128(const uint8_t **data) {
359 uintptr_t result = 0;
360 uintptr_t shift = 0;
361 unsigned char byte;
362 const uint8_t *p = *data;
364 do {
365 byte = *p++;
366 result |= (byte & 0x7f) << shift;
367 shift += 7;
369 while (byte & 0x80);
371 *data = p;
373 if ((byte & 0x40) && (shift < (sizeof(result) << 3))) {
374 result |= (~0 << shift);
377 return result;
380 unsigned getEncodingSize(uint8_t Encoding) {
381 if (Encoding == llvm::dwarf::DW_EH_PE_omit)
382 return 0;
384 switch (Encoding & 0x0F) {
385 case llvm::dwarf::DW_EH_PE_absptr:
386 return sizeof(uintptr_t);
387 case llvm::dwarf::DW_EH_PE_udata2:
388 return sizeof(uint16_t);
389 case llvm::dwarf::DW_EH_PE_udata4:
390 return sizeof(uint32_t);
391 case llvm::dwarf::DW_EH_PE_udata8:
392 return sizeof(uint64_t);
393 case llvm::dwarf::DW_EH_PE_sdata2:
394 return sizeof(int16_t);
395 case llvm::dwarf::DW_EH_PE_sdata4:
396 return sizeof(int32_t);
397 case llvm::dwarf::DW_EH_PE_sdata8:
398 return sizeof(int64_t);
399 default:
400 // not supported
401 abort();
405 /// Read a pointer encoded value and advance pointer
406 /// See Variable Length Data in:
407 /// @link http://dwarfstd.org/Dwarf3.pdf @unlink
408 /// @param data reference variable holding memory pointer to decode from
409 /// @param encoding dwarf encoding type
410 /// @returns decoded value
411 static uintptr_t readEncodedPointer(const uint8_t **data, uint8_t encoding) {
412 uintptr_t result = 0;
413 const uint8_t *p = *data;
415 if (encoding == llvm::dwarf::DW_EH_PE_omit)
416 return(result);
418 // first get value
419 switch (encoding & 0x0F) {
420 case llvm::dwarf::DW_EH_PE_absptr:
421 result = ReadType<uintptr_t>(p);
422 break;
423 case llvm::dwarf::DW_EH_PE_uleb128:
424 result = readULEB128(&p);
425 break;
426 // Note: This case has not been tested
427 case llvm::dwarf::DW_EH_PE_sleb128:
428 result = readSLEB128(&p);
429 break;
430 case llvm::dwarf::DW_EH_PE_udata2:
431 result = ReadType<uint16_t>(p);
432 break;
433 case llvm::dwarf::DW_EH_PE_udata4:
434 result = ReadType<uint32_t>(p);
435 break;
436 case llvm::dwarf::DW_EH_PE_udata8:
437 result = ReadType<uint64_t>(p);
438 break;
439 case llvm::dwarf::DW_EH_PE_sdata2:
440 result = ReadType<int16_t>(p);
441 break;
442 case llvm::dwarf::DW_EH_PE_sdata4:
443 result = ReadType<int32_t>(p);
444 break;
445 case llvm::dwarf::DW_EH_PE_sdata8:
446 result = ReadType<int64_t>(p);
447 break;
448 default:
449 // not supported
450 abort();
451 break;
454 // then add relative offset
455 switch (encoding & 0x70) {
456 case llvm::dwarf::DW_EH_PE_absptr:
457 // do nothing
458 break;
459 case llvm::dwarf::DW_EH_PE_pcrel:
460 result += (uintptr_t)(*data);
461 break;
462 case llvm::dwarf::DW_EH_PE_textrel:
463 case llvm::dwarf::DW_EH_PE_datarel:
464 case llvm::dwarf::DW_EH_PE_funcrel:
465 case llvm::dwarf::DW_EH_PE_aligned:
466 default:
467 // not supported
468 abort();
469 break;
472 // then apply indirection
473 if (encoding & llvm::dwarf::DW_EH_PE_indirect) {
474 result = *((uintptr_t*)result);
477 *data = p;
479 return result;
483 /// Deals with Dwarf actions matching our type infos
484 /// (OurExceptionType_t instances). Returns whether or not a dwarf emitted
485 /// action matches the supplied exception type. If such a match succeeds,
486 /// the resultAction argument will be set with > 0 index value. Only
487 /// corresponding llvm.eh.selector type info arguments, cleanup arguments
488 /// are supported. Filters are not supported.
489 /// See Variable Length Data in:
490 /// @link http://dwarfstd.org/Dwarf3.pdf @unlink
491 /// Also see @link http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html @unlink
492 /// @param resultAction reference variable which will be set with result
493 /// @param classInfo our array of type info pointers (to globals)
494 /// @param actionEntry index into above type info array or 0 (clean up).
495 /// We do not support filters.
496 /// @param exceptionClass exception class (_Unwind_Exception::exception_class)
497 /// of thrown exception.
498 /// @param exceptionObject thrown _Unwind_Exception instance.
499 /// @returns whether or not a type info was found. False is returned if only
500 /// a cleanup was found
501 static bool handleActionValue(int64_t *resultAction,
502 uint8_t TTypeEncoding,
503 const uint8_t *ClassInfo,
504 uintptr_t actionEntry,
505 uint64_t exceptionClass,
506 struct _Unwind_Exception *exceptionObject) {
507 bool ret = false;
509 if (!resultAction ||
510 !exceptionObject ||
511 (exceptionClass != ourBaseExceptionClass))
512 return(ret);
514 struct OurBaseException_t *excp = (struct OurBaseException_t*)
515 (((char*) exceptionObject) + ourBaseFromUnwindOffset);
516 struct OurExceptionType_t *excpType = &(excp->type);
517 int type = excpType->type;
519 #ifdef DEBUG
520 fprintf(stderr,
521 "handleActionValue(...): exceptionObject = <%p>, "
522 "excp = <%p>.\n",
523 (void*)exceptionObject,
524 (void*)excp);
525 #endif
527 const uint8_t *actionPos = (uint8_t*) actionEntry,
528 *tempActionPos;
529 int64_t typeOffset = 0,
530 actionOffset;
532 for (int i = 0; true; ++i) {
533 // Each emitted dwarf action corresponds to a 2 tuple of
534 // type info address offset, and action offset to the next
535 // emitted action.
536 typeOffset = readSLEB128(&actionPos);
537 tempActionPos = actionPos;
538 actionOffset = readSLEB128(&tempActionPos);
540 #ifdef DEBUG
541 fprintf(stderr,
542 "handleActionValue(...):typeOffset: <%" PRIi64 ">, "
543 "actionOffset: <%" PRIi64 ">.\n",
544 typeOffset,
545 actionOffset);
546 #endif
547 assert((typeOffset >= 0) &&
548 "handleActionValue(...):filters are not supported.");
550 // Note: A typeOffset == 0 implies that a cleanup llvm.eh.selector
551 // argument has been matched.
552 if (typeOffset > 0) {
553 #ifdef DEBUG
554 fprintf(stderr,
555 "handleActionValue(...):actionValue <%d> found.\n",
557 #endif
558 unsigned EncSize = getEncodingSize(TTypeEncoding);
559 const uint8_t *EntryP = ClassInfo - typeOffset * EncSize;
560 uintptr_t P = readEncodedPointer(&EntryP, TTypeEncoding);
561 struct OurExceptionType_t *ThisClassInfo =
562 reinterpret_cast<struct OurExceptionType_t *>(P);
563 if (ThisClassInfo->type == type) {
564 *resultAction = i + 1;
565 ret = true;
566 break;
570 #ifdef DEBUG
571 fprintf(stderr,
572 "handleActionValue(...):actionValue not found.\n");
573 #endif
574 if (!actionOffset)
575 break;
577 actionPos += actionOffset;
580 return(ret);
584 /// Deals with the Language specific data portion of the emitted dwarf code.
585 /// See @link http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html @unlink
586 /// @param version unsupported (ignored), unwind version
587 /// @param lsda language specific data area
588 /// @param _Unwind_Action actions minimally supported unwind stage
589 /// (forced specifically not supported)
590 /// @param exceptionClass exception class (_Unwind_Exception::exception_class)
591 /// of thrown exception.
592 /// @param exceptionObject thrown _Unwind_Exception instance.
593 /// @param context unwind system context
594 /// @returns minimally supported unwinding control indicator
595 static _Unwind_Reason_Code handleLsda(int version, const uint8_t *lsda,
596 _Unwind_Action actions,
597 _Unwind_Exception_Class exceptionClass,
598 struct _Unwind_Exception *exceptionObject,
599 struct _Unwind_Context *context) {
600 _Unwind_Reason_Code ret = _URC_CONTINUE_UNWIND;
602 if (!lsda)
603 return(ret);
605 #ifdef DEBUG
606 fprintf(stderr,
607 "handleLsda(...):lsda is non-zero.\n");
608 #endif
610 // Get the current instruction pointer and offset it before next
611 // instruction in the current frame which threw the exception.
612 uintptr_t pc = _Unwind_GetIP(context)-1;
614 // Get beginning current frame's code (as defined by the
615 // emitted dwarf code)
616 uintptr_t funcStart = _Unwind_GetRegionStart(context);
617 uintptr_t pcOffset = pc - funcStart;
618 const uint8_t *ClassInfo = NULL;
620 // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding
621 // dwarf emission
623 // Parse LSDA header.
624 uint8_t lpStartEncoding = *lsda++;
626 if (lpStartEncoding != llvm::dwarf::DW_EH_PE_omit) {
627 readEncodedPointer(&lsda, lpStartEncoding);
630 uint8_t ttypeEncoding = *lsda++;
631 uintptr_t classInfoOffset;
633 if (ttypeEncoding != llvm::dwarf::DW_EH_PE_omit) {
634 // Calculate type info locations in emitted dwarf code which
635 // were flagged by type info arguments to llvm.eh.selector
636 // intrinsic
637 classInfoOffset = readULEB128(&lsda);
638 ClassInfo = lsda + classInfoOffset;
641 // Walk call-site table looking for range that
642 // includes current PC.
644 uint8_t callSiteEncoding = *lsda++;
645 uint32_t callSiteTableLength = readULEB128(&lsda);
646 const uint8_t *callSiteTableStart = lsda;
647 const uint8_t *callSiteTableEnd = callSiteTableStart +
648 callSiteTableLength;
649 const uint8_t *actionTableStart = callSiteTableEnd;
650 const uint8_t *callSitePtr = callSiteTableStart;
652 while (callSitePtr < callSiteTableEnd) {
653 uintptr_t start = readEncodedPointer(&callSitePtr,
654 callSiteEncoding);
655 uintptr_t length = readEncodedPointer(&callSitePtr,
656 callSiteEncoding);
657 uintptr_t landingPad = readEncodedPointer(&callSitePtr,
658 callSiteEncoding);
660 // Note: Action value
661 uintptr_t actionEntry = readULEB128(&callSitePtr);
663 if (exceptionClass != ourBaseExceptionClass) {
664 // We have been notified of a foreign exception being thrown,
665 // and we therefore need to execute cleanup landing pads
666 actionEntry = 0;
669 if (landingPad == 0) {
670 #ifdef DEBUG
671 fprintf(stderr,
672 "handleLsda(...): No landing pad found.\n");
673 #endif
675 continue; // no landing pad for this entry
678 if (actionEntry) {
679 actionEntry += ((uintptr_t) actionTableStart) - 1;
681 else {
682 #ifdef DEBUG
683 fprintf(stderr,
684 "handleLsda(...):No action table found.\n");
685 #endif
688 bool exceptionMatched = false;
690 if ((start <= pcOffset) && (pcOffset < (start + length))) {
691 #ifdef DEBUG
692 fprintf(stderr,
693 "handleLsda(...): Landing pad found.\n");
694 #endif
695 int64_t actionValue = 0;
697 if (actionEntry) {
698 exceptionMatched = handleActionValue(&actionValue,
699 ttypeEncoding,
700 ClassInfo,
701 actionEntry,
702 exceptionClass,
703 exceptionObject);
706 if (!(actions & _UA_SEARCH_PHASE)) {
707 #ifdef DEBUG
708 fprintf(stderr,
709 "handleLsda(...): installed landing pad "
710 "context.\n");
711 #endif
713 // Found landing pad for the PC.
714 // Set Instruction Pointer to so we re-enter function
715 // at landing pad. The landing pad is created by the
716 // compiler to take two parameters in registers.
717 _Unwind_SetGR(context,
718 __builtin_eh_return_data_regno(0),
719 (uintptr_t)exceptionObject);
721 // Note: this virtual register directly corresponds
722 // to the return of the llvm.eh.selector intrinsic
723 if (!actionEntry || !exceptionMatched) {
724 // We indicate cleanup only
725 _Unwind_SetGR(context,
726 __builtin_eh_return_data_regno(1),
729 else {
730 // Matched type info index of llvm.eh.selector intrinsic
731 // passed here.
732 _Unwind_SetGR(context,
733 __builtin_eh_return_data_regno(1),
734 actionValue);
737 // To execute landing pad set here
738 _Unwind_SetIP(context, funcStart + landingPad);
739 ret = _URC_INSTALL_CONTEXT;
741 else if (exceptionMatched) {
742 #ifdef DEBUG
743 fprintf(stderr,
744 "handleLsda(...): setting handler found.\n");
745 #endif
746 ret = _URC_HANDLER_FOUND;
748 else {
749 // Note: Only non-clean up handlers are marked as
750 // found. Otherwise the clean up handlers will be
751 // re-found and executed during the clean up
752 // phase.
753 #ifdef DEBUG
754 fprintf(stderr,
755 "handleLsda(...): cleanup handler found.\n");
756 #endif
759 break;
763 return(ret);
767 /// This is the personality function which is embedded (dwarf emitted), in the
768 /// dwarf unwind info block. Again see: JITDwarfEmitter.cpp.
769 /// See @link http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html @unlink
770 /// @param version unsupported (ignored), unwind version
771 /// @param _Unwind_Action actions minimally supported unwind stage
772 /// (forced specifically not supported)
773 /// @param exceptionClass exception class (_Unwind_Exception::exception_class)
774 /// of thrown exception.
775 /// @param exceptionObject thrown _Unwind_Exception instance.
776 /// @param context unwind system context
777 /// @returns minimally supported unwinding control indicator
778 _Unwind_Reason_Code ourPersonality(int version, _Unwind_Action actions,
779 _Unwind_Exception_Class exceptionClass,
780 struct _Unwind_Exception *exceptionObject,
781 struct _Unwind_Context *context) {
782 #ifdef DEBUG
783 fprintf(stderr,
784 "We are in ourPersonality(...):actions is <%d>.\n",
785 actions);
787 if (actions & _UA_SEARCH_PHASE) {
788 fprintf(stderr, "ourPersonality(...):In search phase.\n");
790 else {
791 fprintf(stderr, "ourPersonality(...):In non-search phase.\n");
793 #endif
795 const uint8_t *lsda = _Unwind_GetLanguageSpecificData(context);
797 #ifdef DEBUG
798 fprintf(stderr,
799 "ourPersonality(...):lsda = <%p>.\n",
800 (void*)lsda);
801 #endif
803 // The real work of the personality function is captured here
804 return(handleLsda(version,
805 lsda,
806 actions,
807 exceptionClass,
808 exceptionObject,
809 context));
813 /// Generates our _Unwind_Exception class from a given character array.
814 /// thereby handling arbitrary lengths (not in standard), and handling
815 /// embedded \0s.
816 /// See @link http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html @unlink
817 /// @param classChars char array to encode. NULL values not checkedf
818 /// @param classCharsSize number of chars in classChars. Value is not checked.
819 /// @returns class value
820 uint64_t genClass(const unsigned char classChars[], size_t classCharsSize)
822 uint64_t ret = classChars[0];
824 for (unsigned i = 1; i < classCharsSize; ++i) {
825 ret <<= 8;
826 ret += classChars[i];
829 return(ret);
832 } // extern "C"
835 // Runtime C Library functions End
839 // Code generation functions
842 /// Generates code to print given constant string
843 /// @param context llvm context
844 /// @param module code for module instance
845 /// @param builder builder instance
846 /// @param toPrint string to print
847 /// @param useGlobal A value of true (default) indicates a GlobalValue is
848 /// generated, and is used to hold the constant string. A value of
849 /// false indicates that the constant string will be stored on the
850 /// stack.
851 void generateStringPrint(llvm::LLVMContext &context,
852 llvm::Module &module,
853 llvm::IRBuilder<> &builder,
854 std::string toPrint,
855 bool useGlobal = true) {
856 llvm::Function *printFunct = module.getFunction("printStr");
858 llvm::Value *stringVar;
859 llvm::Constant *stringConstant =
860 llvm::ConstantDataArray::getString(context, toPrint);
862 if (useGlobal) {
863 // Note: Does not work without allocation
864 stringVar =
865 new llvm::GlobalVariable(module,
866 stringConstant->getType(),
867 true,
868 llvm::GlobalValue::PrivateLinkage,
869 stringConstant,
870 "");
872 else {
873 stringVar = builder.CreateAlloca(stringConstant->getType());
874 builder.CreateStore(stringConstant, stringVar);
877 llvm::Value *cast = builder.CreatePointerCast(stringVar,
878 builder.getInt8PtrTy());
879 builder.CreateCall(printFunct, cast);
883 /// Generates code to print given runtime integer according to constant
884 /// string format, and a given print function.
885 /// @param context llvm context
886 /// @param module code for module instance
887 /// @param builder builder instance
888 /// @param printFunct function used to "print" integer
889 /// @param toPrint string to print
890 /// @param format printf like formating string for print
891 /// @param useGlobal A value of true (default) indicates a GlobalValue is
892 /// generated, and is used to hold the constant string. A value of
893 /// false indicates that the constant string will be stored on the
894 /// stack.
895 void generateIntegerPrint(llvm::LLVMContext &context,
896 llvm::Module &module,
897 llvm::IRBuilder<> &builder,
898 llvm::Function &printFunct,
899 llvm::Value &toPrint,
900 std::string format,
901 bool useGlobal = true) {
902 llvm::Constant *stringConstant =
903 llvm::ConstantDataArray::getString(context, format);
904 llvm::Value *stringVar;
906 if (useGlobal) {
907 // Note: Does not seem to work without allocation
908 stringVar =
909 new llvm::GlobalVariable(module,
910 stringConstant->getType(),
911 true,
912 llvm::GlobalValue::PrivateLinkage,
913 stringConstant,
914 "");
916 else {
917 stringVar = builder.CreateAlloca(stringConstant->getType());
918 builder.CreateStore(stringConstant, stringVar);
921 llvm::Value *cast = builder.CreateBitCast(stringVar,
922 builder.getInt8PtrTy());
923 builder.CreateCall(&printFunct, {&toPrint, cast});
927 /// Generates code to handle finally block type semantics: always runs
928 /// regardless of whether a thrown exception is passing through or the
929 /// parent function is simply exiting. In addition to printing some state
930 /// to stderr, this code will resume the exception handling--runs the
931 /// unwind resume block, if the exception has not been previously caught
932 /// by a catch clause, and will otherwise execute the end block (terminator
933 /// block). In addition this function creates the corresponding function's
934 /// stack storage for the exception pointer and catch flag status.
935 /// @param context llvm context
936 /// @param module code for module instance
937 /// @param builder builder instance
938 /// @param toAddTo parent function to add block to
939 /// @param blockName block name of new "finally" block.
940 /// @param functionId output id used for printing
941 /// @param terminatorBlock terminator "end" block
942 /// @param unwindResumeBlock unwind resume block
943 /// @param exceptionCaughtFlag reference exception caught/thrown status storage
944 /// @param exceptionStorage reference to exception pointer storage
945 /// @param caughtResultStorage reference to landingpad result storage
946 /// @returns newly created block
947 static llvm::BasicBlock *createFinallyBlock(llvm::LLVMContext &context,
948 llvm::Module &module,
949 llvm::IRBuilder<> &builder,
950 llvm::Function &toAddTo,
951 std::string &blockName,
952 std::string &functionId,
953 llvm::BasicBlock &terminatorBlock,
954 llvm::BasicBlock &unwindResumeBlock,
955 llvm::Value **exceptionCaughtFlag,
956 llvm::Value **exceptionStorage,
957 llvm::Value **caughtResultStorage) {
958 assert(exceptionCaughtFlag &&
959 "ExceptionDemo::createFinallyBlock(...):exceptionCaughtFlag "
960 "is NULL");
961 assert(exceptionStorage &&
962 "ExceptionDemo::createFinallyBlock(...):exceptionStorage "
963 "is NULL");
964 assert(caughtResultStorage &&
965 "ExceptionDemo::createFinallyBlock(...):caughtResultStorage "
966 "is NULL");
968 *exceptionCaughtFlag = createEntryBlockAlloca(toAddTo,
969 "exceptionCaught",
970 ourExceptionNotThrownState->getType(),
971 ourExceptionNotThrownState);
973 llvm::PointerType *exceptionStorageType = builder.getInt8PtrTy();
974 *exceptionStorage = createEntryBlockAlloca(toAddTo,
975 "exceptionStorage",
976 exceptionStorageType,
977 llvm::ConstantPointerNull::get(
978 exceptionStorageType));
979 *caughtResultStorage = createEntryBlockAlloca(toAddTo,
980 "caughtResultStorage",
981 ourCaughtResultType,
982 llvm::ConstantAggregateZero::get(
983 ourCaughtResultType));
985 llvm::BasicBlock *ret = llvm::BasicBlock::Create(context,
986 blockName,
987 &toAddTo);
989 builder.SetInsertPoint(ret);
991 std::ostringstream bufferToPrint;
992 bufferToPrint << "Gen: Executing finally block "
993 << blockName << " in " << functionId << "\n";
994 generateStringPrint(context,
995 module,
996 builder,
997 bufferToPrint.str(),
998 USE_GLOBAL_STR_CONSTS);
1000 llvm::SwitchInst *theSwitch = builder.CreateSwitch(builder.CreateLoad(
1001 *exceptionCaughtFlag),
1002 &terminatorBlock,
1004 theSwitch->addCase(ourExceptionCaughtState, &terminatorBlock);
1005 theSwitch->addCase(ourExceptionThrownState, &unwindResumeBlock);
1007 return(ret);
1011 /// Generates catch block semantics which print a string to indicate type of
1012 /// catch executed, sets an exception caught flag, and executes passed in
1013 /// end block (terminator block).
1014 /// @param context llvm context
1015 /// @param module code for module instance
1016 /// @param builder builder instance
1017 /// @param toAddTo parent function to add block to
1018 /// @param blockName block name of new "catch" block.
1019 /// @param functionId output id used for printing
1020 /// @param terminatorBlock terminator "end" block
1021 /// @param exceptionCaughtFlag exception caught/thrown status
1022 /// @returns newly created block
1023 static llvm::BasicBlock *createCatchBlock(llvm::LLVMContext &context,
1024 llvm::Module &module,
1025 llvm::IRBuilder<> &builder,
1026 llvm::Function &toAddTo,
1027 std::string &blockName,
1028 std::string &functionId,
1029 llvm::BasicBlock &terminatorBlock,
1030 llvm::Value &exceptionCaughtFlag) {
1032 llvm::BasicBlock *ret = llvm::BasicBlock::Create(context,
1033 blockName,
1034 &toAddTo);
1036 builder.SetInsertPoint(ret);
1038 std::ostringstream bufferToPrint;
1039 bufferToPrint << "Gen: Executing catch block "
1040 << blockName
1041 << " in "
1042 << functionId
1043 << std::endl;
1044 generateStringPrint(context,
1045 module,
1046 builder,
1047 bufferToPrint.str(),
1048 USE_GLOBAL_STR_CONSTS);
1049 builder.CreateStore(ourExceptionCaughtState, &exceptionCaughtFlag);
1050 builder.CreateBr(&terminatorBlock);
1052 return(ret);
1056 /// Generates a function which invokes a function (toInvoke) and, whose
1057 /// unwind block will "catch" the type info types correspondingly held in the
1058 /// exceptionTypesToCatch argument. If the toInvoke function throws an
1059 /// exception which does not match any type info types contained in
1060 /// exceptionTypesToCatch, the generated code will call _Unwind_Resume
1061 /// with the raised exception. On the other hand the generated code will
1062 /// normally exit if the toInvoke function does not throw an exception.
1063 /// The generated "finally" block is always run regardless of the cause of
1064 /// the generated function exit.
1065 /// The generated function is returned after being verified.
1066 /// @param module code for module instance
1067 /// @param builder builder instance
1068 /// @param fpm a function pass manager holding optional IR to IR
1069 /// transformations
1070 /// @param toInvoke inner function to invoke
1071 /// @param ourId id used to printing purposes
1072 /// @param numExceptionsToCatch length of exceptionTypesToCatch array
1073 /// @param exceptionTypesToCatch array of type info types to "catch"
1074 /// @returns generated function
1075 static llvm::Function *createCatchWrappedInvokeFunction(
1076 llvm::Module &module, llvm::IRBuilder<> &builder,
1077 llvm::legacy::FunctionPassManager &fpm, llvm::Function &toInvoke,
1078 std::string ourId, unsigned numExceptionsToCatch,
1079 unsigned exceptionTypesToCatch[]) {
1081 llvm::LLVMContext &context = module.getContext();
1082 llvm::Function *toPrint32Int = module.getFunction("print32Int");
1084 ArgTypes argTypes;
1085 argTypes.push_back(builder.getInt32Ty());
1087 ArgNames argNames;
1088 argNames.push_back("exceptTypeToThrow");
1090 llvm::Function *ret = createFunction(module,
1091 builder.getVoidTy(),
1092 argTypes,
1093 argNames,
1094 ourId,
1095 llvm::Function::ExternalLinkage,
1096 false,
1097 false);
1099 // Block which calls invoke
1100 llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(context,
1101 "entry",
1102 ret);
1103 // Normal block for invoke
1104 llvm::BasicBlock *normalBlock = llvm::BasicBlock::Create(context,
1105 "normal",
1106 ret);
1107 // Unwind block for invoke
1108 llvm::BasicBlock *exceptionBlock = llvm::BasicBlock::Create(context,
1109 "exception",
1110 ret);
1112 // Block which routes exception to correct catch handler block
1113 llvm::BasicBlock *exceptionRouteBlock = llvm::BasicBlock::Create(context,
1114 "exceptionRoute",
1115 ret);
1117 // Foreign exception handler
1118 llvm::BasicBlock *externalExceptionBlock = llvm::BasicBlock::Create(context,
1119 "externalException",
1120 ret);
1122 // Block which calls _Unwind_Resume
1123 llvm::BasicBlock *unwindResumeBlock = llvm::BasicBlock::Create(context,
1124 "unwindResume",
1125 ret);
1127 // Clean up block which delete exception if needed
1128 llvm::BasicBlock *endBlock = llvm::BasicBlock::Create(context, "end", ret);
1130 std::string nextName;
1131 std::vector<llvm::BasicBlock*> catchBlocks(numExceptionsToCatch);
1132 llvm::Value *exceptionCaughtFlag = NULL;
1133 llvm::Value *exceptionStorage = NULL;
1134 llvm::Value *caughtResultStorage = NULL;
1136 // Finally block which will branch to unwindResumeBlock if
1137 // exception is not caught. Initializes/allocates stack locations.
1138 llvm::BasicBlock *finallyBlock = createFinallyBlock(context,
1139 module,
1140 builder,
1141 *ret,
1142 nextName = "finally",
1143 ourId,
1144 *endBlock,
1145 *unwindResumeBlock,
1146 &exceptionCaughtFlag,
1147 &exceptionStorage,
1148 &caughtResultStorage
1151 for (unsigned i = 0; i < numExceptionsToCatch; ++i) {
1152 nextName = ourTypeInfoNames[exceptionTypesToCatch[i]];
1154 // One catch block per type info to be caught
1155 catchBlocks[i] = createCatchBlock(context,
1156 module,
1157 builder,
1158 *ret,
1159 nextName,
1160 ourId,
1161 *finallyBlock,
1162 *exceptionCaughtFlag);
1165 // Entry Block
1167 builder.SetInsertPoint(entryBlock);
1169 std::vector<llvm::Value*> args;
1170 args.push_back(namedValues["exceptTypeToThrow"]);
1171 builder.CreateInvoke(&toInvoke,
1172 normalBlock,
1173 exceptionBlock,
1174 args);
1176 // End Block
1178 builder.SetInsertPoint(endBlock);
1180 generateStringPrint(context,
1181 module,
1182 builder,
1183 "Gen: In end block: exiting in " + ourId + ".\n",
1184 USE_GLOBAL_STR_CONSTS);
1185 llvm::Function *deleteOurException = module.getFunction("deleteOurException");
1187 // Note: function handles NULL exceptions
1188 builder.CreateCall(deleteOurException,
1189 builder.CreateLoad(exceptionStorage));
1190 builder.CreateRetVoid();
1192 // Normal Block
1194 builder.SetInsertPoint(normalBlock);
1196 generateStringPrint(context,
1197 module,
1198 builder,
1199 "Gen: No exception in " + ourId + "!\n",
1200 USE_GLOBAL_STR_CONSTS);
1202 // Finally block is always called
1203 builder.CreateBr(finallyBlock);
1205 // Unwind Resume Block
1207 builder.SetInsertPoint(unwindResumeBlock);
1209 builder.CreateResume(builder.CreateLoad(caughtResultStorage));
1211 // Exception Block
1213 builder.SetInsertPoint(exceptionBlock);
1215 llvm::Function *personality = module.getFunction("ourPersonality");
1216 ret->setPersonalityFn(personality);
1218 llvm::LandingPadInst *caughtResult =
1219 builder.CreateLandingPad(ourCaughtResultType,
1220 numExceptionsToCatch,
1221 "landingPad");
1223 caughtResult->setCleanup(true);
1225 for (unsigned i = 0; i < numExceptionsToCatch; ++i) {
1226 // Set up type infos to be caught
1227 caughtResult->addClause(module.getGlobalVariable(
1228 ourTypeInfoNames[exceptionTypesToCatch[i]]));
1231 llvm::Value *unwindException = builder.CreateExtractValue(caughtResult, 0);
1232 llvm::Value *retTypeInfoIndex = builder.CreateExtractValue(caughtResult, 1);
1234 // FIXME: Redundant storage which, beyond utilizing value of
1235 // caughtResultStore for unwindException storage, may be alleviated
1236 // altogether with a block rearrangement
1237 builder.CreateStore(caughtResult, caughtResultStorage);
1238 builder.CreateStore(unwindException, exceptionStorage);
1239 builder.CreateStore(ourExceptionThrownState, exceptionCaughtFlag);
1241 // Retrieve exception_class member from thrown exception
1242 // (_Unwind_Exception instance). This member tells us whether or not
1243 // the exception is foreign.
1244 llvm::Value *unwindExceptionClass =
1245 builder.CreateLoad(builder.CreateStructGEP(
1246 ourUnwindExceptionType,
1247 builder.CreatePointerCast(unwindException,
1248 ourUnwindExceptionType->getPointerTo()),
1249 0));
1251 // Branch to the externalExceptionBlock if the exception is foreign or
1252 // to a catch router if not. Either way the finally block will be run.
1253 builder.CreateCondBr(builder.CreateICmpEQ(unwindExceptionClass,
1254 llvm::ConstantInt::get(builder.getInt64Ty(),
1255 ourBaseExceptionClass)),
1256 exceptionRouteBlock,
1257 externalExceptionBlock);
1259 // External Exception Block
1261 builder.SetInsertPoint(externalExceptionBlock);
1263 generateStringPrint(context,
1264 module,
1265 builder,
1266 "Gen: Foreign exception received.\n",
1267 USE_GLOBAL_STR_CONSTS);
1269 // Branch to the finally block
1270 builder.CreateBr(finallyBlock);
1272 // Exception Route Block
1274 builder.SetInsertPoint(exceptionRouteBlock);
1276 // Casts exception pointer (_Unwind_Exception instance) to parent
1277 // (OurException instance).
1279 // Note: ourBaseFromUnwindOffset is usually negative
1280 llvm::Value *typeInfoThrown = builder.CreatePointerCast(
1281 builder.CreateConstGEP1_64(unwindException,
1282 ourBaseFromUnwindOffset),
1283 ourExceptionType->getPointerTo());
1285 // Retrieve thrown exception type info type
1287 // Note: Index is not relative to pointer but instead to structure
1288 // unlike a true getelementptr (GEP) instruction
1289 typeInfoThrown = builder.CreateStructGEP(ourExceptionType, typeInfoThrown, 0);
1291 llvm::Value *typeInfoThrownType =
1292 builder.CreateStructGEP(builder.getInt8PtrTy(), typeInfoThrown, 0);
1294 generateIntegerPrint(context,
1295 module,
1296 builder,
1297 *toPrint32Int,
1298 *(builder.CreateLoad(typeInfoThrownType)),
1299 "Gen: Exception type <%d> received (stack unwound) "
1300 " in " +
1301 ourId +
1302 ".\n",
1303 USE_GLOBAL_STR_CONSTS);
1305 // Route to matched type info catch block or run cleanup finally block
1306 llvm::SwitchInst *switchToCatchBlock = builder.CreateSwitch(retTypeInfoIndex,
1307 finallyBlock,
1308 numExceptionsToCatch);
1310 unsigned nextTypeToCatch;
1312 for (unsigned i = 1; i <= numExceptionsToCatch; ++i) {
1313 nextTypeToCatch = i - 1;
1314 switchToCatchBlock->addCase(llvm::ConstantInt::get(
1315 llvm::Type::getInt32Ty(context), i),
1316 catchBlocks[nextTypeToCatch]);
1319 llvm::verifyFunction(*ret);
1320 fpm.run(*ret);
1322 return(ret);
1326 /// Generates function which throws either an exception matched to a runtime
1327 /// determined type info type (argument to generated function), or if this
1328 /// runtime value matches nativeThrowType, throws a foreign exception by
1329 /// calling nativeThrowFunct.
1330 /// @param module code for module instance
1331 /// @param builder builder instance
1332 /// @param fpm a function pass manager holding optional IR to IR
1333 /// transformations
1334 /// @param ourId id used to printing purposes
1335 /// @param nativeThrowType a runtime argument of this value results in
1336 /// nativeThrowFunct being called to generate/throw exception.
1337 /// @param nativeThrowFunct function which will throw a foreign exception
1338 /// if the above nativeThrowType matches generated function's arg.
1339 /// @returns generated function
1340 static llvm::Function *
1341 createThrowExceptionFunction(llvm::Module &module, llvm::IRBuilder<> &builder,
1342 llvm::legacy::FunctionPassManager &fpm,
1343 std::string ourId, int32_t nativeThrowType,
1344 llvm::Function &nativeThrowFunct) {
1345 llvm::LLVMContext &context = module.getContext();
1346 namedValues.clear();
1347 ArgTypes unwindArgTypes;
1348 unwindArgTypes.push_back(builder.getInt32Ty());
1349 ArgNames unwindArgNames;
1350 unwindArgNames.push_back("exceptTypeToThrow");
1352 llvm::Function *ret = createFunction(module,
1353 builder.getVoidTy(),
1354 unwindArgTypes,
1355 unwindArgNames,
1356 ourId,
1357 llvm::Function::ExternalLinkage,
1358 false,
1359 false);
1361 // Throws either one of our exception or a native C++ exception depending
1362 // on a runtime argument value containing a type info type.
1363 llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(context,
1364 "entry",
1365 ret);
1366 // Throws a foreign exception
1367 llvm::BasicBlock *nativeThrowBlock = llvm::BasicBlock::Create(context,
1368 "nativeThrow",
1369 ret);
1370 // Throws one of our Exceptions
1371 llvm::BasicBlock *generatedThrowBlock = llvm::BasicBlock::Create(context,
1372 "generatedThrow",
1373 ret);
1374 // Retrieved runtime type info type to throw
1375 llvm::Value *exceptionType = namedValues["exceptTypeToThrow"];
1377 // nativeThrowBlock block
1379 builder.SetInsertPoint(nativeThrowBlock);
1381 // Throws foreign exception
1382 builder.CreateCall(&nativeThrowFunct, exceptionType);
1383 builder.CreateUnreachable();
1385 // entry block
1387 builder.SetInsertPoint(entryBlock);
1389 llvm::Function *toPrint32Int = module.getFunction("print32Int");
1390 generateIntegerPrint(context,
1391 module,
1392 builder,
1393 *toPrint32Int,
1394 *exceptionType,
1395 "\nGen: About to throw exception type <%d> in " +
1396 ourId +
1397 ".\n",
1398 USE_GLOBAL_STR_CONSTS);
1400 // Switches on runtime type info type value to determine whether or not
1401 // a foreign exception is thrown. Defaults to throwing one of our
1402 // generated exceptions.
1403 llvm::SwitchInst *theSwitch = builder.CreateSwitch(exceptionType,
1404 generatedThrowBlock,
1407 theSwitch->addCase(llvm::ConstantInt::get(llvm::Type::getInt32Ty(context),
1408 nativeThrowType),
1409 nativeThrowBlock);
1411 // generatedThrow block
1413 builder.SetInsertPoint(generatedThrowBlock);
1415 llvm::Function *createOurException = module.getFunction("createOurException");
1416 llvm::Function *raiseOurException = module.getFunction(
1417 "_Unwind_RaiseException");
1419 // Creates exception to throw with runtime type info type.
1420 llvm::Value *exception = builder.CreateCall(createOurException,
1421 namedValues["exceptTypeToThrow"]);
1423 // Throw generated Exception
1424 builder.CreateCall(raiseOurException, exception);
1425 builder.CreateUnreachable();
1427 llvm::verifyFunction(*ret);
1428 fpm.run(*ret);
1430 return(ret);
1433 static void createStandardUtilityFunctions(unsigned numTypeInfos,
1434 llvm::Module &module,
1435 llvm::IRBuilder<> &builder);
1437 /// Creates test code by generating and organizing these functions into the
1438 /// test case. The test case consists of an outer function setup to invoke
1439 /// an inner function within an environment having multiple catch and single
1440 /// finally blocks. This inner function is also setup to invoke a throw
1441 /// function within an evironment similar in nature to the outer function's
1442 /// catch and finally blocks. Each of these two functions catch mutually
1443 /// exclusive subsets (even or odd) of the type info types configured
1444 /// for this this. All generated functions have a runtime argument which
1445 /// holds a type info type to throw that each function takes and passes it
1446 /// to the inner one if such a inner function exists. This type info type is
1447 /// looked at by the generated throw function to see whether or not it should
1448 /// throw a generated exception with the same type info type, or instead call
1449 /// a supplied a function which in turn will throw a foreign exception.
1450 /// @param module code for module instance
1451 /// @param builder builder instance
1452 /// @param fpm a function pass manager holding optional IR to IR
1453 /// transformations
1454 /// @param nativeThrowFunctName name of external function which will throw
1455 /// a foreign exception
1456 /// @returns outermost generated test function.
1457 llvm::Function *
1458 createUnwindExceptionTest(llvm::Module &module, llvm::IRBuilder<> &builder,
1459 llvm::legacy::FunctionPassManager &fpm,
1460 std::string nativeThrowFunctName) {
1461 // Number of type infos to generate
1462 unsigned numTypeInfos = 6;
1464 // Initialze intrisics and external functions to use along with exception
1465 // and type info globals.
1466 createStandardUtilityFunctions(numTypeInfos,
1467 module,
1468 builder);
1469 llvm::Function *nativeThrowFunct = module.getFunction(nativeThrowFunctName);
1471 // Create exception throw function using the value ~0 to cause
1472 // foreign exceptions to be thrown.
1473 llvm::Function *throwFunct = createThrowExceptionFunction(module,
1474 builder,
1475 fpm,
1476 "throwFunct",
1478 *nativeThrowFunct);
1479 // Inner function will catch even type infos
1480 unsigned innerExceptionTypesToCatch[] = {6, 2, 4};
1481 size_t numExceptionTypesToCatch = sizeof(innerExceptionTypesToCatch) /
1482 sizeof(unsigned);
1484 // Generate inner function.
1485 llvm::Function *innerCatchFunct = createCatchWrappedInvokeFunction(module,
1486 builder,
1487 fpm,
1488 *throwFunct,
1489 "innerCatchFunct",
1490 numExceptionTypesToCatch,
1491 innerExceptionTypesToCatch);
1493 // Outer function will catch odd type infos
1494 unsigned outerExceptionTypesToCatch[] = {3, 1, 5};
1495 numExceptionTypesToCatch = sizeof(outerExceptionTypesToCatch) /
1496 sizeof(unsigned);
1498 // Generate outer function
1499 llvm::Function *outerCatchFunct = createCatchWrappedInvokeFunction(module,
1500 builder,
1501 fpm,
1502 *innerCatchFunct,
1503 "outerCatchFunct",
1504 numExceptionTypesToCatch,
1505 outerExceptionTypesToCatch);
1507 // Return outer function to run
1508 return(outerCatchFunct);
1511 namespace {
1512 /// Represents our foreign exceptions
1513 class OurCppRunException : public std::runtime_error {
1514 public:
1515 OurCppRunException(const std::string reason) :
1516 std::runtime_error(reason) {}
1518 OurCppRunException (const OurCppRunException &toCopy) :
1519 std::runtime_error(toCopy) {}
1521 OurCppRunException &operator = (const OurCppRunException &toCopy) {
1522 return(reinterpret_cast<OurCppRunException&>(
1523 std::runtime_error::operator=(toCopy)));
1526 ~OurCppRunException(void) throw() override {}
1528 } // end anonymous namespace
1530 /// Throws foreign C++ exception.
1531 /// @param ignoreIt unused parameter that allows function to match implied
1532 /// generated function contract.
1533 extern "C"
1534 void throwCppException (int32_t ignoreIt) {
1535 throw(OurCppRunException("thrown by throwCppException(...)"));
1538 typedef void (*OurExceptionThrowFunctType) (int32_t typeToThrow);
1540 /// This is a test harness which runs test by executing generated
1541 /// function with a type info type to throw. Harness wraps the execution
1542 /// of generated function in a C++ try catch clause.
1543 /// @param engine execution engine to use for executing generated function.
1544 /// This demo program expects this to be a JIT instance for demo
1545 /// purposes.
1546 /// @param function generated test function to run
1547 /// @param typeToThrow type info type of generated exception to throw, or
1548 /// indicator to cause foreign exception to be thrown.
1549 static
1550 void runExceptionThrow(llvm::ExecutionEngine *engine,
1551 llvm::Function *function,
1552 int32_t typeToThrow) {
1554 // Find test's function pointer
1555 OurExceptionThrowFunctType functPtr =
1556 reinterpret_cast<OurExceptionThrowFunctType>(
1557 reinterpret_cast<intptr_t>(engine->getPointerToFunction(function)));
1559 try {
1560 // Run test
1561 (*functPtr)(typeToThrow);
1563 catch (OurCppRunException exc) {
1564 // Catch foreign C++ exception
1565 fprintf(stderr,
1566 "\nrunExceptionThrow(...):In C++ catch OurCppRunException "
1567 "with reason: %s.\n",
1568 exc.what());
1570 catch (...) {
1571 // Catch all exceptions including our generated ones. This latter
1572 // functionality works according to the example in rules 1.6.4 of
1573 // http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html (v1.22),
1574 // given that these will be exceptions foreign to C++
1575 // (the _Unwind_Exception::exception_class should be different from
1576 // the one used by C++).
1577 fprintf(stderr,
1578 "\nrunExceptionThrow(...):In C++ catch all.\n");
1583 // End test functions
1586 typedef llvm::ArrayRef<llvm::Type*> TypeArray;
1588 /// This initialization routine creates type info globals and
1589 /// adds external function declarations to module.
1590 /// @param numTypeInfos number of linear type info associated type info types
1591 /// to create as GlobalVariable instances, starting with the value 1.
1592 /// @param module code for module instance
1593 /// @param builder builder instance
1594 static void createStandardUtilityFunctions(unsigned numTypeInfos,
1595 llvm::Module &module,
1596 llvm::IRBuilder<> &builder) {
1598 llvm::LLVMContext &context = module.getContext();
1600 // Exception initializations
1602 // Setup exception catch state
1603 ourExceptionNotThrownState =
1604 llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 0),
1605 ourExceptionThrownState =
1606 llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 1),
1607 ourExceptionCaughtState =
1608 llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 2),
1612 // Create our type info type
1613 ourTypeInfoType = llvm::StructType::get(context,
1614 TypeArray(builder.getInt32Ty()));
1616 llvm::Type *caughtResultFieldTypes[] = {
1617 builder.getInt8PtrTy(),
1618 builder.getInt32Ty()
1621 // Create our landingpad result type
1622 ourCaughtResultType = llvm::StructType::get(context,
1623 TypeArray(caughtResultFieldTypes));
1625 // Create OurException type
1626 ourExceptionType = llvm::StructType::get(context,
1627 TypeArray(ourTypeInfoType));
1629 // Create portion of _Unwind_Exception type
1631 // Note: Declaring only a portion of the _Unwind_Exception struct.
1632 // Does this cause problems?
1633 ourUnwindExceptionType =
1634 llvm::StructType::get(context,
1635 TypeArray(builder.getInt64Ty()));
1637 struct OurBaseException_t dummyException;
1639 // Calculate offset of OurException::unwindException member.
1640 ourBaseFromUnwindOffset = ((uintptr_t) &dummyException) -
1641 ((uintptr_t) &(dummyException.unwindException));
1643 #ifdef DEBUG
1644 fprintf(stderr,
1645 "createStandardUtilityFunctions(...):ourBaseFromUnwindOffset "
1646 "= %" PRIi64 ", sizeof(struct OurBaseException_t) - "
1647 "sizeof(struct _Unwind_Exception) = %lu.\n",
1648 ourBaseFromUnwindOffset,
1649 sizeof(struct OurBaseException_t) -
1650 sizeof(struct _Unwind_Exception));
1651 #endif
1653 size_t numChars = sizeof(ourBaseExcpClassChars) / sizeof(char);
1655 // Create our _Unwind_Exception::exception_class value
1656 ourBaseExceptionClass = genClass(ourBaseExcpClassChars, numChars);
1658 // Type infos
1660 std::string baseStr = "typeInfo", typeInfoName;
1661 std::ostringstream typeInfoNameBuilder;
1662 std::vector<llvm::Constant*> structVals;
1664 llvm::Constant *nextStruct;
1666 // Generate each type info
1668 // Note: First type info is not used.
1669 for (unsigned i = 0; i <= numTypeInfos; ++i) {
1670 structVals.clear();
1671 structVals.push_back(llvm::ConstantInt::get(builder.getInt32Ty(), i));
1672 nextStruct = llvm::ConstantStruct::get(ourTypeInfoType, structVals);
1674 typeInfoNameBuilder.str("");
1675 typeInfoNameBuilder << baseStr << i;
1676 typeInfoName = typeInfoNameBuilder.str();
1678 // Note: Does not seem to work without allocation
1679 new llvm::GlobalVariable(module,
1680 ourTypeInfoType,
1681 true,
1682 llvm::GlobalValue::ExternalLinkage,
1683 nextStruct,
1684 typeInfoName);
1686 ourTypeInfoNames.push_back(typeInfoName);
1687 ourTypeInfoNamesIndex[i] = typeInfoName;
1690 ArgNames argNames;
1691 ArgTypes argTypes;
1692 llvm::Function *funct = NULL;
1694 // print32Int
1696 llvm::Type *retType = builder.getVoidTy();
1698 argTypes.clear();
1699 argTypes.push_back(builder.getInt32Ty());
1700 argTypes.push_back(builder.getInt8PtrTy());
1702 argNames.clear();
1704 createFunction(module,
1705 retType,
1706 argTypes,
1707 argNames,
1708 "print32Int",
1709 llvm::Function::ExternalLinkage,
1710 true,
1711 false);
1713 // print64Int
1715 retType = builder.getVoidTy();
1717 argTypes.clear();
1718 argTypes.push_back(builder.getInt64Ty());
1719 argTypes.push_back(builder.getInt8PtrTy());
1721 argNames.clear();
1723 createFunction(module,
1724 retType,
1725 argTypes,
1726 argNames,
1727 "print64Int",
1728 llvm::Function::ExternalLinkage,
1729 true,
1730 false);
1732 // printStr
1734 retType = builder.getVoidTy();
1736 argTypes.clear();
1737 argTypes.push_back(builder.getInt8PtrTy());
1739 argNames.clear();
1741 createFunction(module,
1742 retType,
1743 argTypes,
1744 argNames,
1745 "printStr",
1746 llvm::Function::ExternalLinkage,
1747 true,
1748 false);
1750 // throwCppException
1752 retType = builder.getVoidTy();
1754 argTypes.clear();
1755 argTypes.push_back(builder.getInt32Ty());
1757 argNames.clear();
1759 createFunction(module,
1760 retType,
1761 argTypes,
1762 argNames,
1763 "throwCppException",
1764 llvm::Function::ExternalLinkage,
1765 true,
1766 false);
1768 // deleteOurException
1770 retType = builder.getVoidTy();
1772 argTypes.clear();
1773 argTypes.push_back(builder.getInt8PtrTy());
1775 argNames.clear();
1777 createFunction(module,
1778 retType,
1779 argTypes,
1780 argNames,
1781 "deleteOurException",
1782 llvm::Function::ExternalLinkage,
1783 true,
1784 false);
1786 // createOurException
1788 retType = builder.getInt8PtrTy();
1790 argTypes.clear();
1791 argTypes.push_back(builder.getInt32Ty());
1793 argNames.clear();
1795 createFunction(module,
1796 retType,
1797 argTypes,
1798 argNames,
1799 "createOurException",
1800 llvm::Function::ExternalLinkage,
1801 true,
1802 false);
1804 // _Unwind_RaiseException
1806 retType = builder.getInt32Ty();
1808 argTypes.clear();
1809 argTypes.push_back(builder.getInt8PtrTy());
1811 argNames.clear();
1813 funct = createFunction(module,
1814 retType,
1815 argTypes,
1816 argNames,
1817 "_Unwind_RaiseException",
1818 llvm::Function::ExternalLinkage,
1819 true,
1820 false);
1822 funct->setDoesNotReturn();
1824 // _Unwind_Resume
1826 retType = builder.getInt32Ty();
1828 argTypes.clear();
1829 argTypes.push_back(builder.getInt8PtrTy());
1831 argNames.clear();
1833 funct = createFunction(module,
1834 retType,
1835 argTypes,
1836 argNames,
1837 "_Unwind_Resume",
1838 llvm::Function::ExternalLinkage,
1839 true,
1840 false);
1842 funct->setDoesNotReturn();
1844 // ourPersonality
1846 retType = builder.getInt32Ty();
1848 argTypes.clear();
1849 argTypes.push_back(builder.getInt32Ty());
1850 argTypes.push_back(builder.getInt32Ty());
1851 argTypes.push_back(builder.getInt64Ty());
1852 argTypes.push_back(builder.getInt8PtrTy());
1853 argTypes.push_back(builder.getInt8PtrTy());
1855 argNames.clear();
1857 createFunction(module,
1858 retType,
1859 argTypes,
1860 argNames,
1861 "ourPersonality",
1862 llvm::Function::ExternalLinkage,
1863 true,
1864 false);
1866 // llvm.eh.typeid.for intrinsic
1868 getDeclaration(&module, llvm::Intrinsic::eh_typeid_for);
1872 //===----------------------------------------------------------------------===//
1873 // Main test driver code.
1874 //===----------------------------------------------------------------------===//
1876 /// Demo main routine which takes the type info types to throw. A test will
1877 /// be run for each given type info type. While type info types with the value
1878 /// of -1 will trigger a foreign C++ exception to be thrown; type info types
1879 /// <= 6 and >= 1 will be caught by test functions; and type info types > 6
1880 /// will result in exceptions which pass through to the test harness. All other
1881 /// type info types are not supported and could cause a crash.
1882 int main(int argc, char *argv[]) {
1883 if (argc == 1) {
1884 fprintf(stderr,
1885 "\nUsage: ExceptionDemo <exception type to throw> "
1886 "[<type 2>...<type n>].\n"
1887 " Each type must have the value of 1 - 6 for "
1888 "generated exceptions to be caught;\n"
1889 " the value -1 for foreign C++ exceptions to be "
1890 "generated and thrown;\n"
1891 " or the values > 6 for exceptions to be ignored.\n"
1892 "\nTry: ExceptionDemo 2 3 7 -1\n"
1893 " for a full test.\n\n");
1894 return(0);
1897 // If not set, exception handling will not be turned on
1898 llvm::TargetOptions Opts;
1900 llvm::InitializeNativeTarget();
1901 llvm::InitializeNativeTargetAsmPrinter();
1902 llvm::LLVMContext Context;
1903 llvm::IRBuilder<> theBuilder(Context);
1905 // Make the module, which holds all the code.
1906 std::unique_ptr<llvm::Module> Owner =
1907 llvm::make_unique<llvm::Module>("my cool jit", Context);
1908 llvm::Module *module = Owner.get();
1910 std::unique_ptr<llvm::RTDyldMemoryManager> MemMgr(new llvm::SectionMemoryManager());
1912 // Build engine with JIT
1913 llvm::EngineBuilder factory(std::move(Owner));
1914 factory.setEngineKind(llvm::EngineKind::JIT);
1915 factory.setTargetOptions(Opts);
1916 factory.setMCJITMemoryManager(std::move(MemMgr));
1917 llvm::ExecutionEngine *executionEngine = factory.create();
1920 llvm::legacy::FunctionPassManager fpm(module);
1922 // Set up the optimizer pipeline.
1923 // Start with registering info about how the
1924 // target lays out data structures.
1925 module->setDataLayout(executionEngine->getDataLayout());
1927 // Optimizations turned on
1928 #ifdef ADD_OPT_PASSES
1930 // Basic AliasAnslysis support for GVN.
1931 fpm.add(llvm::createBasicAliasAnalysisPass());
1933 // Promote allocas to registers.
1934 fpm.add(llvm::createPromoteMemoryToRegisterPass());
1936 // Do simple "peephole" optimizations and bit-twiddling optzns.
1937 fpm.add(llvm::createInstructionCombiningPass());
1939 // Reassociate expressions.
1940 fpm.add(llvm::createReassociatePass());
1942 // Eliminate Common SubExpressions.
1943 fpm.add(llvm::createGVNPass());
1945 // Simplify the control flow graph (deleting unreachable
1946 // blocks, etc).
1947 fpm.add(llvm::createCFGSimplificationPass());
1948 #endif // ADD_OPT_PASSES
1950 fpm.doInitialization();
1952 // Generate test code using function throwCppException(...) as
1953 // the function which throws foreign exceptions.
1954 llvm::Function *toRun =
1955 createUnwindExceptionTest(*module,
1956 theBuilder,
1957 fpm,
1958 "throwCppException");
1960 executionEngine->finalizeObject();
1962 fprintf(stderr, "\nBegin module dump:\n\n");
1964 module->dump();
1966 fprintf(stderr, "\nEnd module dump:\n");
1968 fprintf(stderr, "\n\nBegin Test:\n");
1970 for (int i = 1; i < argc; ++i) {
1971 // Run test for each argument whose value is the exception
1972 // type to throw.
1973 runExceptionThrow(executionEngine,
1974 toRun,
1975 (unsigned) strtoul(argv[i], NULL, 10));
1978 fprintf(stderr, "\nEnd Test:\n\n");
1981 delete executionEngine;
1983 return 0;