summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/lib/Target/X86/X86WinEHState.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/Target/X86/X86WinEHState.cpp')
-rw-r--r--contrib/llvm/lib/Target/X86/X86WinEHState.cpp374
1 files changed, 374 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Target/X86/X86WinEHState.cpp b/contrib/llvm/lib/Target/X86/X86WinEHState.cpp
new file mode 100644
index 0000000..4efaada
--- /dev/null
+++ b/contrib/llvm/lib/Target/X86/X86WinEHState.cpp
@@ -0,0 +1,374 @@
+//===-- X86WinEHState - Insert EH state updates for win32 exceptions ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// All functions using an MSVC EH personality use an explicitly updated state
+// number stored in an exception registration stack object. The registration
+// object is linked into a thread-local chain of registrations stored at fs:00.
+// This pass adds the registration object and EH state updates.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86.h"
+#include "llvm/Analysis/LibCallSemantics.h"
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/CodeGen/WinEHFuncInfo.h"
+#include "llvm/IR/Dominators.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/PatternMatch.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+#include "llvm/Transforms/Utils/Local.h"
+
+using namespace llvm;
+using namespace llvm::PatternMatch;
+
+#define DEBUG_TYPE "winehstate"
+
+namespace {
+class WinEHStatePass : public FunctionPass {
+public:
+ static char ID; // Pass identification, replacement for typeid.
+
+ WinEHStatePass() : FunctionPass(ID) {}
+
+ bool runOnFunction(Function &Fn) override;
+
+ bool doInitialization(Module &M) override;
+
+ bool doFinalization(Module &M) override;
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override;
+
+ const char *getPassName() const override {
+ return "Windows 32-bit x86 EH state insertion";
+ }
+
+private:
+ void emitExceptionRegistrationRecord(Function *F);
+
+ void linkExceptionRegistration(IRBuilder<> &Builder, Value *RegNode,
+ Value *Handler);
+ void unlinkExceptionRegistration(IRBuilder<> &Builder, Value *RegNode);
+
+ Value *emitEHLSDA(IRBuilder<> &Builder, Function *F);
+
+ Function *generateLSDAInEAXThunk(Function *ParentFunc);
+
+ // Module-level type getters.
+ Type *getEHRegistrationType();
+ Type *getSEH3RegistrationType();
+ Type *getSEH4RegistrationType();
+ Type *getCXXEH3RegistrationType();
+
+ // Per-module data.
+ Module *TheModule = nullptr;
+ StructType *EHRegistrationTy = nullptr;
+ StructType *CXXEH3RegistrationTy = nullptr;
+ StructType *SEH3RegistrationTy = nullptr;
+ StructType *SEH4RegistrationTy = nullptr;
+
+ // Per-function state
+ EHPersonality Personality = EHPersonality::Unknown;
+ Function *PersonalityFn = nullptr;
+};
+}
+
+FunctionPass *llvm::createX86WinEHStatePass() { return new WinEHStatePass(); }
+
+char WinEHStatePass::ID = 0;
+
+bool WinEHStatePass::doInitialization(Module &M) {
+ TheModule = &M;
+ return false;
+}
+
+bool WinEHStatePass::doFinalization(Module &M) {
+ assert(TheModule == &M);
+ TheModule = nullptr;
+ EHRegistrationTy = nullptr;
+ CXXEH3RegistrationTy = nullptr;
+ SEH3RegistrationTy = nullptr;
+ SEH4RegistrationTy = nullptr;
+ return false;
+}
+
+void WinEHStatePass::getAnalysisUsage(AnalysisUsage &AU) const {
+ // This pass should only insert a stack allocation, memory accesses, and
+ // framerecovers.
+ 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)
+ return false;
+ PersonalityFn =
+ dyn_cast<Function>(LP->getPersonalityFn()->stripPointerCasts());
+ if (!PersonalityFn)
+ return false;
+ Personality = classifyEHPersonality(PersonalityFn);
+ if (!isMSVCEHPersonality(Personality))
+ return false;
+
+ emitExceptionRegistrationRecord(&F);
+ // FIXME: State insertion.
+
+ // Reset per-function state.
+ PersonalityFn = nullptr;
+ Personality = EHPersonality::Unknown;
+ return true;
+}
+
+/// Get the common EH registration subobject:
+/// typedef _EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE)(
+/// _EXCEPTION_RECORD *, void *, _CONTEXT *, void *);
+/// struct EHRegistrationNode {
+/// EHRegistrationNode *Next;
+/// PEXCEPTION_ROUTINE Handler;
+/// };
+Type *WinEHStatePass::getEHRegistrationType() {
+ if (EHRegistrationTy)
+ return EHRegistrationTy;
+ LLVMContext &Context = TheModule->getContext();
+ EHRegistrationTy = StructType::create(Context, "EHRegistrationNode");
+ Type *FieldTys[] = {
+ EHRegistrationTy->getPointerTo(0), // EHRegistrationNode *Next
+ Type::getInt8PtrTy(Context) // EXCEPTION_DISPOSITION (*Handler)(...)
+ };
+ EHRegistrationTy->setBody(FieldTys, false);
+ return EHRegistrationTy;
+}
+
+/// The __CxxFrameHandler3 registration node:
+/// struct CXXExceptionRegistration {
+/// void *SavedESP;
+/// EHRegistrationNode SubRecord;
+/// int32_t TryLevel;
+/// };
+Type *WinEHStatePass::getCXXEH3RegistrationType() {
+ if (CXXEH3RegistrationTy)
+ return CXXEH3RegistrationTy;
+ LLVMContext &Context = TheModule->getContext();
+ Type *FieldTys[] = {
+ Type::getInt8PtrTy(Context), // void *SavedESP
+ getEHRegistrationType(), // EHRegistrationNode SubRecord
+ Type::getInt32Ty(Context) // int32_t TryLevel
+ };
+ CXXEH3RegistrationTy =
+ StructType::create(FieldTys, "CXXExceptionRegistration");
+ return CXXEH3RegistrationTy;
+}
+
+/// 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:
+/// struct EH4ExceptionRegistration {
+/// void *SavedESP;
+/// _EXCEPTION_POINTERS *ExceptionPointers;
+/// EHRegistrationNode SubRecord;
+/// int32_t EncodedScopeTable;
+/// int32_t TryLevel;
+/// };
+Type *WinEHStatePass::getSEH4RegistrationType() {
+ if (SEH4RegistrationTy)
+ return SEH4RegistrationTy;
+ LLVMContext &Context = TheModule->getContext();
+ Type *FieldTys[] = {
+ Type::getInt8PtrTy(Context), // void *SavedESP
+ Type::getInt8PtrTy(Context), // void *ExceptionPointers
+ getEHRegistrationType(), // EHRegistrationNode SubRecord
+ Type::getInt32Ty(Context), // int32_t EncodedScopeTable
+ Type::getInt32Ty(Context) // int32_t TryLevel
+ };
+ SEH4RegistrationTy = StructType::create(FieldTys, "EH4ExceptionRegistration");
+ return SEH4RegistrationTy;
+}
+
+// Emit an exception registration record. These are stack allocations with the
+// common subobject of two pointers: the previous registration record (the old
+// fs:00) and the personality function for the current frame. The data before
+// and after that is personality function specific.
+void WinEHStatePass::emitExceptionRegistrationRecord(Function *F) {
+ assert(Personality == EHPersonality::MSVC_CXX ||
+ Personality == EHPersonality::MSVC_X86SEH);
+
+ StringRef PersonalityName = PersonalityFn->getName();
+ IRBuilder<> Builder(&F->getEntryBlock(), F->getEntryBlock().begin());
+ Type *Int8PtrType = Builder.getInt8PtrTy();
+ Value *SubRecord = nullptr;
+ if (PersonalityName == "__CxxFrameHandler3") {
+ Type *RegNodeTy = getCXXEH3RegistrationType();
+ Value *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
+ Builder.CreateStore(Builder.getInt32(-1),
+ Builder.CreateStructGEP(RegNodeTy, RegNode, 2));
+ // Handler = __ehhandler$F
+ Function *Trampoline = generateLSDAInEAXThunk(F);
+ SubRecord = Builder.CreateStructGEP(RegNodeTy, RegNode, 1);
+ linkExceptionRegistration(Builder, SubRecord, Trampoline);
+ } else if (PersonalityName == "_except_handler3") {
+ Type *RegNodeTy = getSEH3RegistrationType();
+ Value *RegNode = Builder.CreateAlloca(RegNodeTy);
+ // TryLevel = -1
+ Builder.CreateStore(Builder.getInt32(-1),
+ Builder.CreateStructGEP(RegNodeTy, RegNode, 2));
+ // ScopeTable = llvm.x86.seh.lsda(F)
+ Value *LSDA = emitEHLSDA(Builder, F);
+ Builder.CreateStore(LSDA, Builder.CreateStructGEP(RegNodeTy, RegNode, 1));
+ SubRecord = Builder.CreateStructGEP(RegNodeTy, RegNode, 0);
+ linkExceptionRegistration(Builder, SubRecord, PersonalityFn);
+ } else if (PersonalityName == "_except_handler4") {
+ Type *RegNodeTy = getSEH4RegistrationType();
+ Value *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 = -2
+ Builder.CreateStore(Builder.getInt32(-2),
+ Builder.CreateStructGEP(RegNodeTy, RegNode, 4));
+ // FIXME: XOR the LSDA with __security_cookie.
+ // 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));
+ SubRecord = Builder.CreateStructGEP(RegNodeTy, RegNode, 2);
+ linkExceptionRegistration(Builder, SubRecord, PersonalityFn);
+ } else {
+ llvm_unreachable("unexpected personality function");
+ }
+
+ // FIXME: Insert an unlink before all returns.
+ for (BasicBlock &BB : *F) {
+ TerminatorInst *T = BB.getTerminator();
+ if (!isa<ReturnInst>(T))
+ continue;
+ Builder.SetInsertPoint(T);
+ unlinkExceptionRegistration(Builder, SubRecord);
+ }
+}
+
+Value *WinEHStatePass::emitEHLSDA(IRBuilder<> &Builder, Function *F) {
+ Value *FI8 = Builder.CreateBitCast(F, Type::getInt8PtrTy(F->getContext()));
+ return Builder.CreateCall(
+ Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_lsda), FI8);
+}
+
+/// Generate a thunk that puts the LSDA of ParentFunc in EAX and then calls
+/// PersonalityFn, forwarding the parameters passed to PEXCEPTION_ROUTINE:
+/// typedef _EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE)(
+/// _EXCEPTION_RECORD *, void *, _CONTEXT *, void *);
+/// We essentially want this code:
+/// movl $lsda, %eax
+/// jmpl ___CxxFrameHandler3
+Function *WinEHStatePass::generateLSDAInEAXThunk(Function *ParentFunc) {
+ LLVMContext &Context = ParentFunc->getContext();
+ Type *Int32Ty = Type::getInt32Ty(Context);
+ Type *Int8PtrType = Type::getInt8PtrTy(Context);
+ Type *ArgTys[5] = {Int8PtrType, Int8PtrType, Int8PtrType, Int8PtrType,
+ Int8PtrType};
+ FunctionType *TrampolineTy =
+ FunctionType::get(Int32Ty, makeArrayRef(&ArgTys[0], 4),
+ /*isVarArg=*/false);
+ FunctionType *TargetFuncTy =
+ FunctionType::get(Int32Ty, makeArrayRef(&ArgTys[0], 5),
+ /*isVarArg=*/false);
+ Function *Trampoline = Function::Create(
+ TrampolineTy, GlobalValue::InternalLinkage,
+ Twine("__ehhandler$") + 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++};
+ CallInst *Call = Builder.CreateCall(CastPersonality, Args);
+ // Can't use musttail due to prototype mismatch, but we can use tail.
+ Call->setTailCall(true);
+ // Set inreg so we pass it in EAX.
+ Call->addAttribute(1, Attribute::InReg);
+ Builder.CreateRet(Call);
+ return Trampoline;
+}
+
+void WinEHStatePass::linkExceptionRegistration(IRBuilder<> &Builder,
+ Value *RegNode, Value *Handler) {
+ Type *RegNodeTy = getEHRegistrationType();
+ // Handler = Handler
+ Handler = Builder.CreateBitCast(Handler, Builder.getInt8PtrTy());
+ Builder.CreateStore(Handler, Builder.CreateStructGEP(RegNodeTy, RegNode, 1));
+ // Next = [fs:00]
+ Constant *FSZero =
+ Constant::getNullValue(RegNodeTy->getPointerTo()->getPointerTo(257));
+ Value *Next = Builder.CreateLoad(FSZero);
+ Builder.CreateStore(Next, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
+ // [fs:00] = RegNode
+ Builder.CreateStore(RegNode, FSZero);
+}
+
+void WinEHStatePass::unlinkExceptionRegistration(IRBuilder<> &Builder,
+ Value *RegNode) {
+ // Clone RegNode into the current BB for better address mode folding.
+ if (auto *GEP = dyn_cast<GetElementPtrInst>(RegNode)) {
+ GEP = cast<GetElementPtrInst>(GEP->clone());
+ Builder.Insert(GEP);
+ RegNode = GEP;
+ }
+ Type *RegNodeTy = getEHRegistrationType();
+ // [fs:00] = RegNode->Next
+ Value *Next =
+ Builder.CreateLoad(Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
+ Constant *FSZero =
+ Constant::getNullValue(RegNodeTy->getPointerTo()->getPointerTo(257));
+ Builder.CreateStore(Next, FSZero);
+}
OpenPOWER on IntegriCloud