Skip to content

Commit

Permalink
[cfi-verify] Add blame context printing, and improved print format.
Browse files Browse the repository at this point in the history
Summary:
This update now allows users to specify `--blame-context` and `--blame-context-all` to print source file blame information for the source of the blame.

Also updates the inline printing to correctly identify the top of the inlining stack for blame information.

Patch by Mitch Phillips!

Reviewers: vlad.tsyrklevich

Subscribers: llvm-commits, kcc, pcc

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

llvm-svn: 324035
  • Loading branch information
vlad902 committed Feb 1, 2018
1 parent e2f8718 commit b2c3ea7
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/tools/llvm-cfi-verify/X86/blacklist-match-fun.s
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions llvm/test/tools/llvm-cfi-verify/X86/dot-printing.s
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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%)
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/tools/llvm-cfi-verify/X86/protected-lineinfo.s
Original file line number Diff line number Diff line change
Expand Up @@ -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%)
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/tools/llvm-cfi-verify/X86/unprotected-lineinfo.s
Original file line number Diff line number Diff line change
Expand Up @@ -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%)
Expand Down
152 changes: 114 additions & 38 deletions llvm/tools/llvm-cfi-verify/llvm-cfi-verify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,87 @@ cl::opt<bool> PrintGraphs(
"print-graphs",
cl::desc("Print graphs around indirect CF instructions in DOT format."),
cl::init(false));
cl::opt<unsigned> 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<unsigned> 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<bool> 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<MemoryBuffer> File = std::move(FileOrErr.get());
SmallVector<StringRef, 100> 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;
Expand All @@ -61,17 +139,10 @@ void printIndirectCFInstructions(FileAnalysis &Analysis,
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)
Expand All @@ -88,22 +159,28 @@ void printIndirectCFInstructions(FileAnalysis &Analysis,
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;
}

Expand All @@ -118,25 +195,20 @@ void printIndirectCFInstructions(FileAnalysis &Analysis,
}

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 +
Expand All @@ -147,11 +219,12 @@ void printIndirectCFInstructions(FileAnalysis &Analysis,
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,
Expand All @@ -163,7 +236,7 @@ void printIndirectCFInstructions(FileAnalysis &Analysis,
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";
Expand All @@ -183,6 +256,9 @@ int main(int argc, char **argv) {
InitializeAllAsmParsers();
InitializeAllDisassemblers();

if (PrintBlameContextAll && !PrintBlameContext)
PrintBlameContext.setValue(PrintBlameContextAll);

std::unique_ptr<SpecialCaseList> SpecialCaseList;
if (BlacklistFilename != "-") {
std::string Error;
Expand Down

0 comments on commit b2c3ea7

Please sign in to comment.