libclamav/c++/bytecode2llvm.cpp
f18dc607
 /*
e32caecb
  *  JIT compile ClamAV bytecode.
f18dc607
  *
  *  Copyright (C) 2009 Sourcefire, Inc.
  *
  *  Authors: Török Edvin
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  *  MA 02110-1301, USA.
  */
6b67ec6e
 #define DEBUG_TYPE "clamavjit"
daffb518
 #include "llvm/ADT/DenseMap.h"
d0af4afe
 #include "llvm/CallingConv.h"
3b33bd68
 #include "llvm/DerivedTypes.h"
 #include "llvm/Function.h"
 #include "llvm/ExecutionEngine/ExecutionEngine.h"
 #include "llvm/ExecutionEngine/JIT.h"
 #include "llvm/ExecutionEngine/JITEventListener.h"
 #include "llvm/LLVMContext.h"
 #include "llvm/Module.h"
ee8f1888
 #include "llvm/PassManager.h"
3b33bd68
 #include "llvm/ModuleProvider.h"
 #include "llvm/Support/Compiler.h"
6b67ec6e
 #include "llvm/Support/Debug.h"
3b33bd68
 #include "llvm/Support/CommandLine.h"
d1487222
 #include "llvm/Support/DataTypes.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/ManagedStatic.h"
 #include "llvm/Support/raw_ostream.h"
3b33bd68
 #include "llvm/Support/IRBuilder.h"
 #include "llvm/Support/PrettyStackTrace.h"
d1487222
 #include "llvm/System/Signals.h"
3b33bd68
 #include "llvm/System/Threading.h"
d1487222
 #include "llvm/Target/TargetSelect.h"
ee8f1888
 #include "llvm/Target/TargetData.h"
3b33bd68
 #include "llvm/Support/TargetFolder.h"
ee8f1888
 #include "llvm/Analysis/Verifier.h"
6b67ec6e
 #include "llvm/Transforms/Scalar.h"
 #include "llvm/System/ThreadLocal.h"
d1487222
 #include <cstdlib>
6b67ec6e
 #include <csetjmp>
d1487222
 #include <new>
 
2c7d5adc
 #include "llvm/Config/config.h"
 #ifndef LLVM_MULTITHREADED
 #error "Multithreading support must be available to LLVM!"
 #endif
d1487222
 #include "clamav.h"
 #include "clambc.h"
 #include "bytecode_priv.h"
 #include "bytecode.h"
 
 #define MODULE "libclamav JIT: "
 
 using namespace llvm;
daffb518
 typedef DenseMap<const struct cli_bc_func*, void*> FunctionMapTy;
d1487222
 struct cli_bcengine {
     ExecutionEngine *EE;
     LLVMContext Context;
3b33bd68
     FunctionMapTy compiledFunctions;
d1487222
 };
 
 namespace {
 
6b67ec6e
 static sys::ThreadLocal<const jmp_buf> ExceptionReturn;
 
3b33bd68
 void do_shutdown() {
     llvm_shutdown();
 }
daffb518
 
6b67ec6e
 static void NORETURN jit_exception_handler(void)
 {
     longjmp(*const_cast<jmp_buf*>(ExceptionReturn.get()), 1);
 }
 
3b33bd68
 void llvm_error_handler(void *user_data, const std::string &reason)
 {
     errs() << reason;
6b67ec6e
     jit_exception_handler();
3b33bd68
 }
daffb518
 
e32caecb
 class LLVMTypeMapper {
3b33bd68
 private:
e32caecb
     std::vector<PATypeHolder> TypeMap;
3b33bd68
     LLVMContext &Context;
e32caecb
     unsigned numTypes;
     const Type *getStatic(uint16_t ty)
3b33bd68
     {
 	if (!ty)
 	    return Type::getVoidTy(Context);
ee8f1888
 	if (ty <= 64)
3b33bd68
 	    return IntegerType::get(Context, ty);
 	switch (ty) {
 	    case 65:
 		return PointerType::getUnqual(Type::getInt8Ty(Context));
 	    case 66:
 		return PointerType::getUnqual(Type::getInt16Ty(Context));
 	    case 67:
 		return PointerType::getUnqual(Type::getInt32Ty(Context));
 	    case 68:
 		return PointerType::getUnqual(Type::getInt64Ty(Context));
 	}
e32caecb
 	llvm_unreachable("getStatic");
     }
 public:
     LLVMTypeMapper(LLVMContext &Context, const struct cli_bc_type *types,
d0af4afe
 		   unsigned count, const Type *Hidden=0) : Context(Context), numTypes(count)
e32caecb
     {
 	TypeMap.reserve(count);
 	// During recursive type construction pointers to Type* may be
 	// invalidated, so we must use a TypeHolder to an Opaque type as a
 	// start.
 	for (unsigned i=0;i<count;i++) {
 	    TypeMap.push_back(OpaqueType::get(Context));
 	}
 	std::vector<const Type*> Elts;
 	for (unsigned i=0;i<count;i++) {
 	    const struct cli_bc_type *type = &types[i];
 	    Elts.clear();
 	    unsigned n = type->kind == DArrayType ? 1 : type->numElements;
 	    for (unsigned j=0;j<n;j++) {
 		Elts.push_back(get(type->containedTypes[j]));
 	    }
 	    const Type *Ty;
 	    switch (type->kind) {
 		case DFunctionType:
 		{
 		    assert(Elts.size() > 0 && "Function with no return type?");
 		    const Type *RetTy = Elts[0];
d0af4afe
 		    if (Hidden)
 			Elts[0] = Hidden;
 		    else
 			Elts.erase(Elts.begin());
e32caecb
 		    Ty = FunctionType::get(RetTy, Elts, false);
 		    break;
 		}
 		case DPointerType:
 		    Ty = PointerType::getUnqual(Elts[0]);
 		    break;
 		case DStructType:
 		    Ty = StructType::get(Context, Elts);
 		    break;
 		case DPackedStructType:
 		    Ty = StructType::get(Context, Elts, true);
 		    break;
 		case DArrayType:
 		    Ty = ArrayType::get(Elts[0], type->numElements);
 		    break;
 	    }
 	    // Make the opaque type a concrete type, doing recursive type
 	    // unification if needed.
 	    cast<OpaqueType>(TypeMap[i].get())->refineAbstractTypeTo(Ty);
 	}
     }
 
     const Type *get(uint16_t ty)
     {
 	if (ty < 69)
 	    return getStatic(ty);
3b33bd68
 	ty -= 69;
e32caecb
 	assert(ty < numTypes && "TypeID out of range");
 	return TypeMap[ty].get();
3b33bd68
     }
e32caecb
 };
3b33bd68
 
daffb518
 
e32caecb
 class VISIBILITY_HIDDEN LLVMCodegen {
 private:
     const struct cli_bc *bc;
     Module *M;
     LLVMContext &Context;
     LLVMTypeMapper *TypeMap;
     Function **apiFuncs;
     FunctionMapTy &compiledFunctions;
     Twine BytecodeID;
     ExecutionEngine *EE;
     TargetFolder Folder;
     IRBuilder<false, TargetFolder> Builder;
     Value **Values;
     FunctionPassManager &PM;
     unsigned numLocals;
     unsigned numArgs;
3b33bd68
 
e6d1fe78
     Value *getOperand(const struct cli_bc_func *func, const Type *Ty, operand_t operand)
     {
 	unsigned map[] = {0, 1, 2, 3, 3, 4, 4, 4, 4};
 	if (operand < func->numValues)
 	    return Values[operand];
 	unsigned w = (Ty->getPrimitiveSizeInBits()+7)/8;
 	return convertOperand(func, map[w], operand);
     }
 
ee8f1888
     Value *convertOperand(const struct cli_bc_func *func, const Type *Ty, operand_t operand)
     {
 	unsigned map[] = {0, 1, 2, 3, 3, 4, 4, 4, 4};
 	if (operand < func->numArgs)
 	    return Values[operand];
e6d1fe78
 	if (operand < func->numValues) {
 	    Value *V = Values[operand];
 	    if (V->getType() == Ty)
 		return V;
 	    return Builder.CreateLoad(V);
 	}
ee8f1888
 	unsigned w = (Ty->getPrimitiveSizeInBits()+7)/8;
 	return convertOperand(func, map[w], operand);
     }
 
     Value *convertOperand(const struct cli_bc_func *func,
3b33bd68
 			  const struct cli_bc_inst *inst,  operand_t operand)
     {
ee8f1888
 	return convertOperand(func, inst->interp_op%5, operand);
     }
 
     Value *convertOperand(const struct cli_bc_func *func,
 			  unsigned w, operand_t operand) {
 	if (operand < func->numArgs)
 	    return Values[operand];
 	if (operand < func->numValues)
 	    return Builder.CreateLoad(Values[operand]);
 
 	// Constant
 	operand -= func->numValues;
 	// This was already validated by libclamav.
6b67ec6e
 	assert(operand < func->numConstants && "Constant out of range");
ee8f1888
 	uint64_t *c = &func->constants[operand];
 	uint64_t v;
 	const Type *Ty;
 	switch (w) {
 	    case 0:
 	    case 1:
e32caecb
 		Ty = w ? Type::getInt8Ty(Context) :
ee8f1888
 		    Type::getInt1Ty(Context);
 		v = *(uint8_t*)c;
 		break;
 	    case 2:
 		Ty = Type::getInt16Ty(Context);
 		v = *(uint16_t*)c;
 		break;
 	    case 3:
 		Ty = Type::getInt32Ty(Context);
 		v = *(uint32_t*)c;
 		break;
 	    case 4:
 		Ty = Type::getInt64Ty(Context);
 		v = *(uint64_t*)c;
 		break;
3b33bd68
 	}
ee8f1888
 	return ConstantInt::get(Ty, v);
     }
 
     void Store(uint16_t dest, Value *V)
     {
 	assert(dest >= numArgs && dest < numLocals+numArgs && "Instruction destination out of range");
 	Builder.CreateStore(V, Values[dest]);
3b33bd68
     }
6b67ec6e
 
     // Insert code that calls \arg FHandler if \arg FailCond is true.
     void InsertVerify(Value *FailCond, BasicBlock *&Fail, Function *FHandler, 
 		      Function *F) {
 	if (!Fail) {
 	    Fail = BasicBlock::Create(Context, "fail", F);
 	    CallInst::Create(FHandler,"",Fail);
 	    new UnreachableInst(Context, Fail);
 	}
 	BasicBlock *OkBB = BasicBlock::Create(Context, "", F);
 	Builder.CreateCondBr(FailCond, Fail, OkBB);
 	Builder.SetInsertPoint(OkBB);
     }
e32caecb
 
     const Type* mapType(uint16_t typeID)
     {
 	return TypeMap->get(typeID);
     }
3b33bd68
 public:
     LLVMCodegen(const struct cli_bc *bc, Module *M, FunctionMapTy &cFuncs,
e32caecb
 		ExecutionEngine *EE, FunctionPassManager &PM, Function **apiFuncs)
d0af4afe
 	: bc(bc), M(M), Context(M->getContext()), compiledFunctions(cFuncs),
 	BytecodeID("bc"+Twine(bc->id)), EE(EE),
 	Folder(EE->getTargetData(), Context), Builder(Context, Folder), PM(PM),
 	apiFuncs(apiFuncs)
e32caecb
     {}
daffb518
 
ee8f1888
     bool generate() {
3b33bd68
 	PrettyStackTraceString Trace(BytecodeID.str().c_str());
e32caecb
 	TypeMap = new LLVMTypeMapper(Context, bc->types + 4, bc->num_types - 5);
6b67ec6e
 
c466339d
 	FunctionType *FTy = FunctionType::get(Type::getVoidTy(Context),
6b67ec6e
 						    false);
 	Function *FHandler = Function::Create(FTy, Function::InternalLinkage,
 					      "clamjit.fail", M);
 	FHandler->setDoesNotReturn();
 	FHandler->setDoesNotThrow();
 	FHandler->addFnAttr(Attribute::NoInline);
 	EE->addGlobalMapping(FHandler, (void*)jit_exception_handler); 
 
d0af4afe
 	// The hidden ctx param to all functions
 	const Type *HiddenCtx = PointerType::getUnqual(Type::getInt8Ty(Context));
 
ee8f1888
 	Function **Functions = new Function*[bc->num_func];
daffb518
 	for (unsigned j=0;j<bc->num_func;j++) {
ee8f1888
 	    PrettyStackTraceString CrashInfo("Generate LLVM IR functions");
3b33bd68
 	    // Create LLVM IR Function
daffb518
 	    const struct cli_bc_func *func = &bc->funcs[j];
 	    std::vector<const Type*> argTypes;
d0af4afe
 	    argTypes.push_back(HiddenCtx);
daffb518
 	    for (unsigned a=0;a<func->numArgs;a++) {
3b33bd68
 		argTypes.push_back(mapType(func->types[a]));
 	    }
 	    const Type *RetTy = mapType(func->returnType);
c466339d
 	    FunctionType *FTy =  FunctionType::get(RetTy, argTypes,
3b33bd68
 							 false);
d0af4afe
 	    Functions[j] = Function::Create(FTy, Function::InternalLinkage,
3b33bd68
 					   BytecodeID+"f"+Twine(j), M);
6b67ec6e
 	    Functions[j]->setDoesNotThrow();
d0af4afe
 	    Functions[j]->setCallingConv(CallingConv::Fast);
ee8f1888
 	}
e6d1fe78
 	const Type *I32Ty = Type::getInt32Ty(Context);
ee8f1888
 	for (unsigned j=0;j<bc->num_func;j++) {
 	    PrettyStackTraceString CrashInfo("Generate LLVM IR");
 	    const struct cli_bc_func *func = &bc->funcs[j];
e32caecb
 
3b33bd68
 	    // Create all BasicBlocks
ee8f1888
 	    Function *F = Functions[j];
3b33bd68
 	    BasicBlock **BB = new BasicBlock*[func->numBB];
 	    for (unsigned i=0;i<func->numBB;i++) {
 		BB[i] = BasicBlock::Create(Context, "", F);
daffb518
 	    }
3b33bd68
 
6b67ec6e
 	    BasicBlock *Fail = 0;
ee8f1888
 	    Values = new Value*[func->numValues];
 	    Builder.SetInsertPoint(BB[0]);
 	    Function::arg_iterator I = F->arg_begin();
d0af4afe
 	    assert(F->arg_size() == func->numArgs + 1 && "Mismatched args");
 	    ++I;
ee8f1888
 	    for (unsigned i=0;i<func->numArgs; i++) {
 		assert(I != F->arg_end());
 		Values[i] = &*I;
 		++I;
 	    }
 	    for (unsigned i=func->numArgs;i<func->numValues;i++) {
479fa713
 		if (!func->types[i]) {
 		    //instructions without return value, like store
 		    Values[i] = 0;
 		    continue;
 		}
ee8f1888
 		Values[i] = Builder.CreateAlloca(mapType(func->types[i]));
 	    }
 	    numLocals = func->numLocals;
 	    numArgs = func->numArgs;
3b33bd68
 	    // Generate LLVM IR for each BB
 	    for (unsigned i=0;i<func->numBB;i++) {
 		const struct cli_bc_bb *bb = &func->BB[i];
 		Builder.SetInsertPoint(BB[i]);
 		for (unsigned j=0;j<bb->numInsts;j++) {
ee8f1888
 		    const struct cli_bc_inst *inst = &bb->insts[j];
 		    Value *Op0, *Op1, *Op2;
 		    // libclamav has already validated this.
 		    assert(inst->opcode < OP_INVALID && "Invalid opcode");
 		    switch (inst->opcode) {
 			case OP_JMP:
 			case OP_BRANCH:
 			case OP_CALL_API:
 			case OP_CALL_DIRECT:
 			case OP_ZEXT:
 			case OP_SEXT:
 			case OP_TRUNC:
e6d1fe78
 			case OP_GEP1:
 			case OP_GEP2:
 			case OP_GEPN:
 			case OP_STORE:
a1781898
 			case OP_COPY:
ee8f1888
 			    // these instructions represents operands differently
 			    break;
 			default:
 			    switch (operand_counts[inst->opcode]) {
 				case 1:
 				    Op0 = convertOperand(func, inst, inst->u.unaryop);
 				    break;
 				case 2:
 				    Op0 = convertOperand(func, inst, inst->u.binop[0]);
 				    Op1 = convertOperand(func, inst, inst->u.binop[1]);
 				    break;
 				case 3:
 				    Op0 = convertOperand(func, inst, inst->u.three[0]);
 				    Op1 = convertOperand(func, inst, inst->u.three[1]);
 				    Op2 = convertOperand(func, inst, inst->u.three[2]);
 				    break;
 			    }
 		    }
3b33bd68
 
 		    switch (inst->opcode) {
ee8f1888
 			case OP_ADD:
 			    Store(inst->dest, Builder.CreateAdd(Op0, Op1));
 			    break;
 			case OP_SUB:
 			    Store(inst->dest, Builder.CreateSub(Op0, Op1));
 			    break;
 			case OP_MUL:
 			    Store(inst->dest, Builder.CreateMul(Op0, Op1));
 			    break;
 			case OP_UDIV:
6b67ec6e
 			{
 			    Value *Bad = Builder.CreateICmpEQ(Op1, ConstantInt::get(Op1->getType(), 0));
 			    InsertVerify(Bad, Fail, FHandler, F);
ee8f1888
 			    Store(inst->dest, Builder.CreateUDiv(Op0, Op1));
 			    break;
6b67ec6e
 			}
ee8f1888
 			case OP_SDIV:
6b67ec6e
 			{
 			    //TODO: also verify Op0 == -1 && Op1 = INT_MIN
 			    Value *Bad = Builder.CreateICmpEQ(Op1, ConstantInt::get(Op1->getType(), 0));
 			    InsertVerify(Bad, Fail, FHandler, F);
ee8f1888
 			    Store(inst->dest, Builder.CreateSDiv(Op0, Op1));
 			    break;
6b67ec6e
 			}
ee8f1888
 			case OP_UREM:
6b67ec6e
 			{
 			    Value *Bad = Builder.CreateICmpEQ(Op1, ConstantInt::get(Op1->getType(), 0));
 			    InsertVerify(Bad, Fail, FHandler, F);
ee8f1888
 			    Store(inst->dest, Builder.CreateURem(Op0, Op1));
 			    break;
6b67ec6e
 			}
ee8f1888
 			case OP_SREM:
6b67ec6e
 			{
 			    //TODO: also verify Op0 == -1 && Op1 = INT_MIN
 			    Value *Bad = Builder.CreateICmpEQ(Op1, ConstantInt::get(Op1->getType(), 0));
 			    InsertVerify(Bad, Fail, FHandler, F);
ee8f1888
 			    Store(inst->dest, Builder.CreateSRem(Op0, Op1));
 			    break;
6b67ec6e
 			}
ee8f1888
 			case OP_SHL:
 			    Store(inst->dest, Builder.CreateShl(Op0, Op1));
 			    break;
 			case OP_LSHR:
 			    Store(inst->dest, Builder.CreateLShr(Op0, Op1));
 			    break;
 			case OP_ASHR:
 			    Store(inst->dest, Builder.CreateAShr(Op0, Op1));
 			    break;
 			case OP_AND:
 			    Store(inst->dest, Builder.CreateAnd(Op0, Op1));
 			    break;
 			case OP_OR:
 			    Store(inst->dest, Builder.CreateOr(Op0, Op1));
 			    break;
 			case OP_XOR:
 			    Store(inst->dest, Builder.CreateXor(Op0, Op1));
 			    break;
 			case OP_TRUNC:
 			{
 			    Value *Src = convertOperand(func, inst, inst->u.cast.source);
 			    const Type *Ty = mapType(func->types[inst->dest]);
 			    Store(inst->dest, Builder.CreateTrunc(Src,  Ty));
 			    break;
 			}
 			case OP_ZEXT:
 			{
 			    Value *Src = convertOperand(func, inst, inst->u.cast.source);
 			    const Type *Ty = mapType(func->types[inst->dest]);
 			    Store(inst->dest, Builder.CreateZExt(Src,  Ty));
 			    break;
 			}
 			case OP_SEXT:
 			{
 			    Value *Src = convertOperand(func, inst, inst->u.cast.source);
 			    const Type *Ty = mapType(func->types[inst->dest]);
 			    Store(inst->dest, Builder.CreateSExt(Src,  Ty));
 			    break;
 			}
 			case OP_BRANCH:
 			{
 			    Value *Cond = convertOperand(func, inst, inst->u.branch.condition);
 			    BasicBlock *True = BB[inst->u.branch.br_true];
 			    BasicBlock *False = BB[inst->u.branch.br_false];
 			    if (Cond->getType() != Type::getInt1Ty(Context)) {
 				errs() << MODULE << "type mismatch in condition\n";
 				return false;
 			    }
 			    Builder.CreateCondBr(Cond, True, False);
 			    break;
 			}
 			case OP_JMP:
 			{
 			    BasicBlock *Jmp = BB[inst->u.jump];
 			    Builder.CreateBr(Jmp);
 			    break;
 			}
3b33bd68
 			case OP_RET:
ee8f1888
 			    Builder.CreateRet(Op0);
 			    break;
 			case OP_ICMP_EQ:
 			    Store(inst->dest, Builder.CreateICmpEQ(Op0, Op1));
 			    break;
 			case OP_ICMP_NE:
 			    Store(inst->dest, Builder.CreateICmpNE(Op0, Op1));
 			    break;
 			case OP_ICMP_UGT:
6b67ec6e
 			    Store(inst->dest, Builder.CreateICmpUGT(Op0, Op1));
ee8f1888
 			    break;
 			case OP_ICMP_UGE:
6b67ec6e
 			    Store(inst->dest, Builder.CreateICmpUGE(Op0, Op1));
3b33bd68
 			    break;
ee8f1888
 			case OP_ICMP_ULT:
6b67ec6e
 			    Store(inst->dest, Builder.CreateICmpULT(Op0, Op1));
ee8f1888
 			    break;
 			case OP_ICMP_ULE:
6b67ec6e
 			    Store(inst->dest, Builder.CreateICmpULE(Op0, Op1));
ee8f1888
 			    break;
 			case OP_ICMP_SGT:
6b67ec6e
 			    Store(inst->dest, Builder.CreateICmpSGT(Op0, Op1));
ee8f1888
 			    break;
 			case OP_ICMP_SGE:
6b67ec6e
 			    Store(inst->dest, Builder.CreateICmpSGE(Op0, Op1));
ee8f1888
 			    break;
 			case OP_ICMP_SLT:
6b67ec6e
 			    Store(inst->dest, Builder.CreateICmpSLT(Op0, Op1));
ee8f1888
 			    break;
 			case OP_SELECT:
 			    Store(inst->dest, Builder.CreateSelect(Op0, Op1, Op2));
 			    break;
 			case OP_COPY:
a1781898
 			{
 			    Value *Dest = Values[inst->u.binop[1]];
 			    const PointerType *PTy = cast<PointerType>(Dest->getType());
 			    Op0 = convertOperand(func, PTy->getElementType(), inst->u.binop[0]);
 			    Builder.CreateStore(Op0, Dest);
ee8f1888
 			    break;
a1781898
 			}
ee8f1888
 			case OP_CALL_DIRECT:
 			{
 			    Function *DestF = Functions[inst->u.ops.funcid];
 			    SmallVector<Value*, 2> args;
d0af4afe
 			    args.push_back(&*F->arg_begin()); // pass hidden arg
ee8f1888
 			    for (unsigned a=0;a<inst->u.ops.numOps;a++) {
 				operand_t op = inst->u.ops.ops[a];
d0af4afe
 				args.push_back(convertOperand(func, DestF->getFunctionType()->getParamType(a+1), op));
ee8f1888
 			    }
d0af4afe
 			    CallInst *CI = Builder.CreateCall(DestF, args.begin(), args.end());
 			    CI->setCallingConv(CallingConv::Fast);
 			    Store(inst->dest, CI);
ee8f1888
 			    break;
 			}
e32caecb
 			case OP_CALL_API:
 			{
 			    assert(inst->u.ops.funcid < cli_apicall_maxapi && "APICall out of range");
 			    const struct cli_apicall *api = &cli_apicalls[inst->u.ops.funcid];
 			    std::vector<Value*> args;
 			    Function *DestF = apiFuncs[inst->u.ops.funcid];
d0af4afe
 			    args.push_back(&*F->arg_begin()); // pass hidden arg
e32caecb
 			    for (unsigned a=0;a<inst->u.ops.numOps;a++) {
 				operand_t op = inst->u.ops.ops[a];
d0af4afe
 				args.push_back(convertOperand(func, DestF->getFunctionType()->getParamType(a+1), op));
e32caecb
 			    }
 			    Store(inst->dest, Builder.CreateCall(DestF, args.begin(), args.end()));
 			    break;
 			}
e6d1fe78
 			case OP_GEP1:
 			{
 			    Value *V = Values[inst->u.binop[0]];
 			    Value *Op = convertOperand(func, I32Ty, inst->u.binop[1]);
 			    Store(inst->dest, Builder.CreateGEP(V, Op));
 			    break;
 			}
 			case OP_GEP2:
 			{
 			    std::vector<Value*> Idxs;
 			    Value *V = Values[inst->u.three[0]];
 			    Idxs.push_back(convertOperand(func, I32Ty, inst->u.three[1]));
 			    Idxs.push_back(convertOperand(func, I32Ty, inst->u.three[2]));
 			    Store(inst->dest, Builder.CreateGEP(V, Idxs.begin(), Idxs.end()));
 			    break;
 			}
 			case OP_GEPN:
 			{
 			    std::vector<Value*> Idxs;
 			    assert(inst->u.ops.numOps > 1);
 			    Value *V = Values[inst->u.ops.ops[0]];
 			    for (unsigned a=1;a<inst->u.ops.numOps;a++)
 				Idxs.push_back(convertOperand(func, I32Ty, inst->u.ops.ops[a]));
 			    Store(inst->dest, Builder.CreateGEP(V, Idxs.begin(), Idxs.end()));
 			    break;
 			}
 			case OP_STORE:
 			{
 			    Value *Dest = convertOperand(func, inst, inst->u.binop[1]);
 			    const Type *ETy = cast<PointerType>(Dest->getType())->getElementType();
 			    Builder.CreateStore(getOperand(func, ETy, inst->u.binop[0]),
 						Dest);
 			    break;
 			}
 			case OP_LOAD:
a1781898
 			    Op0 = Builder.CreateLoad(Op0);
e6d1fe78
 			    Store(inst->dest, Op0);
 			    break;
ee8f1888
 			default:
2487a4a3
 			    errs() << "JIT doesn't implement opcode " <<
 				inst->opcode << " yet!\n";
 			    return false;
3b33bd68
 		    }
 		}
 	    }
 
ee8f1888
 	    if (verifyFunction(*F, PrintMessageAction)) {
 		errs() << MODULE << "Verification failed\n";
 		// verification failed
 		return false;
 	    }
 	    PM.run(*F);
 	    delete [] Values;
6b67ec6e
 	    delete [] BB;
ee8f1888
 	}
 
6b67ec6e
 	DEBUG(M->dump());
e32caecb
 	delete TypeMap;
d0af4afe
 	std::vector<const Type*> args;
 	args.push_back(PointerType::getUnqual(Type::getInt8Ty(Context)));
 	FunctionType *Callable = FunctionType::get(Type::getInt32Ty(Context),
 						   args, false);
ee8f1888
 	for (unsigned j=0;j<bc->num_func;j++) {
 	    const struct cli_bc_func *func = &bc->funcs[j];
3b33bd68
 	    PrettyStackTraceString CrashInfo2("Native machine codegen");
6b67ec6e
 
 	    // If prototype matches, add to callable functions
d0af4afe
 	    if (Functions[j]->getFunctionType() == Callable) {
 		// All functions have the Fast calling convention, however
 		// entrypoint can only be C, emit wrapper
 		Function *F = Function::Create(Functions[j]->getFunctionType(),
 					       Function::ExternalLinkage,
 					       Functions[j]->getName()+"_wrap", M);
 		F->setDoesNotThrow();
 		BasicBlock *BB = BasicBlock::Create(Context, "", F);
 		std::vector<Value*> args;
 		for (Function::arg_iterator J=F->arg_begin(),
 		     JE=F->arg_end(); J != JE; ++JE) {
 		    args.push_back(&*J);
 		}
 		CallInst *CI = CallInst::Create(Functions[j], args.begin(), args.end(), "", BB);
 		CI->setCallingConv(CallingConv::Fast);
 		ReturnInst::Create(Context, CI, BB);
 
 		if (verifyFunction(*F, PrintMessageAction));
 		// Codegen current function as executable machine code.
 		void *code = EE->getPointerToFunction(F);
 
6b67ec6e
 		compiledFunctions[func] = code;
d0af4afe
 	    }
daffb518
 	}
6b67ec6e
 	delete [] Functions;
ee8f1888
 	return true;
daffb518
     }
3b33bd68
 };
d1487222
 }
 
85a25497
 int cli_vm_execute_jit(const struct cli_all_bc *bcs, struct cli_bc_ctx *ctx,
 		       const struct cli_bc_func *func)
d1487222
 {
6b67ec6e
     jmp_buf env;
85a25497
     void *code = bcs->engine->compiledFunctions[func];
6b67ec6e
     if (!code) {
 	errs() << MODULE << "Unable to find compiled function\n";
 	return CL_EBYTECODE;
     }
85a25497
     // execute;
6b67ec6e
     if (setjmp(env) == 0) {
 	// setup exception handler to longjmp back here
 	ExceptionReturn.set(&env);
d0af4afe
 	uint32_t result = ((uint32_t (*)(struct cli_bc_ctx *))code)(ctx);
6b67ec6e
 	*(uint32_t*)ctx->values = result;
 	return 0;
     }
     errs() << "\n";
     errs().changeColor(raw_ostream::RED, true) << MODULE 
 	<< "*** JITed code intercepted runtime error!\n";
     errs().resetColor();
     return CL_EBYTECODE;
d1487222
 }
 
daffb518
 
d1487222
 int cli_bytecode_prepare_jit(struct cli_all_bc *bcs)
 {
2487a4a3
   if (!bcs->engine)
       return CL_EBYTECODE;
6b67ec6e
   jmp_buf env;
   // setup exception handler to longjmp back here
   ExceptionReturn.set(&env);  
   if (setjmp(env) != 0) {
       errs() << "\n";
       errs().changeColor(raw_ostream::RED, true) << MODULE 
       << "*** FATAL error encountered during bytecode generation\n";
       errs().resetColor();
       return CL_EBYTECODE;
   }
d1487222
   // LLVM itself never throws exceptions, but operator new may throw bad_alloc
   try {
     Module *M = new Module("ClamAV jit module", bcs->engine->Context);
ee8f1888
     ExistingModuleProvider *MP = new ExistingModuleProvider(M);
d1487222
     {
 	// Create the JIT.
 	std::string ErrorMsg;
ee8f1888
 	EngineBuilder builder(MP);
d1487222
 	builder.setErrorStr(&ErrorMsg);
 	builder.setEngineKind(EngineKind::JIT);
 	builder.setOptLevel(CodeGenOpt::Aggressive);
 	ExecutionEngine *EE = bcs->engine->EE = builder.create();
 	if (!EE) {
 	    if (!ErrorMsg.empty())
 		errs() << MODULE << "error creating execution engine: " << ErrorMsg << "\n";
 	    else
 		errs() << MODULE << "JIT not registered?\n";
 	    return CL_EBYTECODE;
 	}
daffb518
 
 	EE->RegisterJITEventListener(createOProfileJITEventListener());
2487a4a3
 	// Due to LLVM PR4816 only X86 supports non-lazy compilation, disable
 	// for now.
 	// EE->DisableLazyCompilation();
6b67ec6e
 	EE->DisableSymbolSearching();
d1487222
 
ee8f1888
 	FunctionPassManager OurFPM(MP);
 	// Set up the optimizer pipeline.  Start with registering info about how
 	// the target lays out data structures.
 	OurFPM.add(new TargetData(*EE->getTargetData()));
 	// Promote allocas to registers.
 	OurFPM.add(createPromoteMemoryToRegisterPass());
e6d1fe78
 	// Delete dead instructions
 	OurFPM.add(createDeadCodeEliminationPass());
ee8f1888
 	OurFPM.doInitialization();
e32caecb
 
d0af4afe
 	//TODO: create a wrapper that calls pthread_getspecific
 	const Type *HiddenCtx = PointerType::getUnqual(Type::getInt8Ty(bcs->engine->Context));
 
 	LLVMTypeMapper apiMap(bcs->engine->Context, cli_apicall_types, cli_apicall_maxtypes, HiddenCtx);
e32caecb
 	Function **apiFuncs = new Function *[cli_apicall_maxapi];
 	for (unsigned i=0;i<cli_apicall_maxapi;i++) {
 	    const struct cli_apicall *api = &cli_apicalls[i];
 	    const FunctionType *FTy = cast<FunctionType>(apiMap.get(69+api->type));
 	    Function *F = Function::Create(FTy, Function::ExternalLinkage,
 					   api->name, M);
 	    void *dest;
 	    switch (api->kind) {
 		case 0:
 		    dest = (void*)cli_apicalls0[api->idx];
 		    break;
 		case 1:
 		    dest = (void*)cli_apicalls1[api->idx];
 		    break;
 	    }
 	    EE->addGlobalMapping(F, dest);
 	    apiFuncs[i] = F;
 	}
 
daffb518
 	for (unsigned i=0;i<bcs->count;i++) {
3b33bd68
 	    const struct cli_bc *bc = &bcs->all_bcs[i];
4789b8a5
 	    if (bc->state == bc_skip)
 		continue;
e32caecb
 	    LLVMCodegen Codegen(bc, M, bcs->engine->compiledFunctions, EE, 
 				OurFPM, apiFuncs);
ee8f1888
 	    if (!Codegen.generate()) {
 		errs() << MODULE << "JIT codegen failed\n";
 		return CL_EBYTECODE;
 	    }
daffb518
 	}
 
85a25497
 	for (unsigned i=0;i<bcs->count;i++) {
 	    bcs->all_bcs[i].state = bc_jit;
 	}
d1487222
 	// compile all functions now, not lazily!
 	for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) {
 	    Function *Fn = &*I;
 	    if (!Fn->isDeclaration())
 		EE->getPointerToFunction(Fn);
 	}
e32caecb
 	delete [] apiFuncs;
d1487222
     }
     return -1;
   } catch (std::bad_alloc &badalloc) {
       errs() << MODULE << badalloc.what() << "\n";
       return CL_EMEM;
   } catch (...) {
       errs() << MODULE << "Unexpected unknown exception occurred.\n";
       return CL_EBYTECODE;
   }
 }
 
 int bytecode_init(void)
 {
df52b258
     // If already initialized return
     if (llvm_is_multithreaded())
 	return 0;
d1487222
     llvm_install_error_handler(llvm_error_handler);
     sys::PrintStackTraceOnErrorSignal();
     atexit(do_shutdown);
 
     llvm_start_multithreaded();
 
     // If we have a native target, initialize it to ensure it is linked in and
     // usable by the JIT.
     InitializeNativeTarget();
     return 0;
 }
 
 // Called once when loading a new set of BC files
 int cli_bytecode_init_jit(struct cli_all_bc *bcs)
 {
6fa1a75b
     //TODO: if !llvm_is_multi...
3b33bd68
     bcs->engine = new(std::nothrow) struct cli_bcengine;
d1487222
     if (!bcs->engine)
 	return CL_EMEM;
     return 0;
 }
 
 int cli_bytecode_done_jit(struct cli_all_bc *bcs)
 {
2487a4a3
     if (bcs->engine) {
 	if (bcs->engine->EE)
 	    delete bcs->engine->EE;
 	delete bcs->engine;
 	bcs->engine = 0;
     }
d1487222
     return 0;
 }
3b33bd68
 
 void cli_bytecode_debug(int argc, char **argv)
 {
   cl::ParseCommandLineOptions(argc, argv);
 }
2487a4a3
 
 int have_clamjit=1;