[cfi-verify] Add blacklist parsing for result filtering.

Adds blacklist parsing behaviour for filtering results into four categories:

 - Expected Protected: Things that are not in the blacklist and are protected.
 - Unexpected Protected: Things that are in the blacklist and are protected.
 - Expected Unprotected: Things that are in the blacklist and are unprotected.
 - Unexpected Unprotected: Things that are not in the blacklist and are unprotected.

 now can optionally be invoked with a second command line argument, which specifies the blacklist file that the binary was built with.

Current  statistics for chromium:

Reviewers: vlad.tsyrklevich

Subscribers: mgorny, llvm-commits, pcc, kcc

Differential Revision: https://reviews.llvm.org/D39525

llvm-svn: 317364
diff --git a/llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp b/llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp
index d4a46fc..a3c202f 100644
--- a/llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp
+++ b/llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp
@@ -23,6 +23,7 @@
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/SpecialCaseList.h"
 
 #include <cstdlib>
 
@@ -32,48 +33,120 @@
 
 cl::opt<std::string> InputFilename(cl::Positional, cl::desc("<input file>"),
                                    cl::Required);
+cl::opt<std::string> BlacklistFilename(cl::Positional,
+                                       cl::desc("[blacklist file]"),
+                                       cl::init("-"));
 
 ExitOnError ExitOnErr;
 
-void printIndirectCFInstructions(FileAnalysis &Analysis) {
-  uint64_t ProtectedCount = 0;
-  uint64_t UnprotectedCount = 0;
+void printIndirectCFInstructions(FileAnalysis &Analysis,
+                                 const SpecialCaseList *SpecialCaseList) {
+  uint64_t ExpectedProtected = 0;
+  uint64_t UnexpectedProtected = 0;
+  uint64_t ExpectedUnprotected = 0;
+  uint64_t UnexpectedUnprotected = 0;
+
+  symbolize::LLVMSymbolizer &Symbolizer = Analysis.getSymbolizer();
 
   for (uint64_t Address : Analysis.getIndirectInstructions()) {
     const auto &InstrMeta = Analysis.getInstructionOrDie(Address);
 
-    if (Analysis.isIndirectInstructionCFIProtected(Address)) {
+    bool CFIProtected = Analysis.isIndirectInstructionCFIProtected(Address);
+
+    if (CFIProtected)
       outs() << "P ";
-      ProtectedCount++;
-    } else {
+    else
       outs() << "U ";
-      UnprotectedCount++;
-    }
 
     outs() << format_hex(Address, 2) << " | "
            << Analysis.getMCInstrInfo()->getName(
                   InstrMeta.Instruction.getOpcode())
-           << " ";
-    outs() << "\n";
+           << " \n";
 
-    if (Analysis.hasLineTableInfo()) {
-      for (const auto &LineKV : Analysis.getLineInfoForAddressRange(Address)) {
-        outs() << "  " << format_hex(LineKV.first, 2) << " = "
-               << LineKV.second.FileName << ":" << LineKV.second.Line << ":"
-               << LineKV.second.Column << " (" << LineKV.second.FunctionName
-               << ")\n";
+    if (IgnoreDWARFFlag) {
+      if (CFIProtected)
+        ExpectedProtected++;
+      else
+        UnexpectedUnprotected++;
+      continue;
+    }
+
+    auto InliningInfo = Symbolizer.symbolizeInlinedCode(InputFilename, Address);
+    if (!InliningInfo || InliningInfo->getNumberOfFrames() == 0) {
+      errs() << "Failed to symbolise " << format_hex(Address, 2)
+             << " with line tables from " << InputFilename << "\n";
+      exit(EXIT_FAILURE);
+    }
+
+    const auto &LineInfo =
+        InliningInfo->getFrame(InliningInfo->getNumberOfFrames() - 1);
+
+    // Print the inlining symbolisation of this instruction.
+    for (uint32_t i = 0; i < InliningInfo->getNumberOfFrames(); ++i) {
+      const auto &Line = InliningInfo->getFrame(i);
+      outs() << "  " << format_hex(Address, 2) << " = " << Line.FileName << ":"
+             << Line.Line << ":" << Line.Column << " (" << Line.FunctionName
+             << ")\n";
+    }
+
+    if (!SpecialCaseList) {
+      if (CFIProtected)
+        ExpectedProtected++;
+      else
+        UnexpectedUnprotected++;
+      continue;
+    }
+
+    bool MatchesBlacklistRule = false;
+    if (SpecialCaseList->inSection("cfi-icall", "src", LineInfo.FileName) ||
+        SpecialCaseList->inSection("cfi-vcall", "src", LineInfo.FileName)) {
+      outs() << "BLACKLIST MATCH, 'src'\n";
+      MatchesBlacklistRule = true;
+    }
+
+    if (SpecialCaseList->inSection("cfi-icall", "fun", LineInfo.FunctionName) ||
+        SpecialCaseList->inSection("cfi-vcall", "fun", LineInfo.FunctionName)) {
+      outs() << "BLACKLIST MATCH, 'fun'\n";
+      MatchesBlacklistRule = true;
+    }
+
+    if (MatchesBlacklistRule) {
+      if (CFIProtected) {
+        UnexpectedProtected++;
+        outs() << "====> Unexpected Protected\n";
+      } else {
+        ExpectedUnprotected++;
+        outs() << "====> Expected Unprotected\n";
+      }
+    } else {
+      if (CFIProtected) {
+        ExpectedProtected++;
+        outs() << "====> Expected Protected\n";
+      } else {
+        UnexpectedUnprotected++;
+        outs() << "====> Unexpected Unprotected\n";
       }
     }
   }
 
-  if (ProtectedCount || UnprotectedCount)
-    outs() << formatv(
-        "Unprotected: {0} ({1:P}), Protected: {2} ({3:P})\n", UnprotectedCount,
-        (((double)UnprotectedCount) / (UnprotectedCount + ProtectedCount)),
-        ProtectedCount,
-        (((double)ProtectedCount) / (UnprotectedCount + ProtectedCount)));
-  else
+  uint64_t IndirectCFInstructions = ExpectedProtected + UnexpectedProtected +
+                                    ExpectedUnprotected + UnexpectedUnprotected;
+
+  if (IndirectCFInstructions == 0)
     outs() << "No indirect CF instructions found.\n";
+
+  outs() << formatv("Expected Protected: {0} ({1:P})\n"
+                    "Unexpected Protected: {2} ({3:P})\n"
+                    "Expected Unprotected: {4} ({5:P})\n"
+                    "Unexpected Unprotected (BAD): {6} ({7:P})\n",
+                    ExpectedProtected,
+                    ((double)ExpectedProtected) / IndirectCFInstructions,
+                    UnexpectedProtected,
+                    ((double)UnexpectedProtected) / IndirectCFInstructions,
+                    ExpectedUnprotected,
+                    ((double)ExpectedUnprotected) / IndirectCFInstructions,
+                    UnexpectedUnprotected,
+                    ((double)UnexpectedUnprotected) / IndirectCFInstructions);
 }
 
 int main(int argc, char **argv) {
@@ -89,8 +162,18 @@
   InitializeAllAsmParsers();
   InitializeAllDisassemblers();
 
+  std::unique_ptr<SpecialCaseList> SpecialCaseList;
+  if (BlacklistFilename != "-") {
+    std::string Error;
+    SpecialCaseList = SpecialCaseList::create({BlacklistFilename}, Error);
+    if (!SpecialCaseList) {
+      errs() << "Failed to get blacklist: " << Error << "\n";
+      exit(EXIT_FAILURE);
+    }
+  }
+
   FileAnalysis Analysis = ExitOnErr(FileAnalysis::Create(InputFilename));
-  printIndirectCFInstructions(Analysis);
+  printIndirectCFInstructions(Analysis, SpecialCaseList.get());
 
   return EXIT_SUCCESS;
 }