Index: tools/llvm-cfi-verify/CMakeLists.txt =================================================================== --- tools/llvm-cfi-verify/CMakeLists.txt +++ tools/llvm-cfi-verify/CMakeLists.txt @@ -4,6 +4,7 @@ AllTargetsDescs AllTargetsDisassemblers AllTargetsInfos + DebugInfoDWARF MC MCParser Object Index: tools/llvm-cfi-verify/LLVMBuild.txt =================================================================== --- tools/llvm-cfi-verify/LLVMBuild.txt +++ tools/llvm-cfi-verify/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = llvm-cfi-verify parent = Tools -required_libraries = all-targets MC MCDisassembler MCParser Support +required_libraries = all-targets DebugInfoDWARF MC MCDisassembler MCParser Support Index: tools/llvm-cfi-verify/lib/CMakeLists.txt =================================================================== --- tools/llvm-cfi-verify/lib/CMakeLists.txt +++ tools/llvm-cfi-verify/lib/CMakeLists.txt @@ -7,6 +7,7 @@ llvm_update_compile_flags(LLVMCFIVerify) llvm_map_components_to_libnames(libs + DebugInfoDWARF MC MCParser Object Index: tools/llvm-cfi-verify/lib/FileAnalysis.h =================================================================== --- tools/llvm-cfi-verify/lib/FileAnalysis.h +++ tools/llvm-cfi-verify/lib/FileAnalysis.h @@ -12,6 +12,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/BinaryFormat/ELF.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDisassembler/MCDisassembler.h" @@ -65,6 +66,7 @@ FileAnalysis() = delete; FileAnalysis(const FileAnalysis &) = delete; FileAnalysis(FileAnalysis &&Other) = default; + virtual ~FileAnalysis() {} // Check whether the provided instruction is CFI protected in this file. // Returns false if this instruction doesn't exist in this file, if it's not @@ -120,6 +122,18 @@ const MCInstrInfo *getMCInstrInfo() const; const MCInstrAnalysis *getMCInstrAnalysis() const; + // Returns true if this class is using DWARF line tables for elimination. + virtual bool hasLineTableInfo() const; + + // Returns the line table information for the range {Address +- + // DWARFSearchRange}. Returns an empty table if the address has no valid line + // table information, or this analysis object has DWARF handling disabled. + DILineInfoTable getLineInfoForAddressRange(uint64_t Address); + + // Returns whether the provided address has valid line information for + // instructions in the range of Address +- DWARFSearchRange. + virtual bool hasValidLineInfoForAddressRange(uint64_t Address); + protected: // Construct a blank object with the provided triple and features. Used in // testing, where a sub class will dependency inject protected methods to @@ -162,8 +176,12 @@ std::unique_ptr MIA; std::unique_ptr Printer; + // DWARF debug information. + std::unique_ptr DWARF; + // A mapping between the virtual memory address to the instruction metadata - // struct. + // struct. TODO(hctim): Reimplement this as a sorted vector to avoid per- + // insertion allocation. std::map Instructions; // Contains a mapping between a specific address, and a list of instructions Index: tools/llvm-cfi-verify/lib/FileAnalysis.cpp =================================================================== --- tools/llvm-cfi-verify/lib/FileAnalysis.cpp +++ tools/llvm-cfi-verify/lib/FileAnalysis.cpp @@ -11,6 +11,7 @@ #include "GraphBuilder.h" #include "llvm/BinaryFormat/ELF.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDisassembler/MCDisassembler.h" @@ -42,6 +43,19 @@ namespace llvm { namespace cfi_verify { +static cl::opt IgnoreDWARF( + "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 DWARFSearchRange( + "dwarf-search-range", + cl::desc("Address search range used to determine if instruction is valid."), + cl::init(0x10)); + Expected FileAnalysis::Create(StringRef Filename) { // Open the filename provided. Expected> BinaryOrErr = @@ -294,6 +308,28 @@ } Error FileAnalysis::parseCodeSections() { + if (!IgnoreDWARF) { + DWARF.reset(DWARFContext::create(*Object).release()); + if (!DWARF) + return make_error("Could not create DWARF information.", + inconvertibleErrorCode()); + + bool LineInfoValid = false; + + for (auto &Unit : DWARF->compile_units()) { + const auto &LineTable = DWARF->getLineTableForUnit(Unit.get()); + if (LineTable && !LineTable->Rows.empty()) { + LineInfoValid = true; + break; + } + } + + if (!LineInfoValid) + return make_error( + "DWARF line information missing. Did you compile with '-g'?", + inconvertibleErrorCode()); + } + for (const object::SectionRef &Section : Object->sections()) { // Ensure only executable sections get analysed. if (!(object::ELFSectionRef(Section).getFlags() & ELF::SHF_EXECINSTR)) @@ -311,6 +347,19 @@ 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 SectionBytes, uint64_t SectionAddress) { MCInst Instruction; @@ -330,6 +379,11 @@ InstrMeta.VMAddress = VMAddress; InstrMeta.InstructionSize = InstructionSize; InstrMeta.Valid = ValidInstruction; + + // Check if this instruction exists in the range of the DWARF metadata. + if (hasLineTableInfo() && !hasValidLineInfoForAddressRange(VMAddress)) + continue; + addInstruction(InstrMeta); if (!ValidInstruction) Index: tools/llvm-cfi-verify/lib/GraphBuilder.cpp =================================================================== --- tools/llvm-cfi-verify/lib/GraphBuilder.cpp +++ tools/llvm-cfi-verify/lib/GraphBuilder.cpp @@ -221,6 +221,13 @@ continue; } + // Call instructions are not valid in the upwards traversal. + if (ParentDesc.isCall()) { + Result.IntermediateNodes[ParentMeta.VMAddress] = Address; + Result.OrphanedNodes.push_back(ParentMeta.VMAddress); + continue; + } + // Evaluate the branch target to ascertain whether this XRef is the result // of a fallthrough or the target of a branch. uint64_t BranchTarget; Index: tools/llvm-cfi-verify/lib/LLVMBuild.txt =================================================================== --- tools/llvm-cfi-verify/lib/LLVMBuild.txt +++ tools/llvm-cfi-verify/lib/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Library name = CFIVerify parent = Libraries -required_libraries = MC MCDisassembler MCParser Support +required_libraries = DebugInfoDWARF MC MCDisassembler MCParser Support Index: tools/llvm-cfi-verify/llvm-cfi-verify.cpp =================================================================== --- tools/llvm-cfi-verify/llvm-cfi-verify.cpp +++ tools/llvm-cfi-verify/llvm-cfi-verify.cpp @@ -22,6 +22,7 @@ #include "llvm/BinaryFormat/ELF.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Error.h" +#include "llvm/Support/FormatVariadic.h" #include @@ -34,30 +35,62 @@ ExitOnError ExitOnErr; -void printIndirectCFInstructions(const FileAnalysis &Verifier) { - for (uint64_t Address : Verifier.getIndirectInstructions()) { - const auto &InstrMeta = Verifier.getInstructionOrDie(Address); - outs() << format_hex(Address, 2) << " |" - << Verifier.getMCInstrInfo()->getName( +void printIndirectCFInstructions(FileAnalysis &Analysis) { + uint64_t ProtectedCount = 0; + uint64_t UnprotectedCount = 0; + + for (uint64_t Address : Analysis.getIndirectInstructions()) { + const auto &InstrMeta = Analysis.getInstructionOrDie(Address); + + if (Analysis.isIndirectInstructionCFIProtected(Address)) { + outs() << "P "; + ProtectedCount++; + } else { + outs() << "U "; + UnprotectedCount++; + } + + outs() << format_hex(Address, 2) << " | " + << Analysis.getMCInstrInfo()->getName( InstrMeta.Instruction.getOpcode()) << " "; - InstrMeta.Instruction.print(outs()); outs() << "\n"; - outs() << " Protected? " - << Verifier.isIndirectInstructionCFIProtected(Address) << "\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"; + } + } } + + 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 + outs() << "No indirect CF instructions found.\n"; } int main(int argc, char **argv) { - cl::ParseCommandLineOptions(argc, argv); + cl::ParseCommandLineOptions( + argc, argv, + "Identifies whether Control Flow Integrity protects all indirect control " + "flow instructions in the provided object file, DSO or binary.\nNote: " + "Anything statically linked into the provided file *must* be compiled " + "with '-g'. This can be relaxed through the '--ignore-dwarf' flag."); InitializeAllTargetInfos(); InitializeAllTargetMCs(); InitializeAllAsmParsers(); InitializeAllDisassemblers(); - FileAnalysis Verifier = ExitOnErr(FileAnalysis::Create(InputFilename)); - printIndirectCFInstructions(Verifier); + FileAnalysis Analysis = ExitOnErr(FileAnalysis::Create(InputFilename)); + printIndirectCFInstructions(Analysis); return EXIT_SUCCESS; } Index: unittests/tools/llvm-cfi-verify/FileAnalysis.cpp =================================================================== --- unittests/tools/llvm-cfi-verify/FileAnalysis.cpp +++ unittests/tools/llvm-cfi-verify/FileAnalysis.cpp @@ -61,11 +61,31 @@ } }; +class DebugInfoAnalysis : public ELFx86TestFileAnalysis { +public: + void AddValidLines(const std::vector &Addresses) { + for (uint64_t Address : Addresses) + ValidLineInfo.insert(Address); + } + + bool hasValidLineInfoForAddressRange(uint64_t Address) override { + return ValidLineInfo.count(Address); + } + + bool hasLineTableInfo() const override { return true; } + +private: + DenseSet ValidLineInfo; +}; + class BasicFileAnalysisTest : public ::testing::Test { protected: + BasicFileAnalysisTest() : Analysis(new ELFx86TestFileAnalysis()) {} + explicit BasicFileAnalysisTest(std::unique_ptr &&P) + : Analysis(std::move(P)) {} virtual void SetUp() { SuccessfullyInitialised = true; - if (auto Err = Analysis.initialiseDisassemblyMembers()) { + if (auto Err = Analysis->initialiseDisassemblyMembers()) { handleAllErrors(std::move(Err), [&](const UnsupportedDisassembly &E) { SuccessfullyInitialised = false; outs() @@ -76,13 +96,24 @@ } bool SuccessfullyInitialised; - ELFx86TestFileAnalysis Analysis; + std::unique_ptr Analysis; +}; + +class DebugInfoFileAnalysisTest : public BasicFileAnalysisTest { +protected: + DebugInfoFileAnalysisTest() + : BasicFileAnalysisTest( + std::unique_ptr(new DebugInfoAnalysis())) { + DebugAnalysis = static_cast(Analysis.get()); + } + + DebugInfoAnalysis *DebugAnalysis; }; TEST_F(BasicFileAnalysisTest, BasicDisassemblyTraversalTest) { if (!SuccessfullyInitialised) return; - Analysis.parseSectionContents( + Analysis->parseSectionContents( { 0x90, // 0: nop 0xb0, 0x00, // 1: mov $0x0, %al @@ -96,117 +127,118 @@ }, 0xDEADBEEF); - EXPECT_EQ(nullptr, Analysis.getInstruction(0x0)); - EXPECT_EQ(nullptr, Analysis.getInstruction(0x1000)); + EXPECT_EQ(nullptr, Analysis->getInstruction(0x0)); + EXPECT_EQ(nullptr, Analysis->getInstruction(0x1000)); // 0xDEADBEEF: nop - const auto *InstrMeta = Analysis.getInstruction(0xDEADBEEF); + const auto *InstrMeta = Analysis->getInstruction(0xDEADBEEF); EXPECT_NE(nullptr, InstrMeta); EXPECT_EQ(0xDEADBEEF, InstrMeta->VMAddress); EXPECT_EQ(1u, InstrMeta->InstructionSize); EXPECT_TRUE(InstrMeta->Valid); - const auto *NextInstrMeta = Analysis.getNextInstructionSequential(*InstrMeta); - EXPECT_EQ(nullptr, Analysis.getPrevInstructionSequential(*InstrMeta)); + const auto *NextInstrMeta = + Analysis->getNextInstructionSequential(*InstrMeta); + EXPECT_EQ(nullptr, Analysis->getPrevInstructionSequential(*InstrMeta)); const auto *PrevInstrMeta = InstrMeta; // 0xDEADBEEF + 1: mov $0x0, %al - InstrMeta = Analysis.getInstruction(0xDEADBEEF + 1); + InstrMeta = Analysis->getInstruction(0xDEADBEEF + 1); EXPECT_NE(nullptr, InstrMeta); EXPECT_EQ(NextInstrMeta, InstrMeta); EXPECT_EQ(0xDEADBEEF + 1, InstrMeta->VMAddress); EXPECT_EQ(2u, InstrMeta->InstructionSize); EXPECT_TRUE(InstrMeta->Valid); - NextInstrMeta = Analysis.getNextInstructionSequential(*InstrMeta); - EXPECT_EQ(PrevInstrMeta, Analysis.getPrevInstructionSequential(*InstrMeta)); + NextInstrMeta = Analysis->getNextInstructionSequential(*InstrMeta); + EXPECT_EQ(PrevInstrMeta, Analysis->getPrevInstructionSequential(*InstrMeta)); PrevInstrMeta = InstrMeta; // 0xDEADBEEF + 3: mov %rsp, %rbp - InstrMeta = Analysis.getInstruction(0xDEADBEEF + 3); + InstrMeta = Analysis->getInstruction(0xDEADBEEF + 3); EXPECT_NE(nullptr, InstrMeta); EXPECT_EQ(NextInstrMeta, InstrMeta); EXPECT_EQ(0xDEADBEEF + 3, InstrMeta->VMAddress); EXPECT_EQ(3u, InstrMeta->InstructionSize); EXPECT_TRUE(InstrMeta->Valid); - NextInstrMeta = Analysis.getNextInstructionSequential(*InstrMeta); - EXPECT_EQ(PrevInstrMeta, Analysis.getPrevInstructionSequential(*InstrMeta)); + NextInstrMeta = Analysis->getNextInstructionSequential(*InstrMeta); + EXPECT_EQ(PrevInstrMeta, Analysis->getPrevInstructionSequential(*InstrMeta)); PrevInstrMeta = InstrMeta; // 0xDEADBEEF + 6: sub $0x18, %rsp - InstrMeta = Analysis.getInstruction(0xDEADBEEF + 6); + InstrMeta = Analysis->getInstruction(0xDEADBEEF + 6); EXPECT_NE(nullptr, InstrMeta); EXPECT_EQ(NextInstrMeta, InstrMeta); EXPECT_EQ(0xDEADBEEF + 6, InstrMeta->VMAddress); EXPECT_EQ(4u, InstrMeta->InstructionSize); EXPECT_TRUE(InstrMeta->Valid); - NextInstrMeta = Analysis.getNextInstructionSequential(*InstrMeta); - EXPECT_EQ(PrevInstrMeta, Analysis.getPrevInstructionSequential(*InstrMeta)); + NextInstrMeta = Analysis->getNextInstructionSequential(*InstrMeta); + EXPECT_EQ(PrevInstrMeta, Analysis->getPrevInstructionSequential(*InstrMeta)); PrevInstrMeta = InstrMeta; // 0xDEADBEEF + 10: movabs $0x4007c4, %rsi - InstrMeta = Analysis.getInstruction(0xDEADBEEF + 10); + InstrMeta = Analysis->getInstruction(0xDEADBEEF + 10); EXPECT_NE(nullptr, InstrMeta); EXPECT_EQ(NextInstrMeta, InstrMeta); EXPECT_EQ(0xDEADBEEF + 10, InstrMeta->VMAddress); EXPECT_EQ(10u, InstrMeta->InstructionSize); EXPECT_TRUE(InstrMeta->Valid); - EXPECT_EQ(nullptr, Analysis.getNextInstructionSequential(*InstrMeta)); - EXPECT_EQ(PrevInstrMeta, Analysis.getPrevInstructionSequential(*InstrMeta)); + EXPECT_EQ(nullptr, Analysis->getNextInstructionSequential(*InstrMeta)); + EXPECT_EQ(PrevInstrMeta, Analysis->getPrevInstructionSequential(*InstrMeta)); PrevInstrMeta = InstrMeta; // 0xDEADBEEF + 20: (bad) - InstrMeta = Analysis.getInstruction(0xDEADBEEF + 20); + InstrMeta = Analysis->getInstruction(0xDEADBEEF + 20); EXPECT_NE(nullptr, InstrMeta); EXPECT_EQ(0xDEADBEEF + 20, InstrMeta->VMAddress); EXPECT_EQ(1u, InstrMeta->InstructionSize); EXPECT_FALSE(InstrMeta->Valid); - EXPECT_EQ(nullptr, Analysis.getNextInstructionSequential(*InstrMeta)); - EXPECT_EQ(PrevInstrMeta, Analysis.getPrevInstructionSequential(*InstrMeta)); + EXPECT_EQ(nullptr, Analysis->getNextInstructionSequential(*InstrMeta)); + EXPECT_EQ(PrevInstrMeta, Analysis->getPrevInstructionSequential(*InstrMeta)); // 0xDEADBEEF + 21: rex.B (bad) - InstrMeta = Analysis.getInstruction(0xDEADBEEF + 21); + InstrMeta = Analysis->getInstruction(0xDEADBEEF + 21); EXPECT_NE(nullptr, InstrMeta); EXPECT_EQ(0xDEADBEEF + 21, InstrMeta->VMAddress); EXPECT_EQ(2u, InstrMeta->InstructionSize); EXPECT_FALSE(InstrMeta->Valid); - EXPECT_EQ(nullptr, Analysis.getNextInstructionSequential(*InstrMeta)); - EXPECT_EQ(nullptr, Analysis.getPrevInstructionSequential(*InstrMeta)); + EXPECT_EQ(nullptr, Analysis->getNextInstructionSequential(*InstrMeta)); + EXPECT_EQ(nullptr, Analysis->getPrevInstructionSequential(*InstrMeta)); // 0xDEADBEEF + 6: (bad) {%k1} - InstrMeta = Analysis.getInstruction(0xDEADBEEF + 23); + InstrMeta = Analysis->getInstruction(0xDEADBEEF + 23); EXPECT_NE(nullptr, InstrMeta); EXPECT_EQ(0xDEADBEEF + 23, InstrMeta->VMAddress); EXPECT_EQ(5u, InstrMeta->InstructionSize); EXPECT_FALSE(InstrMeta->Valid); - EXPECT_EQ(nullptr, Analysis.getNextInstructionSequential(*InstrMeta)); - EXPECT_EQ(nullptr, Analysis.getPrevInstructionSequential(*InstrMeta)); + EXPECT_EQ(nullptr, Analysis->getNextInstructionSequential(*InstrMeta)); + EXPECT_EQ(nullptr, Analysis->getPrevInstructionSequential(*InstrMeta)); } TEST_F(BasicFileAnalysisTest, PrevAndNextFromBadInst) { if (!SuccessfullyInitialised) return; - Analysis.parseSectionContents( + Analysis->parseSectionContents( { 0x90, // 0: nop 0x2f, // 1: (bad) 0x90 // 2: nop }, 0xDEADBEEF); - const auto &BadInstrMeta = Analysis.getInstructionOrDie(0xDEADBEEF + 1); + const auto &BadInstrMeta = Analysis->getInstructionOrDie(0xDEADBEEF + 1); const auto *GoodInstrMeta = - Analysis.getPrevInstructionSequential(BadInstrMeta); + Analysis->getPrevInstructionSequential(BadInstrMeta); EXPECT_NE(nullptr, GoodInstrMeta); EXPECT_EQ(0xDEADBEEF, GoodInstrMeta->VMAddress); EXPECT_EQ(1u, GoodInstrMeta->InstructionSize); - GoodInstrMeta = Analysis.getNextInstructionSequential(BadInstrMeta); + GoodInstrMeta = Analysis->getNextInstructionSequential(BadInstrMeta); EXPECT_NE(nullptr, GoodInstrMeta); EXPECT_EQ(0xDEADBEEF + 2, GoodInstrMeta->VMAddress); EXPECT_EQ(1u, GoodInstrMeta->InstructionSize); @@ -215,7 +247,7 @@ TEST_F(BasicFileAnalysisTest, CFITrapTest) { if (!SuccessfullyInitialised) return; - Analysis.parseSectionContents( + Analysis->parseSectionContents( { 0x90, // 0: nop 0xb0, 0x00, // 1: mov $0x0, %al @@ -230,27 +262,27 @@ }, 0xDEADBEEF); - EXPECT_FALSE(Analysis.isCFITrap(Analysis.getInstructionOrDie(0xDEADBEEF))); + EXPECT_FALSE(Analysis->isCFITrap(Analysis->getInstructionOrDie(0xDEADBEEF))); EXPECT_FALSE( - Analysis.isCFITrap(Analysis.getInstructionOrDie(0xDEADBEEF + 3))); + Analysis->isCFITrap(Analysis->getInstructionOrDie(0xDEADBEEF + 3))); EXPECT_FALSE( - Analysis.isCFITrap(Analysis.getInstructionOrDie(0xDEADBEEF + 6))); + Analysis->isCFITrap(Analysis->getInstructionOrDie(0xDEADBEEF + 6))); EXPECT_FALSE( - Analysis.isCFITrap(Analysis.getInstructionOrDie(0xDEADBEEF + 10))); + Analysis->isCFITrap(Analysis->getInstructionOrDie(0xDEADBEEF + 10))); EXPECT_FALSE( - Analysis.isCFITrap(Analysis.getInstructionOrDie(0xDEADBEEF + 20))); + Analysis->isCFITrap(Analysis->getInstructionOrDie(0xDEADBEEF + 20))); EXPECT_FALSE( - Analysis.isCFITrap(Analysis.getInstructionOrDie(0xDEADBEEF + 21))); + Analysis->isCFITrap(Analysis->getInstructionOrDie(0xDEADBEEF + 21))); EXPECT_FALSE( - Analysis.isCFITrap(Analysis.getInstructionOrDie(0xDEADBEEF + 23))); + Analysis->isCFITrap(Analysis->getInstructionOrDie(0xDEADBEEF + 23))); EXPECT_TRUE( - Analysis.isCFITrap(Analysis.getInstructionOrDie(0xDEADBEEF + 28))); + Analysis->isCFITrap(Analysis->getInstructionOrDie(0xDEADBEEF + 28))); } TEST_F(BasicFileAnalysisTest, FallThroughTest) { if (!SuccessfullyInitialised) return; - Analysis.parseSectionContents( + Analysis->parseSectionContents( { 0x90, // 0: nop 0xb0, 0x00, // 1: mov $0x0, %al @@ -266,31 +298,31 @@ 0xDEADBEEF); EXPECT_TRUE( - Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF))); + Analysis->canFallThrough(Analysis->getInstructionOrDie(0xDEADBEEF))); EXPECT_TRUE( - Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 1))); + Analysis->canFallThrough(Analysis->getInstructionOrDie(0xDEADBEEF + 1))); EXPECT_FALSE( - Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 3))); + Analysis->canFallThrough(Analysis->getInstructionOrDie(0xDEADBEEF + 3))); EXPECT_FALSE( - Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 4))); + Analysis->canFallThrough(Analysis->getInstructionOrDie(0xDEADBEEF + 4))); EXPECT_FALSE( - Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 6))); + Analysis->canFallThrough(Analysis->getInstructionOrDie(0xDEADBEEF + 6))); EXPECT_FALSE( - Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 8))); + Analysis->canFallThrough(Analysis->getInstructionOrDie(0xDEADBEEF + 8))); EXPECT_FALSE( - Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 10))); + Analysis->canFallThrough(Analysis->getInstructionOrDie(0xDEADBEEF + 10))); EXPECT_FALSE( - Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 15))); + Analysis->canFallThrough(Analysis->getInstructionOrDie(0xDEADBEEF + 15))); EXPECT_TRUE( - Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 17))); + Analysis->canFallThrough(Analysis->getInstructionOrDie(0xDEADBEEF + 17))); EXPECT_FALSE( - Analysis.canFallThrough(Analysis.getInstructionOrDie(0xDEADBEEF + 19))); + Analysis->canFallThrough(Analysis->getInstructionOrDie(0xDEADBEEF + 19))); } TEST_F(BasicFileAnalysisTest, DefiniteNextInstructionTest) { if (!SuccessfullyInitialised) return; - Analysis.parseSectionContents( + Analysis->parseSectionContents( { 0x90, // 0: nop 0xb0, 0x00, // 1: mov $0x0, %al @@ -312,67 +344,67 @@ }, 0xDEADBEEF); - const auto *Current = Analysis.getInstruction(0xDEADBEEF); - const auto *Next = Analysis.getDefiniteNextInstruction(*Current); + const auto *Current = Analysis->getInstruction(0xDEADBEEF); + const auto *Next = Analysis->getDefiniteNextInstruction(*Current); EXPECT_NE(nullptr, Next); EXPECT_EQ(0xDEADBEEF + 1, Next->VMAddress); - Current = Analysis.getInstruction(0xDEADBEEF + 1); - EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current)); + Current = Analysis->getInstruction(0xDEADBEEF + 1); + EXPECT_EQ(nullptr, Analysis->getDefiniteNextInstruction(*Current)); - Current = Analysis.getInstruction(0xDEADBEEF + 3); - EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current)); + Current = Analysis->getInstruction(0xDEADBEEF + 3); + EXPECT_EQ(nullptr, Analysis->getDefiniteNextInstruction(*Current)); - Current = Analysis.getInstruction(0xDEADBEEF + 4); - EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current)); + Current = Analysis->getInstruction(0xDEADBEEF + 4); + EXPECT_EQ(nullptr, Analysis->getDefiniteNextInstruction(*Current)); - Current = Analysis.getInstruction(0xDEADBEEF + 6); - EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current)); + Current = Analysis->getInstruction(0xDEADBEEF + 6); + EXPECT_EQ(nullptr, Analysis->getDefiniteNextInstruction(*Current)); - Current = Analysis.getInstruction(0xDEADBEEF + 8); - Next = Analysis.getDefiniteNextInstruction(*Current); + Current = Analysis->getInstruction(0xDEADBEEF + 8); + Next = Analysis->getDefiniteNextInstruction(*Current); EXPECT_NE(nullptr, Next); EXPECT_EQ(0xDEADBEEF + 10, Next->VMAddress); - Current = Analysis.getInstruction(0xDEADBEEF + 10); - Next = Analysis.getDefiniteNextInstruction(*Current); + Current = Analysis->getInstruction(0xDEADBEEF + 10); + Next = Analysis->getDefiniteNextInstruction(*Current); EXPECT_NE(nullptr, Next); EXPECT_EQ(0xDEADBEEF + 17, Next->VMAddress); - Current = Analysis.getInstruction(0xDEADBEEF + 12); - Next = Analysis.getDefiniteNextInstruction(*Current); + Current = Analysis->getInstruction(0xDEADBEEF + 12); + Next = Analysis->getDefiniteNextInstruction(*Current); EXPECT_NE(nullptr, Next); EXPECT_EQ(0xDEADBEEF + 17, Next->VMAddress); - Current = Analysis.getInstruction(0xDEADBEEF + 17); + Current = Analysis->getInstruction(0xDEADBEEF + 17); // Note, definite next instruction address is out of range and should fail. - EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current)); - Next = Analysis.getDefiniteNextInstruction(*Current); + EXPECT_EQ(nullptr, Analysis->getDefiniteNextInstruction(*Current)); + Next = Analysis->getDefiniteNextInstruction(*Current); - Current = Analysis.getInstruction(0xDEADBEEF + 22); - Next = Analysis.getDefiniteNextInstruction(*Current); + Current = Analysis->getInstruction(0xDEADBEEF + 22); + Next = Analysis->getDefiniteNextInstruction(*Current); EXPECT_NE(nullptr, Next); EXPECT_EQ(0xDEADBEEF + 31, Next->VMAddress); - Current = Analysis.getInstruction(0xDEADBEEF + 27); - EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current)); - Current = Analysis.getInstruction(0xDEADBEEF + 29); - EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current)); - Current = Analysis.getInstruction(0xDEADBEEF + 31); - EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current)); - Current = Analysis.getInstruction(0xDEADBEEF + 33); - EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current)); - - Current = Analysis.getInstruction(0xDEADBEEF + 34); - Next = Analysis.getDefiniteNextInstruction(*Current); + Current = Analysis->getInstruction(0xDEADBEEF + 27); + EXPECT_EQ(nullptr, Analysis->getDefiniteNextInstruction(*Current)); + Current = Analysis->getInstruction(0xDEADBEEF + 29); + EXPECT_EQ(nullptr, Analysis->getDefiniteNextInstruction(*Current)); + Current = Analysis->getInstruction(0xDEADBEEF + 31); + EXPECT_EQ(nullptr, Analysis->getDefiniteNextInstruction(*Current)); + Current = Analysis->getInstruction(0xDEADBEEF + 33); + EXPECT_EQ(nullptr, Analysis->getDefiniteNextInstruction(*Current)); + + Current = Analysis->getInstruction(0xDEADBEEF + 34); + Next = Analysis->getDefiniteNextInstruction(*Current); EXPECT_NE(nullptr, Next); EXPECT_EQ(0xDEADBEEF + 1, Next->VMAddress); - Current = Analysis.getInstruction(0xDEADBEEF + 36); - EXPECT_EQ(nullptr, Analysis.getDefiniteNextInstruction(*Current)); + Current = Analysis->getInstruction(0xDEADBEEF + 36); + EXPECT_EQ(nullptr, Analysis->getDefiniteNextInstruction(*Current)); - Current = Analysis.getInstruction(0xDEADBEEF + 38); - Next = Analysis.getDefiniteNextInstruction(*Current); + Current = Analysis->getInstruction(0xDEADBEEF + 38); + Next = Analysis->getDefiniteNextInstruction(*Current); EXPECT_NE(nullptr, Next); EXPECT_EQ(0xDEADBEEF + 4, Next->VMAddress); } @@ -380,7 +412,7 @@ TEST_F(BasicFileAnalysisTest, ControlFlowXRefsTest) { if (!SuccessfullyInitialised) return; - Analysis.parseSectionContents( + Analysis->parseSectionContents( { 0x90, // 0: nop 0xb0, 0x00, // 1: mov $0x0, %al @@ -401,133 +433,133 @@ 0xeb, 0xdc, // 38: jmp 4 [-36] }, 0xDEADBEEF); - const auto *InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF); + const auto *InstrMetaPtr = &Analysis->getInstructionOrDie(0xDEADBEEF); std::set XRefs = - Analysis.getDirectControlFlowXRefs(*InstrMetaPtr); + Analysis->getDirectControlFlowXRefs(*InstrMetaPtr); EXPECT_TRUE(XRefs.empty()); - InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 1); - XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr); + InstrMetaPtr = &Analysis->getInstructionOrDie(0xDEADBEEF + 1); + XRefs = Analysis->getDirectControlFlowXRefs(*InstrMetaPtr); EXPECT_THAT(XRefs, UnorderedElementsAre( Field(&Instr::VMAddress, Eq(0xDEADBEEF)), Field(&Instr::VMAddress, Eq(0xDEADBEEF + 31)), Field(&Instr::VMAddress, Eq(0xDEADBEEF + 34)))); - InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 3); - XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr); + InstrMetaPtr = &Analysis->getInstructionOrDie(0xDEADBEEF + 3); + XRefs = Analysis->getDirectControlFlowXRefs(*InstrMetaPtr); EXPECT_THAT(XRefs, UnorderedElementsAre( Field(&Instr::VMAddress, Eq(0xDEADBEEF + 1)), Field(&Instr::VMAddress, Eq(0xDEADBEEF + 36)))); - InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 4); - XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr); + InstrMetaPtr = &Analysis->getInstructionOrDie(0xDEADBEEF + 4); + XRefs = Analysis->getDirectControlFlowXRefs(*InstrMetaPtr); EXPECT_THAT(XRefs, UnorderedElementsAre( Field(&Instr::VMAddress, Eq(0xDEADBEEF + 38)))); - InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 6); - EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty()); + InstrMetaPtr = &Analysis->getInstructionOrDie(0xDEADBEEF + 6); + EXPECT_TRUE(Analysis->getDirectControlFlowXRefs(*InstrMetaPtr).empty()); - InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 8); - XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr); - EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty()); + InstrMetaPtr = &Analysis->getInstructionOrDie(0xDEADBEEF + 8); + XRefs = Analysis->getDirectControlFlowXRefs(*InstrMetaPtr); + EXPECT_TRUE(Analysis->getDirectControlFlowXRefs(*InstrMetaPtr).empty()); - InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 10); - XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr); + InstrMetaPtr = &Analysis->getInstructionOrDie(0xDEADBEEF + 10); + XRefs = Analysis->getDirectControlFlowXRefs(*InstrMetaPtr); EXPECT_THAT(XRefs, UnorderedElementsAre( Field(&Instr::VMAddress, Eq(0xDEADBEEF + 8)))); - InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 12); - XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr); - EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty()); + InstrMetaPtr = &Analysis->getInstructionOrDie(0xDEADBEEF + 12); + XRefs = Analysis->getDirectControlFlowXRefs(*InstrMetaPtr); + EXPECT_TRUE(Analysis->getDirectControlFlowXRefs(*InstrMetaPtr).empty()); - InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 17); - XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr); + InstrMetaPtr = &Analysis->getInstructionOrDie(0xDEADBEEF + 17); + XRefs = Analysis->getDirectControlFlowXRefs(*InstrMetaPtr); EXPECT_THAT(XRefs, UnorderedElementsAre( Field(&Instr::VMAddress, Eq(0xDEADBEEF + 10)), Field(&Instr::VMAddress, Eq(0xDEADBEEF + 12)))); - InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 22); - XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr); - EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty()); + InstrMetaPtr = &Analysis->getInstructionOrDie(0xDEADBEEF + 22); + XRefs = Analysis->getDirectControlFlowXRefs(*InstrMetaPtr); + EXPECT_TRUE(Analysis->getDirectControlFlowXRefs(*InstrMetaPtr).empty()); - InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 27); - XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr); - EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty()); + InstrMetaPtr = &Analysis->getInstructionOrDie(0xDEADBEEF + 27); + XRefs = Analysis->getDirectControlFlowXRefs(*InstrMetaPtr); + EXPECT_TRUE(Analysis->getDirectControlFlowXRefs(*InstrMetaPtr).empty()); - InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 29); - XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr); - EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty()); + InstrMetaPtr = &Analysis->getInstructionOrDie(0xDEADBEEF + 29); + XRefs = Analysis->getDirectControlFlowXRefs(*InstrMetaPtr); + EXPECT_TRUE(Analysis->getDirectControlFlowXRefs(*InstrMetaPtr).empty()); - InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 31); - XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr); + InstrMetaPtr = &Analysis->getInstructionOrDie(0xDEADBEEF + 31); + XRefs = Analysis->getDirectControlFlowXRefs(*InstrMetaPtr); EXPECT_THAT(XRefs, UnorderedElementsAre( Field(&Instr::VMAddress, Eq(0xDEADBEEF + 22)), Field(&Instr::VMAddress, Eq(0xDEADBEEF + 29)))); - InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 33); - XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr); + InstrMetaPtr = &Analysis->getInstructionOrDie(0xDEADBEEF + 33); + XRefs = Analysis->getDirectControlFlowXRefs(*InstrMetaPtr); EXPECT_THAT(XRefs, UnorderedElementsAre( Field(&Instr::VMAddress, Eq(0xDEADBEEF + 31)))); - InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 34); - XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr); - EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty()); + InstrMetaPtr = &Analysis->getInstructionOrDie(0xDEADBEEF + 34); + XRefs = Analysis->getDirectControlFlowXRefs(*InstrMetaPtr); + EXPECT_TRUE(Analysis->getDirectControlFlowXRefs(*InstrMetaPtr).empty()); - InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 36); - XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr); - EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty()); + InstrMetaPtr = &Analysis->getInstructionOrDie(0xDEADBEEF + 36); + XRefs = Analysis->getDirectControlFlowXRefs(*InstrMetaPtr); + EXPECT_TRUE(Analysis->getDirectControlFlowXRefs(*InstrMetaPtr).empty()); - InstrMetaPtr = &Analysis.getInstructionOrDie(0xDEADBEEF + 38); - XRefs = Analysis.getDirectControlFlowXRefs(*InstrMetaPtr); - EXPECT_TRUE(Analysis.getDirectControlFlowXRefs(*InstrMetaPtr).empty()); + InstrMetaPtr = &Analysis->getInstructionOrDie(0xDEADBEEF + 38); + XRefs = Analysis->getDirectControlFlowXRefs(*InstrMetaPtr); + EXPECT_TRUE(Analysis->getDirectControlFlowXRefs(*InstrMetaPtr).empty()); } TEST_F(BasicFileAnalysisTest, CFIProtectionInvalidTargets) { if (!SuccessfullyInitialised) return; - Analysis.parseSectionContents( + Analysis->parseSectionContents( { 0x90, // 0: nop 0x0f, 0x0b, // 1: ud2 0x75, 0x00, // 3: jne 5 [+0] }, 0xDEADBEEF); - EXPECT_FALSE(Analysis.isIndirectInstructionCFIProtected(0xDEADBEEF)); - EXPECT_FALSE(Analysis.isIndirectInstructionCFIProtected(0xDEADBEEF + 1)); - EXPECT_FALSE(Analysis.isIndirectInstructionCFIProtected(0xDEADBEEF + 3)); - EXPECT_FALSE(Analysis.isIndirectInstructionCFIProtected(0xDEADC0DE)); + EXPECT_FALSE(Analysis->isIndirectInstructionCFIProtected(0xDEADBEEF)); + EXPECT_FALSE(Analysis->isIndirectInstructionCFIProtected(0xDEADBEEF + 1)); + EXPECT_FALSE(Analysis->isIndirectInstructionCFIProtected(0xDEADBEEF + 3)); + EXPECT_FALSE(Analysis->isIndirectInstructionCFIProtected(0xDEADC0DE)); } TEST_F(BasicFileAnalysisTest, CFIProtectionBasicFallthroughToUd2) { if (!SuccessfullyInitialised) return; - Analysis.parseSectionContents( + Analysis->parseSectionContents( { 0x75, 0x02, // 0: jne 4 [+2] 0x0f, 0x0b, // 2: ud2 0xff, 0x10, // 4: callq *(%rax) }, 0xDEADBEEF); - EXPECT_TRUE(Analysis.isIndirectInstructionCFIProtected(0xDEADBEEF + 4)); + EXPECT_TRUE(Analysis->isIndirectInstructionCFIProtected(0xDEADBEEF + 4)); } TEST_F(BasicFileAnalysisTest, CFIProtectionBasicJumpToUd2) { if (!SuccessfullyInitialised) return; - Analysis.parseSectionContents( + Analysis->parseSectionContents( { 0x75, 0x02, // 0: jne 4 [+2] 0xff, 0x10, // 2: callq *(%rax) 0x0f, 0x0b, // 4: ud2 }, 0xDEADBEEF); - EXPECT_TRUE(Analysis.isIndirectInstructionCFIProtected(0xDEADBEEF + 2)); + EXPECT_TRUE(Analysis->isIndirectInstructionCFIProtected(0xDEADBEEF + 2)); } TEST_F(BasicFileAnalysisTest, CFIProtectionDualPathUd2) { if (!SuccessfullyInitialised) return; - Analysis.parseSectionContents( + Analysis->parseSectionContents( { 0x75, 0x03, // 0: jne 5 [+3] 0x90, // 2: nop @@ -537,13 +569,13 @@ 0x0f, 0x0b, // 9: ud2 }, 0xDEADBEEF); - EXPECT_TRUE(Analysis.isIndirectInstructionCFIProtected(0xDEADBEEF + 3)); + EXPECT_TRUE(Analysis->isIndirectInstructionCFIProtected(0xDEADBEEF + 3)); } TEST_F(BasicFileAnalysisTest, CFIProtectionDualPathSingleUd2) { if (!SuccessfullyInitialised) return; - Analysis.parseSectionContents( + Analysis->parseSectionContents( { 0x75, 0x05, // 0: jne 7 [+5] 0x90, // 2: nop @@ -552,13 +584,13 @@ 0x0f, 0x0b, // 7: ud2 }, 0xDEADBEEF); - EXPECT_TRUE(Analysis.isIndirectInstructionCFIProtected(0xDEADBEEF + 3)); + EXPECT_TRUE(Analysis->isIndirectInstructionCFIProtected(0xDEADBEEF + 3)); } TEST_F(BasicFileAnalysisTest, CFIProtectionDualFailLimitUpwards) { if (!SuccessfullyInitialised) return; - Analysis.parseSectionContents( + Analysis->parseSectionContents( { 0x75, 0x06, // 0: jne 8 [+6] 0x90, // 2: nop @@ -573,7 +605,7 @@ SearchLengthForConditionalBranch; SearchLengthForConditionalBranch = 2; - EXPECT_FALSE(Analysis.isIndirectInstructionCFIProtected(0xDEADBEEF + 6)); + EXPECT_FALSE(Analysis->isIndirectInstructionCFIProtected(0xDEADBEEF + 6)); SearchLengthForConditionalBranch = PrevSearchLengthForConditionalBranch; } @@ -581,7 +613,7 @@ TEST_F(BasicFileAnalysisTest, CFIProtectionDualFailLimitDownwards) { if (!SuccessfullyInitialised) return; - Analysis.parseSectionContents( + Analysis->parseSectionContents( { 0x75, 0x02, // 0: jne 4 [+2] 0xff, 0x10, // 2: callq *(%rax) @@ -595,7 +627,7 @@ uint64_t PrevSearchLengthForUndef = SearchLengthForUndef; SearchLengthForUndef = 2; - EXPECT_FALSE(Analysis.isIndirectInstructionCFIProtected(0xDEADBEEF + 2)); + EXPECT_FALSE(Analysis->isIndirectInstructionCFIProtected(0xDEADBEEF + 2)); SearchLengthForUndef = PrevSearchLengthForUndef; } @@ -603,7 +635,7 @@ TEST_F(BasicFileAnalysisTest, CFIProtectionGoodAndBadPaths) { if (!SuccessfullyInitialised) return; - Analysis.parseSectionContents( + Analysis->parseSectionContents( { 0xeb, 0x02, // 0: jmp 4 [+2] 0x75, 0x02, // 2: jne 6 [+2] @@ -611,13 +643,13 @@ 0x0f, 0x0b, // 6: ud2 }, 0xDEADBEEF); - EXPECT_FALSE(Analysis.isIndirectInstructionCFIProtected(0xDEADBEEF + 4)); + EXPECT_FALSE(Analysis->isIndirectInstructionCFIProtected(0xDEADBEEF + 4)); } TEST_F(BasicFileAnalysisTest, CFIProtectionWithUnconditionalJumpInFallthrough) { if (!SuccessfullyInitialised) return; - Analysis.parseSectionContents( + Analysis->parseSectionContents( { 0x75, 0x04, // 0: jne 6 [+4] 0xeb, 0x00, // 2: jmp 4 [+0] @@ -625,7 +657,7 @@ 0x0f, 0x0b, // 6: ud2 }, 0xDEADBEEF); - EXPECT_TRUE(Analysis.isIndirectInstructionCFIProtected(0xDEADBEEF + 4)); + EXPECT_TRUE(Analysis->isIndirectInstructionCFIProtected(0xDEADBEEF + 4)); } TEST_F(BasicFileAnalysisTest, CFIProtectionComplexExample) { @@ -633,7 +665,7 @@ return; // See unittests/GraphBuilder.cpp::BuildFlowGraphComplexExample for this // graph. - Analysis.parseSectionContents( + Analysis->parseSectionContents( { 0x75, 0x12, // 0: jne 20 [+18] 0xeb, 0x03, // 2: jmp 7 [+3] @@ -650,7 +682,48 @@ 0x0f, 0x0b, // 22: ud2 }, 0xDEADBEEF); - EXPECT_FALSE(Analysis.isIndirectInstructionCFIProtected(0xDEADBEEF + 9)); + EXPECT_FALSE(Analysis->isIndirectInstructionCFIProtected(0xDEADBEEF + 9)); +} + +TEST_F(DebugInfoFileAnalysisTest, LineTableExclusionTests) { + if (!SuccessfullyInitialised) + return; + DebugAnalysis->AddValidLines({0xDEADBEEF, 0xDEADBEEF + 2, 0xDEADBEEF + 4}); + Analysis->parseSectionContents( + { + 0x75, 0x02, // 0: jne 4 [+2] + 0xff, 0x10, // 2: callq *(%rax) + 0x0f, 0x0b, // 4: ud2 + }, + 0xDEADBEEF); + + Analysis->parseSectionContents( + { + 0x75, 0x02, // 0: jne 4 [+2] + 0xff, 0x10, // 2: callq *(%rax) + 0x0f, 0x0b, // 4: ud2 + }, + 0xDEADC0DE); + + EXPECT_TRUE(Analysis->hasValidLineInfoForAddressRange(0xDEADBEEF)); + EXPECT_TRUE(Analysis->hasValidLineInfoForAddressRange(0xDEADBEEF + 2)); + EXPECT_TRUE(Analysis->hasValidLineInfoForAddressRange(0xDEADBEEF + 4)); + + EXPECT_FALSE(Analysis->hasValidLineInfoForAddressRange(0xDEADC0DE)); + EXPECT_FALSE(Analysis->hasValidLineInfoForAddressRange(0xDEADC0DE + 2)); + EXPECT_FALSE(Analysis->hasValidLineInfoForAddressRange(0xDEADC0DE + 4)); + + EXPECT_NE(nullptr, Analysis->getInstruction(0xDEADBEEF)); + EXPECT_NE(nullptr, Analysis->getInstruction(0xDEADBEEF + 2)); + EXPECT_NE(nullptr, Analysis->getInstruction(0xDEADBEEF + 4)); + + EXPECT_EQ(nullptr, Analysis->getInstruction(0xDEADC0DE)); + EXPECT_EQ(nullptr, Analysis->getInstruction(0xDEADC0DE + 2)); + EXPECT_EQ(nullptr, Analysis->getInstruction(0xDEADC0DE + 4)); + + EXPECT_TRUE(Analysis->isIndirectInstructionCFIProtected(0xDEADBEEF + 2)); + + EXPECT_FALSE(Analysis->isIndirectInstructionCFIProtected(0xDEADC0DE + 2)); } } // anonymous namespace