#include "WinException.h"
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/COFF.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/TargetFrameLowering.h"
#include "llvm/CodeGen/TargetLowering.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/CodeGen/WinEHFuncInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Module.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetMachine.h"
using namespace llvm;
WinException::WinException(AsmPrinter *A) : EHStreamer(A) {
useImageRel32 = (A->getDataLayout().getPointerSizeInBits() == 64);
isAArch64 = Asm->TM.getTargetTriple().isAArch64();
isThumb = Asm->TM.getTargetTriple().isThumb();
}
WinException::~WinException() = default;
void WinException::endModule() {
auto &OS = *Asm->OutStreamer;
const Module *M = MMI->getModule();
for (const Function &F : *M)
if (F.hasFnAttribute("safeseh"))
OS.emitCOFFSafeSEH(Asm->getSymbol(&F));
if (M->getModuleFlag("ehcontguard") && !EHContTargets.empty()) {
OS.switchSection(Asm->OutContext.getObjectFileInfo()->getGEHContSection());
for (const MCSymbol *S : EHContTargets) {
OS.emitCOFFSymbolIndex(S);
}
}
}
void WinException::beginFunction(const MachineFunction *MF) {
shouldEmitMoves = shouldEmitPersonality = shouldEmitLSDA = false;
bool hasLandingPads = !MF->getLandingPads().empty();
bool hasEHFunclets = MF->hasEHFunclets();
const Function &F = MF->getFunction();
shouldEmitMoves = Asm->needsSEHMoves() && MF->hasWinCFI();
const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();
unsigned PerEncoding = TLOF.getPersonalityEncoding();
EHPersonality Per = EHPersonality::Unknown;
const Function *PerFn = nullptr;
if (F.hasPersonalityFn()) {
PerFn = dyn_cast<Function>(F.getPersonalityFn()->stripPointerCasts());
Per = classifyEHPersonality(PerFn);
}
bool forceEmitPersonality = F.hasPersonalityFn() &&
!isNoOpWithoutInvoke(Per) &&
F.needsUnwindTableEntry();
shouldEmitPersonality =
forceEmitPersonality || ((hasLandingPads || hasEHFunclets) &&
PerEncoding != dwarf::DW_EH_PE_omit && PerFn);
unsigned LSDAEncoding = TLOF.getLSDAEncoding();
shouldEmitLSDA = shouldEmitPersonality &&
LSDAEncoding != dwarf::DW_EH_PE_omit;
if (!Asm->MAI->usesWindowsCFI()) {
if (Per == EHPersonality::MSVC_X86SEH && !hasEHFunclets) {
const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo();
StringRef FLinkageName =
GlobalValue::dropLLVMManglingEscape(MF->getFunction().getName());
emitEHRegistrationOffsetLabel(FuncInfo, FLinkageName);
}
shouldEmitLSDA = hasEHFunclets;
shouldEmitPersonality = false;
return;
}
beginFunclet(MF->front(), Asm->CurrentFnSym);
}
void WinException::markFunctionEnd() {
if (isAArch64 && CurrentFuncletEntry &&
(shouldEmitMoves || shouldEmitPersonality))
Asm->OutStreamer->emitWinCFIFuncletOrFuncEnd();
}
void WinException::endFunction(const MachineFunction *MF) {
if (!shouldEmitPersonality && !shouldEmitMoves && !shouldEmitLSDA)
return;
const Function &F = MF->getFunction();
EHPersonality Per = EHPersonality::Unknown;
if (F.hasPersonalityFn())
Per = classifyEHPersonality(F.getPersonalityFn()->stripPointerCasts());
if (!isFuncletEHPersonality(Per)) {
MachineFunction *NonConstMF = const_cast<MachineFunction*>(MF);
NonConstMF->tidyLandingPads();
}
endFuncletImpl();
if (Per == EHPersonality::MSVC_TableSEH && MF->hasEHFunclets())
return;
if (shouldEmitPersonality || shouldEmitLSDA) {
Asm->OutStreamer->pushSection();
MCSection *XData = Asm->OutStreamer->getAssociatedXDataSection(
Asm->OutStreamer->getCurrentSectionOnly());
Asm->OutStreamer->switchSection(XData);
if (Per == EHPersonality::MSVC_TableSEH)
emitCSpecificHandlerTable(MF);
else if (Per == EHPersonality::MSVC_X86SEH)
emitExceptHandlerTable(MF);
else if (Per == EHPersonality::MSVC_CXX)
emitCXXFrameHandler3Table(MF);
else if (Per == EHPersonality::CoreCLR)
emitCLRExceptionTable(MF);
else
emitExceptionTable();
Asm->OutStreamer->popSection();
}
if (!MF->getCatchretTargets().empty()) {
EHContTargets.insert(EHContTargets.end(), MF->getCatchretTargets().begin(),
MF->getCatchretTargets().end());
}
}
static MCSymbol *getMCSymbolForMBB(AsmPrinter *Asm,
const MachineBasicBlock *MBB) {
if (!MBB)
return nullptr;
assert(MBB->isEHFuncletEntry());
const MachineFunction *MF = MBB->getParent();
const Function &F = MF->getFunction();
StringRef FuncLinkageName = GlobalValue::dropLLVMManglingEscape(F.getName());
MCContext &Ctx = MF->getContext();
StringRef HandlerPrefix = MBB->isCleanupFuncletEntry() ? "dtor" : "catch";
return Ctx.getOrCreateSymbol("?" + HandlerPrefix + "$" +
Twine(MBB->getNumber()) + "@?0?" +
FuncLinkageName + "@4HA");
}
void WinException::beginFunclet(const MachineBasicBlock &MBB,
MCSymbol *Sym) {
CurrentFuncletEntry = &MBB;
const Function &F = Asm->MF->getFunction();
if (!Sym) {
Sym = getMCSymbolForMBB(Asm, &MBB);
Asm->OutStreamer->beginCOFFSymbolDef(Sym);
Asm->OutStreamer->emitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_STATIC);
Asm->OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION
<< COFF::SCT_COMPLEX_TYPE_SHIFT);
Asm->OutStreamer->endCOFFSymbolDef();
Asm->emitAlignment(std::max(Asm->MF->getAlignment(), MBB.getAlignment()),
&F);
Asm->OutStreamer->emitLabel(Sym);
}
if (shouldEmitMoves || shouldEmitPersonality) {
CurrentFuncletTextSection = Asm->OutStreamer->getCurrentSectionOnly();
Asm->OutStreamer->emitWinCFIStartProc(Sym);
}
if (shouldEmitPersonality) {
const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();
const Function *PerFn = nullptr;
if (F.hasPersonalityFn())
PerFn = dyn_cast<Function>(F.getPersonalityFn()->stripPointerCasts());
const MCSymbol *PersHandlerSym =
TLOF.getCFIPersonalitySymbol(PerFn, Asm->TM, MMI);
if (!CurrentFuncletEntry->isCleanupFuncletEntry())
Asm->OutStreamer->emitWinEHHandler(PersHandlerSym, true, true);
}
}
void WinException::endFunclet() {
if (isAArch64 && CurrentFuncletEntry &&
(shouldEmitMoves || shouldEmitPersonality)) {
Asm->OutStreamer->switchSection(CurrentFuncletTextSection);
Asm->OutStreamer->emitWinCFIFuncletOrFuncEnd();
}
endFuncletImpl();
}
void WinException::endFuncletImpl() {
if (!CurrentFuncletEntry)
return;
const MachineFunction *MF = Asm->MF;
if (shouldEmitMoves || shouldEmitPersonality) {
const Function &F = MF->getFunction();
EHPersonality Per = EHPersonality::Unknown;
if (F.hasPersonalityFn())
Per = classifyEHPersonality(F.getPersonalityFn()->stripPointerCasts());
if (Per == EHPersonality::MSVC_CXX && shouldEmitPersonality &&
!CurrentFuncletEntry->isCleanupFuncletEntry()) {
Asm->OutStreamer->emitWinEHHandlerData();
StringRef FuncLinkageName = GlobalValue::dropLLVMManglingEscape(F.getName());
MCSymbol *FuncInfoXData = Asm->OutContext.getOrCreateSymbol(
Twine("$cppxdata$", FuncLinkageName));
Asm->OutStreamer->emitValue(create32bitRef(FuncInfoXData), 4);
} else if (Per == EHPersonality::MSVC_TableSEH && MF->hasEHFunclets() &&
!CurrentFuncletEntry->isEHFuncletEntry()) {
Asm->OutStreamer->emitWinEHHandlerData();
emitCSpecificHandlerTable(MF);
} else if (shouldEmitPersonality || shouldEmitLSDA) {
Asm->OutStreamer->emitWinEHHandlerData();
} else {
}
Asm->OutStreamer->switchSection(CurrentFuncletTextSection);
Asm->OutStreamer->emitWinCFIEndProc();
}
CurrentFuncletEntry = nullptr;
}
const MCExpr *WinException::create32bitRef(const MCSymbol *Value) {
if (!Value)
return MCConstantExpr::create(0, Asm->OutContext);
return MCSymbolRefExpr::create(Value, useImageRel32
? MCSymbolRefExpr::VK_COFF_IMGREL32
: MCSymbolRefExpr::VK_None,
Asm->OutContext);
}
const MCExpr *WinException::create32bitRef(const GlobalValue *GV) {
if (!GV)
return MCConstantExpr::create(0, Asm->OutContext);
return create32bitRef(Asm->getSymbol(GV));
}
const MCExpr *WinException::getLabel(const MCSymbol *Label) {
return MCSymbolRefExpr::create(Label, MCSymbolRefExpr::VK_COFF_IMGREL32,
Asm->OutContext);
}
const MCExpr *WinException::getLabelPlusOne(const MCSymbol *Label) {
return MCBinaryExpr::createAdd(getLabel(Label),
MCConstantExpr::create(1, Asm->OutContext),
Asm->OutContext);
}
const MCExpr *WinException::getOffset(const MCSymbol *OffsetOf,
const MCSymbol *OffsetFrom) {
return MCBinaryExpr::createSub(
MCSymbolRefExpr::create(OffsetOf, Asm->OutContext),
MCSymbolRefExpr::create(OffsetFrom, Asm->OutContext), Asm->OutContext);
}
const MCExpr *WinException::getOffsetPlusOne(const MCSymbol *OffsetOf,
const MCSymbol *OffsetFrom) {
return MCBinaryExpr::createAdd(getOffset(OffsetOf, OffsetFrom),
MCConstantExpr::create(1, Asm->OutContext),
Asm->OutContext);
}
int WinException::getFrameIndexOffset(int FrameIndex,
const WinEHFuncInfo &FuncInfo) {
const TargetFrameLowering &TFI = *Asm->MF->getSubtarget().getFrameLowering();
Register UnusedReg;
if (Asm->MAI->usesWindowsCFI()) {
StackOffset Offset =
TFI.getFrameIndexReferencePreferSP(*Asm->MF, FrameIndex, UnusedReg,
true);
assert(UnusedReg ==
Asm->MF->getSubtarget()
.getTargetLowering()
->getStackPointerRegisterToSaveRestore());
return Offset.getFixed();
}
assert(FuncInfo.EHRegNodeEndOffset != INT_MAX);
StackOffset Offset = TFI.getFrameIndexReference(*Asm->MF, FrameIndex, UnusedReg);
Offset += StackOffset::getFixed(FuncInfo.EHRegNodeEndOffset);
assert(!Offset.getScalable() &&
"Frame offsets with a scalable component are not supported");
return Offset.getFixed();
}
namespace {
const int NullState = -1;
struct InvokeStateChange {
const MCSymbol *PreviousEndLabel;
const MCSymbol *NewStartLabel;
int NewState;
};
class InvokeStateChangeIterator {
InvokeStateChangeIterator(const WinEHFuncInfo &EHInfo,
MachineFunction::const_iterator MFI,
MachineFunction::const_iterator MFE,
MachineBasicBlock::const_iterator MBBI,
int BaseState)
: EHInfo(EHInfo), MFI(MFI), MFE(MFE), MBBI(MBBI), BaseState(BaseState) {
LastStateChange.PreviousEndLabel = nullptr;
LastStateChange.NewStartLabel = nullptr;
LastStateChange.NewState = BaseState;
scan();
}
public:
static iterator_range<InvokeStateChangeIterator>
range(const WinEHFuncInfo &EHInfo, MachineFunction::const_iterator Begin,
MachineFunction::const_iterator End, int BaseState = NullState) {
assert(Begin != End);
auto BlockBegin = Begin->begin();
auto BlockEnd = std::prev(End)->end();
return make_range(
InvokeStateChangeIterator(EHInfo, Begin, End, BlockBegin, BaseState),
InvokeStateChangeIterator(EHInfo, End, End, BlockEnd, BaseState));
}
bool operator==(const InvokeStateChangeIterator &O) const {
assert(BaseState == O.BaseState);
if (MFI != O.MFI)
return false;
if (MBBI != O.MBBI)
return false;
return CurrentEndLabel == O.CurrentEndLabel;
}
bool operator!=(const InvokeStateChangeIterator &O) const {
return !operator==(O);
}
InvokeStateChange &operator*() { return LastStateChange; }
InvokeStateChange *operator->() { return &LastStateChange; }
InvokeStateChangeIterator &operator++() { return scan(); }
private:
InvokeStateChangeIterator &scan();
const WinEHFuncInfo &EHInfo;
const MCSymbol *CurrentEndLabel = nullptr;
MachineFunction::const_iterator MFI;
MachineFunction::const_iterator MFE;
MachineBasicBlock::const_iterator MBBI;
InvokeStateChange LastStateChange;
bool VisitingInvoke = false;
int BaseState;
};
}
InvokeStateChangeIterator &InvokeStateChangeIterator::scan() {
bool IsNewBlock = false;
for (; MFI != MFE; ++MFI, IsNewBlock = true) {
if (IsNewBlock)
MBBI = MFI->begin();
for (auto MBBE = MFI->end(); MBBI != MBBE; ++MBBI) {
const MachineInstr &MI = *MBBI;
if (!VisitingInvoke && LastStateChange.NewState != BaseState &&
MI.isCall() && !EHStreamer::callToNoUnwindFunction(&MI)) {
LastStateChange.PreviousEndLabel = CurrentEndLabel;
LastStateChange.NewStartLabel = nullptr;
LastStateChange.NewState = BaseState;
CurrentEndLabel = nullptr;
++MBBI;
return *this;
}
if (!MI.isEHLabel())
continue;
MCSymbol *Label = MI.getOperand(0).getMCSymbol();
if (Label == CurrentEndLabel) {
VisitingInvoke = false;
continue;
}
auto InvokeMapIter = EHInfo.LabelToStateMap.find(Label);
if (InvokeMapIter == EHInfo.LabelToStateMap.end())
continue;
auto &StateAndEnd = InvokeMapIter->second;
int NewState = StateAndEnd.first;
VisitingInvoke = true;
if (NewState == LastStateChange.NewState) {
CurrentEndLabel = StateAndEnd.second;
continue;
}
LastStateChange.PreviousEndLabel = CurrentEndLabel;
LastStateChange.NewStartLabel = Label;
LastStateChange.NewState = NewState;
CurrentEndLabel = StateAndEnd.second;
++MBBI;
return *this;
}
}
if (LastStateChange.NewState != BaseState) {
LastStateChange.PreviousEndLabel = CurrentEndLabel;
LastStateChange.NewStartLabel = nullptr;
LastStateChange.NewState = BaseState;
assert(CurrentEndLabel != nullptr);
return *this;
}
CurrentEndLabel = nullptr;
return *this;
}
void WinException::emitCSpecificHandlerTable(const MachineFunction *MF) {
auto &OS = *Asm->OutStreamer;
MCContext &Ctx = Asm->OutContext;
const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo();
bool VerboseAsm = OS.isVerboseAsm();
auto AddComment = [&](const Twine &Comment) {
if (VerboseAsm)
OS.AddComment(Comment);
};
if (!isAArch64) {
StringRef FLinkageName =
GlobalValue::dropLLVMManglingEscape(MF->getFunction().getName());
MCSymbol *ParentFrameOffset =
Ctx.getOrCreateParentFrameOffsetSymbol(FLinkageName);
const MCExpr *MCOffset =
MCConstantExpr::create(FuncInfo.SEHSetFrameOffset, Ctx);
Asm->OutStreamer->emitAssignment(ParentFrameOffset, MCOffset);
}
MCSymbol *TableBegin =
Ctx.createTempSymbol("lsda_begin", true);
MCSymbol *TableEnd =
Ctx.createTempSymbol("lsda_end", true);
const MCExpr *LabelDiff = getOffset(TableEnd, TableBegin);
const MCExpr *EntrySize = MCConstantExpr::create(16, Ctx);
const MCExpr *EntryCount = MCBinaryExpr::createDiv(LabelDiff, EntrySize, Ctx);
AddComment("Number of call sites");
OS.emitValue(EntryCount, 4);
OS.emitLabel(TableBegin);
const MCSymbol *LastStartLabel = nullptr;
int LastEHState = -1;
MachineFunction::const_iterator End = MF->end();
MachineFunction::const_iterator Stop = std::next(MF->begin());
while (Stop != End && !Stop->isEHFuncletEntry())
++Stop;
for (const auto &StateChange :
InvokeStateChangeIterator::range(FuncInfo, MF->begin(), Stop)) {
if (LastEHState != -1)
emitSEHActionsForRange(FuncInfo, LastStartLabel,
StateChange.PreviousEndLabel, LastEHState);
LastStartLabel = StateChange.NewStartLabel;
LastEHState = StateChange.NewState;
}
OS.emitLabel(TableEnd);
}
void WinException::emitSEHActionsForRange(const WinEHFuncInfo &FuncInfo,
const MCSymbol *BeginLabel,
const MCSymbol *EndLabel, int State) {
auto &OS = *Asm->OutStreamer;
MCContext &Ctx = Asm->OutContext;
bool VerboseAsm = OS.isVerboseAsm();
auto AddComment = [&](const Twine &Comment) {
if (VerboseAsm)
OS.AddComment(Comment);
};
assert(BeginLabel && EndLabel);
while (State != -1) {
const SEHUnwindMapEntry &UME = FuncInfo.SEHUnwindMap[State];
const MCExpr *FilterOrFinally;
const MCExpr *ExceptOrNull;
auto *Handler = UME.Handler.get<MachineBasicBlock *>();
if (UME.IsFinally) {
FilterOrFinally = create32bitRef(getMCSymbolForMBB(Asm, Handler));
ExceptOrNull = MCConstantExpr::create(0, Ctx);
} else {
FilterOrFinally = UME.Filter ? create32bitRef(UME.Filter)
: MCConstantExpr::create(1, Ctx);
ExceptOrNull = create32bitRef(Handler->getSymbol());
}
AddComment("LabelStart");
OS.emitValue(getLabel(BeginLabel), 4);
AddComment("LabelEnd");
OS.emitValue(getLabelPlusOne(EndLabel), 4);
AddComment(UME.IsFinally ? "FinallyFunclet" : UME.Filter ? "FilterFunction"
: "CatchAll");
OS.emitValue(FilterOrFinally, 4);
AddComment(UME.IsFinally ? "Null" : "ExceptionHandler");
OS.emitValue(ExceptOrNull, 4);
assert(UME.ToState < State && "states should decrease");
State = UME.ToState;
}
}
void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
const Function &F = MF->getFunction();
auto &OS = *Asm->OutStreamer;
const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo();
StringRef FuncLinkageName = GlobalValue::dropLLVMManglingEscape(F.getName());
SmallVector<std::pair<const MCExpr *, int>, 4> IPToStateTable;
MCSymbol *FuncInfoXData = nullptr;
if (shouldEmitPersonality) {
FuncInfoXData =
Asm->OutContext.getOrCreateSymbol(Twine("$cppxdata$", FuncLinkageName));
computeIP2StateTable(MF, FuncInfo, IPToStateTable);
} else {
FuncInfoXData = Asm->OutContext.getOrCreateLSDASymbol(FuncLinkageName);
}
int UnwindHelpOffset = 0;
if (Asm->MAI->usesWindowsCFI() &&
FuncInfo.UnwindHelpFrameIdx != std::numeric_limits<int>::max())
UnwindHelpOffset =
getFrameIndexOffset(FuncInfo.UnwindHelpFrameIdx, FuncInfo);
MCSymbol *UnwindMapXData = nullptr;
MCSymbol *TryBlockMapXData = nullptr;
MCSymbol *IPToStateXData = nullptr;
if (!FuncInfo.CxxUnwindMap.empty())
UnwindMapXData = Asm->OutContext.getOrCreateSymbol(
Twine("$stateUnwindMap$", FuncLinkageName));
if (!FuncInfo.TryBlockMap.empty())
TryBlockMapXData =
Asm->OutContext.getOrCreateSymbol(Twine("$tryMap$", FuncLinkageName));
if (!IPToStateTable.empty())
IPToStateXData =
Asm->OutContext.getOrCreateSymbol(Twine("$ip2state$", FuncLinkageName));
bool VerboseAsm = OS.isVerboseAsm();
auto AddComment = [&](const Twine &Comment) {
if (VerboseAsm)
OS.AddComment(Comment);
};
OS.emitValueToAlignment(4);
OS.emitLabel(FuncInfoXData);
AddComment("MagicNumber");
OS.emitInt32(0x19930522);
AddComment("MaxState");
OS.emitInt32(FuncInfo.CxxUnwindMap.size());
AddComment("UnwindMap");
OS.emitValue(create32bitRef(UnwindMapXData), 4);
AddComment("NumTryBlocks");
OS.emitInt32(FuncInfo.TryBlockMap.size());
AddComment("TryBlockMap");
OS.emitValue(create32bitRef(TryBlockMapXData), 4);
AddComment("IPMapEntries");
OS.emitInt32(IPToStateTable.size());
AddComment("IPToStateXData");
OS.emitValue(create32bitRef(IPToStateXData), 4);
if (Asm->MAI->usesWindowsCFI() &&
FuncInfo.UnwindHelpFrameIdx != std::numeric_limits<int>::max()) {
AddComment("UnwindHelp");
OS.emitInt32(UnwindHelpOffset);
}
AddComment("ESTypeList");
OS.emitInt32(0);
AddComment("EHFlags");
OS.emitInt32(1);
if (UnwindMapXData) {
OS.emitLabel(UnwindMapXData);
for (const CxxUnwindMapEntry &UME : FuncInfo.CxxUnwindMap) {
MCSymbol *CleanupSym =
getMCSymbolForMBB(Asm, UME.Cleanup.dyn_cast<MachineBasicBlock *>());
AddComment("ToState");
OS.emitInt32(UME.ToState);
AddComment("Action");
OS.emitValue(create32bitRef(CleanupSym), 4);
}
}
if (TryBlockMapXData) {
OS.emitLabel(TryBlockMapXData);
SmallVector<MCSymbol *, 1> HandlerMaps;
for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) {
const WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I];
MCSymbol *HandlerMapXData = nullptr;
if (!TBME.HandlerArray.empty())
HandlerMapXData =
Asm->OutContext.getOrCreateSymbol(Twine("$handlerMap$")
.concat(Twine(I))
.concat("$")
.concat(FuncLinkageName));
HandlerMaps.push_back(HandlerMapXData);
assert(0 <= TBME.TryLow && "bad trymap interval");
assert(TBME.TryLow <= TBME.TryHigh && "bad trymap interval");
assert(TBME.TryHigh < TBME.CatchHigh && "bad trymap interval");
assert(TBME.CatchHigh < int(FuncInfo.CxxUnwindMap.size()) &&
"bad trymap interval");
AddComment("TryLow");
OS.emitInt32(TBME.TryLow);
AddComment("TryHigh");
OS.emitInt32(TBME.TryHigh);
AddComment("CatchHigh");
OS.emitInt32(TBME.CatchHigh);
AddComment("NumCatches");
OS.emitInt32(TBME.HandlerArray.size());
AddComment("HandlerArray");
OS.emitValue(create32bitRef(HandlerMapXData), 4);
}
unsigned ParentFrameOffset = 0;
if (shouldEmitPersonality) {
const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering();
ParentFrameOffset = TFI->getWinEHParentFrameOffset(*MF);
}
for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) {
const WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I];
MCSymbol *HandlerMapXData = HandlerMaps[I];
if (!HandlerMapXData)
continue;
OS.emitLabel(HandlerMapXData);
for (const WinEHHandlerType &HT : TBME.HandlerArray) {
const MCExpr *FrameAllocOffsetRef = nullptr;
if (HT.CatchObj.FrameIndex != INT_MAX) {
int Offset = getFrameIndexOffset(HT.CatchObj.FrameIndex, FuncInfo);
assert(Offset != 0 && "Illegal offset for catch object!");
FrameAllocOffsetRef = MCConstantExpr::create(Offset, Asm->OutContext);
} else {
FrameAllocOffsetRef = MCConstantExpr::create(0, Asm->OutContext);
}
MCSymbol *HandlerSym =
getMCSymbolForMBB(Asm, HT.Handler.dyn_cast<MachineBasicBlock *>());
AddComment("Adjectives");
OS.emitInt32(HT.Adjectives);
AddComment("Type");
OS.emitValue(create32bitRef(HT.TypeDescriptor), 4);
AddComment("CatchObjOffset");
OS.emitValue(FrameAllocOffsetRef, 4);
AddComment("Handler");
OS.emitValue(create32bitRef(HandlerSym), 4);
if (shouldEmitPersonality) {
AddComment("ParentFrameOffset");
OS.emitInt32(ParentFrameOffset);
}
}
}
}
if (IPToStateXData) {
OS.emitLabel(IPToStateXData);
for (auto &IPStatePair : IPToStateTable) {
AddComment("IP");
OS.emitValue(IPStatePair.first, 4);
AddComment("ToState");
OS.emitInt32(IPStatePair.second);
}
}
}
void WinException::computeIP2StateTable(
const MachineFunction *MF, const WinEHFuncInfo &FuncInfo,
SmallVectorImpl<std::pair<const MCExpr *, int>> &IPToStateTable) {
for (MachineFunction::const_iterator FuncletStart = MF->begin(),
FuncletEnd = MF->begin(),
End = MF->end();
FuncletStart != End; FuncletStart = FuncletEnd) {
while (++FuncletEnd != End) {
if (FuncletEnd->isEHFuncletEntry()) {
break;
}
}
if (FuncletStart->isCleanupFuncletEntry())
continue;
MCSymbol *StartLabel;
int BaseState;
if (FuncletStart == MF->begin()) {
BaseState = NullState;
StartLabel = Asm->getFunctionBegin();
} else {
auto *FuncletPad =
cast<FuncletPadInst>(FuncletStart->getBasicBlock()->getFirstNonPHI());
assert(FuncInfo.FuncletBaseStateMap.count(FuncletPad) != 0);
BaseState = FuncInfo.FuncletBaseStateMap.find(FuncletPad)->second;
StartLabel = getMCSymbolForMBB(Asm, &*FuncletStart);
}
assert(StartLabel && "need local function start label");
IPToStateTable.push_back(
std::make_pair(create32bitRef(StartLabel), BaseState));
for (const auto &StateChange : InvokeStateChangeIterator::range(
FuncInfo, FuncletStart, FuncletEnd, BaseState)) {
const MCSymbol *ChangeLabel = StateChange.NewStartLabel;
if (!ChangeLabel)
ChangeLabel = StateChange.PreviousEndLabel;
const MCExpr *LabelExpression = (isAArch64 || isThumb)
? getLabel(ChangeLabel)
: getLabelPlusOne(ChangeLabel);
IPToStateTable.push_back(
std::make_pair(LabelExpression, StateChange.NewState));
}
}
}
void WinException::emitEHRegistrationOffsetLabel(const WinEHFuncInfo &FuncInfo,
StringRef FLinkageName) {
int64_t Offset = 0;
int FI = FuncInfo.EHRegNodeFrameIndex;
if (FI != INT_MAX) {
const TargetFrameLowering *TFI = Asm->MF->getSubtarget().getFrameLowering();
Offset = TFI->getNonLocalFrameIndexReference(*Asm->MF, FI).getFixed();
}
MCContext &Ctx = Asm->OutContext;
MCSymbol *ParentFrameOffset =
Ctx.getOrCreateParentFrameOffsetSymbol(FLinkageName);
Asm->OutStreamer->emitAssignment(ParentFrameOffset,
MCConstantExpr::create(Offset, Ctx));
}
void WinException::emitExceptHandlerTable(const MachineFunction *MF) {
MCStreamer &OS = *Asm->OutStreamer;
const Function &F = MF->getFunction();
StringRef FLinkageName = GlobalValue::dropLLVMManglingEscape(F.getName());
bool VerboseAsm = OS.isVerboseAsm();
auto AddComment = [&](const Twine &Comment) {
if (VerboseAsm)
OS.AddComment(Comment);
};
const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo();
emitEHRegistrationOffsetLabel(FuncInfo, FLinkageName);
MCSymbol *LSDALabel = Asm->OutContext.getOrCreateLSDASymbol(FLinkageName);
OS.emitValueToAlignment(4);
OS.emitLabel(LSDALabel);
const auto *Per = cast<Function>(F.getPersonalityFn()->stripPointerCasts());
StringRef PerName = Per->getName();
int BaseState = -1;
if (PerName == "_except_handler4") {
int GSCookieOffset = -2;
const MachineFrameInfo &MFI = MF->getFrameInfo();
if (MFI.hasStackProtectorIndex()) {
Register UnusedReg;
const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering();
int SSPIdx = MFI.getStackProtectorIndex();
GSCookieOffset =
TFI->getFrameIndexReference(*MF, SSPIdx, UnusedReg).getFixed();
}
int EHCookieOffset = 9999;
if (FuncInfo.EHGuardFrameIndex != INT_MAX) {
Register UnusedReg;
const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering();
int EHGuardIdx = FuncInfo.EHGuardFrameIndex;
EHCookieOffset =
TFI->getFrameIndexReference(*MF, EHGuardIdx, UnusedReg).getFixed();
}
AddComment("GSCookieOffset");
OS.emitInt32(GSCookieOffset);
AddComment("GSCookieXOROffset");
OS.emitInt32(0);
AddComment("EHCookieOffset");
OS.emitInt32(EHCookieOffset);
AddComment("EHCookieXOROffset");
OS.emitInt32(0);
BaseState = -2;
}
assert(!FuncInfo.SEHUnwindMap.empty());
for (const SEHUnwindMapEntry &UME : FuncInfo.SEHUnwindMap) {
auto *Handler = UME.Handler.get<MachineBasicBlock *>();
const MCSymbol *ExceptOrFinally =
UME.IsFinally ? getMCSymbolForMBB(Asm, Handler) : Handler->getSymbol();
int ToState = UME.ToState == -1 ? BaseState : UME.ToState;
AddComment("ToState");
OS.emitInt32(ToState);
AddComment(UME.IsFinally ? "Null" : "FilterFunction");
OS.emitValue(create32bitRef(UME.Filter), 4);
AddComment(UME.IsFinally ? "FinallyFunclet" : "ExceptionHandler");
OS.emitValue(create32bitRef(ExceptOrFinally), 4);
}
}
static int getTryRank(const WinEHFuncInfo &FuncInfo, int State) {
int Rank = 0;
while (State != -1) {
++Rank;
State = FuncInfo.ClrEHUnwindMap[State].TryParentState;
}
return Rank;
}
static int getTryAncestor(const WinEHFuncInfo &FuncInfo, int Left, int Right) {
int LeftRank = getTryRank(FuncInfo, Left);
int RightRank = getTryRank(FuncInfo, Right);
while (LeftRank < RightRank) {
Right = FuncInfo.ClrEHUnwindMap[Right].TryParentState;
--RightRank;
}
while (RightRank < LeftRank) {
Left = FuncInfo.ClrEHUnwindMap[Left].TryParentState;
--LeftRank;
}
while (Left != Right) {
Left = FuncInfo.ClrEHUnwindMap[Left].TryParentState;
Right = FuncInfo.ClrEHUnwindMap[Right].TryParentState;
}
return Left;
}
void WinException::emitCLRExceptionTable(const MachineFunction *MF) {
MCStreamer &OS = *Asm->OutStreamer;
const WinEHFuncInfo &FuncInfo = *MF->getWinEHFuncInfo();
MCSymbol *FuncBeginSym = Asm->getFunctionBegin();
MCSymbol *FuncEndSym = Asm->getFunctionEnd();
struct ClrClause {
const MCSymbol *StartLabel; const MCSymbol *EndLabel; int State; int EnclosingState; };
SmallVector<ClrClause, 8> Clauses;
int NumStates = FuncInfo.ClrEHUnwindMap.size();
assert(NumStates > 0 && "Don't need exception table!");
DenseMap<const MachineBasicBlock *, int> HandlerStates;
for (int State = 0; State < NumStates; ++State) {
MachineBasicBlock *HandlerBlock =
FuncInfo.ClrEHUnwindMap[State].Handler.get<MachineBasicBlock *>();
HandlerStates[HandlerBlock] = State;
assert(FuncInfo.ClrEHUnwindMap[State].HandlerParentState < State &&
"ill-formed state numbering");
}
HandlerStates[&MF->front()] = NullState;
OS.emitInt32(0xffffffff);
OS.emitInt32(NumStates);
SmallVector<std::pair<const MCSymbol *, int>, 4> HandlerStack;
std::unique_ptr<MCSymbol *[]> EndSymbolMap(new MCSymbol *[NumStates]);
SmallVector<int, 4> MinClauseMap((size_t)NumStates, NumStates);
for (MachineFunction::const_iterator FuncletStart = MF->begin(),
FuncletEnd = MF->begin(),
End = MF->end();
FuncletStart != End; FuncletStart = FuncletEnd) {
int FuncletState = HandlerStates[&*FuncletStart];
MCSymbol *EndSymbol = FuncEndSym;
while (++FuncletEnd != End) {
if (FuncletEnd->isEHFuncletEntry()) {
EndSymbol = getMCSymbolForMBB(Asm, &*FuncletEnd);
break;
}
}
OS.emitValue(getOffset(EndSymbol, FuncBeginSym), 4);
if (FuncletState != NullState) {
EndSymbolMap[FuncletState] = EndSymbol;
}
const MCSymbol *CurrentStartLabel = nullptr;
int CurrentState = NullState;
assert(HandlerStack.empty());
for (const auto &StateChange :
InvokeStateChangeIterator::range(FuncInfo, FuncletStart, FuncletEnd)) {
int StillPendingState =
getTryAncestor(FuncInfo, CurrentState, StateChange.NewState);
while (CurrentState != StillPendingState) {
assert(CurrentState != NullState &&
"Failed to find still-pending state!");
Clauses.push_back({CurrentStartLabel, StateChange.PreviousEndLabel,
CurrentState, FuncletState});
CurrentState = FuncInfo.ClrEHUnwindMap[CurrentState].TryParentState;
if (HandlerStack.back().second == CurrentState)
CurrentStartLabel = HandlerStack.pop_back_val().first;
}
if (StateChange.NewState != CurrentState) {
for (int EnteredState = StateChange.NewState;
EnteredState != CurrentState;
EnteredState =
FuncInfo.ClrEHUnwindMap[EnteredState].TryParentState) {
int &MinEnclosingState = MinClauseMap[EnteredState];
if (FuncletState < MinEnclosingState)
MinEnclosingState = FuncletState;
}
HandlerStack.emplace_back(CurrentStartLabel, CurrentState);
CurrentStartLabel = StateChange.NewStartLabel;
CurrentState = StateChange.NewState;
}
}
assert(HandlerStack.empty());
}
OS.emitInt32(Clauses.size());
for (ClrClause &Clause : Clauses) {
const MCExpr *ClauseBegin =
getOffsetPlusOne(Clause.StartLabel, FuncBeginSym);
const MCExpr *ClauseEnd = getOffsetPlusOne(Clause.EndLabel, FuncBeginSym);
const ClrEHUnwindMapEntry &Entry = FuncInfo.ClrEHUnwindMap[Clause.State];
MachineBasicBlock *HandlerBlock = Entry.Handler.get<MachineBasicBlock *>();
MCSymbol *BeginSym = getMCSymbolForMBB(Asm, HandlerBlock);
const MCExpr *HandlerBegin = getOffset(BeginSym, FuncBeginSym);
MCSymbol *EndSym = EndSymbolMap[Clause.State];
const MCExpr *HandlerEnd = getOffset(EndSym, FuncBeginSym);
uint32_t Flags = 0;
switch (Entry.HandlerType) {
case ClrHandlerType::Catch:
break;
case ClrHandlerType::Filter:
Flags |= 1;
break;
case ClrHandlerType::Finally:
Flags |= 2;
break;
case ClrHandlerType::Fault:
Flags |= 4;
break;
}
if (Clause.EnclosingState != MinClauseMap[Clause.State]) {
assert(Clause.EnclosingState > MinClauseMap[Clause.State]);
Flags |= 8;
}
OS.emitInt32(Flags);
OS.emitValue(ClauseBegin, 4);
OS.emitValue(ClauseEnd, 4);
OS.emitValue(HandlerBegin, 4);
OS.emitValue(HandlerEnd, 4);
assert(Entry.HandlerType != ClrHandlerType::Filter && "NYI: filters");
OS.emitInt32(Entry.TypeToken);
}
}