| //===----------- CFIInfoVerifier.cpp - CFI Information Verifier -----------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This pass verifies incoming and outgoing CFI information of basic blocks. CFI |
| // information is information about offset and register set by CFI directives, |
| // valid at the start and end of a basic block. This pass checks that outgoing |
| // information of predecessors matches incoming information of their successors. |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/CodeGen/MachineFunctionPass.h" |
| #include "llvm/CodeGen/MachineModuleInfo.h" |
| #include "llvm/CodeGen/Passes.h" |
| #include "llvm/Target/TargetMachine.h" |
| using namespace llvm; |
| |
| namespace { |
| class CFIInfoVerifier : public MachineFunctionPass { |
| public: |
| static char ID; |
| |
| CFIInfoVerifier() : MachineFunctionPass(ID) { |
| initializeCFIInfoVerifierPass(*PassRegistry::getPassRegistry()); |
| } |
| |
| void getAnalysisUsage(AnalysisUsage &AU) const override { |
| AU.setPreservesAll(); |
| MachineFunctionPass::getAnalysisUsage(AU); |
| } |
| |
| bool runOnMachineFunction(MachineFunction &MF) override { |
| bool NeedsDwarfCFI = (MF.getMMI().hasDebugInfo() || |
| MF.getFunction()->needsUnwindTableEntry()) && |
| (!MF.getTarget().getTargetTriple().isOSDarwin() && |
| !MF.getTarget().getTargetTriple().isOSWindows()); |
| if (!NeedsDwarfCFI) return false; |
| verify(MF); |
| return false; |
| } |
| |
| private: |
| // Go through each MBB in a function and check that outgoing offset and |
| // register of its predecessors match incoming offset and register of that |
| // MBB, as well as that incoming offset and register of its successors match |
| // outgoing offset and register of the MBB. |
| void verify(MachineFunction &MF); |
| void report(const char *msg, MachineBasicBlock &MBB); |
| }; |
| } |
| |
| char CFIInfoVerifier::ID = 0; |
| INITIALIZE_PASS(CFIInfoVerifier, "cfiinfoverifier", |
| "Verify that corresponding in/out CFI info matches", false, |
| false) |
| FunctionPass *llvm::createCFIInfoVerifier() { return new CFIInfoVerifier(); } |
| |
| void CFIInfoVerifier::verify(MachineFunction &MF) { |
| for (auto &CurrMBB : MF) { |
| for (auto Pred : CurrMBB.predecessors()) { |
| // Check that outgoing offset values of predecessors match the incoming |
| // offset value of CurrMBB |
| if (Pred->getOutgoingCFAOffset() != CurrMBB.getIncomingCFAOffset()) { |
| report("The outgoing offset of a predecessor is inconsistent.", |
| CurrMBB); |
| errs() << "Predecessor BB#" << Pred->getNumber() |
| << " has outgoing offset (" << Pred->getOutgoingCFAOffset() |
| << "), while BB#" << CurrMBB.getNumber() |
| << " has incoming offset (" << CurrMBB.getIncomingCFAOffset() |
| << ").\n"; |
| } |
| // Check that outgoing register values of predecessors match the incoming |
| // register value of CurrMBB |
| if (Pred->getOutgoingCFARegister() != CurrMBB.getIncomingCFARegister()) { |
| report("The outgoing register of a predecessor is inconsistent.", |
| CurrMBB); |
| errs() << "Predecessor BB#" << Pred->getNumber() |
| << " has outgoing register (" << Pred->getOutgoingCFARegister() |
| << "), while BB#" << CurrMBB.getNumber() |
| << " has incoming register (" << CurrMBB.getIncomingCFARegister() |
| << ").\n"; |
| } |
| } |
| |
| for (auto Succ : CurrMBB.successors()) { |
| // Check that incoming offset values of successors match the outgoing |
| // offset value of CurrMBB |
| if (Succ->getIncomingCFAOffset() != CurrMBB.getOutgoingCFAOffset()) { |
| report("The incoming offset of a successor is inconsistent.", CurrMBB); |
| errs() << "Successor BB#" << Succ->getNumber() |
| << " has incoming offset (" << Succ->getIncomingCFAOffset() |
| << "), while BB#" << CurrMBB.getNumber() |
| << " has outgoing offset (" << CurrMBB.getOutgoingCFAOffset() |
| << ").\n"; |
| } |
| // Check that incoming register values of successors match the outgoing |
| // register value of CurrMBB |
| if (Succ->getIncomingCFARegister() != CurrMBB.getOutgoingCFARegister()) { |
| report("The incoming register of a successor is inconsistent.", |
| CurrMBB); |
| errs() << "Successor BB#" << Succ->getNumber() |
| << " has incoming register (" << Succ->getIncomingCFARegister() |
| << "), while BB#" << CurrMBB.getNumber() |
| << " has outgoing register (" << CurrMBB.getOutgoingCFARegister() |
| << ").\n"; |
| } |
| } |
| } |
| } |
| |
| void CFIInfoVerifier::report(const char *msg, MachineBasicBlock &MBB) { |
| assert(&MBB); |
| errs() << '\n'; |
| errs() << "*** " << msg << " ***\n" |
| << "- function: " << MBB.getParent()->getName() << "\n"; |
| errs() << "- basic block: BB#" << MBB.getNumber() << ' ' << MBB.getName() |
| << " (" << (const void *)&MBB << ')'; |
| errs() << '\n'; |
| } |