diff options
author | Martin Storsjö <martin@martin.st> | 2021-11-26 00:34:47 +0200 |
---|---|---|
committer | Martin Storsjö <martin@martin.st> | 2022-06-01 11:25:49 +0300 |
commit | 298e9cac9204b788dd6a18dba669b40acf2aaa3c (patch) | |
tree | cdb581b2fbb7538e5ce22593fcb6e027dc083b55 /llvm/lib/MC/MCWin64EH.cpp | |
parent | d4022ff3310635f682e9937c8ffa4aeb0d2e2854 (diff) | |
download | llvm-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.cpp | 62 |
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) { |