aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/MC/MCWin64EH.cpp
diff options
context:
space:
mode:
authorMartin Storsjö <martin@martin.st>2021-11-26 00:34:47 +0200
committerMartin Storsjö <martin@martin.st>2022-06-01 11:25:49 +0300
commit298e9cac9204b788dd6a18dba669b40acf2aaa3c (patch)
treecdb581b2fbb7538e5ce22593fcb6e027dc083b55 /llvm/lib/MC/MCWin64EH.cpp
parentd4022ff3310635f682e9937c8ffa4aeb0d2e2854 (diff)
downloadllvm-298e9cac9204b788dd6a18dba669b40acf2aaa3c.zip
llvm-298e9cac9204b788dd6a18dba669b40acf2aaa3c.tar.gz
llvm-298e9cac9204b788dd6a18dba669b40acf2aaa3c.tar.bz2
[MC] [Win64EH] Check that the SEH unwind opcodes match the actual instructions
It's a fairly common issue that the generating code incorrectly marks instructions as narrow or wide; check that the instruction lengths add up to the expected value, and error out if it doesn't. This allows catching code generation bugs. Also check that prologs and epilogs are properly terminated, to catch other code generation issues. Differential Revision: https://reviews.llvm.org/D125647
Diffstat (limited to 'llvm/lib/MC/MCWin64EH.cpp')
-rw-r--r--llvm/lib/MC/MCWin64EH.cpp62
1 files changed, 61 insertions, 1 deletions
diff --git a/llvm/lib/MC/MCWin64EH.cpp b/llvm/lib/MC/MCWin64EH.cpp
index 67b3d12..7ce5d8c 100644
--- a/llvm/lib/MC/MCWin64EH.cpp
+++ b/llvm/lib/MC/MCWin64EH.cpp
@@ -1197,7 +1197,8 @@ static uint32_t ARMCountOfUnwindCodes(ArrayRef<WinEH::Instruction> Insns) {
return Count;
}
-static uint32_t ARMCountOfInstructionBytes(ArrayRef<WinEH::Instruction> Insns) {
+static uint32_t ARMCountOfInstructionBytes(ArrayRef<WinEH::Instruction> Insns,
+ bool *HasCustom = nullptr) {
uint32_t Count = 0;
for (const auto &I : Insns) {
switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
@@ -1247,12 +1248,50 @@ static uint32_t ARMCountOfInstructionBytes(ArrayRef<WinEH::Instruction> Insns) {
// We can't reason about what instructions this maps to; return a
// phony number to make sure we don't accidentally do epilog packing.
Count += 1000;
+ if (HasCustom)
+ *HasCustom = true;
break;
}
}
return Count;
}
+static void checkARMInstructions(MCStreamer &Streamer,
+ ArrayRef<WinEH::Instruction> Insns,
+ const MCSymbol *Begin, const MCSymbol *End,
+ StringRef Name, StringRef Type) {
+ if (!End)
+ return;
+ Optional<int64_t> MaybeDistance =
+ GetOptionalAbsDifference(Streamer, End, Begin);
+ if (!MaybeDistance)
+ return;
+ uint32_t Distance = (uint32_t)*MaybeDistance;
+ bool HasCustom = false;
+ uint32_t InstructionBytes = ARMCountOfInstructionBytes(Insns, &HasCustom);
+ if (HasCustom)
+ return;
+ if (Distance != InstructionBytes) {
+ Streamer.getContext().reportError(
+ SMLoc(), "Incorrect size for " + Name + " " + Type + ": " +
+ Twine(Distance) +
+ " bytes of instructions in range, but .seh directives "
+ "corresponding to " +
+ Twine(InstructionBytes) + " bytes\n");
+ }
+}
+
+static bool isARMTerminator(const WinEH::Instruction &inst) {
+ switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
+ case Win64EH::UOP_End:
+ case Win64EH::UOP_EndNop:
+ case Win64EH::UOP_WideEndNop:
+ return true;
+ default:
+ return false;
+ }
+}
+
// Unwind opcode encodings and restrictions are documented at
// https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling
static void ARMEmitUnwindCode(MCStreamer &streamer,
@@ -1960,6 +1999,27 @@ static void ARMEmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info,
streamer.emitLabel(Label);
info->Symbol = Label;
+ if (!info->PrologEnd)
+ streamer.getContext().reportError(SMLoc(), "Prologue in " +
+ info->Function->getName() +
+ " not correctly terminated");
+
+ if (info->PrologEnd && !info->Fragment)
+ checkARMInstructions(streamer, info->Instructions, info->Begin,
+ info->PrologEnd, info->Function->getName(),
+ "prologue");
+ for (auto &I : info->EpilogMap) {
+ MCSymbol *EpilogStart = I.first;
+ auto &Epilog = I.second;
+ checkARMInstructions(streamer, Epilog.Instructions, EpilogStart, Epilog.End,
+ info->Function->getName(), "epilogue");
+ if (Epilog.Instructions.empty() ||
+ !isARMTerminator(Epilog.Instructions.back()))
+ streamer.getContext().reportError(
+ SMLoc(), "Epilogue in " + info->Function->getName() +
+ " not correctly terminated");
+ }
+
Optional<int64_t> RawFuncLength;
const MCExpr *FuncLengthExpr = nullptr;
if (!info->FuncletOrFuncEnd) {