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