summaryrefslogtreecommitdiffstats
path: root/llvm/lib/CodeGen/CFIInfoVerifier.cpp
blob: ff5a953c2427f38c325ef92e5b311e44e2c6b83f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//===----------- 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';
}
OpenPOWER on IntegriCloud