[cfi-verify] Add DOT graph printing for GraphResult objects.
Allows users to view GraphResult objects in a DOT directed-graph format. This feature can be turned on through the --print-graphs flag.
Also enabled pretty-printing of instructions in output. Together these features make analysis of unprotected CF instructions much easier by providing a visual control flow graph.
Reviewers: pcc
Subscribers: llvm-commits, kcc, vlad.tsyrklevich
Differential Revision: https://reviews.llvm.org/D39819
llvm-svn: 318211
diff --git a/llvm/tools/llvm-cfi-verify/lib/FileAnalysis.cpp b/llvm/tools/llvm-cfi-verify/lib/FileAnalysis.cpp
index 42de8cb..8f3a683 100644
--- a/llvm/tools/llvm-cfi-verify/lib/FileAnalysis.cpp
+++ b/llvm/tools/llvm-cfi-verify/lib/FileAnalysis.cpp
@@ -273,6 +273,11 @@
   return CFIProtectionStatus::PROTECTED;
 }
 
+void FileAnalysis::printInstruction(const Instr &InstrMeta,
+                                    raw_ostream &OS) const {
+  Printer->printInst(&InstrMeta.Instruction, OS, "", *SubtargetInfo.get());
+}
+
 Error FileAnalysis::initialiseDisassemblyMembers() {
   std::string TripleName = ObjectTriple.getTriple();
   ArchName = "";
diff --git a/llvm/tools/llvm-cfi-verify/lib/FileAnalysis.h b/llvm/tools/llvm-cfi-verify/lib/FileAnalysis.h
index dfeff13..820c368 100644
--- a/llvm/tools/llvm-cfi-verify/lib/FileAnalysis.h
+++ b/llvm/tools/llvm-cfi-verify/lib/FileAnalysis.h
@@ -145,6 +145,10 @@
   // flow instruction in this file.
   CFIProtectionStatus validateCFIProtection(const GraphResult &Graph) const;
 
+  // Prints an instruction to the provided stream using this object's pretty-
+  // printers.
+  void printInstruction(const Instr &InstrMeta, raw_ostream &OS) const;
+
 protected:
   // Construct a blank object with the provided triple and features. Used in
   // testing, where a sub class will dependency inject protected methods to
diff --git a/llvm/tools/llvm-cfi-verify/lib/GraphBuilder.cpp b/llvm/tools/llvm-cfi-verify/lib/GraphBuilder.cpp
index 7366ff0..ff92171 100644
--- a/llvm/tools/llvm-cfi-verify/lib/GraphBuilder.cpp
+++ b/llvm/tools/llvm-cfi-verify/lib/GraphBuilder.cpp
@@ -71,6 +71,30 @@
   return Addresses;
 }
 
+void printPairToDOT(const FileAnalysis &Analysis, raw_ostream &OS,
+                          uint64_t From, uint64_t To) {
+  OS << "  \"" << format_hex(From, 2) << ": ";
+  Analysis.printInstruction(Analysis.getInstructionOrDie(From), OS);
+  OS << "\" -> \"" << format_hex(To, 2) << ": ";
+  Analysis.printInstruction(Analysis.getInstructionOrDie(To), OS);
+  OS << "\"\n";
+}
+
+void GraphResult::printToDOT(const FileAnalysis &Analysis,
+                             raw_ostream &OS) const {
+  std::map<uint64_t, uint64_t> SortedIntermediateNodes(
+      IntermediateNodes.begin(), IntermediateNodes.end());
+  OS << "digraph graph_" << format_hex(BaseAddress, 2) << " {\n";
+  for (const auto &KV : SortedIntermediateNodes)
+    printPairToDOT(Analysis, OS, KV.first, KV.second);
+
+  for (auto &BranchNode : ConditionalBranchNodes) {
+    for (auto &V : {BranchNode.Target, BranchNode.Fallthrough})
+      printPairToDOT(Analysis, OS, BranchNode.Address, V);
+  }
+  OS << "}\n";
+}
+
 GraphResult GraphBuilder::buildFlowGraph(const FileAnalysis &Analysis,
                                          uint64_t Address) {
   GraphResult Result;
diff --git a/llvm/tools/llvm-cfi-verify/lib/GraphBuilder.h b/llvm/tools/llvm-cfi-verify/lib/GraphBuilder.h
index 12d9c95..d1ce509 100644
--- a/llvm/tools/llvm-cfi-verify/lib/GraphBuilder.h
+++ b/llvm/tools/llvm-cfi-verify/lib/GraphBuilder.h
@@ -89,6 +89,9 @@
   // base. The provided address must be part of this graph, and must not be a
   // conditional branch.
   std::vector<uint64_t> flattenAddress(uint64_t Address) const;
+
+  // Print the DOT representation of this result.
+  void printToDOT(const FileAnalysis &Analysis, raw_ostream &OS) const;
 };
 
 class GraphBuilder {
diff --git a/llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp b/llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp
index 8ae905e..245ce05 100644
--- a/llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp
+++ b/llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp
@@ -37,6 +37,10 @@
 cl::opt<std::string> BlacklistFilename(cl::Positional,
                                        cl::desc("[blacklist file]"),
                                        cl::init("-"));
+cl::opt<bool> PrintGraphs(
+    "print-graphs",
+    cl::desc("Print graphs around indirect CF instructions in DOT format."),
+    cl::init(false));
 
 ExitOnError ExitOnErr;
 
@@ -62,10 +66,12 @@
     else
       outs() << "U ";
 
-    outs() << format_hex(Address, 2) << " | "
-           << Analysis.getMCInstrInfo()->getName(
-                  InstrMeta.Instruction.getOpcode())
-           << " \n";
+    outs() << format_hex(Address, 2) << " | ";
+    Analysis.printInstruction(InstrMeta, outs());
+    outs() << " \n";
+
+    if (PrintGraphs)
+      Graph.printToDOT(Analysis, outs());
 
     if (IgnoreDWARFFlag) {
       if (CFIProtected)