Index: llvm/trunk/test/tools/llvm-cfi-verify/X86/blacklist-expected-unprotected.s =================================================================== --- llvm/trunk/test/tools/llvm-cfi-verify/X86/blacklist-expected-unprotected.s +++ llvm/trunk/test/tools/llvm-cfi-verify/X86/blacklist-expected-unprotected.s @@ -3,7 +3,7 @@ # RUN: echo "src:*tiny*" > %t.blacklist.txt # RUN: llvm-cfi-verify %t.o %t.blacklist.txt | FileCheck %s -# CHECK-LABEL: U +# CHECK-LABEL: {{^Instruction: .* \(FAIL_BAD_CONDITIONAL_BRANCH\)}} # CHECK-NEXT: tiny.cc:11 # CHECK-NEXT: {{^Blacklist Match:.*blacklist\.txt:1$}} # CHECK-NEXT: ====> Expected Unprotected Index: llvm/trunk/test/tools/llvm-cfi-verify/X86/blacklist-match-fun.s =================================================================== --- llvm/trunk/test/tools/llvm-cfi-verify/X86/blacklist-match-fun.s +++ llvm/trunk/test/tools/llvm-cfi-verify/X86/blacklist-match-fun.s @@ -3,7 +3,7 @@ # RUN: echo "fun:*main*" > %t.blacklist.txt # RUN: llvm-cfi-verify %t.o %t.blacklist.txt | FileCheck %s -# CHECK-LABEL: U +# CHECK-LABEL: {{^Instruction: .* \(FAIL_BAD_CONDITIONAL_BRANCH\)}} # CHECK-NEXT: tiny.cc:11 # CHECK-NEXT: {{^Blacklist Match:.*blacklist\.txt:1$}} # CHECK-NEXT: ====> Expected Unprotected Index: llvm/trunk/test/tools/llvm-cfi-verify/X86/blacklist-unexpected-protected.s =================================================================== --- llvm/trunk/test/tools/llvm-cfi-verify/X86/blacklist-unexpected-protected.s +++ llvm/trunk/test/tools/llvm-cfi-verify/X86/blacklist-unexpected-protected.s @@ -3,7 +3,7 @@ # RUN: echo "src:*tiny*" > %t.blacklist.txt # RUN: llvm-cfi-verify %t.o %t.blacklist.txt | FileCheck %s -# CHECK-LABEL: P +# CHECK-LABEL: {{^Instruction: .* \(PROTECTED\)}} # CHECK-NEXT: tiny.cc:11 # CHECK-NEXT: {{^Blacklist Match:.*blacklist\.txt:1$}} # CHECK-NEXT: ====> Unexpected Protected Index: llvm/trunk/test/tools/llvm-cfi-verify/X86/dot-printing.s =================================================================== --- llvm/trunk/test/tools/llvm-cfi-verify/X86/dot-printing.s +++ llvm/trunk/test/tools/llvm-cfi-verify/X86/dot-printing.s @@ -3,14 +3,15 @@ # RUN: llvm-cfi-verify -print-graphs %t.o | FileCheck %s # The expected output is as follows: -# P 0x7b | callq *%rax +# ----------------- Begin Instruction ----------------- +# PROTECTED 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-LABEL: {{^Instruction: .* \(PROTECTED\):.*callq +\*%rax}} # CHECK-NEXT: digraph # CHECK-NEXT: {{^.*jbe.*->.*callq \*%rax}} # CHECK-NEXT: {{^.*jbe.*->.*ud2}} Index: llvm/trunk/test/tools/llvm-cfi-verify/X86/indirect-cf-elimination.s =================================================================== --- llvm/trunk/test/tools/llvm-cfi-verify/X86/indirect-cf-elimination.s +++ llvm/trunk/test/tools/llvm-cfi-verify/X86/indirect-cf-elimination.s @@ -1,5 +1,5 @@ # RUN: llvm-mc %s -filetype obj -triple x86_64-linux-elf -o %t.o -# RUN: llvm-cfi-verify %t.o 2>&1 | FileCheck %s +# RUN: llvm-cfi-verify %t.o 2>&1 --summarize | FileCheck %s # This is the same file as protected-lineinfo.s, however contains a hand- # assembled function (fake_function) that has no line table information @@ -10,6 +10,8 @@ # reporting of the cfi-verify program. It should only find a single indirect CF # instruction at `tiny.cc:11` (see protected-lineinfo.s for the source). +# CHECK-NOT: Begin Instruction + # CHECK: Expected Protected: 1 (100.00%) # CHECK: Unexpected Protected: 0 (0.00%) # CHECK: Expected Unprotected: 0 (0.00%) Index: llvm/trunk/test/tools/llvm-cfi-verify/X86/protected-lineinfo.s =================================================================== --- llvm/trunk/test/tools/llvm-cfi-verify/X86/protected-lineinfo.s +++ llvm/trunk/test/tools/llvm-cfi-verify/X86/protected-lineinfo.s @@ -2,7 +2,7 @@ # RUN: -triple x86_64-linux-elf -o %t.o # RUN: llvm-cfi-verify %t.o | FileCheck %s -# CHECK-LABEL: P +# CHECK-LABEL: {{^Instruction: .* \(PROTECTED\)}} # CHECK-NEXT: tiny.cc:11 # CHECK: Expected Protected: 1 (100.00%) Index: llvm/trunk/test/tools/llvm-cfi-verify/X86/unprotected-lineinfo.s =================================================================== --- llvm/trunk/test/tools/llvm-cfi-verify/X86/unprotected-lineinfo.s +++ llvm/trunk/test/tools/llvm-cfi-verify/X86/unprotected-lineinfo.s @@ -2,7 +2,7 @@ # RUN: -triple x86_64-linux-elf -o %t.o # RUN: llvm-cfi-verify %t.o | FileCheck %s -# CHECK-LABEL: U +# CHECK-LABEL: {{^Instruction: .* \(FAIL_BAD_CONDITIONAL_BRANCH\)}} # CHECK-NEXT: tiny.cc:11 # CHECK: Expected Protected: 0 (0.00%) Index: llvm/trunk/tools/llvm-cfi-verify/llvm-cfi-verify.cpp =================================================================== --- llvm/trunk/tools/llvm-cfi-verify/llvm-cfi-verify.cpp +++ llvm/trunk/tools/llvm-cfi-verify/llvm-cfi-verify.cpp @@ -41,9 +41,87 @@ "print-graphs", cl::desc("Print graphs around indirect CF instructions in DOT format."), cl::init(false)); +cl::opt PrintBlameContext( + "blame-context", + cl::desc("Print the blame context (if possible) for BAD instructions. This " + "specifies the number of lines of context to include, where zero " + "disables this feature."), + cl::init(0)); +cl::opt PrintBlameContextAll( + "blame-context-all", + cl::desc("Prints the blame context (if possible) for ALL instructions. " + "This specifies the number of lines of context for non-BAD " + "instructions (see --blame-context). If --blame-context is " + "unspecified, it prints this number of contextual lines for BAD " + "instructions as well."), + cl::init(0)); +cl::opt Summarize("summarize", cl::desc("Print the summary only."), + cl::init(false)); ExitOnError ExitOnErr; +void printBlameContext(const DILineInfo &LineInfo, unsigned Context) { + auto FileOrErr = MemoryBuffer::getFile(LineInfo.FileName); + if (!FileOrErr) { + errs() << "Could not open file: " << LineInfo.FileName << "\n"; + return; + } + + std::unique_ptr File = std::move(FileOrErr.get()); + SmallVector Lines; + File->getBuffer().split(Lines, '\n'); + + for (unsigned i = std::max(1l, (long)LineInfo.Line - Context); + i < + std::min(Lines.size() + 1, (unsigned long)LineInfo.Line + Context + 1); + ++i) { + if (i == LineInfo.Line) + outs() << ">"; + else + outs() << " "; + + outs() << i << ": " << Lines[i - 1] << "\n"; + } +} + +void printInstructionInformation(const FileAnalysis &Analysis, + const Instr &InstrMeta, + const GraphResult &Graph, + CFIProtectionStatus ProtectionStatus) { + outs() << "Instruction: " << format_hex(InstrMeta.VMAddress, 2) << " (" + << stringCFIProtectionStatus(ProtectionStatus) << "): "; + Analysis.printInstruction(InstrMeta, outs()); + outs() << " \n"; + + if (PrintGraphs) + Graph.printToDOT(Analysis, outs()); +} + +void printInstructionStatus(unsigned BlameLine, bool CFIProtected, + const DILineInfo &LineInfo) { + if (BlameLine) { + outs() << "Blacklist Match: " << BlacklistFilename << ":" << BlameLine + << "\n"; + if (CFIProtected) + outs() << "====> Unexpected Protected\n"; + else + outs() << "====> Expected Unprotected\n"; + + if (PrintBlameContextAll) + printBlameContext(LineInfo, PrintBlameContextAll); + } else { + if (CFIProtected) { + outs() << "====> Expected Protected\n"; + if (PrintBlameContextAll) + printBlameContext(LineInfo, PrintBlameContextAll); + } else { + outs() << "====> Unexpected Unprotected (BAD)\n"; + if (PrintBlameContext) + printBlameContext(LineInfo, PrintBlameContext); + } + } +} + void printIndirectCFInstructions(FileAnalysis &Analysis, const SpecialCaseList *SpecialCaseList) { uint64_t ExpectedProtected = 0; @@ -61,17 +139,10 @@ Analysis.validateCFIProtection(Graph); bool CFIProtected = (ProtectionStatus == CFIProtectionStatus::PROTECTED); - if (CFIProtected) - outs() << "P "; - else - outs() << "U "; - - outs() << format_hex(Address, 2) << " | "; - Analysis.printInstruction(InstrMeta, outs()); - outs() << " \n"; - - if (PrintGraphs) - Graph.printToDOT(Analysis, outs()); + if (!Summarize) { + outs() << "-----------------------------------------------------\n"; + printInstructionInformation(Analysis, InstrMeta, Graph, ProtectionStatus); + } if (IgnoreDWARFFlag) { if (CFIProtected) @@ -88,22 +159,28 @@ exit(EXIT_FAILURE); } - const auto &LineInfo = - InliningInfo->getFrame(InliningInfo->getNumberOfFrames() - 1); + const auto &LineInfo = InliningInfo->getFrame(0); // 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 (!Summarize) { + 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) + if (CFIProtected) { + if (PrintBlameContextAll && !Summarize) + printBlameContext(LineInfo, PrintBlameContextAll); ExpectedProtected++; - else + } else { + if (PrintBlameContext && !Summarize) + printBlameContext(LineInfo, PrintBlameContext); UnexpectedUnprotected++; + } continue; } @@ -118,25 +195,20 @@ } if (BlameLine) { - outs() << "Blacklist Match: " << BlacklistFilename << ":" << BlameLine - << "\n"; BlameCounter[BlameLine]++; - if (CFIProtected) { + if (CFIProtected) UnexpectedProtected++; - outs() << "====> Unexpected Protected\n"; - } else { + else ExpectedUnprotected++; - outs() << "====> Expected Unprotected\n"; - } } else { - if (CFIProtected) { + if (CFIProtected) ExpectedProtected++; - outs() << "====> Expected Protected\n"; - } else { + else UnexpectedUnprotected++; - outs() << "====> Unexpected Unprotected\n"; - } } + + if (!Summarize) + printInstructionStatus(BlameLine, CFIProtected, LineInfo); } uint64_t IndirectCFInstructions = ExpectedProtected + UnexpectedProtected + @@ -147,11 +219,12 @@ return; } - 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, + outs() << formatv("\nTotal Indirect CF Instructions: {0}\n" + "Expected Protected: {1} ({2:P})\n" + "Unexpected Protected: {3} ({4:P})\n" + "Expected Unprotected: {5} ({6:P})\n" + "Unexpected Unprotected (BAD): {7} ({8:P})\n", + IndirectCFInstructions, ExpectedProtected, ((double)ExpectedProtected) / IndirectCFInstructions, UnexpectedProtected, ((double)UnexpectedProtected) / IndirectCFInstructions, @@ -163,7 +236,7 @@ if (!SpecialCaseList) return; - outs() << "Blacklist Results:\n"; + outs() << "\nBlacklist Results:\n"; for (const auto &KV : BlameCounter) { outs() << " " << BlacklistFilename << ":" << KV.first << " affects " << KV.second << " indirect CF instructions.\n"; @@ -183,6 +256,9 @@ InitializeAllAsmParsers(); InitializeAllDisassemblers(); + if (PrintBlameContextAll && !PrintBlameContext) + PrintBlameContext.setValue(PrintBlameContextAll); + std::unique_ptr SpecialCaseList; if (BlacklistFilename != "-") { std::string Error;