summaryrefslogtreecommitdiff
path: root/tools/llvm-cfi-verify
diff options
context:
space:
mode:
Diffstat (limited to 'tools/llvm-cfi-verify')
-rw-r--r--tools/llvm-cfi-verify/CMakeLists.txt2
-rw-r--r--tools/llvm-cfi-verify/LLVMBuild.txt2
-rw-r--r--tools/llvm-cfi-verify/lib/CMakeLists.txt4
-rw-r--r--tools/llvm-cfi-verify/lib/FileAnalysis.cpp49
-rw-r--r--tools/llvm-cfi-verify/lib/FileAnalysis.h9
-rw-r--r--tools/llvm-cfi-verify/lib/LLVMBuild.txt2
-rw-r--r--tools/llvm-cfi-verify/llvm-cfi-verify.cpp135
7 files changed, 147 insertions, 56 deletions
diff --git a/tools/llvm-cfi-verify/CMakeLists.txt b/tools/llvm-cfi-verify/CMakeLists.txt
index 07c6504bf48e..de6a46e78595 100644
--- a/tools/llvm-cfi-verify/CMakeLists.txt
+++ b/tools/llvm-cfi-verify/CMakeLists.txt
@@ -4,11 +4,11 @@ set(LLVM_LINK_COMPONENTS
AllTargetsDescs
AllTargetsDisassemblers
AllTargetsInfos
- DebugInfoDWARF
MC
MCParser
Object
Support
+ Symbolize
)
add_llvm_tool(llvm-cfi-verify
diff --git a/tools/llvm-cfi-verify/LLVMBuild.txt b/tools/llvm-cfi-verify/LLVMBuild.txt
index 5c4ce2630903..d5e932302728 100644
--- a/tools/llvm-cfi-verify/LLVMBuild.txt
+++ b/tools/llvm-cfi-verify/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = llvm-cfi-verify
parent = Tools
-required_libraries = all-targets DebugInfoDWARF MC MCDisassembler MCParser Support
+required_libraries = all-targets MC MCDisassembler MCParser Support Symbolize
diff --git a/tools/llvm-cfi-verify/lib/CMakeLists.txt b/tools/llvm-cfi-verify/lib/CMakeLists.txt
index c90e4ed485ea..cd728e004b26 100644
--- a/tools/llvm-cfi-verify/lib/CMakeLists.txt
+++ b/tools/llvm-cfi-verify/lib/CMakeLists.txt
@@ -11,5 +11,7 @@ llvm_map_components_to_libnames(libs
MC
MCParser
Object
- Support)
+ Support
+ Symbolize)
target_link_libraries(LLVMCFIVerify ${libs})
+set_target_properties(LLVMCFIVerify PROPERTIES FOLDER "Libraries") \ No newline at end of file
diff --git a/tools/llvm-cfi-verify/lib/FileAnalysis.cpp b/tools/llvm-cfi-verify/lib/FileAnalysis.cpp
index 278e861dfd3a..0d4e1f497ff8 100644
--- a/tools/llvm-cfi-verify/lib/FileAnalysis.cpp
+++ b/tools/llvm-cfi-verify/lib/FileAnalysis.cpp
@@ -39,22 +39,20 @@
#include <functional>
using Instr = llvm::cfi_verify::FileAnalysis::Instr;
+using LLVMSymbolizer = llvm::symbolize::LLVMSymbolizer;
namespace llvm {
namespace cfi_verify {
-static cl::opt<bool> IgnoreDWARF(
+bool IgnoreDWARFFlag;
+
+static cl::opt<bool, true> IgnoreDWARFArg(
"ignore-dwarf",
cl::desc(
"Ignore all DWARF data. This relaxes the requirements for all "
"statically linked libraries to have been compiled with '-g', but "
"will result in false positives for 'CFI unprotected' instructions."),
- cl::init(false));
-
-cl::opt<unsigned long long> DWARFSearchRange(
- "dwarf-search-range",
- cl::desc("Address search range used to determine if instruction is valid."),
- cl::init(0x10));
+ cl::location(IgnoreDWARFFlag), cl::init(false));
Expected<FileAnalysis> FileAnalysis::Create(StringRef Filename) {
// Open the filename provided.
@@ -256,12 +254,16 @@ const MCInstrAnalysis *FileAnalysis::getMCInstrAnalysis() const {
return MIA.get();
}
+LLVMSymbolizer &FileAnalysis::getSymbolizer() { return *Symbolizer; }
+
Error FileAnalysis::initialiseDisassemblyMembers() {
std::string TripleName = ObjectTriple.getTriple();
ArchName = "";
MCPU = "";
std::string ErrorString;
+ Symbolizer.reset(new LLVMSymbolizer());
+
ObjectTarget =
TargetRegistry::lookupTarget(ArchName, ObjectTriple, ErrorString);
if (!ObjectTarget)
@@ -308,8 +310,8 @@ Error FileAnalysis::initialiseDisassemblyMembers() {
}
Error FileAnalysis::parseCodeSections() {
- if (!IgnoreDWARF) {
- DWARF.reset(DWARFContext::create(*Object).release());
+ if (!IgnoreDWARFFlag) {
+ std::unique_ptr<DWARFContext> DWARF = DWARFContext::create(*Object);
if (!DWARF)
return make_error<StringError>("Could not create DWARF information.",
inconvertibleErrorCode());
@@ -347,21 +349,9 @@ Error FileAnalysis::parseCodeSections() {
return Error::success();
}
-DILineInfoTable FileAnalysis::getLineInfoForAddressRange(uint64_t Address) {
- if (!hasLineTableInfo())
- return DILineInfoTable();
-
- return DWARF->getLineInfoForAddressRange(Address, DWARFSearchRange);
-}
-
-bool FileAnalysis::hasValidLineInfoForAddressRange(uint64_t Address) {
- return !getLineInfoForAddressRange(Address).empty();
-}
-
-bool FileAnalysis::hasLineTableInfo() const { return DWARF != nullptr; }
-
void FileAnalysis::parseSectionContents(ArrayRef<uint8_t> SectionBytes,
uint64_t SectionAddress) {
+ assert(Symbolizer && "Symbolizer is uninitialised.");
MCInst Instruction;
Instr InstrMeta;
uint64_t InstructionSize;
@@ -381,8 +371,19 @@ void FileAnalysis::parseSectionContents(ArrayRef<uint8_t> SectionBytes,
InstrMeta.Valid = ValidInstruction;
// Check if this instruction exists in the range of the DWARF metadata.
- if (hasLineTableInfo() && !hasValidLineInfoForAddressRange(VMAddress))
- continue;
+ if (!IgnoreDWARFFlag) {
+ auto LineInfo =
+ Symbolizer->symbolizeCode(Object->getFileName(), VMAddress);
+ if (!LineInfo) {
+ handleAllErrors(LineInfo.takeError(), [](const ErrorInfoBase &E) {
+ errs() << "Symbolizer failed to get line: " << E.message() << "\n";
+ });
+ continue;
+ }
+
+ if (LineInfo->FileName == "<invalid>")
+ continue;
+ }
addInstruction(InstrMeta);
diff --git a/tools/llvm-cfi-verify/lib/FileAnalysis.h b/tools/llvm-cfi-verify/lib/FileAnalysis.h
index 9945a2110a28..e0eecb037c37 100644
--- a/tools/llvm-cfi-verify/lib/FileAnalysis.h
+++ b/tools/llvm-cfi-verify/lib/FileAnalysis.h
@@ -12,7 +12,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/BinaryFormat/ELF.h"
-#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/Symbolize/Symbolize.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDisassembler/MCDisassembler.h"
@@ -44,6 +44,8 @@
namespace llvm {
namespace cfi_verify {
+extern bool IgnoreDWARFFlag;
+
// Disassembler and analysis tool for machine code files. Keeps track of non-
// sequential control flows, including indirect control flow instructions.
class FileAnalysis {
@@ -120,6 +122,7 @@ public:
const MCRegisterInfo *getRegisterInfo() const;
const MCInstrInfo *getMCInstrInfo() const;
const MCInstrAnalysis *getMCInstrAnalysis() const;
+ symbolize::LLVMSymbolizer &getSymbolizer();
// Returns true if this class is using DWARF line tables for elimination.
bool hasLineTableInfo() const;
@@ -175,8 +178,8 @@ private:
std::unique_ptr<const MCInstrAnalysis> MIA;
std::unique_ptr<MCInstPrinter> Printer;
- // DWARF debug information.
- std::unique_ptr<DWARFContext> DWARF;
+ // Symbolizer used for debug information parsing.
+ std::unique_ptr<symbolize::LLVMSymbolizer> Symbolizer;
// A mapping between the virtual memory address to the instruction metadata
// struct. TODO(hctim): Reimplement this as a sorted vector to avoid per-
diff --git a/tools/llvm-cfi-verify/lib/LLVMBuild.txt b/tools/llvm-cfi-verify/lib/LLVMBuild.txt
index 99b678fc88a1..c0ae1905521a 100644
--- a/tools/llvm-cfi-verify/lib/LLVMBuild.txt
+++ b/tools/llvm-cfi-verify/lib/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Library
name = CFIVerify
parent = Libraries
-required_libraries = DebugInfoDWARF MC MCDisassembler MCParser Support
+required_libraries = DebugInfoDWARF MC MCDisassembler MCParser Support Symbolize
diff --git a/tools/llvm-cfi-verify/llvm-cfi-verify.cpp b/tools/llvm-cfi-verify/llvm-cfi-verify.cpp
index d4a46fcc226b..3b4a5c155d04 100644
--- a/tools/llvm-cfi-verify/llvm-cfi-verify.cpp
+++ b/tools/llvm-cfi-verify/llvm-cfi-verify.cpp
@@ -23,6 +23,7 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/SpecialCaseList.h"
#include <cstdlib>
@@ -32,48 +33,122 @@ using namespace llvm::cfi_verify;
cl::opt<std::string> InputFilename(cl::Positional, cl::desc("<input file>"),
cl::Required);
+cl::opt<std::string> BlacklistFilename(cl::Positional,
+ cl::desc("[blacklist file]"),
+ cl::init("-"));
ExitOnError ExitOnErr;
-void printIndirectCFInstructions(FileAnalysis &Analysis) {
- uint64_t ProtectedCount = 0;
- uint64_t UnprotectedCount = 0;
+void printIndirectCFInstructions(FileAnalysis &Analysis,
+ const SpecialCaseList *SpecialCaseList) {
+ uint64_t ExpectedProtected = 0;
+ uint64_t UnexpectedProtected = 0;
+ uint64_t ExpectedUnprotected = 0;
+ uint64_t UnexpectedUnprotected = 0;
+
+ symbolize::LLVMSymbolizer &Symbolizer = Analysis.getSymbolizer();
for (uint64_t Address : Analysis.getIndirectInstructions()) {
const auto &InstrMeta = Analysis.getInstructionOrDie(Address);
- if (Analysis.isIndirectInstructionCFIProtected(Address)) {
+ bool CFIProtected = Analysis.isIndirectInstructionCFIProtected(Address);
+
+ if (CFIProtected)
outs() << "P ";
- ProtectedCount++;
- } else {
+ else
outs() << "U ";
- UnprotectedCount++;
- }
outs() << format_hex(Address, 2) << " | "
<< Analysis.getMCInstrInfo()->getName(
InstrMeta.Instruction.getOpcode())
- << " ";
- outs() << "\n";
-
- if (Analysis.hasLineTableInfo()) {
- for (const auto &LineKV : Analysis.getLineInfoForAddressRange(Address)) {
- outs() << " " << format_hex(LineKV.first, 2) << " = "
- << LineKV.second.FileName << ":" << LineKV.second.Line << ":"
- << LineKV.second.Column << " (" << LineKV.second.FunctionName
- << ")\n";
+ << " \n";
+
+ if (IgnoreDWARFFlag) {
+ if (CFIProtected)
+ ExpectedProtected++;
+ else
+ UnexpectedUnprotected++;
+ continue;
+ }
+
+ auto InliningInfo = Symbolizer.symbolizeInlinedCode(InputFilename, Address);
+ if (!InliningInfo || InliningInfo->getNumberOfFrames() == 0) {
+ errs() << "Failed to symbolise " << format_hex(Address, 2)
+ << " with line tables from " << InputFilename << "\n";
+ exit(EXIT_FAILURE);
+ }
+
+ const auto &LineInfo =
+ InliningInfo->getFrame(InliningInfo->getNumberOfFrames() - 1);
+
+ // 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 (!SpecialCaseList) {
+ if (CFIProtected)
+ ExpectedProtected++;
+ else
+ UnexpectedUnprotected++;
+ continue;
+ }
+
+ bool MatchesBlacklistRule = false;
+ if (SpecialCaseList->inSection("cfi-icall", "src", LineInfo.FileName) ||
+ SpecialCaseList->inSection("cfi-vcall", "src", LineInfo.FileName)) {
+ outs() << "BLACKLIST MATCH, 'src'\n";
+ MatchesBlacklistRule = true;
+ }
+
+ if (SpecialCaseList->inSection("cfi-icall", "fun", LineInfo.FunctionName) ||
+ SpecialCaseList->inSection("cfi-vcall", "fun", LineInfo.FunctionName)) {
+ outs() << "BLACKLIST MATCH, 'fun'\n";
+ MatchesBlacklistRule = true;
+ }
+
+ if (MatchesBlacklistRule) {
+ if (CFIProtected) {
+ UnexpectedProtected++;
+ outs() << "====> Unexpected Protected\n";
+ } else {
+ ExpectedUnprotected++;
+ outs() << "====> Expected Unprotected\n";
+ }
+ } else {
+ if (CFIProtected) {
+ ExpectedProtected++;
+ outs() << "====> Expected Protected\n";
+ } else {
+ UnexpectedUnprotected++;
+ outs() << "====> Unexpected Unprotected\n";
}
}
}
- if (ProtectedCount || UnprotectedCount)
- outs() << formatv(
- "Unprotected: {0} ({1:P}), Protected: {2} ({3:P})\n", UnprotectedCount,
- (((double)UnprotectedCount) / (UnprotectedCount + ProtectedCount)),
- ProtectedCount,
- (((double)ProtectedCount) / (UnprotectedCount + ProtectedCount)));
- else
+ uint64_t IndirectCFInstructions = ExpectedProtected + UnexpectedProtected +
+ ExpectedUnprotected + UnexpectedUnprotected;
+
+ if (IndirectCFInstructions == 0) {
outs() << "No indirect CF instructions found.\n";
+ 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,
+ ((double)ExpectedProtected) / IndirectCFInstructions,
+ UnexpectedProtected,
+ ((double)UnexpectedProtected) / IndirectCFInstructions,
+ ExpectedUnprotected,
+ ((double)ExpectedUnprotected) / IndirectCFInstructions,
+ UnexpectedUnprotected,
+ ((double)UnexpectedUnprotected) / IndirectCFInstructions);
}
int main(int argc, char **argv) {
@@ -89,8 +164,18 @@ int main(int argc, char **argv) {
InitializeAllAsmParsers();
InitializeAllDisassemblers();
+ std::unique_ptr<SpecialCaseList> SpecialCaseList;
+ if (BlacklistFilename != "-") {
+ std::string Error;
+ SpecialCaseList = SpecialCaseList::create({BlacklistFilename}, Error);
+ if (!SpecialCaseList) {
+ errs() << "Failed to get blacklist: " << Error << "\n";
+ exit(EXIT_FAILURE);
+ }
+ }
+
FileAnalysis Analysis = ExitOnErr(FileAnalysis::Create(InputFilename));
- printIndirectCFInstructions(Analysis);
+ printIndirectCFInstructions(Analysis, SpecialCaseList.get());
return EXIT_SUCCESS;
}