diff options
Diffstat (limited to 'tools/llvm-cfi-verify')
-rw-r--r-- | tools/llvm-cfi-verify/CMakeLists.txt | 2 | ||||
-rw-r--r-- | tools/llvm-cfi-verify/LLVMBuild.txt | 2 | ||||
-rw-r--r-- | tools/llvm-cfi-verify/lib/CMakeLists.txt | 4 | ||||
-rw-r--r-- | tools/llvm-cfi-verify/lib/FileAnalysis.cpp | 49 | ||||
-rw-r--r-- | tools/llvm-cfi-verify/lib/FileAnalysis.h | 9 | ||||
-rw-r--r-- | tools/llvm-cfi-verify/lib/LLVMBuild.txt | 2 | ||||
-rw-r--r-- | tools/llvm-cfi-verify/llvm-cfi-verify.cpp | 135 |
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; } |