189c3c8c4SVlad Tsyrklevich //===- FileAnalysis.cpp -----------------------------------------*- C++ -*-===//
289c3c8c4SVlad Tsyrklevich //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
689c3c8c4SVlad Tsyrklevich //
789c3c8c4SVlad Tsyrklevich //===----------------------------------------------------------------------===//
889c3c8c4SVlad Tsyrklevich
989c3c8c4SVlad Tsyrklevich #include "FileAnalysis.h"
105ff01cdcSMitch Phillips #include "GraphBuilder.h"
1189c3c8c4SVlad Tsyrklevich
1289c3c8c4SVlad Tsyrklevich #include "llvm/BinaryFormat/ELF.h"
137db6f7a3SMitch Phillips #include "llvm/DebugInfo/DWARF/DWARFContext.h"
14*db29f437Sserge-sans-paille #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
1589c3c8c4SVlad Tsyrklevich #include "llvm/MC/MCAsmInfo.h"
1689c3c8c4SVlad Tsyrklevich #include "llvm/MC/MCContext.h"
1789c3c8c4SVlad Tsyrklevich #include "llvm/MC/MCDisassembler/MCDisassembler.h"
1889c3c8c4SVlad Tsyrklevich #include "llvm/MC/MCInst.h"
1989c3c8c4SVlad Tsyrklevich #include "llvm/MC/MCInstPrinter.h"
2089c3c8c4SVlad Tsyrklevich #include "llvm/MC/MCInstrAnalysis.h"
2189c3c8c4SVlad Tsyrklevich #include "llvm/MC/MCInstrDesc.h"
2289c3c8c4SVlad Tsyrklevich #include "llvm/MC/MCInstrInfo.h"
2389c3c8c4SVlad Tsyrklevich #include "llvm/MC/MCObjectFileInfo.h"
2489c3c8c4SVlad Tsyrklevich #include "llvm/MC/MCRegisterInfo.h"
2589c3c8c4SVlad Tsyrklevich #include "llvm/MC/MCSubtargetInfo.h"
264b63ca13SMirko Brkusanin #include "llvm/MC/MCTargetOptions.h"
2789b57061SReid Kleckner #include "llvm/MC/TargetRegistry.h"
2889c3c8c4SVlad Tsyrklevich #include "llvm/Object/Binary.h"
2989c3c8c4SVlad Tsyrklevich #include "llvm/Object/COFF.h"
3089c3c8c4SVlad Tsyrklevich #include "llvm/Object/ELFObjectFile.h"
3189c3c8c4SVlad Tsyrklevich #include "llvm/Object/ObjectFile.h"
3289c3c8c4SVlad Tsyrklevich #include "llvm/Support/Casting.h"
3389c3c8c4SVlad Tsyrklevich #include "llvm/Support/CommandLine.h"
3489c3c8c4SVlad Tsyrklevich #include "llvm/Support/Error.h"
3589c3c8c4SVlad Tsyrklevich #include "llvm/Support/MemoryBuffer.h"
3689c3c8c4SVlad Tsyrklevich #include "llvm/Support/TargetSelect.h"
3789c3c8c4SVlad Tsyrklevich #include "llvm/Support/raw_ostream.h"
3889c3c8c4SVlad Tsyrklevich
3989c3c8c4SVlad Tsyrklevich using Instr = llvm::cfi_verify::FileAnalysis::Instr;
40c15bdf55SMitch Phillips using LLVMSymbolizer = llvm::symbolize::LLVMSymbolizer;
4189c3c8c4SVlad Tsyrklevich
4289c3c8c4SVlad Tsyrklevich namespace llvm {
4389c3c8c4SVlad Tsyrklevich namespace cfi_verify {
4489c3c8c4SVlad Tsyrklevich
45c15bdf55SMitch Phillips bool IgnoreDWARFFlag;
46c15bdf55SMitch Phillips
47c15bdf55SMitch Phillips static cl::opt<bool, true> IgnoreDWARFArg(
487db6f7a3SMitch Phillips "ignore-dwarf",
497db6f7a3SMitch Phillips cl::desc(
507db6f7a3SMitch Phillips "Ignore all DWARF data. This relaxes the requirements for all "
517db6f7a3SMitch Phillips "statically linked libraries to have been compiled with '-g', but "
527db6f7a3SMitch Phillips "will result in false positives for 'CFI unprotected' instructions."),
53c15bdf55SMitch Phillips cl::location(IgnoreDWARFFlag), cl::init(false));
547db6f7a3SMitch Phillips
stringCFIProtectionStatus(CFIProtectionStatus Status)553b9ea32eSMitch Phillips StringRef stringCFIProtectionStatus(CFIProtectionStatus Status) {
563b9ea32eSMitch Phillips switch (Status) {
573b9ea32eSMitch Phillips case CFIProtectionStatus::PROTECTED:
583b9ea32eSMitch Phillips return "PROTECTED";
593b9ea32eSMitch Phillips case CFIProtectionStatus::FAIL_NOT_INDIRECT_CF:
603b9ea32eSMitch Phillips return "FAIL_NOT_INDIRECT_CF";
613b9ea32eSMitch Phillips case CFIProtectionStatus::FAIL_ORPHANS:
623b9ea32eSMitch Phillips return "FAIL_ORPHANS";
633b9ea32eSMitch Phillips case CFIProtectionStatus::FAIL_BAD_CONDITIONAL_BRANCH:
643b9ea32eSMitch Phillips return "FAIL_BAD_CONDITIONAL_BRANCH";
652e7be2a6SMitch Phillips case CFIProtectionStatus::FAIL_REGISTER_CLOBBERED:
662e7be2a6SMitch Phillips return "FAIL_REGISTER_CLOBBERED";
673b9ea32eSMitch Phillips case CFIProtectionStatus::FAIL_INVALID_INSTRUCTION:
683b9ea32eSMitch Phillips return "FAIL_INVALID_INSTRUCTION";
693b9ea32eSMitch Phillips }
703b9ea32eSMitch Phillips llvm_unreachable("Attempted to stringify an unknown enum value.");
713b9ea32eSMitch Phillips }
723b9ea32eSMitch Phillips
Create(StringRef Filename)7389c3c8c4SVlad Tsyrklevich Expected<FileAnalysis> FileAnalysis::Create(StringRef Filename) {
7489c3c8c4SVlad Tsyrklevich // Open the filename provided.
7589c3c8c4SVlad Tsyrklevich Expected<object::OwningBinary<object::Binary>> BinaryOrErr =
7689c3c8c4SVlad Tsyrklevich object::createBinary(Filename);
7789c3c8c4SVlad Tsyrklevich if (!BinaryOrErr)
7889c3c8c4SVlad Tsyrklevich return BinaryOrErr.takeError();
7989c3c8c4SVlad Tsyrklevich
8089c3c8c4SVlad Tsyrklevich // Construct the object and allow it to take ownership of the binary.
8189c3c8c4SVlad Tsyrklevich object::OwningBinary<object::Binary> Binary = std::move(BinaryOrErr.get());
8289c3c8c4SVlad Tsyrklevich FileAnalysis Analysis(std::move(Binary));
8389c3c8c4SVlad Tsyrklevich
8489c3c8c4SVlad Tsyrklevich Analysis.Object = dyn_cast<object::ObjectFile>(Analysis.Binary.getBinary());
8589c3c8c4SVlad Tsyrklevich if (!Analysis.Object)
86d9af383dSMitch Phillips return make_error<UnsupportedDisassembly>("Failed to cast object");
8789c3c8c4SVlad Tsyrklevich
884099b249SJoel Galenson switch (Analysis.Object->getArch()) {
894099b249SJoel Galenson case Triple::x86:
904099b249SJoel Galenson case Triple::x86_64:
914099b249SJoel Galenson case Triple::aarch64:
924099b249SJoel Galenson case Triple::aarch64_be:
934099b249SJoel Galenson break;
944099b249SJoel Galenson default:
954099b249SJoel Galenson return make_error<UnsupportedDisassembly>("Unsupported architecture.");
964099b249SJoel Galenson }
974099b249SJoel Galenson
9889c3c8c4SVlad Tsyrklevich Analysis.ObjectTriple = Analysis.Object->makeTriple();
9989c3c8c4SVlad Tsyrklevich Analysis.Features = Analysis.Object->getFeatures();
10089c3c8c4SVlad Tsyrklevich
10189c3c8c4SVlad Tsyrklevich // Init the rest of the object.
10289c3c8c4SVlad Tsyrklevich if (auto InitResponse = Analysis.initialiseDisassemblyMembers())
103c55cf4afSBill Wendling return std::move(InitResponse);
10489c3c8c4SVlad Tsyrklevich
10589c3c8c4SVlad Tsyrklevich if (auto SectionParseResponse = Analysis.parseCodeSections())
106c55cf4afSBill Wendling return std::move(SectionParseResponse);
10789c3c8c4SVlad Tsyrklevich
1086cc0e63eSJoel Galenson if (auto SymbolTableParseResponse = Analysis.parseSymbolTable())
109c55cf4afSBill Wendling return std::move(SymbolTableParseResponse);
1106cc0e63eSJoel Galenson
111c55cf4afSBill Wendling return std::move(Analysis);
11289c3c8c4SVlad Tsyrklevich }
11389c3c8c4SVlad Tsyrklevich
FileAnalysis(object::OwningBinary<object::Binary> Binary)11489c3c8c4SVlad Tsyrklevich FileAnalysis::FileAnalysis(object::OwningBinary<object::Binary> Binary)
11589c3c8c4SVlad Tsyrklevich : Binary(std::move(Binary)) {}
11689c3c8c4SVlad Tsyrklevich
FileAnalysis(const Triple & ObjectTriple,const SubtargetFeatures & Features)11789c3c8c4SVlad Tsyrklevich FileAnalysis::FileAnalysis(const Triple &ObjectTriple,
11889c3c8c4SVlad Tsyrklevich const SubtargetFeatures &Features)
11989c3c8c4SVlad Tsyrklevich : ObjectTriple(ObjectTriple), Features(Features) {}
12089c3c8c4SVlad Tsyrklevich
12189c3c8c4SVlad Tsyrklevich const Instr *
getPrevInstructionSequential(const Instr & InstrMeta) const12289c3c8c4SVlad Tsyrklevich FileAnalysis::getPrevInstructionSequential(const Instr &InstrMeta) const {
12389c3c8c4SVlad Tsyrklevich std::map<uint64_t, Instr>::const_iterator KV =
12489c3c8c4SVlad Tsyrklevich Instructions.find(InstrMeta.VMAddress);
12589c3c8c4SVlad Tsyrklevich if (KV == Instructions.end() || KV == Instructions.begin())
12689c3c8c4SVlad Tsyrklevich return nullptr;
12789c3c8c4SVlad Tsyrklevich
12889c3c8c4SVlad Tsyrklevich if (!(--KV)->second.Valid)
12989c3c8c4SVlad Tsyrklevich return nullptr;
13089c3c8c4SVlad Tsyrklevich
13189c3c8c4SVlad Tsyrklevich return &KV->second;
13289c3c8c4SVlad Tsyrklevich }
13389c3c8c4SVlad Tsyrklevich
13489c3c8c4SVlad Tsyrklevich const Instr *
getNextInstructionSequential(const Instr & InstrMeta) const13589c3c8c4SVlad Tsyrklevich FileAnalysis::getNextInstructionSequential(const Instr &InstrMeta) const {
13689c3c8c4SVlad Tsyrklevich std::map<uint64_t, Instr>::const_iterator KV =
13789c3c8c4SVlad Tsyrklevich Instructions.find(InstrMeta.VMAddress);
13889c3c8c4SVlad Tsyrklevich if (KV == Instructions.end() || ++KV == Instructions.end())
13989c3c8c4SVlad Tsyrklevich return nullptr;
14089c3c8c4SVlad Tsyrklevich
14189c3c8c4SVlad Tsyrklevich if (!KV->second.Valid)
14289c3c8c4SVlad Tsyrklevich return nullptr;
14389c3c8c4SVlad Tsyrklevich
14489c3c8c4SVlad Tsyrklevich return &KV->second;
14589c3c8c4SVlad Tsyrklevich }
14689c3c8c4SVlad Tsyrklevich
usesRegisterOperand(const Instr & InstrMeta) const14789c3c8c4SVlad Tsyrklevich bool FileAnalysis::usesRegisterOperand(const Instr &InstrMeta) const {
14889c3c8c4SVlad Tsyrklevich for (const auto &Operand : InstrMeta.Instruction) {
14989c3c8c4SVlad Tsyrklevich if (Operand.isReg())
15089c3c8c4SVlad Tsyrklevich return true;
15189c3c8c4SVlad Tsyrklevich }
15289c3c8c4SVlad Tsyrklevich return false;
15389c3c8c4SVlad Tsyrklevich }
15489c3c8c4SVlad Tsyrklevich
getInstruction(uint64_t Address) const15589c3c8c4SVlad Tsyrklevich const Instr *FileAnalysis::getInstruction(uint64_t Address) const {
15689c3c8c4SVlad Tsyrklevich const auto &InstrKV = Instructions.find(Address);
15789c3c8c4SVlad Tsyrklevich if (InstrKV == Instructions.end())
15889c3c8c4SVlad Tsyrklevich return nullptr;
15989c3c8c4SVlad Tsyrklevich
16089c3c8c4SVlad Tsyrklevich return &InstrKV->second;
16189c3c8c4SVlad Tsyrklevich }
16289c3c8c4SVlad Tsyrklevich
getInstructionOrDie(uint64_t Address) const16389c3c8c4SVlad Tsyrklevich const Instr &FileAnalysis::getInstructionOrDie(uint64_t Address) const {
16489c3c8c4SVlad Tsyrklevich const auto &InstrKV = Instructions.find(Address);
16589c3c8c4SVlad Tsyrklevich assert(InstrKV != Instructions.end() && "Address doesn't exist.");
16689c3c8c4SVlad Tsyrklevich return InstrKV->second;
16789c3c8c4SVlad Tsyrklevich }
16889c3c8c4SVlad Tsyrklevich
isCFITrap(const Instr & InstrMeta) const1690ee26324SVlad Tsyrklevich bool FileAnalysis::isCFITrap(const Instr &InstrMeta) const {
17006e7e579SJoel Galenson const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
1716cc0e63eSJoel Galenson return InstrDesc.isTrap() || willTrapOnCFIViolation(InstrMeta);
1726cc0e63eSJoel Galenson }
1736cc0e63eSJoel Galenson
willTrapOnCFIViolation(const Instr & InstrMeta) const1746cc0e63eSJoel Galenson bool FileAnalysis::willTrapOnCFIViolation(const Instr &InstrMeta) const {
1756cc0e63eSJoel Galenson const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
1766cc0e63eSJoel Galenson if (!InstrDesc.isCall())
1776cc0e63eSJoel Galenson return false;
1786cc0e63eSJoel Galenson uint64_t Target;
1796cc0e63eSJoel Galenson if (!MIA->evaluateBranch(InstrMeta.Instruction, InstrMeta.VMAddress,
1806cc0e63eSJoel Galenson InstrMeta.InstructionSize, Target))
1816cc0e63eSJoel Galenson return false;
1828590a3e3SKazu Hirata return TrapOnFailFunctionAddresses.contains(Target);
1830ee26324SVlad Tsyrklevich }
1840ee26324SVlad Tsyrklevich
canFallThrough(const Instr & InstrMeta) const1850ee26324SVlad Tsyrklevich bool FileAnalysis::canFallThrough(const Instr &InstrMeta) const {
1860ee26324SVlad Tsyrklevich if (!InstrMeta.Valid)
1870ee26324SVlad Tsyrklevich return false;
1880ee26324SVlad Tsyrklevich
1890ee26324SVlad Tsyrklevich if (isCFITrap(InstrMeta))
1900ee26324SVlad Tsyrklevich return false;
1910ee26324SVlad Tsyrklevich
1920ee26324SVlad Tsyrklevich const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
1930ee26324SVlad Tsyrklevich if (InstrDesc.mayAffectControlFlow(InstrMeta.Instruction, *RegisterInfo))
1940ee26324SVlad Tsyrklevich return InstrDesc.isConditionalBranch();
1950ee26324SVlad Tsyrklevich
1960ee26324SVlad Tsyrklevich return true;
1970ee26324SVlad Tsyrklevich }
1980ee26324SVlad Tsyrklevich
1990ee26324SVlad Tsyrklevich const Instr *
getDefiniteNextInstruction(const Instr & InstrMeta) const2000ee26324SVlad Tsyrklevich FileAnalysis::getDefiniteNextInstruction(const Instr &InstrMeta) const {
2010ee26324SVlad Tsyrklevich if (!InstrMeta.Valid)
2020ee26324SVlad Tsyrklevich return nullptr;
2030ee26324SVlad Tsyrklevich
2040ee26324SVlad Tsyrklevich if (isCFITrap(InstrMeta))
2050ee26324SVlad Tsyrklevich return nullptr;
2060ee26324SVlad Tsyrklevich
2070ee26324SVlad Tsyrklevich const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
2080ee26324SVlad Tsyrklevich const Instr *NextMetaPtr;
2090ee26324SVlad Tsyrklevich if (InstrDesc.mayAffectControlFlow(InstrMeta.Instruction, *RegisterInfo)) {
2100ee26324SVlad Tsyrklevich if (InstrDesc.isConditionalBranch())
2110ee26324SVlad Tsyrklevich return nullptr;
2120ee26324SVlad Tsyrklevich
2130ee26324SVlad Tsyrklevich uint64_t Target;
2140ee26324SVlad Tsyrklevich if (!MIA->evaluateBranch(InstrMeta.Instruction, InstrMeta.VMAddress,
2150ee26324SVlad Tsyrklevich InstrMeta.InstructionSize, Target))
2160ee26324SVlad Tsyrklevich return nullptr;
2170ee26324SVlad Tsyrklevich
2180ee26324SVlad Tsyrklevich NextMetaPtr = getInstruction(Target);
2190ee26324SVlad Tsyrklevich } else {
2200ee26324SVlad Tsyrklevich NextMetaPtr =
2210ee26324SVlad Tsyrklevich getInstruction(InstrMeta.VMAddress + InstrMeta.InstructionSize);
2220ee26324SVlad Tsyrklevich }
2230ee26324SVlad Tsyrklevich
2240ee26324SVlad Tsyrklevich if (!NextMetaPtr || !NextMetaPtr->Valid)
2250ee26324SVlad Tsyrklevich return nullptr;
2260ee26324SVlad Tsyrklevich
2270ee26324SVlad Tsyrklevich return NextMetaPtr;
2280ee26324SVlad Tsyrklevich }
2290ee26324SVlad Tsyrklevich
2300ee26324SVlad Tsyrklevich std::set<const Instr *>
getDirectControlFlowXRefs(const Instr & InstrMeta) const2310ee26324SVlad Tsyrklevich FileAnalysis::getDirectControlFlowXRefs(const Instr &InstrMeta) const {
2320ee26324SVlad Tsyrklevich std::set<const Instr *> CFCrossReferences;
2330ee26324SVlad Tsyrklevich const Instr *PrevInstruction = getPrevInstructionSequential(InstrMeta);
2340ee26324SVlad Tsyrklevich
2350ee26324SVlad Tsyrklevich if (PrevInstruction && canFallThrough(*PrevInstruction))
2360ee26324SVlad Tsyrklevich CFCrossReferences.insert(PrevInstruction);
2370ee26324SVlad Tsyrklevich
2380ee26324SVlad Tsyrklevich const auto &TargetRefsKV = StaticBranchTargetings.find(InstrMeta.VMAddress);
2390ee26324SVlad Tsyrklevich if (TargetRefsKV == StaticBranchTargetings.end())
2400ee26324SVlad Tsyrklevich return CFCrossReferences;
2410ee26324SVlad Tsyrklevich
2420ee26324SVlad Tsyrklevich for (uint64_t SourceInstrAddress : TargetRefsKV->second) {
2430ee26324SVlad Tsyrklevich const auto &SourceInstrKV = Instructions.find(SourceInstrAddress);
2440ee26324SVlad Tsyrklevich if (SourceInstrKV == Instructions.end()) {
2450ee26324SVlad Tsyrklevich errs() << "Failed to find source instruction at address "
2460ee26324SVlad Tsyrklevich << format_hex(SourceInstrAddress, 2)
2470ee26324SVlad Tsyrklevich << " for the cross-reference to instruction at address "
2480ee26324SVlad Tsyrklevich << format_hex(InstrMeta.VMAddress, 2) << ".\n";
2490ee26324SVlad Tsyrklevich continue;
2500ee26324SVlad Tsyrklevich }
2510ee26324SVlad Tsyrklevich
2520ee26324SVlad Tsyrklevich CFCrossReferences.insert(&SourceInstrKV->second);
2530ee26324SVlad Tsyrklevich }
2540ee26324SVlad Tsyrklevich
2550ee26324SVlad Tsyrklevich return CFCrossReferences;
2560ee26324SVlad Tsyrklevich }
2570ee26324SVlad Tsyrklevich
25877fc1f60SAlexey Lapshin const std::set<object::SectionedAddress> &
getIndirectInstructions() const25977fc1f60SAlexey Lapshin FileAnalysis::getIndirectInstructions() const {
26089c3c8c4SVlad Tsyrklevich return IndirectInstructions;
26189c3c8c4SVlad Tsyrklevich }
26289c3c8c4SVlad Tsyrklevich
getRegisterInfo() const26389c3c8c4SVlad Tsyrklevich const MCRegisterInfo *FileAnalysis::getRegisterInfo() const {
26489c3c8c4SVlad Tsyrklevich return RegisterInfo.get();
26589c3c8c4SVlad Tsyrklevich }
26689c3c8c4SVlad Tsyrklevich
getMCInstrInfo() const26789c3c8c4SVlad Tsyrklevich const MCInstrInfo *FileAnalysis::getMCInstrInfo() const { return MII.get(); }
26889c3c8c4SVlad Tsyrklevich
getMCInstrAnalysis() const26989c3c8c4SVlad Tsyrklevich const MCInstrAnalysis *FileAnalysis::getMCInstrAnalysis() const {
27089c3c8c4SVlad Tsyrklevich return MIA.get();
27189c3c8c4SVlad Tsyrklevich }
27289c3c8c4SVlad Tsyrklevich
27377fc1f60SAlexey Lapshin Expected<DIInliningInfo>
symbolizeInlinedCode(object::SectionedAddress Address)27477fc1f60SAlexey Lapshin FileAnalysis::symbolizeInlinedCode(object::SectionedAddress Address) {
2753b9ea32eSMitch Phillips assert(Symbolizer != nullptr && "Symbolizer is invalid.");
27677fc1f60SAlexey Lapshin
277adcd0268SBenjamin Kramer return Symbolizer->symbolizeInlinedCode(std::string(Object->getFileName()),
278adcd0268SBenjamin Kramer Address);
2793b9ea32eSMitch Phillips }
2803b9ea32eSMitch Phillips
2813b9ea32eSMitch Phillips CFIProtectionStatus
validateCFIProtection(const GraphResult & Graph) const2823b9ea32eSMitch Phillips FileAnalysis::validateCFIProtection(const GraphResult &Graph) const {
2833b9ea32eSMitch Phillips const Instr *InstrMetaPtr = getInstruction(Graph.BaseAddress);
2843b9ea32eSMitch Phillips if (!InstrMetaPtr)
2853b9ea32eSMitch Phillips return CFIProtectionStatus::FAIL_INVALID_INSTRUCTION;
2863b9ea32eSMitch Phillips
2873b9ea32eSMitch Phillips const auto &InstrDesc = MII->get(InstrMetaPtr->Instruction.getOpcode());
2883b9ea32eSMitch Phillips if (!InstrDesc.mayAffectControlFlow(InstrMetaPtr->Instruction, *RegisterInfo))
2893b9ea32eSMitch Phillips return CFIProtectionStatus::FAIL_NOT_INDIRECT_CF;
2903b9ea32eSMitch Phillips
2913b9ea32eSMitch Phillips if (!usesRegisterOperand(*InstrMetaPtr))
2923b9ea32eSMitch Phillips return CFIProtectionStatus::FAIL_NOT_INDIRECT_CF;
2933b9ea32eSMitch Phillips
2943b9ea32eSMitch Phillips if (!Graph.OrphanedNodes.empty())
2953b9ea32eSMitch Phillips return CFIProtectionStatus::FAIL_ORPHANS;
2963b9ea32eSMitch Phillips
2973b9ea32eSMitch Phillips for (const auto &BranchNode : Graph.ConditionalBranchNodes) {
2983b9ea32eSMitch Phillips if (!BranchNode.CFIProtection)
2993b9ea32eSMitch Phillips return CFIProtectionStatus::FAIL_BAD_CONDITIONAL_BRANCH;
3003b9ea32eSMitch Phillips }
3013b9ea32eSMitch Phillips
3022e7be2a6SMitch Phillips if (indirectCFOperandClobber(Graph) != Graph.BaseAddress)
3032e7be2a6SMitch Phillips return CFIProtectionStatus::FAIL_REGISTER_CLOBBERED;
3042e7be2a6SMitch Phillips
3053b9ea32eSMitch Phillips return CFIProtectionStatus::PROTECTED;
3063b9ea32eSMitch Phillips }
307c15bdf55SMitch Phillips
indirectCFOperandClobber(const GraphResult & Graph) const3082e7be2a6SMitch Phillips uint64_t FileAnalysis::indirectCFOperandClobber(const GraphResult &Graph) const {
3092e7be2a6SMitch Phillips assert(Graph.OrphanedNodes.empty() && "Orphaned nodes should be empty.");
3102e7be2a6SMitch Phillips
3112e7be2a6SMitch Phillips // Get the set of registers we must check to ensure they're not clobbered.
3122e7be2a6SMitch Phillips const Instr &IndirectCF = getInstructionOrDie(Graph.BaseAddress);
3132e7be2a6SMitch Phillips DenseSet<unsigned> RegisterNumbers;
3142e7be2a6SMitch Phillips for (const auto &Operand : IndirectCF.Instruction) {
3152e7be2a6SMitch Phillips if (Operand.isReg())
3162e7be2a6SMitch Phillips RegisterNumbers.insert(Operand.getReg());
3172e7be2a6SMitch Phillips }
3182e7be2a6SMitch Phillips assert(RegisterNumbers.size() && "Zero register operands on indirect CF.");
3192e7be2a6SMitch Phillips
3202e7be2a6SMitch Phillips // Now check all branches to indirect CFs and ensure no clobbering happens.
3212e7be2a6SMitch Phillips for (const auto &Branch : Graph.ConditionalBranchNodes) {
3222e7be2a6SMitch Phillips uint64_t Node;
3232e7be2a6SMitch Phillips if (Branch.IndirectCFIsOnTargetPath)
3242e7be2a6SMitch Phillips Node = Branch.Target;
3252e7be2a6SMitch Phillips else
3262e7be2a6SMitch Phillips Node = Branch.Fallthrough;
3272e7be2a6SMitch Phillips
32806e7e579SJoel Galenson // Some architectures (e.g., AArch64) cannot load in an indirect branch, so
32906e7e579SJoel Galenson // we allow them one load.
33006e7e579SJoel Galenson bool canLoad = !MII->get(IndirectCF.Instruction.getOpcode()).mayLoad();
33106e7e579SJoel Galenson
33206e7e579SJoel Galenson // We walk backwards from the indirect CF. It is the last node returned by
33306e7e579SJoel Galenson // Graph.flattenAddress, so we skip it since we already handled it.
33406e7e579SJoel Galenson DenseSet<unsigned> CurRegisterNumbers = RegisterNumbers;
33506e7e579SJoel Galenson std::vector<uint64_t> Nodes = Graph.flattenAddress(Node);
33606e7e579SJoel Galenson for (auto I = Nodes.rbegin() + 1, E = Nodes.rend(); I != E; ++I) {
33706e7e579SJoel Galenson Node = *I;
3382e7be2a6SMitch Phillips const Instr &NodeInstr = getInstructionOrDie(Node);
3392e7be2a6SMitch Phillips const auto &InstrDesc = MII->get(NodeInstr.Instruction.getOpcode());
3402e7be2a6SMitch Phillips
34106e7e579SJoel Galenson for (auto RI = CurRegisterNumbers.begin(), RE = CurRegisterNumbers.end();
34206e7e579SJoel Galenson RI != RE; ++RI) {
34306e7e579SJoel Galenson unsigned RegNum = *RI;
3442e7be2a6SMitch Phillips if (InstrDesc.hasDefOfPhysReg(NodeInstr.Instruction, RegNum,
34506e7e579SJoel Galenson *RegisterInfo)) {
34606e7e579SJoel Galenson if (!canLoad || !InstrDesc.mayLoad())
3472e7be2a6SMitch Phillips return Node;
34806e7e579SJoel Galenson canLoad = false;
34906e7e579SJoel Galenson CurRegisterNumbers.erase(RI);
35006e7e579SJoel Galenson // Add the registers this load reads to those we check for clobbers.
35106e7e579SJoel Galenson for (unsigned i = InstrDesc.getNumDefs(),
35206e7e579SJoel Galenson e = InstrDesc.getNumOperands(); i != e; i++) {
353dd073e08SNathan Sidwell const auto &Operand = NodeInstr.Instruction.getOperand(i);
35406e7e579SJoel Galenson if (Operand.isReg())
35506e7e579SJoel Galenson CurRegisterNumbers.insert(Operand.getReg());
3562e7be2a6SMitch Phillips }
35706e7e579SJoel Galenson break;
35806e7e579SJoel Galenson }
35906e7e579SJoel Galenson }
3602e7be2a6SMitch Phillips }
3612e7be2a6SMitch Phillips }
3622e7be2a6SMitch Phillips
3632e7be2a6SMitch Phillips return Graph.BaseAddress;
3642e7be2a6SMitch Phillips }
3652e7be2a6SMitch Phillips
printInstruction(const Instr & InstrMeta,raw_ostream & OS) const36602993892SMitch Phillips void FileAnalysis::printInstruction(const Instr &InstrMeta,
36702993892SMitch Phillips raw_ostream &OS) const {
368aa708763SFangrui Song Printer->printInst(&InstrMeta.Instruction, 0, "", *SubtargetInfo.get(), OS);
36902993892SMitch Phillips }
37002993892SMitch Phillips
initialiseDisassemblyMembers()37189c3c8c4SVlad Tsyrklevich Error FileAnalysis::initialiseDisassemblyMembers() {
37289c3c8c4SVlad Tsyrklevich std::string TripleName = ObjectTriple.getTriple();
37389c3c8c4SVlad Tsyrklevich ArchName = "";
37489c3c8c4SVlad Tsyrklevich MCPU = "";
37589c3c8c4SVlad Tsyrklevich std::string ErrorString;
37689c3c8c4SVlad Tsyrklevich
3774f30a3d3SFangrui Song LLVMSymbolizer::Options Opt;
3784f30a3d3SFangrui Song Opt.UseSymbolTable = false;
3794f30a3d3SFangrui Song Symbolizer.reset(new LLVMSymbolizer(Opt));
380c15bdf55SMitch Phillips
38189c3c8c4SVlad Tsyrklevich ObjectTarget =
38289c3c8c4SVlad Tsyrklevich TargetRegistry::lookupTarget(ArchName, ObjectTriple, ErrorString);
38389c3c8c4SVlad Tsyrklevich if (!ObjectTarget)
384d9af383dSMitch Phillips return make_error<UnsupportedDisassembly>(
385d9af383dSMitch Phillips (Twine("Couldn't find target \"") + ObjectTriple.getTriple() +
3865ff01cdcSMitch Phillips "\", failed with error: " + ErrorString)
3875ff01cdcSMitch Phillips .str());
38889c3c8c4SVlad Tsyrklevich
38989c3c8c4SVlad Tsyrklevich RegisterInfo.reset(ObjectTarget->createMCRegInfo(TripleName));
39089c3c8c4SVlad Tsyrklevich if (!RegisterInfo)
391d9af383dSMitch Phillips return make_error<UnsupportedDisassembly>(
392d9af383dSMitch Phillips "Failed to initialise RegisterInfo.");
39389c3c8c4SVlad Tsyrklevich
3944b63ca13SMirko Brkusanin MCTargetOptions MCOptions;
3954b63ca13SMirko Brkusanin AsmInfo.reset(
3964b63ca13SMirko Brkusanin ObjectTarget->createMCAsmInfo(*RegisterInfo, TripleName, MCOptions));
39789c3c8c4SVlad Tsyrklevich if (!AsmInfo)
398d9af383dSMitch Phillips return make_error<UnsupportedDisassembly>("Failed to initialise AsmInfo.");
39989c3c8c4SVlad Tsyrklevich
40089c3c8c4SVlad Tsyrklevich SubtargetInfo.reset(ObjectTarget->createMCSubtargetInfo(
40189c3c8c4SVlad Tsyrklevich TripleName, MCPU, Features.getString()));
40289c3c8c4SVlad Tsyrklevich if (!SubtargetInfo)
403d9af383dSMitch Phillips return make_error<UnsupportedDisassembly>(
404d9af383dSMitch Phillips "Failed to initialise SubtargetInfo.");
40589c3c8c4SVlad Tsyrklevich
40689c3c8c4SVlad Tsyrklevich MII.reset(ObjectTarget->createMCInstrInfo());
40789c3c8c4SVlad Tsyrklevich if (!MII)
408d9af383dSMitch Phillips return make_error<UnsupportedDisassembly>("Failed to initialise MII.");
40989c3c8c4SVlad Tsyrklevich
410632ebc4aSPhilipp Krones Context.reset(new MCContext(Triple(TripleName), AsmInfo.get(),
411c2f819afSPhilipp Krones RegisterInfo.get(), SubtargetInfo.get()));
41289c3c8c4SVlad Tsyrklevich
41389c3c8c4SVlad Tsyrklevich Disassembler.reset(
41489c3c8c4SVlad Tsyrklevich ObjectTarget->createMCDisassembler(*SubtargetInfo, *Context));
41589c3c8c4SVlad Tsyrklevich
41689c3c8c4SVlad Tsyrklevich if (!Disassembler)
417d9af383dSMitch Phillips return make_error<UnsupportedDisassembly>(
418d9af383dSMitch Phillips "No disassembler available for target");
41989c3c8c4SVlad Tsyrklevich
42089c3c8c4SVlad Tsyrklevich MIA.reset(ObjectTarget->createMCInstrAnalysis(MII.get()));
42189c3c8c4SVlad Tsyrklevich
42289c3c8c4SVlad Tsyrklevich Printer.reset(ObjectTarget->createMCInstPrinter(
42389c3c8c4SVlad Tsyrklevich ObjectTriple, AsmInfo->getAssemblerDialect(), *AsmInfo, *MII,
42489c3c8c4SVlad Tsyrklevich *RegisterInfo));
42589c3c8c4SVlad Tsyrklevich
42689c3c8c4SVlad Tsyrklevich return Error::success();
42789c3c8c4SVlad Tsyrklevich }
42889c3c8c4SVlad Tsyrklevich
parseCodeSections()42989c3c8c4SVlad Tsyrklevich Error FileAnalysis::parseCodeSections() {
430c15bdf55SMitch Phillips if (!IgnoreDWARFFlag) {
431c15bdf55SMitch Phillips std::unique_ptr<DWARFContext> DWARF = DWARFContext::create(*Object);
4327db6f7a3SMitch Phillips if (!DWARF)
4337db6f7a3SMitch Phillips return make_error<StringError>("Could not create DWARF information.",
4347db6f7a3SMitch Phillips inconvertibleErrorCode());
4357db6f7a3SMitch Phillips
4367db6f7a3SMitch Phillips bool LineInfoValid = false;
4377db6f7a3SMitch Phillips
4387db6f7a3SMitch Phillips for (auto &Unit : DWARF->compile_units()) {
4397db6f7a3SMitch Phillips const auto &LineTable = DWARF->getLineTableForUnit(Unit.get());
4407db6f7a3SMitch Phillips if (LineTable && !LineTable->Rows.empty()) {
4417db6f7a3SMitch Phillips LineInfoValid = true;
4427db6f7a3SMitch Phillips break;
4437db6f7a3SMitch Phillips }
4447db6f7a3SMitch Phillips }
4457db6f7a3SMitch Phillips
4467db6f7a3SMitch Phillips if (!LineInfoValid)
4477db6f7a3SMitch Phillips return make_error<StringError>(
4487db6f7a3SMitch Phillips "DWARF line information missing. Did you compile with '-g'?",
4497db6f7a3SMitch Phillips inconvertibleErrorCode());
4507db6f7a3SMitch Phillips }
4517db6f7a3SMitch Phillips
45289c3c8c4SVlad Tsyrklevich for (const object::SectionRef &Section : Object->sections()) {
45389c3c8c4SVlad Tsyrklevich // Ensure only executable sections get analysed.
45489c3c8c4SVlad Tsyrklevich if (!(object::ELFSectionRef(Section).getFlags() & ELF::SHF_EXECINSTR))
45589c3c8c4SVlad Tsyrklevich continue;
45689c3c8c4SVlad Tsyrklevich
4576cc0e63eSJoel Galenson // Avoid checking the PLT since it produces spurious failures on AArch64
4586cc0e63eSJoel Galenson // when ignoring DWARF data.
459bcc00e1aSGeorge Rimar Expected<StringRef> NameOrErr = Section.getName();
460bcc00e1aSGeorge Rimar if (NameOrErr && *NameOrErr == ".plt")
4616cc0e63eSJoel Galenson continue;
462bcc00e1aSGeorge Rimar consumeError(NameOrErr.takeError());
4636cc0e63eSJoel Galenson
464e183340cSFangrui Song Expected<StringRef> Contents = Section.getContents();
465e183340cSFangrui Song if (!Contents)
466e183340cSFangrui Song return Contents.takeError();
467e183340cSFangrui Song ArrayRef<uint8_t> SectionBytes = arrayRefFromStringRef(*Contents);
46889c3c8c4SVlad Tsyrklevich
46977fc1f60SAlexey Lapshin parseSectionContents(SectionBytes,
47077fc1f60SAlexey Lapshin {Section.getAddress(), Section.getIndex()});
47189c3c8c4SVlad Tsyrklevich }
47289c3c8c4SVlad Tsyrklevich return Error::success();
47389c3c8c4SVlad Tsyrklevich }
47489c3c8c4SVlad Tsyrklevich
parseSectionContents(ArrayRef<uint8_t> SectionBytes,object::SectionedAddress Address)47589c3c8c4SVlad Tsyrklevich void FileAnalysis::parseSectionContents(ArrayRef<uint8_t> SectionBytes,
47677fc1f60SAlexey Lapshin object::SectionedAddress Address) {
477c15bdf55SMitch Phillips assert(Symbolizer && "Symbolizer is uninitialised.");
47889c3c8c4SVlad Tsyrklevich MCInst Instruction;
47989c3c8c4SVlad Tsyrklevich Instr InstrMeta;
48089c3c8c4SVlad Tsyrklevich uint64_t InstructionSize;
48189c3c8c4SVlad Tsyrklevich
48289c3c8c4SVlad Tsyrklevich for (uint64_t Byte = 0; Byte < SectionBytes.size();) {
48389c3c8c4SVlad Tsyrklevich bool ValidInstruction =
48489c3c8c4SVlad Tsyrklevich Disassembler->getInstruction(Instruction, InstructionSize,
4856fdd6a7bSFangrui Song SectionBytes.drop_front(Byte), 0,
48689c3c8c4SVlad Tsyrklevich outs()) == MCDisassembler::Success;
48789c3c8c4SVlad Tsyrklevich
48889c3c8c4SVlad Tsyrklevich Byte += InstructionSize;
48989c3c8c4SVlad Tsyrklevich
49077fc1f60SAlexey Lapshin uint64_t VMAddress = Address.Address + Byte - InstructionSize;
49189c3c8c4SVlad Tsyrklevich InstrMeta.Instruction = Instruction;
49289c3c8c4SVlad Tsyrklevich InstrMeta.VMAddress = VMAddress;
49389c3c8c4SVlad Tsyrklevich InstrMeta.InstructionSize = InstructionSize;
49489c3c8c4SVlad Tsyrklevich InstrMeta.Valid = ValidInstruction;
4957db6f7a3SMitch Phillips
49689c3c8c4SVlad Tsyrklevich addInstruction(InstrMeta);
49789c3c8c4SVlad Tsyrklevich
49889c3c8c4SVlad Tsyrklevich if (!ValidInstruction)
49989c3c8c4SVlad Tsyrklevich continue;
50089c3c8c4SVlad Tsyrklevich
50189c3c8c4SVlad Tsyrklevich // Skip additional parsing for instructions that do not affect the control
50289c3c8c4SVlad Tsyrklevich // flow.
50389c3c8c4SVlad Tsyrklevich const auto &InstrDesc = MII->get(Instruction.getOpcode());
50489c3c8c4SVlad Tsyrklevich if (!InstrDesc.mayAffectControlFlow(Instruction, *RegisterInfo))
50589c3c8c4SVlad Tsyrklevich continue;
50689c3c8c4SVlad Tsyrklevich
50789c3c8c4SVlad Tsyrklevich uint64_t Target;
50889c3c8c4SVlad Tsyrklevich if (MIA->evaluateBranch(Instruction, VMAddress, InstructionSize, Target)) {
50989c3c8c4SVlad Tsyrklevich // If the target can be evaluated, it's not indirect.
51089c3c8c4SVlad Tsyrklevich StaticBranchTargetings[Target].push_back(VMAddress);
51189c3c8c4SVlad Tsyrklevich continue;
51289c3c8c4SVlad Tsyrklevich }
51389c3c8c4SVlad Tsyrklevich
51489c3c8c4SVlad Tsyrklevich if (!usesRegisterOperand(InstrMeta))
51589c3c8c4SVlad Tsyrklevich continue;
51689c3c8c4SVlad Tsyrklevich
51706e7e579SJoel Galenson if (InstrDesc.isReturn())
51806e7e579SJoel Galenson continue;
51906e7e579SJoel Galenson
520d64af525SMitch Phillips // Check if this instruction exists in the range of the DWARF metadata.
521d64af525SMitch Phillips if (!IgnoreDWARFFlag) {
522adcd0268SBenjamin Kramer auto LineInfo =
523adcd0268SBenjamin Kramer Symbolizer->symbolizeCode(std::string(Object->getFileName()),
524adcd0268SBenjamin Kramer {VMAddress, Address.SectionIndex});
525d64af525SMitch Phillips if (!LineInfo) {
526d64af525SMitch Phillips handleAllErrors(LineInfo.takeError(), [](const ErrorInfoBase &E) {
527d64af525SMitch Phillips errs() << "Symbolizer failed to get line: " << E.message() << "\n";
528d64af525SMitch Phillips });
529d64af525SMitch Phillips continue;
530d64af525SMitch Phillips }
531d64af525SMitch Phillips
5329abf668cSMichael Pozulp if (LineInfo->FileName == DILineInfo::BadString)
533d64af525SMitch Phillips continue;
534d64af525SMitch Phillips }
535d64af525SMitch Phillips
53677fc1f60SAlexey Lapshin IndirectInstructions.insert({VMAddress, Address.SectionIndex});
53789c3c8c4SVlad Tsyrklevich }
53889c3c8c4SVlad Tsyrklevich }
53989c3c8c4SVlad Tsyrklevich
addInstruction(const Instr & Instruction)54089c3c8c4SVlad Tsyrklevich void FileAnalysis::addInstruction(const Instr &Instruction) {
54189c3c8c4SVlad Tsyrklevich const auto &KV =
54289c3c8c4SVlad Tsyrklevich Instructions.insert(std::make_pair(Instruction.VMAddress, Instruction));
54389c3c8c4SVlad Tsyrklevich if (!KV.second) {
54489c3c8c4SVlad Tsyrklevich errs() << "Failed to add instruction at address "
54589c3c8c4SVlad Tsyrklevich << format_hex(Instruction.VMAddress, 2)
54689c3c8c4SVlad Tsyrklevich << ": Instruction at this address already exists.\n";
54789c3c8c4SVlad Tsyrklevich exit(EXIT_FAILURE);
54889c3c8c4SVlad Tsyrklevich }
54989c3c8c4SVlad Tsyrklevich }
55089c3c8c4SVlad Tsyrklevich
parseSymbolTable()5516cc0e63eSJoel Galenson Error FileAnalysis::parseSymbolTable() {
5526cc0e63eSJoel Galenson // Functions that will trap on CFI violations.
5536cc0e63eSJoel Galenson SmallSet<StringRef, 4> TrapOnFailFunctions;
5546cc0e63eSJoel Galenson TrapOnFailFunctions.insert("__cfi_slowpath");
5556cc0e63eSJoel Galenson TrapOnFailFunctions.insert("__cfi_slowpath_diag");
5566cc0e63eSJoel Galenson TrapOnFailFunctions.insert("abort");
5576cc0e63eSJoel Galenson
5586cc0e63eSJoel Galenson // Look through the list of symbols for functions that will trap on CFI
5596cc0e63eSJoel Galenson // violations.
5606cc0e63eSJoel Galenson for (auto &Sym : Object->symbols()) {
5616cc0e63eSJoel Galenson auto SymNameOrErr = Sym.getName();
5626cc0e63eSJoel Galenson if (!SymNameOrErr)
5636cc0e63eSJoel Galenson consumeError(SymNameOrErr.takeError());
5648590a3e3SKazu Hirata else if (TrapOnFailFunctions.contains(*SymNameOrErr)) {
5656cc0e63eSJoel Galenson auto AddrOrErr = Sym.getAddress();
5666cc0e63eSJoel Galenson if (!AddrOrErr)
5676cc0e63eSJoel Galenson consumeError(AddrOrErr.takeError());
5686cc0e63eSJoel Galenson else
5696cc0e63eSJoel Galenson TrapOnFailFunctionAddresses.insert(*AddrOrErr);
5706cc0e63eSJoel Galenson }
5716cc0e63eSJoel Galenson }
5726cc0e63eSJoel Galenson if (auto *ElfObject = dyn_cast<object::ELFObjectFileBase>(Object)) {
5736cc0e63eSJoel Galenson for (const auto &Addr : ElfObject->getPltAddresses()) {
5747f8c49b0SFangrui Song if (!Addr.first)
5757f8c49b0SFangrui Song continue;
5767f8c49b0SFangrui Song object::SymbolRef Sym(*Addr.first, Object);
5776cc0e63eSJoel Galenson auto SymNameOrErr = Sym.getName();
5786cc0e63eSJoel Galenson if (!SymNameOrErr)
5796cc0e63eSJoel Galenson consumeError(SymNameOrErr.takeError());
5808590a3e3SKazu Hirata else if (TrapOnFailFunctions.contains(*SymNameOrErr))
5816cc0e63eSJoel Galenson TrapOnFailFunctionAddresses.insert(Addr.second);
5826cc0e63eSJoel Galenson }
5836cc0e63eSJoel Galenson }
5846cc0e63eSJoel Galenson return Error::success();
5856cc0e63eSJoel Galenson }
5866cc0e63eSJoel Galenson
UnsupportedDisassembly(StringRef Text)587adcd0268SBenjamin Kramer UnsupportedDisassembly::UnsupportedDisassembly(StringRef Text)
588adcd0268SBenjamin Kramer : Text(std::string(Text)) {}
589d9af383dSMitch Phillips
59089c3c8c4SVlad Tsyrklevich char UnsupportedDisassembly::ID;
log(raw_ostream & OS) const59189c3c8c4SVlad Tsyrklevich void UnsupportedDisassembly::log(raw_ostream &OS) const {
592d9af383dSMitch Phillips OS << "Could not initialise disassembler: " << Text;
59389c3c8c4SVlad Tsyrklevich }
59489c3c8c4SVlad Tsyrklevich
convertToErrorCode() const59589c3c8c4SVlad Tsyrklevich std::error_code UnsupportedDisassembly::convertToErrorCode() const {
59689c3c8c4SVlad Tsyrklevich return std::error_code();
59789c3c8c4SVlad Tsyrklevich }
59889c3c8c4SVlad Tsyrklevich
59989c3c8c4SVlad Tsyrklevich } // namespace cfi_verify
60089c3c8c4SVlad Tsyrklevich } // namespace llvm
601