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