//===-- X86WinEHState - Insert EH state updates for win32 exceptions ------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // 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/ADT/PostOrderIterator.h" #include "llvm/Analysis/CFG.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/WinEHFuncInfo.h" #include "llvm/IR/CFG.h" #include "llvm/IR/EHPersonalities.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/IntrinsicsX86.h" #include "llvm/IR/Module.h" #include "llvm/Pass.h" #include "llvm/Support/Debug.h" #include <deque> usingnamespacellvm; #define DEBUG_TYPE … namespace { const int OverdefinedState = …; class WinEHStatePass : public FunctionPass { … }; } // namespace FunctionPass *llvm::createX86WinEHStatePass() { … } char WinEHStatePass::ID = …; INITIALIZE_PASS(…) bool WinEHStatePass::doInitialization(Module &M) { … } bool WinEHStatePass::doFinalization(Module &M) { … } void WinEHStatePass::getAnalysisUsage(AnalysisUsage &AU) const { … } bool WinEHStatePass::runOnFunction(Function &F) { … } /// 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::getEHLinkRegistrationType() { … } /// The __CxxFrameHandler3 registration node: /// struct CXXExceptionRegistration { /// void *SavedESP; /// EHRegistrationNode SubRecord; /// int32_t TryLevel; /// }; Type *WinEHStatePass::getCXXEHRegistrationType() { … } /// The _except_handler3/4 registration node: /// struct EH4ExceptionRegistration { /// void *SavedESP; /// _EXCEPTION_POINTERS *ExceptionPointers; /// EHRegistrationNode SubRecord; /// int32_t EncodedScopeTable; /// int32_t TryLevel; /// }; Type *WinEHStatePass::getSEHRegistrationType() { … } // 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) { … } Value *WinEHStatePass::emitEHLSDA(IRBuilder<> &Builder, Function *F) { … } /// 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) { … } void WinEHStatePass::linkExceptionRegistration(IRBuilder<> &Builder, Function *Handler) { … } void WinEHStatePass::unlinkExceptionRegistration(IRBuilder<> &Builder) { … } // Calls to setjmp(p) are lowered to _setjmp3(p, 0) by the frontend. // The idea behind _setjmp3 is that it takes an optional number of personality // specific parameters to indicate how to restore the personality-specific frame // state when longjmp is initiated. Typically, the current TryLevel is saved. void WinEHStatePass::rewriteSetJmpCall(IRBuilder<> &Builder, Function &F, CallBase &Call, Value *State) { … } // Figure out what state we should assign calls in this block. int WinEHStatePass::getBaseStateForBB( DenseMap<BasicBlock *, ColorVector> &BlockColors, WinEHFuncInfo &FuncInfo, BasicBlock *BB) { … } // Calculate the state a call-site is in. int WinEHStatePass::getStateForCall( DenseMap<BasicBlock *, ColorVector> &BlockColors, WinEHFuncInfo &FuncInfo, CallBase &Call) { … } // Calculate the intersection of all the FinalStates for a BasicBlock's // predecessors. static int getPredState(DenseMap<BasicBlock *, int> &FinalStates, Function &F, int ParentBaseState, BasicBlock *BB) { … } // Calculate the intersection of all the InitialStates for a BasicBlock's // successors. static int getSuccState(DenseMap<BasicBlock *, int> &InitialStates, Function &F, int ParentBaseState, BasicBlock *BB) { … } bool WinEHStatePass::isStateStoreNeeded(EHPersonality Personality, CallBase &Call) { … } void WinEHStatePass::addStateStores(Function &F, WinEHFuncInfo &FuncInfo) { … } void WinEHStatePass::insertStateNumberStore(Instruction *IP, int State) { … }