X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FX86%2FX86WinEHState.cpp;h=dce94a9e9ef7830a2ccde818209fb28d288b519b;hb=09816bb5493ff7d0645dc5b254a18a6c0d0a4078;hp=8a4a8161a0340c13d4d107507773a72ffa1a1fd1;hpb=f0e3e4cd84a73ebd9b5edf35a915431a5419614e;p=oota-llvm.git diff --git a/lib/Target/X86/X86WinEHState.cpp b/lib/Target/X86/X86WinEHState.cpp index 8a4a8161a03..dce94a9e9ef 100644 --- a/lib/Target/X86/X86WinEHState.cpp +++ b/lib/Target/X86/X86WinEHState.cpp @@ -15,7 +15,8 @@ //===----------------------------------------------------------------------===// #include "X86.h" -#include "llvm/Analysis/LibCallSemantics.h" +#include "llvm/Analysis/CFG.h" +#include "llvm/Analysis/EHPersonalities.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/WinEHFuncInfo.h" @@ -38,12 +39,16 @@ using namespace llvm::PatternMatch; #define DEBUG_TYPE "winehstate" +namespace llvm { void initializeWinEHStatePassPass(PassRegistry &); } + namespace { class WinEHStatePass : public FunctionPass { public: static char ID; // Pass identification, replacement for typeid. - WinEHStatePass() : FunctionPass(ID) {} + WinEHStatePass() : FunctionPass(ID) { + initializeWinEHStatePassPass(*PassRegistry::getPassRegistry()); + } bool runOnFunction(Function &Fn) override; @@ -60,31 +65,28 @@ public: private: void emitExceptionRegistrationRecord(Function *F); - void linkExceptionRegistration(IRBuilder<> &Builder, Value *Handler); + void linkExceptionRegistration(IRBuilder<> &Builder, Function *Handler); void unlinkExceptionRegistration(IRBuilder<> &Builder); - void addCXXStateStores(Function &F, MachineModuleInfo &MMI); - void addCXXStateStoresToFunclet(Value *ParentRegNode, WinEHFuncInfo &FuncInfo, - Function &F, int BaseState); + void addStateStores(Function &F, WinEHFuncInfo &FuncInfo); void insertStateNumberStore(Value *ParentRegNode, Instruction *IP, int State); Value *emitEHLSDA(IRBuilder<> &Builder, Function *F); Function *generateLSDAInEAXThunk(Function *ParentFunc); - int escapeRegNode(Function &F); - // Module-level type getters. - Type *getEHRegistrationType(); - Type *getSEH3RegistrationType(); - Type *getSEH4RegistrationType(); - Type *getCXXEH3RegistrationType(); + Type *getEHLinkRegistrationType(); + Type *getSEHRegistrationType(); + Type *getCXXEHRegistrationType(); // Per-module data. Module *TheModule = nullptr; - StructType *EHRegistrationTy = nullptr; - StructType *CXXEH3RegistrationTy = nullptr; - StructType *SEH3RegistrationTy = nullptr; - StructType *SEH4RegistrationTy = nullptr; + StructType *EHLinkRegistrationTy = nullptr; + StructType *CXXEHRegistrationTy = nullptr; + StructType *SEHRegistrationTy = nullptr; + Function *FrameRecover = nullptr; + Function *FrameAddress = nullptr; + Function *FrameEscape = nullptr; // Per-function state EHPersonality Personality = EHPersonality::Unknown; @@ -109,50 +111,57 @@ FunctionPass *llvm::createX86WinEHStatePass() { return new WinEHStatePass(); } char WinEHStatePass::ID = 0; +INITIALIZE_PASS(WinEHStatePass, "x86-winehstate", + "Insert stores for EH state numbers", false, false) + bool WinEHStatePass::doInitialization(Module &M) { TheModule = &M; + FrameEscape = Intrinsic::getDeclaration(TheModule, Intrinsic::localescape); + FrameRecover = Intrinsic::getDeclaration(TheModule, Intrinsic::localrecover); + FrameAddress = Intrinsic::getDeclaration(TheModule, Intrinsic::frameaddress); return false; } bool WinEHStatePass::doFinalization(Module &M) { assert(TheModule == &M); TheModule = nullptr; - EHRegistrationTy = nullptr; - CXXEH3RegistrationTy = nullptr; - SEH3RegistrationTy = nullptr; - SEH4RegistrationTy = nullptr; + EHLinkRegistrationTy = nullptr; + CXXEHRegistrationTy = nullptr; + SEHRegistrationTy = nullptr; + FrameEscape = nullptr; + FrameRecover = nullptr; + FrameAddress = nullptr; return false; } void WinEHStatePass::getAnalysisUsage(AnalysisUsage &AU) const { // This pass should only insert a stack allocation, memory accesses, and - // framerecovers. + // localrecovers. AU.setPreservesCFG(); } bool WinEHStatePass::runOnFunction(Function &F) { - // If this is an outlined handler, don't do anything. We'll do state insertion - // for it in the parent. - StringRef WinEHParentName = - F.getFnAttribute("wineh-parent").getValueAsString(); - if (WinEHParentName != F.getName() && !WinEHParentName.empty()) - return false; - - // Check the personality. Do nothing if this is not an MSVC personality. - LandingPadInst *LP = nullptr; - for (BasicBlock &BB : F) { - LP = BB.getLandingPadInst(); - if (LP) - break; - } - if (!LP) + // Check the personality. Do nothing if this personality doesn't use funclets. + if (!F.hasPersonalityFn()) return false; PersonalityFn = - dyn_cast(LP->getPersonalityFn()->stripPointerCasts()); + dyn_cast(F.getPersonalityFn()->stripPointerCasts()); if (!PersonalityFn) return false; Personality = classifyEHPersonality(PersonalityFn); - if (!isMSVCEHPersonality(Personality)) + if (!isFuncletEHPersonality(Personality)) + return false; + + // Skip this function if there are no EH pads and we aren't using IR-level + // outlining. + bool HasPads = false; + for (BasicBlock &BB : F) { + if (BB.isEHPad()) { + HasPads = true; + break; + } + } + if (!HasPads) return false; // Disable frame pointer elimination in this function. @@ -162,12 +171,13 @@ bool WinEHStatePass::runOnFunction(Function &F) { emitExceptionRegistrationRecord(&F); - auto *MMIPtr = getAnalysisIfAvailable(); - assert(MMIPtr && "MachineModuleInfo should always be available"); - MachineModuleInfo &MMI = *MMIPtr; - if (Personality == EHPersonality::MSVC_CXX) { - addCXXStateStores(F, MMI); - } + // The state numbers calculated here in IR must agree with what we calculate + // later on for the MachineFunction. In particular, if an IR pass deletes an + // unreachable EH pad after this point before machine CFG construction, we + // will be in trouble. If this assumption is ever broken, we should turn the + // numbers into an immutable analysis pass. + WinEHFuncInfo FuncInfo; + addStateStores(F, FuncInfo); // Reset per-function state. PersonalityFn = nullptr; @@ -182,17 +192,17 @@ bool WinEHStatePass::runOnFunction(Function &F) { /// EHRegistrationNode *Next; /// PEXCEPTION_ROUTINE Handler; /// }; -Type *WinEHStatePass::getEHRegistrationType() { - if (EHRegistrationTy) - return EHRegistrationTy; +Type *WinEHStatePass::getEHLinkRegistrationType() { + if (EHLinkRegistrationTy) + return EHLinkRegistrationTy; LLVMContext &Context = TheModule->getContext(); - EHRegistrationTy = StructType::create(Context, "EHRegistrationNode"); + EHLinkRegistrationTy = StructType::create(Context, "EHRegistrationNode"); Type *FieldTys[] = { - EHRegistrationTy->getPointerTo(0), // EHRegistrationNode *Next + EHLinkRegistrationTy->getPointerTo(0), // EHRegistrationNode *Next Type::getInt8PtrTy(Context) // EXCEPTION_DISPOSITION (*Handler)(...) }; - EHRegistrationTy->setBody(FieldTys, false); - return EHRegistrationTy; + EHLinkRegistrationTy->setBody(FieldTys, false); + return EHLinkRegistrationTy; } /// The __CxxFrameHandler3 registration node: @@ -201,40 +211,21 @@ Type *WinEHStatePass::getEHRegistrationType() { /// EHRegistrationNode SubRecord; /// int32_t TryLevel; /// }; -Type *WinEHStatePass::getCXXEH3RegistrationType() { - if (CXXEH3RegistrationTy) - return CXXEH3RegistrationTy; +Type *WinEHStatePass::getCXXEHRegistrationType() { + if (CXXEHRegistrationTy) + return CXXEHRegistrationTy; LLVMContext &Context = TheModule->getContext(); Type *FieldTys[] = { Type::getInt8PtrTy(Context), // void *SavedESP - getEHRegistrationType(), // EHRegistrationNode SubRecord + getEHLinkRegistrationType(), // EHRegistrationNode SubRecord Type::getInt32Ty(Context) // int32_t TryLevel }; - CXXEH3RegistrationTy = + CXXEHRegistrationTy = StructType::create(FieldTys, "CXXExceptionRegistration"); - return CXXEH3RegistrationTy; + return CXXEHRegistrationTy; } -/// The _except_handler3 registration node: -/// struct EH3ExceptionRegistration { -/// EHRegistrationNode SubRecord; -/// void *ScopeTable; -/// int32_t TryLevel; -/// }; -Type *WinEHStatePass::getSEH3RegistrationType() { - if (SEH3RegistrationTy) - return SEH3RegistrationTy; - LLVMContext &Context = TheModule->getContext(); - Type *FieldTys[] = { - getEHRegistrationType(), // EHRegistrationNode SubRecord - Type::getInt8PtrTy(Context), // void *ScopeTable - Type::getInt32Ty(Context) // int32_t TryLevel - }; - SEH3RegistrationTy = StructType::create(FieldTys, "EH3ExceptionRegistration"); - return SEH3RegistrationTy; -} - -/// The _except_handler4 registration node: +/// The _except_handler3/4 registration node: /// struct EH4ExceptionRegistration { /// void *SavedESP; /// _EXCEPTION_POINTERS *ExceptionPointers; @@ -242,19 +233,19 @@ Type *WinEHStatePass::getSEH3RegistrationType() { /// int32_t EncodedScopeTable; /// int32_t TryLevel; /// }; -Type *WinEHStatePass::getSEH4RegistrationType() { - if (SEH4RegistrationTy) - return SEH4RegistrationTy; +Type *WinEHStatePass::getSEHRegistrationType() { + if (SEHRegistrationTy) + return SEHRegistrationTy; LLVMContext &Context = TheModule->getContext(); Type *FieldTys[] = { Type::getInt8PtrTy(Context), // void *SavedESP Type::getInt8PtrTy(Context), // void *ExceptionPointers - getEHRegistrationType(), // EHRegistrationNode SubRecord + getEHLinkRegistrationType(), // EHRegistrationNode SubRecord Type::getInt32Ty(Context), // int32_t EncodedScopeTable Type::getInt32Ty(Context) // int32_t TryLevel }; - SEH4RegistrationTy = StructType::create(FieldTys, "EH4ExceptionRegistration"); - return SEH4RegistrationTy; + SEHRegistrationTy = StructType::create(FieldTys, "SEHExceptionRegistration"); + return SEHRegistrationTy; } // Emit an exception registration record. These are stack allocations with the @@ -268,48 +259,49 @@ void WinEHStatePass::emitExceptionRegistrationRecord(Function *F) { StringRef PersonalityName = PersonalityFn->getName(); IRBuilder<> Builder(&F->getEntryBlock(), F->getEntryBlock().begin()); Type *Int8PtrType = Builder.getInt8PtrTy(); - if (PersonalityName == "__CxxFrameHandler3") { - RegNodeTy = getCXXEH3RegistrationType(); + if (Personality == EHPersonality::MSVC_CXX) { + RegNodeTy = getCXXEHRegistrationType(); RegNode = Builder.CreateAlloca(RegNodeTy); - // FIXME: We can skip this in -GS- mode, when we figure that out. // SavedESP = llvm.stacksave() Value *SP = Builder.CreateCall( Intrinsic::getDeclaration(TheModule, Intrinsic::stacksave), {}); Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0)); // TryLevel = -1 StateFieldIndex = 2; - insertStateNumberStore(RegNode, Builder.GetInsertPoint(), -1); + insertStateNumberStore(RegNode, &*Builder.GetInsertPoint(), -1); // Handler = __ehhandler$F Function *Trampoline = generateLSDAInEAXThunk(F); Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 1); linkExceptionRegistration(Builder, Trampoline); - } else if (PersonalityName == "_except_handler3") { - RegNodeTy = getSEH3RegistrationType(); - RegNode = Builder.CreateAlloca(RegNodeTy); - // TryLevel = -1 - StateFieldIndex = 2; - insertStateNumberStore(RegNode, Builder.GetInsertPoint(), -1); - // ScopeTable = llvm.x86.seh.lsda(F) - Value *LSDA = emitEHLSDA(Builder, F); - Builder.CreateStore(LSDA, Builder.CreateStructGEP(RegNodeTy, RegNode, 1)); - Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 0); - linkExceptionRegistration(Builder, PersonalityFn); - } else if (PersonalityName == "_except_handler4") { - RegNodeTy = getSEH4RegistrationType(); + } else if (Personality == EHPersonality::MSVC_X86SEH) { + // If _except_handler4 is in use, some additional guard checks and prologue + // stuff is required. + bool UseStackGuard = (PersonalityName == "_except_handler4"); + RegNodeTy = getSEHRegistrationType(); RegNode = Builder.CreateAlloca(RegNodeTy); // SavedESP = llvm.stacksave() Value *SP = Builder.CreateCall( Intrinsic::getDeclaration(TheModule, Intrinsic::stacksave), {}); Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0)); - // TryLevel = -1 + // TryLevel = -2 / -1 StateFieldIndex = 4; - insertStateNumberStore(RegNode, Builder.GetInsertPoint(), -1); - // FIXME: XOR the LSDA with __security_cookie. + insertStateNumberStore(RegNode, &*Builder.GetInsertPoint(), + UseStackGuard ? -2 : -1); // ScopeTable = llvm.x86.seh.lsda(F) Value *FI8 = Builder.CreateBitCast(F, Int8PtrType); Value *LSDA = Builder.CreateCall( Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_lsda), FI8); - Builder.CreateStore(LSDA, Builder.CreateStructGEP(RegNodeTy, RegNode, 1)); + Type *Int32Ty = Type::getInt32Ty(TheModule->getContext()); + LSDA = Builder.CreatePtrToInt(LSDA, Int32Ty); + // If using _except_handler4, xor the address of the table with + // __security_cookie. + if (UseStackGuard) { + Value *Cookie = + TheModule->getOrInsertGlobal("__security_cookie", Int32Ty); + Value *Val = Builder.CreateLoad(Int32Ty, Cookie); + LSDA = Builder.CreateXor(LSDA, Val); + } + Builder.CreateStore(LSDA, Builder.CreateStructGEP(RegNodeTy, RegNode, 3)); Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 2); linkExceptionRegistration(Builder, PersonalityFn); } else { @@ -351,16 +343,18 @@ Function *WinEHStatePass::generateLSDAInEAXThunk(Function *ParentFunc) { FunctionType *TargetFuncTy = FunctionType::get(Int32Ty, makeArrayRef(&ArgTys[0], 5), /*isVarArg=*/false); - Function *Trampoline = Function::Create( - TrampolineTy, GlobalValue::InternalLinkage, - Twine("__ehhandler$") + ParentFunc->getName(), TheModule); + Function *Trampoline = + Function::Create(TrampolineTy, GlobalValue::InternalLinkage, + Twine("__ehhandler$") + GlobalValue::getRealLinkageName( + ParentFunc->getName()), + TheModule); BasicBlock *EntryBB = BasicBlock::Create(Context, "entry", Trampoline); IRBuilder<> Builder(EntryBB); Value *LSDA = emitEHLSDA(Builder, ParentFunc); Value *CastPersonality = Builder.CreateBitCast(PersonalityFn, TargetFuncTy->getPointerTo()); auto AI = Trampoline->arg_begin(); - Value *Args[5] = {LSDA, AI++, AI++, AI++, AI++}; + Value *Args[5] = {LSDA, &*AI++, &*AI++, &*AI++, &*AI++}; CallInst *Call = Builder.CreateCall(CastPersonality, Args); // Can't use musttail due to prototype mismatch, but we can use tail. Call->setTailCall(true); @@ -371,11 +365,14 @@ Function *WinEHStatePass::generateLSDAInEAXThunk(Function *ParentFunc) { } void WinEHStatePass::linkExceptionRegistration(IRBuilder<> &Builder, - Value *Handler) { - Type *LinkTy = getEHRegistrationType(); + Function *Handler) { + // Emit the .safeseh directive for this function. + Handler->addFnAttr("safeseh"); + + Type *LinkTy = getEHLinkRegistrationType(); // Handler = Handler - Handler = Builder.CreateBitCast(Handler, Builder.getInt8PtrTy()); - Builder.CreateStore(Handler, Builder.CreateStructGEP(LinkTy, Link, 1)); + Value *HandlerI8 = Builder.CreateBitCast(Handler, Builder.getInt8PtrTy()); + Builder.CreateStore(HandlerI8, Builder.CreateStructGEP(LinkTy, Link, 1)); // Next = [fs:00] Constant *FSZero = Constant::getNullValue(LinkTy->getPointerTo()->getPointerTo(257)); @@ -392,7 +389,7 @@ void WinEHStatePass::unlinkExceptionRegistration(IRBuilder<> &Builder) { Builder.Insert(GEP); Link = GEP; } - Type *LinkTy = getEHRegistrationType(); + Type *LinkTy = getEHLinkRegistrationType(); // [fs:00] = Link->Next Value *Next = Builder.CreateLoad(Builder.CreateStructGEP(LinkTy, Link, 0)); @@ -401,88 +398,50 @@ void WinEHStatePass::unlinkExceptionRegistration(IRBuilder<> &Builder) { Builder.CreateStore(Next, FSZero); } -void WinEHStatePass::addCXXStateStores(Function &F, MachineModuleInfo &MMI) { - WinEHFuncInfo &FuncInfo = MMI.getWinEHFuncInfo(&F); - calculateWinCXXEHStateNumbers(&F, FuncInfo); - - // The base state for the parent is -1. - addCXXStateStoresToFunclet(RegNode, FuncInfo, F, -1); - - // Set up RegNodeEscapeIndex - int RegNodeEscapeIndex = escapeRegNode(F); - - // Only insert stores in catch handlers. - Function *FrameRecover = - Intrinsic::getDeclaration(TheModule, Intrinsic::framerecover); - Function *FrameAddress = - Intrinsic::getDeclaration(TheModule, Intrinsic::frameaddress); - Constant *FI8 = - ConstantExpr::getBitCast(&F, Type::getInt8PtrTy(TheModule->getContext())); - for (auto P : FuncInfo.HandlerBaseState) { - Function *Handler = const_cast(P.first); - int BaseState = P.second; - IRBuilder<> Builder(&Handler->getEntryBlock(), - Handler->getEntryBlock().begin()); - // FIXME: Find and reuse such a call if present. - Value *ParentFP = Builder.CreateCall(FrameAddress, {Builder.getInt32(1)}); - Value *RecoveredRegNode = Builder.CreateCall( - FrameRecover, {FI8, ParentFP, Builder.getInt32(RegNodeEscapeIndex)}); - RecoveredRegNode = - Builder.CreateBitCast(RecoveredRegNode, RegNodeTy->getPointerTo(0)); - addCXXStateStoresToFunclet(RecoveredRegNode, FuncInfo, *Handler, BaseState); - } -} - -/// Escape RegNode so that we can access it from child handlers. Find the call -/// to frameescape, if any, in the entry block and append RegNode to the list -/// of arguments. -int WinEHStatePass::escapeRegNode(Function &F) { - // Find the call to frameescape and extract its arguments. - IntrinsicInst *EscapeCall = nullptr; - for (Instruction &I : F.getEntryBlock()) { - IntrinsicInst *II = dyn_cast(&I); - if (II && II->getIntrinsicID() == Intrinsic::frameescape) { - EscapeCall = II; - break; - } - } - SmallVector Args; - if (EscapeCall) { - auto Ops = EscapeCall->arg_operands(); - Args.append(Ops.begin(), Ops.end()); - } - Args.push_back(RegNode); - - // Replace the call (if it exists) with new one. Otherwise, insert at the end - // of the entry block. - IRBuilder<> Builder(&F.getEntryBlock(), - EscapeCall ? EscapeCall : F.getEntryBlock().end()); +void WinEHStatePass::addStateStores(Function &F, WinEHFuncInfo &FuncInfo) { + // Mark the registration node. The backend needs to know which alloca it is so + // that it can recover the original frame pointer. + IRBuilder<> Builder(RegNode->getParent(), std::next(RegNode->getIterator())); + Value *RegNodeI8 = Builder.CreateBitCast(RegNode, Builder.getInt8PtrTy()); Builder.CreateCall( - Intrinsic::getDeclaration(TheModule, Intrinsic::frameescape), Args); - if (EscapeCall) - EscapeCall->eraseFromParent(); - return Args.size() - 1; -} + Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_ehregnode), + {RegNodeI8}); + + // Calculate state numbers. + if (isAsynchronousEHPersonality(Personality)) + calculateSEHStateNumbers(&F, FuncInfo); + else + calculateWinCXXEHStateNumbers(&F, FuncInfo); -void WinEHStatePass::addCXXStateStoresToFunclet(Value *ParentRegNode, - WinEHFuncInfo &FuncInfo, - Function &F, int BaseState) { // Iterate all the instructions and emit state number stores. + DenseMap BlockColors = colorEHFunclets(F); for (BasicBlock &BB : F) { + // Figure out what state we should assign calls in this block. + int BaseState = -1; + auto &BBColors = BlockColors[&BB]; + + assert(BBColors.size() == 1 && + "multi-color BB not removed by preparation"); + BasicBlock *FuncletEntryBB = BBColors.front(); + if (auto *FuncletPad = + dyn_cast(FuncletEntryBB->getFirstNonPHI())) { + auto BaseStateI = FuncInfo.FuncletBaseStateMap.find(FuncletPad); + if (BaseStateI != FuncInfo.FuncletBaseStateMap.end()) + BaseState = BaseStateI->second; + } + for (Instruction &I : BB) { if (auto *CI = dyn_cast(&I)) { // Possibly throwing call instructions have no actions to take after // an unwind. Ensure they are in the -1 state. if (CI->doesNotThrow()) continue; - insertStateNumberStore(ParentRegNode, CI, BaseState); + insertStateNumberStore(RegNode, CI, BaseState); } else if (auto *II = dyn_cast(&I)) { // Look up the state number of the landingpad this unwinds to. - LandingPadInst *LPI = II->getUnwindDest()->getLandingPadInst(); - // FIXME: Why does this assertion fail? - //assert(FuncInfo.LandingPadStateMap.count(LPI) && "LP has no state!"); - int State = FuncInfo.LandingPadStateMap[LPI]; - insertStateNumberStore(ParentRegNode, II, State); + assert(FuncInfo.InvokeStateMap.count(II) && "invoke has no state!"); + int State = FuncInfo.InvokeStateMap[II]; + insertStateNumberStore(RegNode, II, State); } } }