bool PNaClSjLjEH::runOnModule(Module &M) { Type *JmpBufTy = ArrayType::get(Type::getInt8Ty(M.getContext()), kPNaClJmpBufSize); // Define "struct ExceptionFrame". StructType *ExceptionFrameTy = StructType::create(M.getContext(), "ExceptionFrame"); Type *ExceptionFrameFields[] = { JmpBufTy, // jmp_buf ExceptionFrameTy->getPointerTo(), // struct ExceptionFrame *next Type::getInt32Ty(M.getContext()) // Exception info (clause list ID) }; ExceptionFrameTy->setBody(ExceptionFrameFields); ExceptionInfoWriter ExcInfoWriter(&M.getContext()); for (Module::iterator Func = M.begin(), E = M.end(); Func != E; ++Func) { FuncRewriter Rewriter(ExceptionFrameTy, &ExcInfoWriter, Func); Rewriter.expandFunc(); } ExcInfoWriter.defineGlobalVariables(&M); return true; }
Function *GCOVProfiler::insertCounterWriteout( ArrayRef<std::pair<GlobalVariable *, MDNode *> > CountersBySP) { FunctionType *WriteoutFTy = FunctionType::get(Type::getVoidTy(*Ctx), false); Function *WriteoutF = M->getFunction("__llvm_gcov_writeout"); if (!WriteoutF) WriteoutF = Function::Create(WriteoutFTy, GlobalValue::InternalLinkage, "__llvm_gcov_writeout", M); WriteoutF->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); WriteoutF->addFnAttr(Attribute::NoInline); if (Options.NoRedZone) WriteoutF->addFnAttr(Attribute::NoRedZone); BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", WriteoutF); IRBuilder<> Builder(BB); Constant *StartFile = getStartFileFunc(); Constant *EmitFunction = getEmitFunctionFunc(); Constant *EmitArcs = getEmitArcsFunc(); Constant *SummaryInfo = getSummaryInfoFunc(); Constant *EndFile = getEndFileFunc(); NamedMDNode *CUNodes = M->getNamedMetadata("llvm.dbg.cu"); if (!CUNodes) { Builder.CreateRetVoid(); return WriteoutF; } // Collect the relevant data into a large constant data structure that we can // walk to write out everything. StructType *StartFileCallArgsTy = StructType::create( {Builder.getInt8PtrTy(), Builder.getInt8PtrTy(), Builder.getInt32Ty()}); StructType *EmitFunctionCallArgsTy = StructType::create( {Builder.getInt32Ty(), Builder.getInt8PtrTy(), Builder.getInt32Ty(), Builder.getInt8Ty(), Builder.getInt32Ty()}); StructType *EmitArcsCallArgsTy = StructType::create( {Builder.getInt32Ty(), Builder.getInt64Ty()->getPointerTo()}); StructType *FileInfoTy = StructType::create({StartFileCallArgsTy, Builder.getInt32Ty(), EmitFunctionCallArgsTy->getPointerTo(), EmitArcsCallArgsTy->getPointerTo()}); Constant *Zero32 = Builder.getInt32(0); // Build an explicit array of two zeros for use in ConstantExpr GEP building. Constant *TwoZero32s[] = {Zero32, Zero32}; SmallVector<Constant *, 8> FileInfos; for (int i : llvm::seq<int>(0, CUNodes->getNumOperands())) { auto *CU = cast<DICompileUnit>(CUNodes->getOperand(i)); // Skip module skeleton (and module) CUs. if (CU->getDWOId()) continue; std::string FilenameGcda = mangleName(CU, GCovFileType::GCDA); uint32_t CfgChecksum = FileChecksums.empty() ? 0 : FileChecksums[i]; auto *StartFileCallArgs = ConstantStruct::get( StartFileCallArgsTy, {Builder.CreateGlobalStringPtr(FilenameGcda), Builder.CreateGlobalStringPtr(ReversedVersion), Builder.getInt32(CfgChecksum)}); SmallVector<Constant *, 8> EmitFunctionCallArgsArray; SmallVector<Constant *, 8> EmitArcsCallArgsArray; for (int j : llvm::seq<int>(0, CountersBySP.size())) { auto *SP = cast_or_null<DISubprogram>(CountersBySP[j].second); uint32_t FuncChecksum = Funcs.empty() ? 0 : Funcs[j]->getFuncChecksum(); EmitFunctionCallArgsArray.push_back(ConstantStruct::get( EmitFunctionCallArgsTy, {Builder.getInt32(j), Options.FunctionNamesInData ? Builder.CreateGlobalStringPtr(getFunctionName(SP)) : Constant::getNullValue(Builder.getInt8PtrTy()), Builder.getInt32(FuncChecksum), Builder.getInt8(Options.UseCfgChecksum), Builder.getInt32(CfgChecksum)})); GlobalVariable *GV = CountersBySP[j].first; unsigned Arcs = cast<ArrayType>(GV->getValueType())->getNumElements(); EmitArcsCallArgsArray.push_back(ConstantStruct::get( EmitArcsCallArgsTy, {Builder.getInt32(Arcs), ConstantExpr::getInBoundsGetElementPtr( GV->getValueType(), GV, TwoZero32s)})); } // Create global arrays for the two emit calls. int CountersSize = CountersBySP.size(); assert(CountersSize == (int)EmitFunctionCallArgsArray.size() && "Mismatched array size!"); assert(CountersSize == (int)EmitArcsCallArgsArray.size() && "Mismatched array size!"); auto *EmitFunctionCallArgsArrayTy = ArrayType::get(EmitFunctionCallArgsTy, CountersSize); auto *EmitFunctionCallArgsArrayGV = new GlobalVariable( *M, EmitFunctionCallArgsArrayTy, /*isConstant*/ true, GlobalValue::InternalLinkage, ConstantArray::get(EmitFunctionCallArgsArrayTy, EmitFunctionCallArgsArray), Twine("__llvm_internal_gcov_emit_function_args.") + Twine(i)); auto *EmitArcsCallArgsArrayTy = ArrayType::get(EmitArcsCallArgsTy, CountersSize); EmitFunctionCallArgsArrayGV->setUnnamedAddr( GlobalValue::UnnamedAddr::Global); auto *EmitArcsCallArgsArrayGV = new GlobalVariable( *M, EmitArcsCallArgsArrayTy, /*isConstant*/ true, GlobalValue::InternalLinkage, ConstantArray::get(EmitArcsCallArgsArrayTy, EmitArcsCallArgsArray), Twine("__llvm_internal_gcov_emit_arcs_args.") + Twine(i)); EmitArcsCallArgsArrayGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); FileInfos.push_back(ConstantStruct::get( FileInfoTy, {StartFileCallArgs, Builder.getInt32(CountersSize), ConstantExpr::getInBoundsGetElementPtr(EmitFunctionCallArgsArrayTy, EmitFunctionCallArgsArrayGV, TwoZero32s), ConstantExpr::getInBoundsGetElementPtr( EmitArcsCallArgsArrayTy, EmitArcsCallArgsArrayGV, TwoZero32s)})); } // If we didn't find anything to actually emit, bail on out. if (FileInfos.empty()) { Builder.CreateRetVoid(); return WriteoutF; } // To simplify code, we cap the number of file infos we write out to fit // easily in a 32-bit signed integer. This gives consistent behavior between // 32-bit and 64-bit systems without requiring (potentially very slow) 64-bit // operations on 32-bit systems. It also seems unreasonable to try to handle // more than 2 billion files. if ((int64_t)FileInfos.size() > (int64_t)INT_MAX) FileInfos.resize(INT_MAX); // Create a global for the entire data structure so we can walk it more // easily. auto *FileInfoArrayTy = ArrayType::get(FileInfoTy, FileInfos.size()); auto *FileInfoArrayGV = new GlobalVariable( *M, FileInfoArrayTy, /*isConstant*/ true, GlobalValue::InternalLinkage, ConstantArray::get(FileInfoArrayTy, FileInfos), "__llvm_internal_gcov_emit_file_info"); FileInfoArrayGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); // Create the CFG for walking this data structure. auto *FileLoopHeader = BasicBlock::Create(*Ctx, "file.loop.header", WriteoutF); auto *CounterLoopHeader = BasicBlock::Create(*Ctx, "counter.loop.header", WriteoutF); auto *FileLoopLatch = BasicBlock::Create(*Ctx, "file.loop.latch", WriteoutF); auto *ExitBB = BasicBlock::Create(*Ctx, "exit", WriteoutF); // We always have at least one file, so just branch to the header. Builder.CreateBr(FileLoopHeader); // The index into the files structure is our loop induction variable. Builder.SetInsertPoint(FileLoopHeader); PHINode *IV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2); IV->addIncoming(Builder.getInt32(0), BB); auto *FileInfoPtr = Builder.CreateInBoundsGEP(FileInfoArrayGV, {Builder.getInt32(0), IV}); auto *StartFileCallArgsPtr = Builder.CreateStructGEP(FileInfoPtr, 0); Builder.CreateCall( StartFile, {Builder.CreateLoad(Builder.CreateStructGEP(StartFileCallArgsPtr, 0)), Builder.CreateLoad(Builder.CreateStructGEP(StartFileCallArgsPtr, 1)), Builder.CreateLoad(Builder.CreateStructGEP(StartFileCallArgsPtr, 2))}); auto *NumCounters = Builder.CreateLoad(Builder.CreateStructGEP(FileInfoPtr, 1)); auto *EmitFunctionCallArgsArray = Builder.CreateLoad(Builder.CreateStructGEP(FileInfoPtr, 2)); auto *EmitArcsCallArgsArray = Builder.CreateLoad(Builder.CreateStructGEP(FileInfoPtr, 3)); auto *EnterCounterLoopCond = Builder.CreateICmpSLT(Builder.getInt32(0), NumCounters); Builder.CreateCondBr(EnterCounterLoopCond, CounterLoopHeader, FileLoopLatch); Builder.SetInsertPoint(CounterLoopHeader); auto *JV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2); JV->addIncoming(Builder.getInt32(0), FileLoopHeader); auto *EmitFunctionCallArgsPtr = Builder.CreateInBoundsGEP(EmitFunctionCallArgsArray, {JV}); Builder.CreateCall( EmitFunction, {Builder.CreateLoad(Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 0)), Builder.CreateLoad(Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 1)), Builder.CreateLoad(Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 2)), Builder.CreateLoad(Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 3)), Builder.CreateLoad( Builder.CreateStructGEP(EmitFunctionCallArgsPtr, 4))}); auto *EmitArcsCallArgsPtr = Builder.CreateInBoundsGEP(EmitArcsCallArgsArray, {JV}); Builder.CreateCall( EmitArcs, {Builder.CreateLoad(Builder.CreateStructGEP(EmitArcsCallArgsPtr, 0)), Builder.CreateLoad(Builder.CreateStructGEP(EmitArcsCallArgsPtr, 1))}); auto *NextJV = Builder.CreateAdd(JV, Builder.getInt32(1)); auto *CounterLoopCond = Builder.CreateICmpSLT(NextJV, NumCounters); Builder.CreateCondBr(CounterLoopCond, CounterLoopHeader, FileLoopLatch); JV->addIncoming(NextJV, CounterLoopHeader); Builder.SetInsertPoint(FileLoopLatch); Builder.CreateCall(SummaryInfo, {}); Builder.CreateCall(EndFile, {}); auto *NextIV = Builder.CreateAdd(IV, Builder.getInt32(1)); auto *FileLoopCond = Builder.CreateICmpSLT(NextIV, Builder.getInt32(FileInfos.size())); Builder.CreateCondBr(FileLoopCond, FileLoopHeader, ExitBB); IV->addIncoming(NextIV, FileLoopLatch); Builder.SetInsertPoint(ExitBB); Builder.CreateRetVoid(); return WriteoutF; }
static bool ExpandVarArgCall(Module *M, InstType *Call, DataLayout *DL) { FunctionType *FuncType = cast<FunctionType>( Call->getCalledValue()->getType()->getPointerElementType()); if (!FuncType->isFunctionVarArg()) return false; if (auto *F = dyn_cast<Function>(Call->getCalledValue())) if (isEmscriptenJSArgsFunc(M, F->getName())) return false; Function *F = Call->getParent()->getParent(); LLVMContext &Ctx = M->getContext(); SmallVector<AttributeSet, 8> Attrs; Attrs.push_back(Call->getAttributes().getFnAttributes()); Attrs.push_back(Call->getAttributes().getRetAttributes()); // Split argument list into fixed and variable arguments. SmallVector<Value *, 8> FixedArgs; SmallVector<Value *, 8> VarArgs; SmallVector<Type *, 8> VarArgsTypes; for (unsigned I = 0, E = FuncType->getNumParams(); I < E; ++I) { FixedArgs.push_back(Call->getArgOperand(I)); // AttributeSets use 1-based indexing. Attrs.push_back(Call->getAttributes().getParamAttributes(I + 1)); } for (unsigned I = FuncType->getNumParams(), E = Call->getNumArgOperands(); I < E; ++I) { Value *ArgVal = Call->getArgOperand(I); VarArgs.push_back(ArgVal); bool isByVal = Call->getAttributes().hasAttribute(I + 1, Attribute::ByVal); // For "byval" arguments we must dereference the pointer. VarArgsTypes.push_back(isByVal ? ArgVal->getType()->getPointerElementType() : ArgVal->getType()); } if (VarArgsTypes.size() == 0) { // Some buggy code (e.g. 176.gcc in Spec2k) uses va_arg on an // empty argument list, which gives undefined behaviour in C. To // work around such programs, we create a dummy varargs buffer on // the stack even though there are no arguments to put in it. // This allows va_arg to read an undefined value from the stack // rather than crashing by reading from an uninitialized pointer. // An alternative would be to pass a null pointer to catch the // invalid use of va_arg. VarArgsTypes.push_back(Type::getInt32Ty(Ctx)); } // Create struct type for packing variable arguments into. StructType *VarArgsTy = StructType::get(Ctx, VarArgsTypes); // Allocate space for the variable argument buffer. Do this at the // start of the function so that we don't leak space if the function // is called in a loop. IRBuilder<> IRB(F->getEntryBlock().getFirstInsertionPt()); auto *Buf = IRB.CreateAlloca(VarArgsTy, nullptr, "vararg_buffer"); // Call llvm.lifetime.start/end intrinsics to indicate that Buf is // only used for the duration of the function call, so that the // stack space can be reused elsewhere. auto LifetimeStart = Intrinsic::getDeclaration(M, Intrinsic::lifetime_start); auto LifetimeEnd = Intrinsic::getDeclaration(M, Intrinsic::lifetime_end); auto *I8Ptr = Type::getInt8Ty(Ctx)->getPointerTo(); auto *BufPtr = IRB.CreateBitCast(Buf, I8Ptr, "vararg_lifetime_bitcast"); auto *BufSize = ConstantInt::get(Ctx, APInt(64, DL->getTypeAllocSize(VarArgsTy))); IRB.CreateCall2(LifetimeStart, BufSize, BufPtr); // Copy variable arguments into buffer. int Index = 0; IRB.SetInsertPoint(Call); for (Value *Arg : VarArgs) { Value *Indexes[] = {ConstantInt::get(Ctx, APInt(32, 0)), ConstantInt::get(Ctx, APInt(32, Index))}; Value *Ptr = IRB.CreateInBoundsGEP(Buf, Indexes, "vararg_ptr"); bool isByVal = Call->getAttributes().hasAttribute( FuncType->getNumParams() + Index + 1, Attribute::ByVal); if (isByVal) IRB.CreateMemCpy(Ptr, Arg, DL->getTypeAllocSize( Arg->getType()->getPointerElementType()), /*Align=*/1); else IRB.CreateStore(Arg, Ptr); ++Index; } // Cast function to new type to add our extra pointer argument. SmallVector<Type *, 8> ArgTypes(FuncType->param_begin(), FuncType->param_end()); ArgTypes.push_back(VarArgsTy->getPointerTo()); FunctionType *NFTy = FunctionType::get(FuncType->getReturnType(), ArgTypes, /*isVarArg=*/false); Value *CastFunc = IRB.CreateBitCast(Call->getCalledValue(), NFTy->getPointerTo(), "vararg_func"); // Create the converted function call. FixedArgs.push_back(Buf); Instruction *NewCall; if (auto *C = dyn_cast<CallInst>(Call)) { auto *N = IRB.CreateCall(CastFunc, FixedArgs); N->setAttributes(AttributeSet::get(Ctx, Attrs)); NewCall = N; IRB.CreateCall2(LifetimeEnd, BufSize, BufPtr); } else if (auto *C = dyn_cast<InvokeInst>(Call)) { auto *N = IRB.CreateInvoke(CastFunc, C->getNormalDest(), C->getUnwindDest(), FixedArgs, C->getName()); N->setAttributes(AttributeSet::get(Ctx, Attrs)); (IRBuilder<>(C->getNormalDest()->getFirstInsertionPt())) .CreateCall2(LifetimeEnd, BufSize, BufPtr); (IRBuilder<>(C->getUnwindDest()->getFirstInsertionPt())) .CreateCall2(LifetimeEnd, BufSize, BufPtr); NewCall = N; } else { llvm_unreachable("not a call/invoke"); } NewCall->takeName(Call); Call->replaceAllUsesWith(NewCall); Call->eraseFromParent(); return true; }
int main() { InitializeNativeTarget(); LLVMContext& Context = getGlobalContext(); Module *M = new Module("test C++ exception handling ", Context); StructType* MyStructType = StructType::create(Context, "struct.MyStruct"); Type* MyStructFields[] = { Type::getInt32Ty(Context), Type::getInt32Ty(Context) }; MyStructType->setBody(MyStructFields); GlobalValue* throwFunc = cast<GlobalValue>(M->getOrInsertFunction("throwMyStruct", Type::getVoidTy(Context), NULL)); GlobalValue* MyStructTypeInfo = cast<GlobalValue>(M->getOrInsertGlobal("MyStructTypeInfo", Type::getInt8Ty(Context))); Function* gxx_personality = Function::Create(FunctionType::get(Type::getInt32Ty(Context), true), Function::ExternalLinkage, "__gxx_personality_v0", M); Function* begin_catch = Function::Create(FunctionType::get(Type::getInt8PtrTy(Context), Type::getInt8PtrTy(Context), false), Function::ExternalLinkage, "__cxa_begin_catch", M); Function* end_catch = Function::Create(FunctionType::get(Type::getVoidTy(Context), false), Function::ExternalLinkage, "__cxa_end_catch", M); Function* testExceptions = cast<Function>(M->getOrInsertFunction("testExceptions", Type::getInt32Ty(Context), NULL)); BasicBlock* entryBB = BasicBlock::Create(Context, "", testExceptions); BasicBlock* landPadBB = BasicBlock::Create(Context, "landPad", testExceptions); BasicBlock* noErrorBB = BasicBlock::Create(Context, "noError", testExceptions); IRBuilder<> builder(entryBB); Value* invokeThrow = builder.CreateInvoke(throwFunc, noErrorBB, landPadBB); builder.SetInsertPoint(noErrorBB); builder.CreateRet( builder.getInt32(666) ); // should never happen //writing landingpad! <<<<<<< builder.SetInsertPoint(landPadBB); Value* gxx_personality_i8 = builder.CreateBitCast(gxx_personality, Type::getInt8PtrTy(Context)); Type* caughtType = StructType::get(builder.getInt8PtrTy(), builder.getInt32Ty(), NULL); LandingPadInst* caughtResult = builder.CreateLandingPad(caughtType, gxx_personality_i8, 1); // we can catch any C++ exception we want // but now we are catching MyStruct caughtResult->addClause(MyStructTypeInfo); //we are sure to catch MyStruct so no other checks are needed //if throwMyStruct() throws anything but MyStruct it won't pass to the current landingpad BB Value* thrownExctn = builder.CreateExtractValue(caughtResult, 0); Value* thrownObject = builder.CreateCall(begin_catch, thrownExctn); Value* object = builder.CreateBitCast(thrownObject, MyStructType->getPointerTo()); Value* resultPtr = builder.CreateStructGEP(object, 1); Value* result = builder.CreateLoad(resultPtr); builder.CreateCall(end_catch); builder.CreateRet( result ); // << z.y TargetOptions Opts; Opts.JITExceptionHandling = true; // DO NOT FORGET THIS OPTION !!!!!!11 ExecutionEngine* EE = EngineBuilder(M) .setEngineKind(EngineKind::JIT) .setTargetOptions(Opts) .create(); EE->addGlobalMapping(throwFunc, reinterpret_cast<void*>(&throwMyStruct)); EE->addGlobalMapping(MyStructTypeInfo, MyStruct::getTypeInfo()); verifyFunction(*testExceptions); outs() << *testExceptions; std::vector<GenericValue> noArgs; GenericValue gv = EE->runFunction(testExceptions, noArgs); outs() << "\ntestExceptions result: " << gv.IntVal << "\n"; delete EE; llvm_shutdown(); return 0; }