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 > >