Index: tools/llvm-cfi-verify/lib/FileAnalysis.h =================================================================== --- tools/llvm-cfi-verify/lib/FileAnalysis.h +++ tools/llvm-cfi-verify/lib/FileAnalysis.h @@ -140,6 +140,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 Index: tools/llvm-cfi-verify/lib/FileAnalysis.cpp =================================================================== --- tools/llvm-cfi-verify/lib/FileAnalysis.cpp +++ tools/llvm-cfi-verify/lib/FileAnalysis.cpp @@ -273,6 +273,12 @@ return 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 = ""; Index: tools/llvm-cfi-verify/lib/GraphBuilder.h =================================================================== --- tools/llvm-cfi-verify/lib/GraphBuilder.h +++ 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 flattenAddress(uint64_t Address) const; + + // Print the DOT representation of this result. + void printToDOT(const FileAnalysis &Analysis, raw_ostream &OS) const; }; class GraphBuilder { Index: tools/llvm-cfi-verify/lib/GraphBuilder.cpp =================================================================== --- tools/llvm-cfi-verify/lib/GraphBuilder.cpp +++ tools/llvm-cfi-verify/lib/GraphBuilder.cpp @@ -71,6 +71,29 @@ 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 { + + OS << "digraph graph_" << format_hex(BaseAddress, 2) << " {\n"; + for (const auto &KV : IntermediateNodes) + 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; Index: tools/llvm-cfi-verify/llvm-cfi-verify.cpp =================================================================== --- tools/llvm-cfi-verify/llvm-cfi-verify.cpp +++ tools/llvm-cfi-verify/llvm-cfi-verify.cpp @@ -37,6 +37,10 @@ cl::opt BlacklistFilename(cl::Positional, cl::desc("[blacklist file]"), cl::init("-")); +cl::opt 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)