From a0cefd153d712feea7eed7585331511cc0948c7e Mon Sep 17 00:00:00 2001 From: Mitch Phillips Date: Tue, 14 Nov 2017 22:43:13 +0000 Subject: [PATCH] [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 --- test/tools/llvm-cfi-verify/X86/dot-printing.s | 18 ++++++++++++++ tools/llvm-cfi-verify/lib/FileAnalysis.cpp | 5 ++++ tools/llvm-cfi-verify/lib/FileAnalysis.h | 4 ++++ tools/llvm-cfi-verify/lib/GraphBuilder.cpp | 24 +++++++++++++++++++ tools/llvm-cfi-verify/lib/GraphBuilder.h | 3 +++ tools/llvm-cfi-verify/llvm-cfi-verify.cpp | 14 +++++++---- 6 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 test/tools/llvm-cfi-verify/X86/dot-printing.s diff --git a/test/tools/llvm-cfi-verify/X86/dot-printing.s b/test/tools/llvm-cfi-verify/X86/dot-printing.s new file mode 100644 index 00000000000..5e0a2090d82 --- /dev/null +++ b/test/tools/llvm-cfi-verify/X86/dot-printing.s @@ -0,0 +1,18 @@ +# RUN: llvm-mc %S/Inputs/protected-lineinfo.s -filetype obj \ +# RUN: -triple x86_64-linux-elf -o %t.o +# RUN: llvm-cfi-verify -print-graphs %t.o | FileCheck %s + +# The expected output is as follows: +# P 0x7b | callq *%rax +# digraph graph_0x7b { +# "0x77: jbe 2" -> "0x7b: callq *%rax" +# "0x77: jbe 2" -> "0x79: ud2" +# } +# 0x7b = tiny.cc:11:3 (main) + +# CHECK: {{^P.*callq +\*%rax.*$}} +# CHECK-NEXT: digraph +# CHECK-NEXT: {{^.*jbe.*->.*callq \*%rax}} +# CHECK-NEXT: {{^.*jbe.*->.*ud2}} +# CHECK-NEXT: } +# CHECK-NEXT: tiny.cc:11 diff --git a/tools/llvm-cfi-verify/lib/FileAnalysis.cpp b/tools/llvm-cfi-verify/lib/FileAnalysis.cpp index 42de8cb4f7d..8f3a6837cfa 100644 --- a/tools/llvm-cfi-verify/lib/FileAnalysis.cpp +++ b/tools/llvm-cfi-verify/lib/FileAnalysis.cpp @@ -273,6 +273,11 @@ FileAnalysis::validateCFIProtection(const GraphResult &Graph) const { 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/tools/llvm-cfi-verify/lib/FileAnalysis.h b/tools/llvm-cfi-verify/lib/FileAnalysis.h index dfeff13863b..820c3683540 100644 --- a/tools/llvm-cfi-verify/lib/FileAnalysis.h +++ b/tools/llvm-cfi-verify/lib/FileAnalysis.h @@ -145,6 +145,10 @@ public: // 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/tools/llvm-cfi-verify/lib/GraphBuilder.cpp b/tools/llvm-cfi-verify/lib/GraphBuilder.cpp index 7366ff0cf30..ff921713302 100644 --- a/tools/llvm-cfi-verify/lib/GraphBuilder.cpp +++ b/tools/llvm-cfi-verify/lib/GraphBuilder.cpp @@ -71,6 +71,30 @@ std::vector GraphResult::flattenAddress(uint64_t Address) const { 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 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/tools/llvm-cfi-verify/lib/GraphBuilder.h b/tools/llvm-cfi-verify/lib/GraphBuilder.h index 12d9c95e3cf..d1ce5096ed9 100644 --- a/tools/llvm-cfi-verify/lib/GraphBuilder.h +++ b/tools/llvm-cfi-verify/lib/GraphBuilder.h @@ -89,6 +89,9 @@ struct GraphResult { // 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 { diff --git a/tools/llvm-cfi-verify/llvm-cfi-verify.cpp b/tools/llvm-cfi-verify/llvm-cfi-verify.cpp index 8ae905e2636..245ce05a254 100644 --- a/tools/llvm-cfi-verify/llvm-cfi-verify.cpp +++ b/tools/llvm-cfi-verify/llvm-cfi-verify.cpp @@ -37,6 +37,10 @@ cl::opt InputFilename(cl::Positional, cl::desc(""), 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 @@ void printIndirectCFInstructions(FileAnalysis &Analysis, 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)