summaryrefslogtreecommitdiffstats
path: root/llvm/lib/CodeGen/AsmPrinter
diff options
context:
space:
mode:
authorDavid Majnemer <david.majnemer@gmail.com>2015-03-30 22:58:10 +0000
committerDavid Majnemer <david.majnemer@gmail.com>2015-03-30 22:58:10 +0000
commitcde33036ed74db02088f5e3558afa33384cc4a13 (patch)
treee9f3517e12e60cb09d52aed542ba40869d8ba68b /llvm/lib/CodeGen/AsmPrinter
parent5fe5ef9e0ecc888d17f30ff6e1b977a0ebce7fa3 (diff)
downloadbcm5719-llvm-cde33036ed74db02088f5e3558afa33384cc4a13.tar.gz
bcm5719-llvm-cde33036ed74db02088f5e3558afa33384cc4a13.zip
[WinEH] Run cleanup handlers when an exception is thrown
Generate tables in the .xdata section representing what actions to take when an exception is thrown. This currently fills in state for cleanups, catch handlers are still unfinished. llvm-svn: 233636
Diffstat (limited to 'llvm/lib/CodeGen/AsmPrinter')
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp28
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/EHStreamer.h4
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/Win64Exception.cpp212
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/Win64Exception.h7
4 files changed, 236 insertions, 15 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp
index 14df4c91625..6f64d8f790a 100644
--- a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp
@@ -188,20 +188,12 @@ bool EHStreamer::callToNoUnwindFunction(const MachineInstr *MI) {
return MarkedNoUnwind;
}
-/// Compute the call-site table. The entry for an invoke has a try-range
-/// containing the call, a non-zero landing pad, and an appropriate action. The
-/// entry for an ordinary call has a try-range containing the call and zero for
-/// the landing pad and the action. Calls marked 'nounwind' have no entry and
-/// must not be contained in the try-range of any entry - they form gaps in the
-/// table. Entries must be ordered by try-range address.
-void EHStreamer::
-computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites,
- const SmallVectorImpl<const LandingPadInfo *> &LandingPads,
- const SmallVectorImpl<unsigned> &FirstActions) {
+void EHStreamer::computePadMap(
+ const SmallVectorImpl<const LandingPadInfo *> &LandingPads,
+ RangeMapType &PadMap) {
// Invokes and nounwind calls have entries in PadMap (due to being bracketed
// by try-range labels when lowered). Ordinary calls do not, so appropriate
// try-ranges for them need be deduced so we can put them in the LSDA.
- RangeMapType PadMap;
for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) {
const LandingPadInfo *LandingPad = LandingPads[i];
for (unsigned j = 0, E = LandingPad->BeginLabels.size(); j != E; ++j) {
@@ -211,6 +203,20 @@ computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites,
PadMap[BeginLabel] = P;
}
}
+}
+
+/// Compute the call-site table. The entry for an invoke has a try-range
+/// containing the call, a non-zero landing pad, and an appropriate action. The
+/// entry for an ordinary call has a try-range containing the call and zero for
+/// the landing pad and the action. Calls marked 'nounwind' have no entry and
+/// must not be contained in the try-range of any entry - they form gaps in the
+/// table. Entries must be ordered by try-range address.
+void EHStreamer::
+computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites,
+ const SmallVectorImpl<const LandingPadInfo *> &LandingPads,
+ const SmallVectorImpl<unsigned> &FirstActions) {
+ RangeMapType PadMap;
+ computePadMap(LandingPads, PadMap);
// The end label of the previous invoke or nounwind try-range.
MCSymbol *LastLabel = nullptr;
diff --git a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h
index 94d0585347e..aa42373b488 100644
--- a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h
+++ b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h
@@ -80,13 +80,15 @@ protected:
/// `false' otherwise.
bool callToNoUnwindFunction(const MachineInstr *MI);
+ void computePadMap(const SmallVectorImpl<const LandingPadInfo *> &LandingPads,
+ RangeMapType &PadMap);
+
/// Compute the call-site table. The entry for an invoke has a try-range
/// containing the call, a non-zero landing pad and an appropriate action.
/// The entry for an ordinary call has a try-range containing the call and
/// zero for the landing pad and the action. Calls marked 'nounwind' have
/// no entry and must not be contained in the try-range of any entry - they
/// form gaps in the table. Entries must be ordered by try-range address.
-
void computeCallSiteTable(SmallVectorImpl<CallSiteEntry> &CallSites,
const SmallVectorImpl<const LandingPadInfo *> &LPs,
const SmallVectorImpl<unsigned> &FirstActions);
diff --git a/llvm/lib/CodeGen/AsmPrinter/Win64Exception.cpp b/llvm/lib/CodeGen/AsmPrinter/Win64Exception.cpp
index 7d76eaddb56..974e94dcb6a 100644
--- a/llvm/lib/CodeGen/AsmPrinter/Win64Exception.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/Win64Exception.cpp
@@ -19,6 +19,7 @@
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/WinEHFuncInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Mangler.h"
#include "llvm/IR/Module.h"
@@ -82,7 +83,7 @@ void Win64Exception::beginFunction(const MachineFunction *MF) {
/// endFunction - Gather and emit post-function exception information.
///
-void Win64Exception::endFunction(const MachineFunction *) {
+void Win64Exception::endFunction(const MachineFunction *MF) {
if (!shouldEmitPersonality && !shouldEmitMoves)
return;
@@ -100,6 +101,8 @@ void Win64Exception::endFunction(const MachineFunction *) {
EHPersonality Per = MMI->getPersonalityType();
if (Per == EHPersonality::MSVC_Win64SEH)
emitCSpecificHandlerTable();
+ else if (Per == EHPersonality::MSVC_CXX)
+ emitCXXFrameHandler3Table(MF);
else
emitExceptionTable();
@@ -108,11 +111,19 @@ void Win64Exception::endFunction(const MachineFunction *) {
Asm->OutStreamer.EmitWinCFIEndProc();
}
-const MCSymbolRefExpr *Win64Exception::createImageRel32(const MCSymbol *Value) {
+const MCExpr *Win64Exception::createImageRel32(const MCSymbol *Value) {
+ if (!Value)
+ return MCConstantExpr::Create(0, Asm->OutContext);
return MCSymbolRefExpr::Create(Value, MCSymbolRefExpr::VK_COFF_IMGREL32,
Asm->OutContext);
}
+const MCExpr *Win64Exception::createImageRel32(const GlobalValue *GV) {
+ if (!GV)
+ return MCConstantExpr::Create(0, Asm->OutContext);
+ return createImageRel32(Asm->getSymbol(GV));
+}
+
/// Emit the language-specific data that __C_specific_handler expects. This
/// handler lives in the x64 Microsoft C runtime and allows catching or cleaning
/// up after faults with __try, __except, and __finally. The typeinfo values
@@ -237,3 +248,200 @@ void Win64Exception::emitCSpecificHandlerTable() {
}
}
}
+
+void Win64Exception::emitCXXFrameHandler3Table(const MachineFunction *MF) {
+ const Function *F = MF->getFunction();
+ const Function *ParentF = MMI->getWinEHParent(F);
+ auto &OS = Asm->OutStreamer;
+
+ StringRef ParentLinkageName =
+ GlobalValue::getRealLinkageName(ParentF->getName());
+
+ MCSymbol *FuncInfoXData =
+ Asm->OutContext.GetOrCreateSymbol(Twine("$cppxdata$", ParentLinkageName));
+ OS.EmitValue(createImageRel32(FuncInfoXData), 4);
+
+ // The Itanium LSDA table sorts similar landing pads together to simplify the
+ // actions table, but we don't need that.
+ SmallVector<const LandingPadInfo *, 64> LandingPads;
+ const std::vector<LandingPadInfo> &PadInfos = MMI->getLandingPads();
+ LandingPads.reserve(PadInfos.size());
+ for (const auto &LP : PadInfos)
+ LandingPads.push_back(&LP);
+
+ RangeMapType PadMap;
+ computePadMap(LandingPads, PadMap);
+
+ // The end label of the previous invoke or nounwind try-range.
+ MCSymbol *LastLabel = Asm->getFunctionBegin();
+
+ // Whether there is a potentially throwing instruction (currently this means
+ // an ordinary call) between the end of the previous try-range and now.
+ bool SawPotentiallyThrowing = false;
+
+ WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF);
+
+ int LastEHState = -2;
+
+ // The parent function and the catch handlers contribute to the 'ip2state'
+ // table.
+ for (const auto &MBB : *MF) {
+ for (const auto &MI : MBB) {
+ if (!MI.isEHLabel()) {
+ if (MI.isCall())
+ SawPotentiallyThrowing |= !callToNoUnwindFunction(&MI);
+ continue;
+ }
+
+ // End of the previous try-range?
+ MCSymbol *BeginLabel = MI.getOperand(0).getMCSymbol();
+ if (BeginLabel == LastLabel)
+ SawPotentiallyThrowing = false;
+
+ // Beginning of a new try-range?
+ RangeMapType::const_iterator L = PadMap.find(BeginLabel);
+ if (L == PadMap.end())
+ // Nope, it was just some random label.
+ continue;
+
+ const PadRange &P = L->second;
+ const LandingPadInfo *LandingPad = LandingPads[P.PadIndex];
+ assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] &&
+ "Inconsistent landing pad map!");
+
+ if (SawPotentiallyThrowing) {
+ FuncInfo.IPToStateList.push_back(std::make_pair(LastLabel, -1));
+ SawPotentiallyThrowing = false;
+ LastEHState = -1;
+ }
+
+ if (LandingPad->WinEHState != LastEHState)
+ FuncInfo.IPToStateList.push_back(
+ std::make_pair(BeginLabel, LandingPad->WinEHState));
+ LastEHState = LandingPad->WinEHState;
+ LastLabel = LandingPad->EndLabels[P.RangeIndex];
+ }
+ }
+
+ if (ParentF != F)
+ return;
+
+ MCSymbol *UnwindMapXData = nullptr;
+ MCSymbol *TryBlockMapXData = nullptr;
+ MCSymbol *IPToStateXData = nullptr;
+ if (!FuncInfo.UnwindMap.empty())
+ UnwindMapXData = Asm->OutContext.GetOrCreateSymbol(
+ Twine("$stateUnwindMap$", ParentLinkageName));
+ if (!FuncInfo.TryBlockMap.empty())
+ TryBlockMapXData = Asm->OutContext.GetOrCreateSymbol(
+ Twine("$tryMap$", ParentLinkageName));
+ if (!FuncInfo.IPToStateList.empty())
+ IPToStateXData = Asm->OutContext.GetOrCreateSymbol(
+ Twine("$ip2state$", ParentLinkageName));
+
+ // FuncInfo {
+ // uint32_t MagicNumber
+ // int32_t MaxState;
+ // UnwindMapEntry *UnwindMap;
+ // uint32_t NumTryBlocks;
+ // TryBlockMapEntry *TryBlockMap;
+ // uint32_t IPMapEntries;
+ // IPToStateMapEntry *IPToStateMap;
+ // uint32_t UnwindHelp; // (x64/ARM only)
+ // ESTypeList *ESTypeList;
+ // int32_t EHFlags;
+ // }
+ // EHFlags & 1 -> Synchronous exceptions only, no async exceptions.
+ // EHFlags & 2 -> ???
+ // EHFlags & 4 -> The function is noexcept(true), unwinding can't continue.
+ OS.EmitLabel(FuncInfoXData);
+ OS.EmitIntValue(0x19930522, 4); // MagicNumber
+ OS.EmitIntValue(FuncInfo.UnwindMap.size(), 4); // MaxState
+ OS.EmitValue(createImageRel32(UnwindMapXData), 4); // UnwindMap
+ OS.EmitIntValue(FuncInfo.TryBlockMap.size(), 4); // NumTryBlocks
+ OS.EmitValue(createImageRel32(TryBlockMapXData), 4); // TryBlockMap
+ OS.EmitIntValue(FuncInfo.IPToStateList.size(), 4); // IPMapEntries
+ OS.EmitValue(createImageRel32(IPToStateXData), 4); // IPToStateMap
+ OS.EmitIntValue(FuncInfo.UnwindHelpFrameOffset, 4); // UnwindHelp
+ OS.EmitIntValue(0, 4); // ESTypeList
+ OS.EmitIntValue(1, 4); // EHFlags
+
+ // UnwindMapEntry {
+ // int32_t ToState;
+ // void (*Action)();
+ // };
+ if (UnwindMapXData) {
+ OS.EmitLabel(UnwindMapXData);
+ for (const WinEHUnwindMapEntry &UME : FuncInfo.UnwindMap) {
+ OS.EmitIntValue(UME.ToState, 4); // ToState
+ OS.EmitValue(createImageRel32(UME.Cleanup), 4); // Action
+ }
+ }
+
+ // TryBlockMap {
+ // int32_t TryLow;
+ // int32_t TryHigh;
+ // int32_t CatchHigh;
+ // int32_t NumCatches;
+ // HandlerType *HandlerArray;
+ // };
+ if (TryBlockMapXData) {
+ OS.EmitLabel(TryBlockMapXData);
+ SmallVector<MCSymbol *, 1> HandlerMaps;
+ for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) {
+ WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I];
+ MCSymbol *HandlerMapXData = nullptr;
+
+ if (!TBME.HandlerArray.empty())
+ HandlerMapXData =
+ Asm->OutContext.GetOrCreateSymbol(Twine("$handlerMap$")
+ .concat(Twine(I))
+ .concat("$")
+ .concat(ParentLinkageName));
+
+ HandlerMaps.push_back(HandlerMapXData);
+
+ assert(TBME.TryLow <= TBME.TryHigh);
+ assert(TBME.CatchHigh > TBME.TryHigh);
+ OS.EmitIntValue(TBME.TryLow, 4); // TryLow
+ OS.EmitIntValue(TBME.TryHigh, 4); // TryHigh
+ OS.EmitIntValue(TBME.CatchHigh, 4); // CatchHigh
+ OS.EmitIntValue(TBME.HandlerArray.size(), 4); // NumCatches
+ OS.EmitValue(createImageRel32(HandlerMapXData), 4); // HandlerArray
+ }
+
+ for (size_t I = 0, E = FuncInfo.TryBlockMap.size(); I != E; ++I) {
+ WinEHTryBlockMapEntry &TBME = FuncInfo.TryBlockMap[I];
+ MCSymbol *HandlerMapXData = HandlerMaps[I];
+ if (!HandlerMapXData)
+ continue;
+ // HandlerType {
+ // int32_t Adjectives;
+ // TypeDescriptor *Type;
+ // int32_t CatchObjOffset;
+ // void (*Handler)();
+ // int32_t ParentFrameOffset; // x64 only
+ // };
+ OS.EmitLabel(HandlerMapXData);
+ for (const WinEHHandlerType &HT : TBME.HandlerArray) {
+ OS.EmitIntValue(HT.Adjectives, 4); // Adjectives
+ OS.EmitValue(createImageRel32(HT.TypeDescriptor), 4); // Type
+ OS.EmitIntValue(0, 4); // CatchObjOffset
+ OS.EmitValue(createImageRel32(HT.Handler), 4); // Handler
+ OS.EmitIntValue(0, 4); // ParentFrameOffset
+ }
+ }
+ }
+
+ // IPToStateMapEntry {
+ // void *IP;
+ // int32_t State;
+ // };
+ if (IPToStateXData) {
+ OS.EmitLabel(IPToStateXData);
+ for (auto &IPStatePair : FuncInfo.IPToStateList) {
+ OS.EmitValue(createImageRel32(IPStatePair.first), 4); // IP
+ OS.EmitIntValue(IPStatePair.second, 4); // State
+ }
+ }
+}
diff --git a/llvm/lib/CodeGen/AsmPrinter/Win64Exception.h b/llvm/lib/CodeGen/AsmPrinter/Win64Exception.h
index b2d5d1bce56..eb02ca47b39 100644
--- a/llvm/lib/CodeGen/AsmPrinter/Win64Exception.h
+++ b/llvm/lib/CodeGen/AsmPrinter/Win64Exception.h
@@ -17,7 +17,9 @@
#include "EHStreamer.h"
namespace llvm {
+class GlobalValue;
class MachineFunction;
+class MCExpr;
class Win64Exception : public EHStreamer {
/// Per-function flag to indicate if personality info should be emitted.
@@ -31,7 +33,10 @@ class Win64Exception : public EHStreamer {
void emitCSpecificHandlerTable();
- const MCSymbolRefExpr *createImageRel32(const MCSymbol *Value);
+ void emitCXXFrameHandler3Table(const MachineFunction *MF);
+
+ const MCExpr *createImageRel32(const MCSymbol *Value);
+ const MCExpr *createImageRel32(const GlobalValue *GV);
public:
//===--------------------------------------------------------------------===//
OpenPOWER on IntegriCloud