xref: /llvm-project/llvm/examples/ExceptionDemo/ExceptionDemo.cpp (revision 847acbbc529133b2300721a809751891200f37f5)
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 /// Generates code to print given runtime integer according to constant
887 /// string format, and a given print function.
888 /// @param context llvm context
889 /// @param module code for module instance
890 /// @param builder builder instance
891 /// @param printFunct function used to "print" integer
892 /// @param toPrint string to print
893 /// @param format printf like formatting string for print
894 /// @param useGlobal A value of true (default) indicates a GlobalValue is
895 ///        generated, and is used to hold the constant string. A value of
896 ///        false indicates that the constant string will be stored on the
897 ///        stack.
898 void generateIntegerPrint(llvm::LLVMContext &context, llvm::Module &module,
899                           llvm::IRBuilder<> &builder,
900                           llvm::Function &printFunct, llvm::Value *toPrint,
901                           std::string format, bool useGlobal = true) {
902   llvm::Constant *stringConstant =
903     llvm::ConstantDataArray::getString(context, format);
904   llvm::Value *stringVar;
905 
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                              "");
915   }
916   else {
917     stringVar = builder.CreateAlloca(stringConstant->getType());
918     builder.CreateStore(stringConstant, stringVar);
919   }
920 
921   llvm::Value *cast = builder.CreateBitCast(stringVar,
922                                             builder.getPtrTy());
923   builder.CreateCall(&printFunct, {toPrint, cast});
924 }
925 
926 /// Generates code to handle finally block type semantics: always runs
927 /// regardless of whether a thrown exception is passing through or the
928 /// parent function is simply exiting. In addition to printing some state
929 /// to stderr, this code will resume the exception handling--runs the
930 /// unwind resume block, if the exception has not been previously caught
931 /// by a catch clause, and will otherwise execute the end block (terminator
932 /// block). In addition this function creates the corresponding function's
933 /// stack storage for the exception pointer and catch flag status.
934 /// @param context llvm context
935 /// @param module code for module instance
936 /// @param builder builder instance
937 /// @param toAddTo parent function to add block to
938 /// @param blockName block name of new "finally" block.
939 /// @param functionId output id used for printing
940 /// @param terminatorBlock terminator "end" block
941 /// @param unwindResumeBlock unwind resume block
942 /// @param exceptionCaughtFlag reference exception caught/thrown status storage
943 /// @param exceptionStorage reference to exception pointer storage
944 /// @param caughtResultStorage reference to landingpad result storage
945 /// @returns newly created block
946 static llvm::BasicBlock *createFinallyBlock(llvm::LLVMContext &context,
947                                             llvm::Module &module,
948                                             llvm::IRBuilder<> &builder,
949                                             llvm::Function &toAddTo,
950                                             std::string &blockName,
951                                             std::string &functionId,
952                                             llvm::BasicBlock &terminatorBlock,
953                                             llvm::BasicBlock &unwindResumeBlock,
954                                             llvm::Value **exceptionCaughtFlag,
955                                             llvm::Value **exceptionStorage,
956                                             llvm::Value **caughtResultStorage) {
957   assert(exceptionCaughtFlag &&
958          "ExceptionDemo::createFinallyBlock(...):exceptionCaughtFlag "
959          "is NULL");
960   assert(exceptionStorage &&
961          "ExceptionDemo::createFinallyBlock(...):exceptionStorage "
962          "is NULL");
963   assert(caughtResultStorage &&
964          "ExceptionDemo::createFinallyBlock(...):caughtResultStorage "
965          "is NULL");
966 
967   *exceptionCaughtFlag = createEntryBlockAlloca(toAddTo,
968                                          "exceptionCaught",
969                                          ourExceptionNotThrownState->getType(),
970                                          ourExceptionNotThrownState);
971 
972   llvm::PointerType *exceptionStorageType = builder.getPtrTy();
973   *exceptionStorage = createEntryBlockAlloca(toAddTo,
974                                              "exceptionStorage",
975                                              exceptionStorageType,
976                                              llvm::ConstantPointerNull::get(
977                                                exceptionStorageType));
978   *caughtResultStorage = createEntryBlockAlloca(toAddTo,
979                                               "caughtResultStorage",
980                                               ourCaughtResultType,
981                                               llvm::ConstantAggregateZero::get(
982                                                 ourCaughtResultType));
983 
984   llvm::BasicBlock *ret = llvm::BasicBlock::Create(context,
985                                                    blockName,
986                                                    &toAddTo);
987 
988   builder.SetInsertPoint(ret);
989 
990   std::ostringstream bufferToPrint;
991   bufferToPrint << "Gen: Executing finally block "
992     << blockName << " in " << functionId << "\n";
993   generateStringPrint(context,
994                       module,
995                       builder,
996                       bufferToPrint.str(),
997                       USE_GLOBAL_STR_CONSTS);
998 
999   llvm::SwitchInst *theSwitch = builder.CreateSwitch(
1000       builder.CreateLoad(ourExceptionNotThrownState->getType(),
1001                          *exceptionCaughtFlag),
1002       &terminatorBlock, 2);
1003   theSwitch->addCase(ourExceptionCaughtState, &terminatorBlock);
1004   theSwitch->addCase(ourExceptionThrownState, &unwindResumeBlock);
1005 
1006   return(ret);
1007 }
1008 
1009 
1010 /// Generates catch block semantics which print a string to indicate type of
1011 /// catch executed, sets an exception caught flag, and executes passed in
1012 /// end block (terminator block).
1013 /// @param context llvm context
1014 /// @param module code for module instance
1015 /// @param builder builder instance
1016 /// @param toAddTo parent function to add block to
1017 /// @param blockName block name of new "catch" block.
1018 /// @param functionId output id used for printing
1019 /// @param terminatorBlock terminator "end" block
1020 /// @param exceptionCaughtFlag exception caught/thrown status
1021 /// @returns newly created block
1022 static llvm::BasicBlock *createCatchBlock(llvm::LLVMContext &context,
1023                                           llvm::Module &module,
1024                                           llvm::IRBuilder<> &builder,
1025                                           llvm::Function &toAddTo,
1026                                           std::string &blockName,
1027                                           std::string &functionId,
1028                                           llvm::BasicBlock &terminatorBlock,
1029                                           llvm::Value &exceptionCaughtFlag) {
1030 
1031   llvm::BasicBlock *ret = llvm::BasicBlock::Create(context,
1032                                                    blockName,
1033                                                    &toAddTo);
1034 
1035   builder.SetInsertPoint(ret);
1036 
1037   std::ostringstream bufferToPrint;
1038   bufferToPrint << "Gen: Executing catch block "
1039   << blockName
1040   << " in "
1041   << functionId
1042   << std::endl;
1043   generateStringPrint(context,
1044                       module,
1045                       builder,
1046                       bufferToPrint.str(),
1047                       USE_GLOBAL_STR_CONSTS);
1048   builder.CreateStore(ourExceptionCaughtState, &exceptionCaughtFlag);
1049   builder.CreateBr(&terminatorBlock);
1050 
1051   return(ret);
1052 }
1053 
1054 
1055 /// Generates a function which invokes a function (toInvoke) and, whose
1056 /// unwind block will "catch" the type info types correspondingly held in the
1057 /// exceptionTypesToCatch argument. If the toInvoke function throws an
1058 /// exception which does not match any type info types contained in
1059 /// exceptionTypesToCatch, the generated code will call _Unwind_Resume
1060 /// with the raised exception. On the other hand the generated code will
1061 /// normally exit if the toInvoke function does not throw an exception.
1062 /// The generated "finally" block is always run regardless of the cause of
1063 /// the generated function exit.
1064 /// The generated function is returned after being verified.
1065 /// @param module code for module instance
1066 /// @param builder builder instance
1067 /// @param fpm a function pass manager holding optional IR to IR
1068 ///        transformations
1069 /// @param toInvoke inner function to invoke
1070 /// @param ourId id used to printing purposes
1071 /// @param numExceptionsToCatch length of exceptionTypesToCatch array
1072 /// @param exceptionTypesToCatch array of type info types to "catch"
1073 /// @returns generated function
1074 static llvm::Function *createCatchWrappedInvokeFunction(
1075     llvm::Module &module, llvm::IRBuilder<> &builder,
1076     llvm::legacy::FunctionPassManager &fpm, llvm::Function &toInvoke,
1077     std::string ourId, unsigned numExceptionsToCatch,
1078     unsigned exceptionTypesToCatch[]) {
1079 
1080   llvm::LLVMContext &context = module.getContext();
1081   llvm::Function *toPrint32Int = module.getFunction("print32Int");
1082 
1083   ArgTypes argTypes;
1084   argTypes.push_back(builder.getInt32Ty());
1085 
1086   ArgNames argNames;
1087   argNames.push_back("exceptTypeToThrow");
1088 
1089   llvm::Function *ret = createFunction(module,
1090                                        builder.getVoidTy(),
1091                                        argTypes,
1092                                        argNames,
1093                                        ourId,
1094                                        llvm::Function::ExternalLinkage,
1095                                        false,
1096                                        false);
1097 
1098   // Block which calls invoke
1099   llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(context,
1100                                                           "entry",
1101                                                           ret);
1102   // Normal block for invoke
1103   llvm::BasicBlock *normalBlock = llvm::BasicBlock::Create(context,
1104                                                            "normal",
1105                                                            ret);
1106   // Unwind block for invoke
1107   llvm::BasicBlock *exceptionBlock = llvm::BasicBlock::Create(context,
1108                                                               "exception",
1109                                                               ret);
1110 
1111   // Block which routes exception to correct catch handler block
1112   llvm::BasicBlock *exceptionRouteBlock = llvm::BasicBlock::Create(context,
1113                                                              "exceptionRoute",
1114                                                              ret);
1115 
1116   // Foreign exception handler
1117   llvm::BasicBlock *externalExceptionBlock = llvm::BasicBlock::Create(context,
1118                                                           "externalException",
1119                                                           ret);
1120 
1121   // Block which calls _Unwind_Resume
1122   llvm::BasicBlock *unwindResumeBlock = llvm::BasicBlock::Create(context,
1123                                                                "unwindResume",
1124                                                                ret);
1125 
1126   // Clean up block which delete exception if needed
1127   llvm::BasicBlock *endBlock = llvm::BasicBlock::Create(context, "end", ret);
1128 
1129   std::string nextName;
1130   std::vector<llvm::BasicBlock*> catchBlocks(numExceptionsToCatch);
1131   llvm::Value *exceptionCaughtFlag = NULL;
1132   llvm::Value *exceptionStorage = NULL;
1133   llvm::Value *caughtResultStorage = NULL;
1134 
1135   // Finally block which will branch to unwindResumeBlock if
1136   // exception is not caught. Initializes/allocates stack locations.
1137   llvm::BasicBlock *finallyBlock = createFinallyBlock(context,
1138                                                       module,
1139                                                       builder,
1140                                                       *ret,
1141                                                       nextName = "finally",
1142                                                       ourId,
1143                                                       *endBlock,
1144                                                       *unwindResumeBlock,
1145                                                       &exceptionCaughtFlag,
1146                                                       &exceptionStorage,
1147                                                       &caughtResultStorage
1148                                                       );
1149 
1150   for (unsigned i = 0; i < numExceptionsToCatch; ++i) {
1151     nextName = ourTypeInfoNames[exceptionTypesToCatch[i]];
1152 
1153     // One catch block per type info to be caught
1154     catchBlocks[i] = createCatchBlock(context,
1155                                       module,
1156                                       builder,
1157                                       *ret,
1158                                       nextName,
1159                                       ourId,
1160                                       *finallyBlock,
1161                                       *exceptionCaughtFlag);
1162   }
1163 
1164   // Entry Block
1165 
1166   builder.SetInsertPoint(entryBlock);
1167 
1168   std::vector<llvm::Value*> args;
1169   args.push_back(namedValues["exceptTypeToThrow"]);
1170   builder.CreateInvoke(&toInvoke,
1171                        normalBlock,
1172                        exceptionBlock,
1173                        args);
1174 
1175   // End Block
1176 
1177   builder.SetInsertPoint(endBlock);
1178 
1179   generateStringPrint(context,
1180                       module,
1181                       builder,
1182                       "Gen: In end block: exiting in " + ourId + ".\n",
1183                       USE_GLOBAL_STR_CONSTS);
1184   llvm::Function *deleteOurException = module.getFunction("deleteOurException");
1185 
1186   // Note: function handles NULL exceptions
1187   builder.CreateCall(deleteOurException,
1188                      builder.CreateLoad(builder.getPtrTy(), exceptionStorage));
1189   builder.CreateRetVoid();
1190 
1191   // Normal Block
1192 
1193   builder.SetInsertPoint(normalBlock);
1194 
1195   generateStringPrint(context,
1196                       module,
1197                       builder,
1198                       "Gen: No exception in " + ourId + "!\n",
1199                       USE_GLOBAL_STR_CONSTS);
1200 
1201   // Finally block is always called
1202   builder.CreateBr(finallyBlock);
1203 
1204   // Unwind Resume Block
1205 
1206   builder.SetInsertPoint(unwindResumeBlock);
1207 
1208   builder.CreateResume(
1209       builder.CreateLoad(ourCaughtResultType, caughtResultStorage));
1210 
1211   // Exception Block
1212 
1213   builder.SetInsertPoint(exceptionBlock);
1214 
1215   llvm::Function *personality = module.getFunction("ourPersonality");
1216   ret->setPersonalityFn(personality);
1217 
1218   llvm::LandingPadInst *caughtResult =
1219     builder.CreateLandingPad(ourCaughtResultType,
1220                              numExceptionsToCatch,
1221                              "landingPad");
1222 
1223   caughtResult->setCleanup(true);
1224 
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]]));
1229   }
1230 
1231   llvm::Value *unwindException = builder.CreateExtractValue(caughtResult, 0);
1232   llvm::Value *retTypeInfoIndex = builder.CreateExtractValue(caughtResult, 1);
1233 
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);
1240 
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 = builder.CreateLoad(
1245       builder.getInt64Ty(),
1246       builder.CreateStructGEP(ourUnwindExceptionType, unwindException, 0));
1247 
1248   // Branch to the externalExceptionBlock if the exception is foreign or
1249   // to a catch router if not. Either way the finally block will be run.
1250   builder.CreateCondBr(builder.CreateICmpEQ(unwindExceptionClass,
1251                             llvm::ConstantInt::get(builder.getInt64Ty(),
1252                                                    ourBaseExceptionClass)),
1253                        exceptionRouteBlock,
1254                        externalExceptionBlock);
1255 
1256   // External Exception Block
1257 
1258   builder.SetInsertPoint(externalExceptionBlock);
1259 
1260   generateStringPrint(context,
1261                       module,
1262                       builder,
1263                       "Gen: Foreign exception received.\n",
1264                       USE_GLOBAL_STR_CONSTS);
1265 
1266   // Branch to the finally block
1267   builder.CreateBr(finallyBlock);
1268 
1269   // Exception Route Block
1270 
1271   builder.SetInsertPoint(exceptionRouteBlock);
1272 
1273   // Casts exception pointer (_Unwind_Exception instance) to parent
1274   // (OurException instance).
1275   //
1276   // Note: ourBaseFromUnwindOffset is usually negative
1277   llvm::Value *typeInfoThrown = builder.CreateConstGEP1_64(
1278       builder.getInt8Ty(), unwindException, ourBaseFromUnwindOffset);
1279 
1280   // Retrieve thrown exception type info type
1281   //
1282   // Note: Index is not relative to pointer but instead to structure
1283   //       unlike a true getelementptr (GEP) instruction
1284   typeInfoThrown = builder.CreateStructGEP(ourExceptionType, typeInfoThrown, 0);
1285 
1286   llvm::Value *typeInfoThrownType =
1287       builder.CreateStructGEP(ourTypeInfoType, typeInfoThrown, 0);
1288 
1289   llvm::Value *ti32 =
1290       builder.CreateLoad(builder.getInt32Ty(), typeInfoThrownType);
1291   generateIntegerPrint(context, module, builder, *toPrint32Int, ti32,
1292                        "Gen: Exception type <%d> received (stack unwound) "
1293                        " in " +
1294                            ourId + ".\n",
1295                        USE_GLOBAL_STR_CONSTS);
1296 
1297   // Route to matched type info catch block or run cleanup finally block
1298   llvm::SwitchInst *switchToCatchBlock = builder.CreateSwitch(retTypeInfoIndex,
1299                                                           finallyBlock,
1300                                                           numExceptionsToCatch);
1301 
1302   unsigned nextTypeToCatch;
1303 
1304   for (unsigned i = 1; i <= numExceptionsToCatch; ++i) {
1305     nextTypeToCatch = i - 1;
1306     switchToCatchBlock->addCase(llvm::ConstantInt::get(builder.getInt32Ty(), i),
1307                                 catchBlocks[nextTypeToCatch]);
1308   }
1309 
1310   llvm::verifyFunction(*ret);
1311   fpm.run(*ret);
1312 
1313   return(ret);
1314 }
1315 
1316 
1317 /// Generates function which throws either an exception matched to a runtime
1318 /// determined type info type (argument to generated function), or if this
1319 /// runtime value matches nativeThrowType, throws a foreign exception by
1320 /// calling nativeThrowFunct.
1321 /// @param module code for module instance
1322 /// @param builder builder instance
1323 /// @param fpm a function pass manager holding optional IR to IR
1324 ///        transformations
1325 /// @param ourId id used to printing purposes
1326 /// @param nativeThrowType a runtime argument of this value results in
1327 ///        nativeThrowFunct being called to generate/throw exception.
1328 /// @param nativeThrowFunct function which will throw a foreign exception
1329 ///        if the above nativeThrowType matches generated function's arg.
1330 /// @returns generated function
1331 static llvm::Function *
1332 createThrowExceptionFunction(llvm::Module &module, llvm::IRBuilder<> &builder,
1333                              llvm::legacy::FunctionPassManager &fpm,
1334                              std::string ourId, int32_t nativeThrowType,
1335                              llvm::Function &nativeThrowFunct) {
1336   llvm::LLVMContext &context = module.getContext();
1337   namedValues.clear();
1338   ArgTypes unwindArgTypes;
1339   unwindArgTypes.push_back(builder.getInt32Ty());
1340   ArgNames unwindArgNames;
1341   unwindArgNames.push_back("exceptTypeToThrow");
1342 
1343   llvm::Function *ret = createFunction(module,
1344                                        builder.getVoidTy(),
1345                                        unwindArgTypes,
1346                                        unwindArgNames,
1347                                        ourId,
1348                                        llvm::Function::ExternalLinkage,
1349                                        false,
1350                                        false);
1351 
1352   // Throws either one of our exception or a native C++ exception depending
1353   // on a runtime argument value containing a type info type.
1354   llvm::BasicBlock *entryBlock = llvm::BasicBlock::Create(context,
1355                                                           "entry",
1356                                                           ret);
1357   // Throws a foreign exception
1358   llvm::BasicBlock *nativeThrowBlock = llvm::BasicBlock::Create(context,
1359                                                                 "nativeThrow",
1360                                                                 ret);
1361   // Throws one of our Exceptions
1362   llvm::BasicBlock *generatedThrowBlock = llvm::BasicBlock::Create(context,
1363                                                              "generatedThrow",
1364                                                              ret);
1365   // Retrieved runtime type info type to throw
1366   llvm::Value *exceptionType = namedValues["exceptTypeToThrow"];
1367 
1368   // nativeThrowBlock block
1369 
1370   builder.SetInsertPoint(nativeThrowBlock);
1371 
1372   // Throws foreign exception
1373   builder.CreateCall(&nativeThrowFunct, exceptionType);
1374   builder.CreateUnreachable();
1375 
1376   // entry block
1377 
1378   builder.SetInsertPoint(entryBlock);
1379 
1380   llvm::Function *toPrint32Int = module.getFunction("print32Int");
1381   generateIntegerPrint(context, module, builder, *toPrint32Int,
1382                        builder.CreateZExt(exceptionType, builder.getInt32Ty()),
1383                        "\nGen: About to throw exception type <%d> in " + ourId +
1384                            ".\n",
1385                        USE_GLOBAL_STR_CONSTS);
1386 
1387   // Switches on runtime type info type value to determine whether or not
1388   // a foreign exception is thrown. Defaults to throwing one of our
1389   // generated exceptions.
1390   llvm::SwitchInst *theSwitch = builder.CreateSwitch(exceptionType,
1391                                                      generatedThrowBlock,
1392                                                      1);
1393 
1394   theSwitch->addCase(llvm::ConstantInt::get(llvm::Type::getInt32Ty(context),
1395                                             nativeThrowType),
1396                      nativeThrowBlock);
1397 
1398   // generatedThrow block
1399 
1400   builder.SetInsertPoint(generatedThrowBlock);
1401 
1402   llvm::Function *createOurException = module.getFunction("createOurException");
1403   llvm::Function *raiseOurException = module.getFunction(
1404                                         "_Unwind_RaiseException");
1405 
1406   // Creates exception to throw with runtime type info type.
1407   llvm::Value *exception = builder.CreateCall(createOurException,
1408                                               namedValues["exceptTypeToThrow"]);
1409 
1410   // Throw generated Exception
1411   builder.CreateCall(raiseOurException, exception);
1412   builder.CreateUnreachable();
1413 
1414   llvm::verifyFunction(*ret);
1415   fpm.run(*ret);
1416 
1417   return(ret);
1418 }
1419 
1420 static void createStandardUtilityFunctions(unsigned numTypeInfos,
1421                                            llvm::Module &module,
1422                                            llvm::IRBuilder<> &builder);
1423 
1424 /// Creates test code by generating and organizing these functions into the
1425 /// test case. The test case consists of an outer function setup to invoke
1426 /// an inner function within an environment having multiple catch and single
1427 /// finally blocks. This inner function is also setup to invoke a throw
1428 /// function within an evironment similar in nature to the outer function's
1429 /// catch and finally blocks. Each of these two functions catch mutually
1430 /// exclusive subsets (even or odd) of the type info types configured
1431 /// for this this. All generated functions have a runtime argument which
1432 /// holds a type info type to throw that each function takes and passes it
1433 /// to the inner one if such a inner function exists. This type info type is
1434 /// looked at by the generated throw function to see whether or not it should
1435 /// throw a generated exception with the same type info type, or instead call
1436 /// a supplied a function which in turn will throw a foreign exception.
1437 /// @param module code for module instance
1438 /// @param builder builder instance
1439 /// @param fpm a function pass manager holding optional IR to IR
1440 ///        transformations
1441 /// @param nativeThrowFunctName name of external function which will throw
1442 ///        a foreign exception
1443 /// @returns outermost generated test function.
1444 llvm::Function *
1445 createUnwindExceptionTest(llvm::Module &module, llvm::IRBuilder<> &builder,
1446                           llvm::legacy::FunctionPassManager &fpm,
1447                           std::string nativeThrowFunctName) {
1448   // Number of type infos to generate
1449   unsigned numTypeInfos = 6;
1450 
1451   // Initialze intrisics and external functions to use along with exception
1452   // and type info globals.
1453   createStandardUtilityFunctions(numTypeInfos,
1454                                  module,
1455                                  builder);
1456   llvm::Function *nativeThrowFunct = module.getFunction(nativeThrowFunctName);
1457 
1458   // Create exception throw function using the value ~0 to cause
1459   // foreign exceptions to be thrown.
1460   llvm::Function *throwFunct = createThrowExceptionFunction(module,
1461                                                             builder,
1462                                                             fpm,
1463                                                             "throwFunct",
1464                                                             ~0,
1465                                                             *nativeThrowFunct);
1466   // Inner function will catch even type infos
1467   unsigned innerExceptionTypesToCatch[] = {6, 2, 4};
1468   size_t numExceptionTypesToCatch = sizeof(innerExceptionTypesToCatch) /
1469                                     sizeof(unsigned);
1470 
1471   // Generate inner function.
1472   llvm::Function *innerCatchFunct = createCatchWrappedInvokeFunction(module,
1473                                                     builder,
1474                                                     fpm,
1475                                                     *throwFunct,
1476                                                     "innerCatchFunct",
1477                                                     numExceptionTypesToCatch,
1478                                                     innerExceptionTypesToCatch);
1479 
1480   // Outer function will catch odd type infos
1481   unsigned outerExceptionTypesToCatch[] = {3, 1, 5};
1482   numExceptionTypesToCatch = sizeof(outerExceptionTypesToCatch) /
1483   sizeof(unsigned);
1484 
1485   // Generate outer function
1486   llvm::Function *outerCatchFunct = createCatchWrappedInvokeFunction(module,
1487                                                     builder,
1488                                                     fpm,
1489                                                     *innerCatchFunct,
1490                                                     "outerCatchFunct",
1491                                                     numExceptionTypesToCatch,
1492                                                     outerExceptionTypesToCatch);
1493 
1494   // Return outer function to run
1495   return(outerCatchFunct);
1496 }
1497 
1498 namespace {
1499 /// Represents our foreign exceptions
1500 class OurCppRunException : public std::runtime_error {
1501 public:
1502   OurCppRunException(const std::string reason) :
1503   std::runtime_error(reason) {}
1504 
1505   OurCppRunException (const OurCppRunException &toCopy) :
1506   std::runtime_error(toCopy) {}
1507 
1508   OurCppRunException &operator = (const OurCppRunException &toCopy) {
1509     return(reinterpret_cast<OurCppRunException&>(
1510                                  std::runtime_error::operator=(toCopy)));
1511   }
1512 
1513   ~OurCppRunException(void) throw() override {}
1514 };
1515 } // end anonymous namespace
1516 
1517 /// Throws foreign C++ exception.
1518 /// @param ignoreIt unused parameter that allows function to match implied
1519 ///        generated function contract.
1520 extern "C"
1521 void throwCppException (int32_t ignoreIt) {
1522   throw(OurCppRunException("thrown by throwCppException(...)"));
1523 }
1524 
1525 typedef void (*OurExceptionThrowFunctType) (int32_t typeToThrow);
1526 
1527 /// This is a test harness which runs test by executing generated
1528 /// function with a type info type to throw. Harness wraps the execution
1529 /// of generated function in a C++ try catch clause.
1530 /// @param engine execution engine to use for executing generated function.
1531 ///        This demo program expects this to be a JIT instance for demo
1532 ///        purposes.
1533 /// @param function generated test function to run
1534 /// @param typeToThrow type info type of generated exception to throw, or
1535 ///        indicator to cause foreign exception to be thrown.
1536 static void runExceptionThrow(llvm::orc::LLJIT *JIT, std::string function,
1537                               int32_t typeToThrow) {
1538 
1539   // Find test's function pointer
1540   OurExceptionThrowFunctType functPtr =
1541       ExitOnErr(JIT->lookup(function)).toPtr<OurExceptionThrowFunctType>();
1542 
1543   try {
1544     // Run test
1545     (*functPtr)(typeToThrow);
1546   }
1547   catch (OurCppRunException exc) {
1548     // Catch foreign C++ exception
1549     fprintf(stderr,
1550             "\nrunExceptionThrow(...):In C++ catch OurCppRunException "
1551             "with reason: %s.\n",
1552             exc.what());
1553   }
1554   catch (...) {
1555     // Catch all exceptions including our generated ones. This latter
1556     // functionality works according to the example in rules 1.6.4 of
1557     // http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html (v1.22),
1558     // given that these will be exceptions foreign to C++
1559     // (the _Unwind_Exception::exception_class should be different from
1560     // the one used by C++).
1561     fprintf(stderr,
1562             "\nrunExceptionThrow(...):In C++ catch all.\n");
1563   }
1564 }
1565 
1566 //
1567 // End test functions
1568 //
1569 
1570 /// This initialization routine creates type info globals and
1571 /// adds external function declarations to module.
1572 /// @param numTypeInfos number of linear type info associated type info types
1573 ///        to create as GlobalVariable instances, starting with the value 1.
1574 /// @param module code for module instance
1575 /// @param builder builder instance
1576 static void createStandardUtilityFunctions(unsigned numTypeInfos,
1577                                            llvm::Module &module,
1578                                            llvm::IRBuilder<> &builder) {
1579 
1580   llvm::LLVMContext &context = module.getContext();
1581 
1582   // Exception initializations
1583 
1584   // Setup exception catch state
1585   ourExceptionNotThrownState =
1586     llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 0),
1587   ourExceptionThrownState =
1588     llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 1),
1589   ourExceptionCaughtState =
1590     llvm::ConstantInt::get(llvm::Type::getInt8Ty(context), 2),
1591 
1592 
1593 
1594   // Create our type info type
1595   ourTypeInfoType = llvm::StructType::get(context,
1596                                           TypeArray(builder.getInt32Ty()));
1597 
1598   llvm::Type *caughtResultFieldTypes[] = {
1599     builder.getPtrTy(),
1600     builder.getInt32Ty()
1601   };
1602 
1603   // Create our landingpad result type
1604   ourCaughtResultType = llvm::StructType::get(context,
1605                                             TypeArray(caughtResultFieldTypes));
1606 
1607   // Create OurException type
1608   ourExceptionType = llvm::StructType::get(context,
1609                                            TypeArray(ourTypeInfoType));
1610 
1611   // Create portion of _Unwind_Exception type
1612   //
1613   // Note: Declaring only a portion of the _Unwind_Exception struct.
1614   //       Does this cause problems?
1615   ourUnwindExceptionType =
1616     llvm::StructType::get(context,
1617                     TypeArray(builder.getInt64Ty()));
1618 
1619   struct OurBaseException_t dummyException;
1620 
1621   // Calculate offset of OurException::unwindException member.
1622   ourBaseFromUnwindOffset = ((uintptr_t) &dummyException) -
1623                             ((uintptr_t) &(dummyException.unwindException));
1624 
1625 #ifdef DEBUG
1626   fprintf(stderr,
1627           "createStandardUtilityFunctions(...):ourBaseFromUnwindOffset "
1628           "= %" PRIi64 ", sizeof(struct OurBaseException_t) - "
1629           "sizeof(struct _Unwind_Exception) = %lu.\n",
1630           ourBaseFromUnwindOffset,
1631           sizeof(struct OurBaseException_t) -
1632           sizeof(struct _Unwind_Exception));
1633 #endif
1634 
1635   size_t numChars = sizeof(ourBaseExcpClassChars) / sizeof(char);
1636 
1637   // Create our _Unwind_Exception::exception_class value
1638   ourBaseExceptionClass = genClass(ourBaseExcpClassChars, numChars);
1639 
1640   // Type infos
1641 
1642   std::string baseStr = "typeInfo", typeInfoName;
1643   std::ostringstream typeInfoNameBuilder;
1644   std::vector<llvm::Constant*> structVals;
1645 
1646   llvm::Constant *nextStruct;
1647 
1648   // Generate each type info
1649   //
1650   // Note: First type info is not used.
1651   for (unsigned i = 0; i <= numTypeInfos; ++i) {
1652     structVals.clear();
1653     structVals.push_back(llvm::ConstantInt::get(builder.getInt32Ty(), i));
1654     nextStruct = llvm::ConstantStruct::get(ourTypeInfoType, structVals);
1655 
1656     typeInfoNameBuilder.str("");
1657     typeInfoNameBuilder << baseStr << i;
1658     typeInfoName = typeInfoNameBuilder.str();
1659 
1660     // Note: Does not seem to work without allocation
1661     new llvm::GlobalVariable(module,
1662                              ourTypeInfoType,
1663                              true,
1664                              llvm::GlobalValue::ExternalLinkage,
1665                              nextStruct,
1666                              typeInfoName);
1667 
1668     ourTypeInfoNames.push_back(typeInfoName);
1669     ourTypeInfoNamesIndex[i] = typeInfoName;
1670   }
1671 
1672   ArgNames argNames;
1673   ArgTypes argTypes;
1674   llvm::Function *funct = NULL;
1675 
1676   // print32Int
1677 
1678   llvm::Type *retType = builder.getVoidTy();
1679 
1680   argTypes.clear();
1681   argTypes.push_back(builder.getInt32Ty());
1682   argTypes.push_back(builder.getPtrTy());
1683 
1684   argNames.clear();
1685 
1686   createFunction(module,
1687                  retType,
1688                  argTypes,
1689                  argNames,
1690                  "print32Int",
1691                  llvm::Function::ExternalLinkage,
1692                  true,
1693                  false);
1694 
1695   // print64Int
1696 
1697   retType = builder.getVoidTy();
1698 
1699   argTypes.clear();
1700   argTypes.push_back(builder.getInt64Ty());
1701   argTypes.push_back(builder.getPtrTy());
1702 
1703   argNames.clear();
1704 
1705   createFunction(module,
1706                  retType,
1707                  argTypes,
1708                  argNames,
1709                  "print64Int",
1710                  llvm::Function::ExternalLinkage,
1711                  true,
1712                  false);
1713 
1714   // printStr
1715 
1716   retType = builder.getVoidTy();
1717 
1718   argTypes.clear();
1719   argTypes.push_back(builder.getPtrTy());
1720 
1721   argNames.clear();
1722 
1723   createFunction(module,
1724                  retType,
1725                  argTypes,
1726                  argNames,
1727                  "printStr",
1728                  llvm::Function::ExternalLinkage,
1729                  true,
1730                  false);
1731 
1732   // throwCppException
1733 
1734   retType = builder.getVoidTy();
1735 
1736   argTypes.clear();
1737   argTypes.push_back(builder.getInt32Ty());
1738 
1739   argNames.clear();
1740 
1741   createFunction(module,
1742                  retType,
1743                  argTypes,
1744                  argNames,
1745                  "throwCppException",
1746                  llvm::Function::ExternalLinkage,
1747                  true,
1748                  false);
1749 
1750   // deleteOurException
1751 
1752   retType = builder.getVoidTy();
1753 
1754   argTypes.clear();
1755   argTypes.push_back(builder.getPtrTy());
1756 
1757   argNames.clear();
1758 
1759   createFunction(module,
1760                  retType,
1761                  argTypes,
1762                  argNames,
1763                  "deleteOurException",
1764                  llvm::Function::ExternalLinkage,
1765                  true,
1766                  false);
1767 
1768   // createOurException
1769 
1770   retType = builder.getPtrTy();
1771 
1772   argTypes.clear();
1773   argTypes.push_back(builder.getInt32Ty());
1774 
1775   argNames.clear();
1776 
1777   createFunction(module,
1778                  retType,
1779                  argTypes,
1780                  argNames,
1781                  "createOurException",
1782                  llvm::Function::ExternalLinkage,
1783                  true,
1784                  false);
1785 
1786   // _Unwind_RaiseException
1787 
1788   retType = builder.getInt32Ty();
1789 
1790   argTypes.clear();
1791   argTypes.push_back(builder.getPtrTy());
1792 
1793   argNames.clear();
1794 
1795   funct = createFunction(module,
1796                          retType,
1797                          argTypes,
1798                          argNames,
1799                          "_Unwind_RaiseException",
1800                          llvm::Function::ExternalLinkage,
1801                          true,
1802                          false);
1803 
1804   funct->setDoesNotReturn();
1805 
1806   // _Unwind_Resume
1807 
1808   retType = builder.getInt32Ty();
1809 
1810   argTypes.clear();
1811   argTypes.push_back(builder.getPtrTy());
1812 
1813   argNames.clear();
1814 
1815   funct = createFunction(module,
1816                          retType,
1817                          argTypes,
1818                          argNames,
1819                          "_Unwind_Resume",
1820                          llvm::Function::ExternalLinkage,
1821                          true,
1822                          false);
1823 
1824   funct->setDoesNotReturn();
1825 
1826   // ourPersonality
1827 
1828   retType = builder.getInt32Ty();
1829 
1830   argTypes.clear();
1831   argTypes.push_back(builder.getInt32Ty());
1832   argTypes.push_back(builder.getInt32Ty());
1833   argTypes.push_back(builder.getInt64Ty());
1834   argTypes.push_back(builder.getPtrTy());
1835   argTypes.push_back(builder.getPtrTy());
1836 
1837   argNames.clear();
1838 
1839   createFunction(module,
1840                  retType,
1841                  argTypes,
1842                  argNames,
1843                  "ourPersonality",
1844                  llvm::Function::ExternalLinkage,
1845                  true,
1846                  false);
1847 
1848   // llvm.eh.typeid.for intrinsic
1849 
1850   getOrInsertDeclaration(&module, llvm::Intrinsic::eh_typeid_for,
1851                          builder.getPtrTy());
1852 }
1853 
1854 
1855 //===----------------------------------------------------------------------===//
1856 // Main test driver code.
1857 //===----------------------------------------------------------------------===//
1858 
1859 /// Demo main routine which takes the type info types to throw. A test will
1860 /// be run for each given type info type. While type info types with the value
1861 /// of -1 will trigger a foreign C++ exception to be thrown; type info types
1862 /// <= 6 and >= 1 will be caught by test functions; and type info types > 6
1863 /// will result in exceptions which pass through to the test harness. All other
1864 /// type info types are not supported and could cause a crash.
1865 int main(int argc, char *argv[]) {
1866   if (argc == 1) {
1867     fprintf(stderr,
1868             "\nUsage: ExceptionDemo <exception type to throw> "
1869             "[<type 2>...<type n>].\n"
1870             "   Each type must have the value of 1 - 6 for "
1871             "generated exceptions to be caught;\n"
1872             "   the value -1 for foreign C++ exceptions to be "
1873             "generated and thrown;\n"
1874             "   or the values > 6 for exceptions to be ignored.\n"
1875             "\nTry: ExceptionDemo 2 3 7 -1\n"
1876             "   for a full test.\n\n");
1877     return(0);
1878   }
1879 
1880   llvm::InitializeNativeTarget();
1881   llvm::InitializeNativeTargetAsmPrinter();
1882   auto Context = std::make_unique<llvm::LLVMContext>();
1883   llvm::IRBuilder<> theBuilder(*Context);
1884 
1885   // Make the module, which holds all the code.
1886   std::unique_ptr<llvm::Module> Owner =
1887       std::make_unique<llvm::Module>("my cool jit", *Context);
1888   llvm::Module *module = Owner.get();
1889 
1890   // Build LLJIT
1891   std::unique_ptr<llvm::orc::LLJIT> JIT =
1892       ExitOnErr(llvm::orc::LLJITBuilder().create());
1893 
1894   // Set up the optimizer pipeline.
1895   llvm::legacy::FunctionPassManager fpm(module);
1896 
1897   // Optimizations turned on
1898 #ifdef ADD_OPT_PASSES
1899 
1900   // Basic AliasAnslysis support for GVN.
1901   fpm.add(llvm::createBasicAliasAnalysisPass());
1902 
1903   // Promote allocas to registers.
1904   fpm.add(llvm::createPromoteMemoryToRegisterPass());
1905 
1906   // Do simple "peephole" optimizations and bit-twiddling optzns.
1907   fpm.add(llvm::createInstructionCombiningPass());
1908 
1909   // Reassociate expressions.
1910   fpm.add(llvm::createReassociatePass());
1911 
1912   // Eliminate Common SubExpressions.
1913   fpm.add(llvm::createGVNPass());
1914 
1915   // Simplify the control flow graph (deleting unreachable
1916   // blocks, etc).
1917   fpm.add(llvm::createCFGSimplificationPass());
1918 #endif  // ADD_OPT_PASSES
1919 
1920   fpm.doInitialization();
1921 
1922   // Generate test code using function throwCppException(...) as
1923   // the function which throws foreign exceptions.
1924   createUnwindExceptionTest(*module, theBuilder, fpm, "throwCppException");
1925 
1926   ExitOnErr(JIT->addIRModule(
1927       llvm::orc::ThreadSafeModule(std::move(Owner), std::move(Context))));
1928 
1929 #ifndef NDEBUG
1930   fprintf(stderr, "\nBegin module dump:\n\n");
1931 
1932   module->print(llvm::errs(), nullptr);
1933 
1934   fprintf(stderr, "\nEnd module dump:\n");
1935 #endif
1936 
1937   fprintf(stderr, "\n\nBegin Test:\n");
1938   std::string toRun = "outerCatchFunct";
1939 
1940   for (int i = 1; i < argc; ++i) {
1941     // Run test for each argument whose value is the exception
1942     // type to throw.
1943     runExceptionThrow(JIT.get(), toRun, (unsigned)strtoul(argv[i], NULL, 10));
1944   }
1945 
1946   fprintf(stderr, "\nEnd Test:\n\n");
1947 
1948   return 0;
1949 }
1950