27 #include "llvm/IR/IntrinsicsX86.h"
35 #define DEBUG_TYPE "winehstate"
38 const int OverdefinedState = INT_MIN;
48 bool doInitialization(
Module &
M)
override;
50 bool doFinalization(
Module &
M)
override;
55 return "Windows 32-bit x86 EH state insertion";
59 void emitExceptionRegistrationRecord(
Function *
F);
79 Type *getEHLinkRegistrationType();
80 Type *getSEHRegistrationType();
81 Type *getCXXEHRegistrationType();
84 Module *TheModule =
nullptr;
94 bool UseStackGuard =
false;
95 int ParentBaseState = 0;
107 int StateFieldIndex = ~0U;
119 "Insert stores for EH state numbers",
false,
false)
121 bool WinEHStatePass::doInitialization(
Module &M) {
126 bool WinEHStatePass::doFinalization(
Module &M) {
129 EHLinkRegistrationTy =
nullptr;
130 CXXEHRegistrationTy =
nullptr;
131 SEHRegistrationTy =
nullptr;
133 CxxLongjmpUnwind =
nullptr;
134 SehLongjmpUnwind =
nullptr;
139 void WinEHStatePass::getAnalysisUsage(
AnalysisUsage &AU)
const {
149 if (
F.hasAvailableExternallyLinkage())
153 if (!
F.hasPersonalityFn())
156 dyn_cast<Function>(
F.getPersonalityFn()->stripPointerCasts());
165 bool HasPads =
false;
176 SetJmp3 = TheModule->getOrInsertFunction(
179 {Int8PtrType, Type::getInt32Ty(TheModule->getContext())},
182 emitExceptionRegistrationRecord(&
F);
190 addStateStores(
F, FuncInfo);
193 PersonalityFn =
nullptr;
195 UseStackGuard =
false;
197 EHGuardNode =
nullptr;
209 Type *WinEHStatePass::getEHLinkRegistrationType() {
210 if (EHLinkRegistrationTy)
211 return EHLinkRegistrationTy;
218 EHLinkRegistrationTy->setBody(FieldTys,
false);
219 return EHLinkRegistrationTy;
228 Type *WinEHStatePass::getCXXEHRegistrationType() {
229 if (CXXEHRegistrationTy)
230 return CXXEHRegistrationTy;
234 getEHLinkRegistrationType(),
237 CXXEHRegistrationTy =
239 return CXXEHRegistrationTy;
250 Type *WinEHStatePass::getSEHRegistrationType() {
251 if (SEHRegistrationTy)
252 return SEHRegistrationTy;
257 getEHLinkRegistrationType(),
262 return SEHRegistrationTy;
269 void WinEHStatePass::emitExceptionRegistrationRecord(
Function *
F) {
282 RegNodeTy = getCXXEHRegistrationType();
283 RegNode =
Builder.CreateAlloca(RegNodeTy);
287 Builder.CreateStore(SP,
Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
290 ParentBaseState = -1;
291 insertStateNumberStore(&*
Builder.GetInsertPoint(), ParentBaseState);
293 Function *Trampoline = generateLSDAInEAXThunk(
F);
294 Link =
Builder.CreateStructGEP(RegNodeTy, RegNode, 1);
295 linkExceptionRegistration(
Builder, Trampoline);
297 CxxLongjmpUnwind = TheModule->getOrInsertFunction(
298 "__CxxLongjmpUnwind",
300 cast<Function>(CxxLongjmpUnwind.getCallee()->stripPointerCasts())
305 StringRef PersonalityName = PersonalityFn->getName();
306 UseStackGuard = (PersonalityName ==
"_except_handler4");
309 RegNodeTy = getSEHRegistrationType();
310 RegNode =
Builder.CreateAlloca(RegNodeTy);
317 Builder.CreateStore(SP,
Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
320 ParentBaseState = UseStackGuard ? -2 : -1;
321 insertStateNumberStore(&*
Builder.GetInsertPoint(), ParentBaseState);
328 Cookie = TheModule->getOrInsertGlobal(
"__security_cookie",
Int32Ty);
330 LSDA =
Builder.CreateXor(LSDA, Val);
332 Builder.CreateStore(LSDA,
Builder.CreateStructGEP(RegNodeTy, RegNode, 3));
339 TheModule, Intrinsic::frameaddress,
341 TheModule->getDataLayout().getAllocaAddrSpace())),
342 Builder.getInt32(0),
"frameaddr");
344 FrameAddrI32 =
Builder.CreateXor(FrameAddrI32, Val);
345 Builder.CreateStore(FrameAddrI32, EHGuardNode);
349 Link =
Builder.CreateStructGEP(RegNodeTy, RegNode, 2);
350 linkExceptionRegistration(
Builder, PersonalityFn);
352 SehLongjmpUnwind = TheModule->getOrInsertFunction(
353 UseStackGuard ?
"_seh_longjmp_unwind4" :
"_seh_longjmp_unwind",
356 cast<Function>(SehLongjmpUnwind.getCallee()->stripPointerCasts())
365 if (!isa<ReturnInst>(T))
368 unlinkExceptionRegistration(
Builder);
389 Type *ArgTys[5] = {Int8PtrType, Int8PtrType, Int8PtrType, Int8PtrType,
407 Value *CastPersonality =
410 Value *
Args[5] = {LSDA, &*AI++, &*AI++, &*AI++, &*AI++};
413 Call->setTailCall(
true);
415 Call->addParamAttr(0, Attribute::InReg);
425 Type *LinkTy = getEHLinkRegistrationType();
440 if (
auto *
GEP = dyn_cast<GetElementPtrInst>(
Link)) {
441 GEP = cast<GetElementPtrInst>(
GEP->clone());
445 Type *LinkTy = getEHLinkRegistrationType();
451 Builder.CreateStore(Next, FSZero);
461 if (
Call.arg_size() != 2)
465 Call.getOperandBundlesAsDefs(OpBundles);
469 OptionalArgs.push_back(CxxLongjmpUnwind.getCallee());
470 OptionalArgs.push_back(State);
471 OptionalArgs.push_back(emitEHLSDA(
Builder, &
F));
473 OptionalArgs.push_back(SehLongjmpUnwind.getCallee());
474 OptionalArgs.push_back(State);
476 OptionalArgs.push_back(Cookie);
484 Args.push_back(
Builder.getInt32(OptionalArgs.size()));
485 Args.append(OptionalArgs.begin(), OptionalArgs.end());
488 if (
auto *CI = dyn_cast<CallInst>(&Call)) {
493 auto *II = cast<InvokeInst>(&Call);
494 NewCall =
Builder.CreateInvoke(
495 SetJmp3, II->getNormalDest(), II->getUnwindDest(),
Args, OpBundles);
502 Call.replaceAllUsesWith(NewCall);
503 Call.eraseFromParent();
507 int 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 int WinEHStatePass::getStateForCall(
529 if (
auto *II = dyn_cast<InvokeInst>(&Call)) {
536 return getBaseStateForBB(BlockColors, FuncInfo,
Call.getParent());
545 if (&
F.getEntryBlock() ==
BB)
546 return ParentBaseState;
550 return OverdefinedState;
552 int CommonState = OverdefinedState;
556 auto PredEndState = FinalStates.
find(PredBB);
557 if (PredEndState == FinalStates.
end())
558 return OverdefinedState;
562 if (isa<CatchReturnInst>(PredBB->getTerminator()))
563 return OverdefinedState;
565 int PredState = PredEndState->second;
566 assert(PredState != OverdefinedState &&
567 "overdefined BBs shouldn't be in FinalStates");
568 if (CommonState == OverdefinedState)
569 CommonState = PredState;
573 if (CommonState != PredState)
574 return OverdefinedState;
586 if (isa<CatchReturnInst>(
BB->getTerminator()))
587 return OverdefinedState;
589 int CommonState = OverdefinedState;
593 auto SuccStartState = InitialStates.
find(SuccBB);
594 if (SuccStartState == InitialStates.
end())
595 return OverdefinedState;
598 if (SuccBB->isEHPad())
599 return OverdefinedState;
601 int SuccState = SuccStartState->second;
602 assert(SuccState != OverdefinedState &&
603 "overdefined BBs shouldn't be in FinalStates");
604 if (CommonState == OverdefinedState)
605 CommonState = SuccState;
609 if (CommonState != SuccState)
610 return OverdefinedState;
616 bool WinEHStatePass::isStateStoreNeeded(
EHPersonality Personality,
620 return !
Call.doesNotAccessMemory();
623 return !
Call.doesNotThrow();
637 Value *EHGuardNodeI8 =
660 std::deque<BasicBlock *> Worklist;
663 int InitialState = OverdefinedState;
665 if (&
F.getEntryBlock() ==
BB)
666 InitialState = FinalState = ParentBaseState;
668 auto *
Call = dyn_cast<CallBase>(&
I);
669 if (!Call || !isStateStoreNeeded(Personality, *Call))
672 int State = getStateForCall(BlockColors, FuncInfo, *Call);
673 if (InitialState == OverdefinedState)
674 InitialState = State;
679 if (InitialState == OverdefinedState) {
680 Worklist.push_back(
BB);
684 <<
" InitialState=" << InitialState <<
'\n');
686 <<
" FinalState=" << FinalState <<
'\n');
687 InitialStates.
insert({
BB, InitialState});
688 FinalStates.
insert({
BB, FinalState});
692 while (!Worklist.empty()) {
694 Worklist.pop_front();
696 if (InitialStates.
count(
BB) != 0)
700 if (PredState == OverdefinedState)
705 InitialStates.
insert({
BB, PredState});
706 FinalStates.
insert({
BB, PredState});
708 Worklist.push_back(SuccBB);
714 if (SuccState == OverdefinedState)
719 FinalStates.
insert({
BB, SuccState});
725 auto &BBColors = BlockColors[
BB];
732 <<
" PrevState=" << PrevState <<
'\n');
735 auto *
Call = dyn_cast<CallBase>(&
I);
736 if (!Call || !isStateStoreNeeded(Personality, *Call))
739 int State = getStateForCall(BlockColors, FuncInfo, *Call);
740 if (State != PrevState)
741 insertStateNumberStore(&
I, State);
746 auto EndState = FinalStates.
find(
BB);
747 if (EndState != FinalStates.
end())
748 if (EndState->second != PrevState)
749 insertStateNumberStore(
BB->getTerminator(), EndState->second);
755 auto *
Call = dyn_cast<CallBase>(&
I);
758 if (
Call->getCalledOperand()->stripPointerCasts() !=
759 SetJmp3.getCallee()->stripPointerCasts())
762 SetJmp3Calls.push_back(Call);
766 for (
CallBase *Call : SetJmp3Calls) {
767 auto &BBColors = BlockColors[
Call->getParent()];
769 bool InCleanup = isa<CleanupPadInst>(FuncletEntryBB->
getFirstNonPHI());
774 Value *StateField =
Builder.CreateStructGEP(RegNode->getAllocatedType(),
775 RegNode, StateFieldIndex);
778 State =
Builder.getInt32(getStateForCall(BlockColors, FuncInfo, *Call));
780 rewriteSetJmpCall(
Builder,
F, *Call, State);
784 void WinEHStatePass::insertStateNumberStore(
Instruction *
IP,
int State) {
786 Value *StateField =
Builder.CreateStructGEP(RegNode->getAllocatedType(),
787 RegNode, StateFieldIndex);