28#include "llvm/IR/IntrinsicsX86.h"
36#define DEBUG_TYPE "winehstate"
39const int OverdefinedState = INT_MIN;
56 return "Windows 32-bit x86 EH state insertion";
60 void emitExceptionRegistrationRecord(
Function *
F);
63 void unlinkExceptionRegistration(
IRBuilder<> &Builder);
65 void insertStateNumberStore(
Instruction *IP,
int State);
82 Type *getEHLinkRegistrationType();
83 Type *getSEHRegistrationType();
84 Type *getCXXEHRegistrationType();
87 Module *TheModule =
nullptr;
97 bool UseStackGuard =
false;
98 int ParentBaseState = 0;
107 Type *RegNodeTy =
nullptr;
113 int StateFieldIndex = ~0U;
116 Value *Link =
nullptr;
122char WinEHStatePass::ID = 0;
125 "Insert stores for EH state numbers",
false,
false)
127bool WinEHStatePass::doInitialization(
Module &M) {
132bool WinEHStatePass::doFinalization(
Module &M) {
135 EHLinkRegistrationTy =
nullptr;
136 CXXEHRegistrationTy =
nullptr;
137 SEHRegistrationTy =
nullptr;
139 CxxLongjmpUnwind =
nullptr;
140 SehLongjmpUnwind =
nullptr;
145void WinEHStatePass::getAnalysisUsage(
AnalysisUsage &AU)
const {
151bool WinEHStatePass::runOnFunction(
Function &
F) {
155 if (
F.hasAvailableExternallyLinkage())
159 if (!
F.hasPersonalityFn())
161 PersonalityFn = dyn_cast<Function>(
F.getPersonalityFn()->stripPointerCasts());
170 bool HasPads =
false;
180 Type *Int8PtrType = PointerType::getUnqual(TheModule->getContext());
181 SetJmp3 = TheModule->getOrInsertFunction(
182 "_setjmp3", FunctionType::get(
184 {Int8PtrType, Type::getInt32Ty(TheModule->getContext())},
187 emitExceptionRegistrationRecord(&
F);
195 addStateStores(
F, FuncInfo);
196 updateEspForInAllocas(
F);
199 PersonalityFn =
nullptr;
200 Personality = EHPersonality::Unknown;
201 UseStackGuard =
false;
204 EHGuardNode =
nullptr;
216Type *WinEHStatePass::getEHLinkRegistrationType() {
217 if (EHLinkRegistrationTy)
218 return EHLinkRegistrationTy;
221 PointerType::getUnqual(Context),
222 PointerType::getUnqual(Context)
225 return EHLinkRegistrationTy;
234Type *WinEHStatePass::getCXXEHRegistrationType() {
235 if (CXXEHRegistrationTy)
236 return CXXEHRegistrationTy;
239 PointerType::getUnqual(Context),
240 getEHLinkRegistrationType(),
243 CXXEHRegistrationTy =
245 return CXXEHRegistrationTy;
256Type *WinEHStatePass::getSEHRegistrationType() {
257 if (SEHRegistrationTy)
258 return SEHRegistrationTy;
261 PointerType::getUnqual(Context),
262 PointerType::getUnqual(Context),
263 getEHLinkRegistrationType(),
268 return SEHRegistrationTy;
275void WinEHStatePass::emitExceptionRegistrationRecord(
Function *
F) {
276 assert(Personality == EHPersonality::MSVC_CXX ||
277 Personality == EHPersonality::MSVC_X86SEH);
279 IRBuilder<> Builder(&
F->getEntryBlock(),
F->getEntryBlock().begin());
280 Type *Int8PtrType = Builder.getPtrTy();
284 if (Personality == EHPersonality::MSVC_CXX) {
285 RegNodeTy = getCXXEHRegistrationType();
286 RegNode = Builder.CreateAlloca(RegNodeTy);
288 Value *SP = Builder.CreateStackSave();
289 Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
292 ParentBaseState = -1;
293 insertStateNumberStore(&*Builder.GetInsertPoint(), ParentBaseState);
295 Function *Trampoline = generateLSDAInEAXThunk(
F);
296 Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 1);
297 linkExceptionRegistration(Builder, Trampoline);
299 CxxLongjmpUnwind = TheModule->getOrInsertFunction(
300 "__CxxLongjmpUnwind",
301 FunctionType::get(VoidTy, Int8PtrType,
false));
302 cast<Function>(CxxLongjmpUnwind.getCallee()->stripPointerCasts())
304 }
else if (Personality == EHPersonality::MSVC_X86SEH) {
307 StringRef PersonalityName = PersonalityFn->getName();
308 UseStackGuard = (PersonalityName ==
"_except_handler4");
311 RegNodeTy = getSEHRegistrationType();
312 RegNode = Builder.CreateAlloca(RegNodeTy);
314 EHGuardNode = Builder.CreateAlloca(Int32Ty);
317 Value *SP = Builder.CreateStackSave();
318 Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
321 ParentBaseState = UseStackGuard ? -2 : -1;
322 insertStateNumberStore(&*Builder.GetInsertPoint(), ParentBaseState);
324 Value *LSDA = emitEHLSDA(Builder,
F);
325 LSDA = Builder.CreatePtrToInt(LSDA, Int32Ty);
329 Cookie = TheModule->getOrInsertGlobal(
"__security_cookie", Int32Ty);
330 Value *Val = Builder.CreateLoad(Int32Ty, Cookie,
"cookie");
331 LSDA = Builder.CreateXor(LSDA, Val);
333 Builder.CreateStore(LSDA, Builder.CreateStructGEP(RegNodeTy, RegNode, 3));
337 Value *Val = Builder.CreateLoad(Int32Ty, Cookie);
338 Value *FrameAddr = Builder.CreateIntrinsic(
339 Intrinsic::frameaddress,
340 Builder.getPtrTy(TheModule->getDataLayout().getAllocaAddrSpace()),
341 Builder.getInt32(0),
nullptr,
"frameaddr");
342 Value *FrameAddrI32 = Builder.CreatePtrToInt(FrameAddr, Int32Ty);
343 FrameAddrI32 = Builder.CreateXor(FrameAddrI32, Val);
344 Builder.CreateStore(FrameAddrI32, EHGuardNode);
348 Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 2);
349 linkExceptionRegistration(Builder, PersonalityFn);
351 SehLongjmpUnwind = TheModule->getOrInsertFunction(
352 UseStackGuard ?
"_seh_longjmp_unwind4" :
"_seh_longjmp_unwind",
353 FunctionType::get(
Type::getVoidTy(TheModule->getContext()), Int8PtrType,
355 cast<Function>(SehLongjmpUnwind.getCallee()->stripPointerCasts())
364 if (!isa<ReturnInst>(
T))
368 if (
CallInst *CI = BB.getTerminatingMustTailCall())
371 Builder.SetInsertPoint(
T);
372 unlinkExceptionRegistration(Builder);
390 Type *Int8PtrType = PointerType::getUnqual(Context);
391 Type *ArgTys[5] = {Int8PtrType, Int8PtrType, Int8PtrType, Int8PtrType,
394 FunctionType::get(Int32Ty,
ArrayRef(&ArgTys[0], 4),
397 FunctionType::get(Int32Ty,
ArrayRef(&ArgTys[0], 5),
401 Twine(
"__ehhandler$") +
408 Value *LSDA = emitEHLSDA(Builder, ParentFunc);
410 Value *
Args[5] = {LSDA, &*AI++, &*AI++, &*AI++, &*AI++};
413 Call->setTailCall(
true);
415 Call->addParamAttr(0, Attribute::InReg);
420void WinEHStatePass::linkExceptionRegistration(
IRBuilder<> &Builder,
426 Type *LinkTy = getEHLinkRegistrationType();
437void WinEHStatePass::unlinkExceptionRegistration(
IRBuilder<> &Builder) {
439 if (
auto *
GEP = dyn_cast<GetElementPtrInst>(Link)) {
440 GEP = cast<GetElementPtrInst>(
GEP->clone());
446 Type *LinkTy = getEHLinkRegistrationType();
461 if (
Call.arg_size() != 2)
465 Call.getOperandBundlesAsDefs(OpBundles);
468 if (Personality == EHPersonality::MSVC_CXX) {
469 OptionalArgs.
push_back(CxxLongjmpUnwind.getCallee());
471 OptionalArgs.
push_back(emitEHLSDA(Builder, &
F));
472 }
else if (Personality == EHPersonality::MSVC_X86SEH) {
473 OptionalArgs.
push_back(SehLongjmpUnwind.getCallee());
488 if (
auto *CI = dyn_cast<CallInst>(&Call)) {
493 auto *
II = cast<InvokeInst>(&Call);
495 II->getUnwindDest(), Args, OpBundles);
502 Call.replaceAllUsesWith(NewCall);
503 Call.eraseFromParent();
507int WinEHStatePass::getBaseStateForBB(
510 int BaseState = ParentBaseState;
511 auto &BBColors = BlockColors[BB];
513 assert(BBColors.size() == 1 &&
"multi-color BB not removed by preparation");
515 if (
auto *FuncletPad =
519 BaseState = BaseStateI->second;
526 const Function *CF = Call.getCalledFunction();
531 return isIntrinsic(Call, Intrinsic::seh_scope_end);
535 return isIntrinsic(Call, Intrinsic::seh_scope_begin);
539int WinEHStatePass::getStateForCall(
542 if (
auto *
II = dyn_cast<InvokeInst>(&Call)) {
544 return getBaseStateForBB(BlockColors, FuncInfo,
II->getNormalDest());
553 return getBaseStateForBB(BlockColors, FuncInfo,
Call.getParent());
562 if (&
F.getEntryBlock() == BB)
563 return ParentBaseState;
567 return OverdefinedState;
569 int CommonState = OverdefinedState;
573 auto PredEndState = FinalStates.
find(PredBB);
574 if (PredEndState == FinalStates.
end())
575 return OverdefinedState;
579 if (isa<CatchReturnInst>(PredBB->getTerminator()))
580 return OverdefinedState;
582 int PredState = PredEndState->second;
583 assert(PredState != OverdefinedState &&
584 "overdefined BBs shouldn't be in FinalStates");
585 if (CommonState == OverdefinedState)
586 CommonState = PredState;
590 if (CommonState != PredState)
591 return OverdefinedState;
604 return OverdefinedState;
606 int CommonState = OverdefinedState;
610 auto SuccStartState = InitialStates.
find(SuccBB);
611 if (SuccStartState == InitialStates.
end())
612 return OverdefinedState;
615 if (SuccBB->isEHPad())
616 return OverdefinedState;
618 int SuccState = SuccStartState->second;
619 assert(SuccState != OverdefinedState &&
620 "overdefined BBs shouldn't be in FinalStates");
621 if (CommonState == OverdefinedState)
622 CommonState = SuccState;
626 if (CommonState != SuccState)
627 return OverdefinedState;
633bool WinEHStatePass::isStateStoreNeeded(
EHPersonality Personality,
641 return !
Call.doesNotAccessMemory();
644 return !
Call.doesNotThrow();
652 Builder.
CreateIntrinsic(Intrinsic::x86_seh_ehregnode, {}, {RegNodeI8});
656 Value *EHGuardNodeI8 =
658 Builder.
CreateIntrinsic(Intrinsic::x86_seh_ehguard, {}, {EHGuardNodeI8});
677 std::deque<BasicBlock *> Worklist;
680 int InitialState = OverdefinedState;
682 if (&
F.getEntryBlock() == BB)
683 InitialState = FinalState = ParentBaseState;
685 auto *
Call = dyn_cast<CallBase>(&
I);
686 if (!Call || !isStateStoreNeeded(Personality, *Call))
689 int State = getStateForCall(BlockColors, FuncInfo, *Call);
690 if (InitialState == OverdefinedState)
691 InitialState = State;
696 if (InitialState == OverdefinedState) {
697 Worklist.push_back(BB);
701 <<
" InitialState=" << InitialState <<
'\n');
703 <<
" FinalState=" << FinalState <<
'\n');
704 InitialStates.
insert({BB, InitialState});
705 FinalStates.
insert({BB, FinalState});
709 while (!Worklist.empty()) {
711 Worklist.pop_front();
713 if (InitialStates.
count(BB) != 0)
716 int PredState =
getPredState(FinalStates,
F, ParentBaseState, BB);
717 if (PredState == OverdefinedState)
722 InitialStates.
insert({BB, PredState});
723 FinalStates.
insert({BB, PredState});
725 Worklist.push_back(SuccBB);
730 int SuccState =
getSuccState(InitialStates,
F, ParentBaseState, BB);
731 if (SuccState == OverdefinedState)
736 FinalStates.
insert({BB, SuccState});
742 auto &BBColors = BlockColors[BB];
747 int PrevState =
getPredState(FinalStates,
F, ParentBaseState, BB);
749 <<
" PrevState=" << PrevState <<
'\n');
752 auto *
Call = dyn_cast<CallBase>(&
I);
753 if (!Call || !isStateStoreNeeded(Personality, *Call))
756 int State = getStateForCall(BlockColors, FuncInfo, *Call);
757 if (State != PrevState)
758 insertStateNumberStore(&
I, State);
763 auto EndState = FinalStates.
find(BB);
764 if (EndState != FinalStates.
end())
765 if (EndState->second != PrevState)
766 insertStateNumberStore(BB->getTerminator(), EndState->second);
772 auto *
Call = dyn_cast<CallBase>(&
I);
775 if (
Call->getCalledOperand()->stripPointerCasts() !=
776 SetJmp3.getCallee()->stripPointerCasts())
783 for (
CallBase *Call : SetJmp3Calls) {
784 auto &BBColors = BlockColors[
Call->getParent()];
786 bool InCleanup = isa<CleanupPadInst>(FuncletEntryBB->
getFirstNonPHI());
792 RegNode, StateFieldIndex);
795 State = Builder.
getInt32(getStateForCall(BlockColors, FuncInfo, *Call));
797 rewriteSetJmpCall(Builder,
F, *Call, State);
801void WinEHStatePass::insertStateNumberStore(
Instruction *IP,
int State) {
804 RegNode, StateFieldIndex);
808void WinEHStatePass::updateEspForInAllocas(
Function &
F) {
811 if (
auto *Alloca = dyn_cast<AllocaInst>(&
I)) {
812 if (Alloca->isStaticAlloca())
814 IRBuilder<> Builder(Alloca->getNextNonDebugInstruction());
820 if (
auto *
II = dyn_cast<IntrinsicInst>(&
I)) {
821 if (
II->getIntrinsicID() != Intrinsic::stackrestore)
This file provides various utilities for inspecting and working with the control flow graph in LLVM I...
Module.h This file contains the declarations for the Module class.
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static int getPredState(DenseMap< BasicBlock *, int > &FinalStates, Function &F, int ParentBaseState, BasicBlock *BB)
static bool isSehScopeEnd(const CallBase &Call)
static bool isSehScopeBegin(const CallBase &Call)
static bool isIntrinsic(const CallBase &Call, Intrinsic::ID ID)
static int getSuccState(DenseMap< BasicBlock *, int > &InitialStates, Function &F, int ParentBaseState, BasicBlock *BB)
an instruction to allocate memory on the stack
Represent the analysis usage information of a pass.
void setPreservesCFG()
This function should be called by the pass, iff they do not:
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
LLVM Basic Block Representation.
const Instruction * getFirstNonPHI() const
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
const Instruction & front() const
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
bool isEHPad() const
Return true if this basic block is an exception handling block.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
void setCallingConv(CallingConv::ID CC)
void setAttributes(AttributeList A)
Set the attributes for this call.
This class represents a function call, abstracting a target machine's calling convention.
void setTailCallKind(TailCallKind TCK)
This is an important base class in LLVM.
static Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
iterator find(const_arg_type_t< KeyT > Val)
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
FunctionPass class - This class is used to implement most global optimizations.
virtual bool runOnFunction(Function &F)=0
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
void addFnAttr(Attribute::AttrKind Kind)
Add function attributes to this function.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
Intrinsic::ID getIntrinsicID() const LLVM_READONLY
getIntrinsicID - This method returns the ID number of the specified function, or Intrinsic::not_intri...
bool isIntrinsic() const
isIntrinsic - Returns true if the function's name starts with "llvm.".
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
void setComdat(Comdat *C)
const Comdat * getComdat() const
static StringRef dropLLVMManglingEscape(StringRef Name)
If the given string begins with the GlobalValue name mangling escape character '\1',...
@ InternalLinkage
Rename collisions when linking (static functions).
CallInst * CreateStackSave(const Twine &Name="")
Create a call to llvm.stacksave.
CallInst * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > Types, ArrayRef< Value * > Args, Instruction *FMFSource=nullptr, const Twine &Name="")
Create a call to intrinsic ID with Args, mangled using Types.
InvokeInst * CreateInvoke(FunctionType *Ty, Value *Callee, BasicBlock *NormalDest, BasicBlock *UnwindDest, ArrayRef< Value * > Args, ArrayRef< OperandBundleDef > OpBundles, const Twine &Name="")
Create an invoke instruction.
Value * CreateStructGEP(Type *Ty, Value *Ptr, unsigned Idx, const Twine &Name="")
IntegerType * getInt32Ty()
Fetch the type representing a 32-bit integer.
ReturnInst * CreateRet(Value *V)
Create a 'ret <val>' instruction.
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
InstTy * Insert(InstTy *I, const Twine &Name="") const
Insert and return the specified instruction.
Value * CreateBitCast(Value *V, Type *DestTy, const Twine &Name="")
LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)
Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...
LLVMContext & getContext() const
StoreInst * CreateStore(Value *Val, Value *Ptr, bool isVolatile=false)
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
PointerType * getPtrTy(unsigned AddrSpace=0)
Fetch the type representing a pointer.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
This is an important class for using LLVM in a threaded context.
A Module instance is used to store all the information related to an LLVM module.
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
virtual bool doInitialization(Module &)
doInitialization - Virtual method overridden by subclasses to do any necessary initialization before ...
virtual bool doFinalization(Module &)
doFinalization - Virtual method overriden by subclasses to do any necessary clean up after all passes...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Class to represent struct types.
static StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
static Type * getVoidTy(LLVMContext &C)
static IntegerType * getInt32Ty(LLVMContext &C)
LLVM Value Representation.
StringRef getName() const
Return a constant reference to the value's name.
void takeName(Value *V)
Transfer the name from V to this value.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
@ X86_StdCall
stdcall is mostly used by the Win32 API.
@ C
The default llvm calling convention, compatible with C.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
This is an optimization pass for GlobalISel generic memory operations.
FunctionPass * createX86WinEHStatePass()
Return an IR pass that inserts EH registration stack objects and explicit EH state updates.
auto successors(const MachineBasicBlock *BB)
DenseMap< BasicBlock *, ColorVector > colorEHFunclets(Function &F)
If an EH funclet personality is in use (see isFuncletEHPersonality), this will recompute which blocks...
void calculateWinCXXEHStateNumbers(const Function *ParentFn, WinEHFuncInfo &FuncInfo)
Analyze the IR in ParentFn and it's handlers to build WinEHFuncInfo, which describes the state number...
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
EHPersonality classifyEHPersonality(const Value *Pers)
See if the given exception handling personality function is one that we understand.
bool isFuncletEHPersonality(EHPersonality Pers)
Returns true if this is a personality function that invokes handler funclets (which must return to it...
void calculateSEHStateNumbers(const Function *ParentFn, WinEHFuncInfo &FuncInfo)
bool isAsynchronousEHPersonality(EHPersonality Pers)
Returns true if this personality function catches asynchronous exceptions.
auto predecessors(const MachineBasicBlock *BB)
DenseMap< const FuncletPadInst *, int > FuncletBaseStateMap
DenseMap< const InvokeInst *, int > InvokeStateMap