ExceptionDemo.cpp 70 KB

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