Vapor Nide
2012-Dec-27 00:25 UTC
[LLVMdev] Throwing an exception from JITed code, and catching in C++
Hi everyone, I am writing an application that uses LLVM JIT and I would like to throw an exception from the JIT and catch it in the C++ code that invokes the JIT. This does not seem to work. I've written what is hopefully a super simple demonstration to reproduce this. I would appreciate any help with this. Thank you The demonstration is composed of: 1) thrower.cpp - a source file that contains a single function, throwInt(), that throws an int. This is compiled to thrower.s with clang and then to thrower.s.bc with llvm-as. 2) catcher.cpp - a source file that contains a main() that JITs thrower.s.bc and then calls throwInt(). This is compiled using g++. When I run catcher it just prints this: terminate called after throwing an instance of 'int' I am using LLVM and CLANG 3.0, and gcc 4.7.2. Here are all of the files needed to reproduce this: 1) thrower.cpp 2) catcher.cpp 3) Makefile This is how I run the test: make LLVM_BIN=path/to/llvm-3.0.src/Release/bin/ $ cat thrower.cpp ################ void throwInt() { throw 1; } $ cat thrower.s ################ ; ModuleID = 'thrower.cpp' target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" @_ZTIi = external constant i8* define void @_Z8throwIntv() uwtable { %1 = call i8* @__cxa_allocate_exception(i64 4) nounwind %2 = bitcast i8* %1 to i32* store i32 1, i32* %2 call void @__cxa_throw(i8* %1, i8* bitcast (i8** @_ZTIi to i8*), i8* null) noreturn unreachable ; No predecessors! ret void } declare i8* @__cxa_allocate_exception(i64) declare void @__cxa_throw(i8*, i8*, i8*) $ cat catcher.cpp ################ #include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/ExecutionEngine/JIT.h" #include "llvm/Support/IRReader.h" #include "llvm/Support/TargetSelect.h" #include using namespace llvm; int main(int, char**) { LLVMContext& context = getGlobalContext(); InitializeNativeTarget(); SMDiagnostic error; Module* m = ParseIRFile("./thrower.s.bc", error, context); if (!m) { printf("could not load module\n"); return 1; } ExecutionEngine* ee = ExecutionEngine::create(m); if (!ee) { printf("could not create execution engine\n"); return 1; } Function* throwsIntFunction = ee->FindFunctionNamed("_Z8throwIntv"); if (!throwsIntFunction) { printf("could not find function\n"); return 1; } typedef void (*throwsIntType)(); throwsIntType throwsInt = reinterpret_cast(ee->getPointerToFunction(throwsIntFunction)); if (!throwsInt) { printf("could not get pointer to function\n"); return 1; } try { throwsInt(); } catch (int ex) { printf("caught an int\n"); } } $ cat Makefile ################ LLVM_CXX_FLAGS=$(shell $(LLVM_BIN)/llvm-config --cxxflags) LLVM_LIBS=$(shell $(LLVM_BIN)/llvm-config --libs) LLVM_LD_FLAGS=$(shell $(LLVM_BIN)/llvm-config --ldflags) all : tested .PHONY: clean clean: rm thrower.s thrower.s.bc catcher tested thrower.s : thrower.cpp Makefile $(LLVM_BIN)/clang -S -emit-llvm thrower.cpp thrower.s.bc : thrower.s Makefile $(LLVM_BIN)/llvm-as thrower.s catcher : catcher.cpp Makefile g++ -g catcher.cpp -o catcher $(LLVM_CXX_FLAGS) $(LLVM_LIBS) $(LLVM_LD_FLAGS) -Wno-cast-qual -fexceptions -O0 tested : thrower.s.bc catcher Makefile ./catcher touch tested
Vapor Nide
2012-Dec-27 01:03 UTC
[LLVMdev] Throwing an exception from JITed code, and catching in C++
If anyone else needs the answer to this question it is to add these two lines: #include "llvm/Target/TargetOptions.h" llvm::JITExceptionHandling = true; ----------------------------------------> From: vaporanide at live.com > To: llvmdev at cs.uiuc.edu > Subject: Throwing an exception from JITed code, and catching in C++ > Date: Wed, 26 Dec 2012 19:25:06 -0500 > > > > Hi everyone, > > I am writing an application that uses LLVM JIT and I would like to throw an exception from the JIT and catch it in the C++ code that invokes the JIT. > This does not seem to work. > I've written what is hopefully a super simple demonstration to reproduce this. > I would appreciate any help with this. > > Thank you > > The demonstration is composed of: > 1) thrower.cpp - a source file that contains a single function, throwInt(), that throws an int. This is compiled to thrower.s with clang and then to thrower.s.bc with llvm-as. > 2) catcher.cpp - a source file that contains a main() that JITs thrower.s.bc and then calls throwInt(). This is compiled using g++. > > When I run catcher it just prints this: > terminate called after throwing an instance of 'int' > > I am using LLVM and CLANG 3.0, and gcc 4.7.2. > > Here are all of the files needed to reproduce this: > 1) thrower.cpp > 2) catcher.cpp > 3) Makefile > > This is how I run the test: > make LLVM_BIN=path/to/llvm-3.0.src/Release/bin/ > > $ cat thrower.cpp ################ > void throwInt() > { > throw 1; > } > > $ cat thrower.s ################ > ; ModuleID = 'thrower.cpp' > target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" > target triple = "x86_64-unknown-linux-gnu" > > @_ZTIi = external constant i8* > > define void @_Z8throwIntv() uwtable { > %1 = call i8* @__cxa_allocate_exception(i64 4) nounwind > %2 = bitcast i8* %1 to i32* > store i32 1, i32* %2 > call void @__cxa_throw(i8* %1, i8* bitcast (i8** @_ZTIi to i8*), i8* null) noreturn > unreachable > ; No predecessors! > ret void > } > > declare i8* @__cxa_allocate_exception(i64) > > declare void @__cxa_throw(i8*, i8*, i8*) > > $ cat catcher.cpp ################ > #include "llvm/LLVMContext.h" > #include "llvm/Module.h" > #include "llvm/ExecutionEngine/JIT.h" > #include "llvm/Support/IRReader.h" > #include "llvm/Support/TargetSelect.h" > #include > > using namespace llvm; > > int main(int, char**) > { > LLVMContext& context = getGlobalContext(); > InitializeNativeTarget(); > SMDiagnostic error; > Module* m = ParseIRFile("./thrower.s.bc", error, context); > if (!m) > { > printf("could not load module\n"); > return 1; > } > > ExecutionEngine* ee = ExecutionEngine::create(m); > if (!ee) > { > printf("could not create execution engine\n"); > return 1; > } > > Function* throwsIntFunction = ee->FindFunctionNamed("_Z8throwIntv"); > if (!throwsIntFunction) > { > printf("could not find function\n"); > return 1; > } > > typedef void (*throwsIntType)(); > throwsIntType throwsInt = reinterpret_cast(ee->getPointerToFunction(throwsIntFunction)); > if (!throwsInt) > { > printf("could not get pointer to function\n"); > return 1; > } > > try > { > throwsInt(); > } > catch (int ex) > { > printf("caught an int\n"); > } > } > > $ cat Makefile ################ > LLVM_CXX_FLAGS=$(shell $(LLVM_BIN)/llvm-config --cxxflags) > LLVM_LIBS=$(shell $(LLVM_BIN)/llvm-config --libs) > LLVM_LD_FLAGS=$(shell $(LLVM_BIN)/llvm-config --ldflags) > > all : tested > > .PHONY: clean > clean: > rm thrower.s thrower.s.bc catcher tested > > thrower.s : thrower.cpp Makefile > $(LLVM_BIN)/clang -S -emit-llvm thrower.cpp > > thrower.s.bc : thrower.s Makefile > $(LLVM_BIN)/llvm-as thrower.s > > catcher : catcher.cpp Makefile > g++ -g catcher.cpp -o catcher $(LLVM_CXX_FLAGS) $(LLVM_LIBS) $(LLVM_LD_FLAGS) -Wno-cast-qual -fexceptions -O0 > > tested : thrower.s.bc catcher Makefile > ./catcher > touch tested > >