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