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"
14db29f437Sserge-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();
99537cdf92SElena Lepilkina Expected<SubtargetFeatures> Features = Analysis.Object->getFeatures();
100537cdf92SElena Lepilkina if (!Features)
101537cdf92SElena Lepilkina return Features.takeError();
102537cdf92SElena Lepilkina
103537cdf92SElena Lepilkina Analysis.Features = *Features;
10489c3c8c4SVlad Tsyrklevich
10589c3c8c4SVlad Tsyrklevich // Init the rest of the object.
10689c3c8c4SVlad Tsyrklevich if (auto InitResponse = Analysis.initialiseDisassemblyMembers())
107c55cf4afSBill Wendling return std::move(InitResponse);
10889c3c8c4SVlad Tsyrklevich
10989c3c8c4SVlad Tsyrklevich if (auto SectionParseResponse = Analysis.parseCodeSections())
110c55cf4afSBill Wendling return std::move(SectionParseResponse);
11189c3c8c4SVlad Tsyrklevich
1126cc0e63eSJoel Galenson if (auto SymbolTableParseResponse = Analysis.parseSymbolTable())
113c55cf4afSBill Wendling return std::move(SymbolTableParseResponse);
1146cc0e63eSJoel Galenson
115c55cf4afSBill Wendling return std::move(Analysis);
11689c3c8c4SVlad Tsyrklevich }
11789c3c8c4SVlad Tsyrklevich
FileAnalysis(object::OwningBinary<object::Binary> Binary)11889c3c8c4SVlad Tsyrklevich FileAnalysis::FileAnalysis(object::OwningBinary<object::Binary> Binary)
11989c3c8c4SVlad Tsyrklevich : Binary(std::move(Binary)) {}
12089c3c8c4SVlad Tsyrklevich
FileAnalysis(const Triple & ObjectTriple,const SubtargetFeatures & Features)12189c3c8c4SVlad Tsyrklevich FileAnalysis::FileAnalysis(const Triple &ObjectTriple,
12289c3c8c4SVlad Tsyrklevich const SubtargetFeatures &Features)
12389c3c8c4SVlad Tsyrklevich : ObjectTriple(ObjectTriple), Features(Features) {}
12489c3c8c4SVlad Tsyrklevich
12589c3c8c4SVlad Tsyrklevich const Instr *
getPrevInstructionSequential(const Instr & InstrMeta) const12689c3c8c4SVlad Tsyrklevich FileAnalysis::getPrevInstructionSequential(const Instr &InstrMeta) const {
12789c3c8c4SVlad Tsyrklevich std::map<uint64_t, Instr>::const_iterator KV =
12889c3c8c4SVlad Tsyrklevich Instructions.find(InstrMeta.VMAddress);
12989c3c8c4SVlad Tsyrklevich if (KV == Instructions.end() || KV == Instructions.begin())
13089c3c8c4SVlad Tsyrklevich return nullptr;
13189c3c8c4SVlad Tsyrklevich
13289c3c8c4SVlad Tsyrklevich if (!(--KV)->second.Valid)
13389c3c8c4SVlad Tsyrklevich return nullptr;
13489c3c8c4SVlad Tsyrklevich
13589c3c8c4SVlad Tsyrklevich return &KV->second;
13689c3c8c4SVlad Tsyrklevich }
13789c3c8c4SVlad Tsyrklevich
13889c3c8c4SVlad Tsyrklevich const Instr *
getNextInstructionSequential(const Instr & InstrMeta) const13989c3c8c4SVlad Tsyrklevich FileAnalysis::getNextInstructionSequential(const Instr &InstrMeta) const {
14089c3c8c4SVlad Tsyrklevich std::map<uint64_t, Instr>::const_iterator KV =
14189c3c8c4SVlad Tsyrklevich Instructions.find(InstrMeta.VMAddress);
14289c3c8c4SVlad Tsyrklevich if (KV == Instructions.end() || ++KV == Instructions.end())
14389c3c8c4SVlad Tsyrklevich return nullptr;
14489c3c8c4SVlad Tsyrklevich
14589c3c8c4SVlad Tsyrklevich if (!KV->second.Valid)
14689c3c8c4SVlad Tsyrklevich return nullptr;
14789c3c8c4SVlad Tsyrklevich
14889c3c8c4SVlad Tsyrklevich return &KV->second;
14989c3c8c4SVlad Tsyrklevich }
15089c3c8c4SVlad Tsyrklevich
usesRegisterOperand(const Instr & InstrMeta) const15189c3c8c4SVlad Tsyrklevich bool FileAnalysis::usesRegisterOperand(const Instr &InstrMeta) const {
15289c3c8c4SVlad Tsyrklevich for (const auto &Operand : InstrMeta.Instruction) {
15389c3c8c4SVlad Tsyrklevich if (Operand.isReg())
15489c3c8c4SVlad Tsyrklevich return true;
15589c3c8c4SVlad Tsyrklevich }
15689c3c8c4SVlad Tsyrklevich return false;
15789c3c8c4SVlad Tsyrklevich }
15889c3c8c4SVlad Tsyrklevich
getInstruction(uint64_t Address) const15989c3c8c4SVlad Tsyrklevich const Instr *FileAnalysis::getInstruction(uint64_t Address) const {
16089c3c8c4SVlad Tsyrklevich const auto &InstrKV = Instructions.find(Address);
16189c3c8c4SVlad Tsyrklevich if (InstrKV == Instructions.end())
16289c3c8c4SVlad Tsyrklevich return nullptr;
16389c3c8c4SVlad Tsyrklevich
16489c3c8c4SVlad Tsyrklevich return &InstrKV->second;
16589c3c8c4SVlad Tsyrklevich }
16689c3c8c4SVlad Tsyrklevich
getInstructionOrDie(uint64_t Address) const16789c3c8c4SVlad Tsyrklevich const Instr &FileAnalysis::getInstructionOrDie(uint64_t Address) const {
16889c3c8c4SVlad Tsyrklevich const auto &InstrKV = Instructions.find(Address);
16989c3c8c4SVlad Tsyrklevich assert(InstrKV != Instructions.end() && "Address doesn't exist.");
17089c3c8c4SVlad Tsyrklevich return InstrKV->second;
17189c3c8c4SVlad Tsyrklevich }
17289c3c8c4SVlad Tsyrklevich
isCFITrap(const Instr & InstrMeta) const1730ee26324SVlad Tsyrklevich bool FileAnalysis::isCFITrap(const Instr &InstrMeta) const {
17406e7e579SJoel Galenson const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
1756cc0e63eSJoel Galenson return InstrDesc.isTrap() || willTrapOnCFIViolation(InstrMeta);
1766cc0e63eSJoel Galenson }
1776cc0e63eSJoel Galenson
willTrapOnCFIViolation(const Instr & InstrMeta) const1786cc0e63eSJoel Galenson bool FileAnalysis::willTrapOnCFIViolation(const Instr &InstrMeta) const {
1796cc0e63eSJoel Galenson const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
1806cc0e63eSJoel Galenson if (!InstrDesc.isCall())
1816cc0e63eSJoel Galenson return false;
1826cc0e63eSJoel Galenson uint64_t Target;
1836cc0e63eSJoel Galenson if (!MIA->evaluateBranch(InstrMeta.Instruction, InstrMeta.VMAddress,
1846cc0e63eSJoel Galenson InstrMeta.InstructionSize, Target))
1856cc0e63eSJoel Galenson return false;
1868590a3e3SKazu Hirata return TrapOnFailFunctionAddresses.contains(Target);
1870ee26324SVlad Tsyrklevich }
1880ee26324SVlad Tsyrklevich
canFallThrough(const Instr & InstrMeta) const1890ee26324SVlad Tsyrklevich bool FileAnalysis::canFallThrough(const Instr &InstrMeta) const {
1900ee26324SVlad Tsyrklevich if (!InstrMeta.Valid)
1910ee26324SVlad Tsyrklevich return false;
1920ee26324SVlad Tsyrklevich
1930ee26324SVlad Tsyrklevich if (isCFITrap(InstrMeta))
1940ee26324SVlad Tsyrklevich return false;
1950ee26324SVlad Tsyrklevich
1960ee26324SVlad Tsyrklevich const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
1970ee26324SVlad Tsyrklevich if (InstrDesc.mayAffectControlFlow(InstrMeta.Instruction, *RegisterInfo))
1980ee26324SVlad Tsyrklevich return InstrDesc.isConditionalBranch();
1990ee26324SVlad Tsyrklevich
2000ee26324SVlad Tsyrklevich return true;
2010ee26324SVlad Tsyrklevich }
2020ee26324SVlad Tsyrklevich
2030ee26324SVlad Tsyrklevich const Instr *
getDefiniteNextInstruction(const Instr & InstrMeta) const2040ee26324SVlad Tsyrklevich FileAnalysis::getDefiniteNextInstruction(const Instr &InstrMeta) const {
2050ee26324SVlad Tsyrklevich if (!InstrMeta.Valid)
2060ee26324SVlad Tsyrklevich return nullptr;
2070ee26324SVlad Tsyrklevich
2080ee26324SVlad Tsyrklevich if (isCFITrap(InstrMeta))
2090ee26324SVlad Tsyrklevich return nullptr;
2100ee26324SVlad Tsyrklevich
2110ee26324SVlad Tsyrklevich const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
2120ee26324SVlad Tsyrklevich const Instr *NextMetaPtr;
2130ee26324SVlad Tsyrklevich if (InstrDesc.mayAffectControlFlow(InstrMeta.Instruction, *RegisterInfo)) {
2140ee26324SVlad Tsyrklevich if (InstrDesc.isConditionalBranch())
2150ee26324SVlad Tsyrklevich return nullptr;
2160ee26324SVlad Tsyrklevich
2170ee26324SVlad Tsyrklevich uint64_t Target;
2180ee26324SVlad Tsyrklevich if (!MIA->evaluateBranch(InstrMeta.Instruction, InstrMeta.VMAddress,
2190ee26324SVlad Tsyrklevich InstrMeta.InstructionSize, Target))
2200ee26324SVlad Tsyrklevich return nullptr;
2210ee26324SVlad Tsyrklevich
2220ee26324SVlad Tsyrklevich NextMetaPtr = getInstruction(Target);
2230ee26324SVlad Tsyrklevich } else {
2240ee26324SVlad Tsyrklevich NextMetaPtr =
2250ee26324SVlad Tsyrklevich getInstruction(InstrMeta.VMAddress + InstrMeta.InstructionSize);
2260ee26324SVlad Tsyrklevich }
2270ee26324SVlad Tsyrklevich
2280ee26324SVlad Tsyrklevich if (!NextMetaPtr || !NextMetaPtr->Valid)
2290ee26324SVlad Tsyrklevich return nullptr;
2300ee26324SVlad Tsyrklevich
2310ee26324SVlad Tsyrklevich return NextMetaPtr;
2320ee26324SVlad Tsyrklevich }
2330ee26324SVlad Tsyrklevich
2340ee26324SVlad Tsyrklevich std::set<const Instr *>
getDirectControlFlowXRefs(const Instr & InstrMeta) const2350ee26324SVlad Tsyrklevich FileAnalysis::getDirectControlFlowXRefs(const Instr &InstrMeta) const {
2360ee26324SVlad Tsyrklevich std::set<const Instr *> CFCrossReferences;
2370ee26324SVlad Tsyrklevich const Instr *PrevInstruction = getPrevInstructionSequential(InstrMeta);
2380ee26324SVlad Tsyrklevich
2390ee26324SVlad Tsyrklevich if (PrevInstruction && canFallThrough(*PrevInstruction))
2400ee26324SVlad Tsyrklevich CFCrossReferences.insert(PrevInstruction);
2410ee26324SVlad Tsyrklevich
2420ee26324SVlad Tsyrklevich const auto &TargetRefsKV = StaticBranchTargetings.find(InstrMeta.VMAddress);
2430ee26324SVlad Tsyrklevich if (TargetRefsKV == StaticBranchTargetings.end())
2440ee26324SVlad Tsyrklevich return CFCrossReferences;
2450ee26324SVlad Tsyrklevich
2460ee26324SVlad Tsyrklevich for (uint64_t SourceInstrAddress : TargetRefsKV->second) {
2470ee26324SVlad Tsyrklevich const auto &SourceInstrKV = Instructions.find(SourceInstrAddress);
2480ee26324SVlad Tsyrklevich if (SourceInstrKV == Instructions.end()) {
2490ee26324SVlad Tsyrklevich errs() << "Failed to find source instruction at address "
2500ee26324SVlad Tsyrklevich << format_hex(SourceInstrAddress, 2)
2510ee26324SVlad Tsyrklevich << " for the cross-reference to instruction at address "
2520ee26324SVlad Tsyrklevich << format_hex(InstrMeta.VMAddress, 2) << ".\n";
2530ee26324SVlad Tsyrklevich continue;
2540ee26324SVlad Tsyrklevich }
2550ee26324SVlad Tsyrklevich
2560ee26324SVlad Tsyrklevich CFCrossReferences.insert(&SourceInstrKV->second);
2570ee26324SVlad Tsyrklevich }
2580ee26324SVlad Tsyrklevich
2590ee26324SVlad Tsyrklevich return CFCrossReferences;
2600ee26324SVlad Tsyrklevich }
2610ee26324SVlad Tsyrklevich
26277fc1f60SAlexey Lapshin const std::set<object::SectionedAddress> &
getIndirectInstructions() const26377fc1f60SAlexey Lapshin FileAnalysis::getIndirectInstructions() const {
26489c3c8c4SVlad Tsyrklevich return IndirectInstructions;
26589c3c8c4SVlad Tsyrklevich }
26689c3c8c4SVlad Tsyrklevich
getRegisterInfo() const26789c3c8c4SVlad Tsyrklevich const MCRegisterInfo *FileAnalysis::getRegisterInfo() const {
26889c3c8c4SVlad Tsyrklevich return RegisterInfo.get();
26989c3c8c4SVlad Tsyrklevich }
27089c3c8c4SVlad Tsyrklevich
getMCInstrInfo() const27189c3c8c4SVlad Tsyrklevich const MCInstrInfo *FileAnalysis::getMCInstrInfo() const { return MII.get(); }
27289c3c8c4SVlad Tsyrklevich
getMCInstrAnalysis() const27389c3c8c4SVlad Tsyrklevich const MCInstrAnalysis *FileAnalysis::getMCInstrAnalysis() const {
27489c3c8c4SVlad Tsyrklevich return MIA.get();
27589c3c8c4SVlad Tsyrklevich }
27689c3c8c4SVlad Tsyrklevich
27777fc1f60SAlexey Lapshin Expected<DIInliningInfo>
symbolizeInlinedCode(object::SectionedAddress Address)27877fc1f60SAlexey Lapshin FileAnalysis::symbolizeInlinedCode(object::SectionedAddress Address) {
2793b9ea32eSMitch Phillips assert(Symbolizer != nullptr && "Symbolizer is invalid.");
28077fc1f60SAlexey Lapshin
281adcd0268SBenjamin Kramer return Symbolizer->symbolizeInlinedCode(std::string(Object->getFileName()),
282adcd0268SBenjamin Kramer Address);
2833b9ea32eSMitch Phillips }
2843b9ea32eSMitch Phillips
2853b9ea32eSMitch Phillips CFIProtectionStatus
validateCFIProtection(const GraphResult & Graph) const2863b9ea32eSMitch Phillips FileAnalysis::validateCFIProtection(const GraphResult &Graph) const {
2873b9ea32eSMitch Phillips const Instr *InstrMetaPtr = getInstruction(Graph.BaseAddress);
2883b9ea32eSMitch Phillips if (!InstrMetaPtr)
2893b9ea32eSMitch Phillips return CFIProtectionStatus::FAIL_INVALID_INSTRUCTION;
2903b9ea32eSMitch Phillips
2913b9ea32eSMitch Phillips const auto &InstrDesc = MII->get(InstrMetaPtr->Instruction.getOpcode());
2923b9ea32eSMitch Phillips if (!InstrDesc.mayAffectControlFlow(InstrMetaPtr->Instruction, *RegisterInfo))
2933b9ea32eSMitch Phillips return CFIProtectionStatus::FAIL_NOT_INDIRECT_CF;
2943b9ea32eSMitch Phillips
2953b9ea32eSMitch Phillips if (!usesRegisterOperand(*InstrMetaPtr))
2963b9ea32eSMitch Phillips return CFIProtectionStatus::FAIL_NOT_INDIRECT_CF;
2973b9ea32eSMitch Phillips
2983b9ea32eSMitch Phillips if (!Graph.OrphanedNodes.empty())
2993b9ea32eSMitch Phillips return CFIProtectionStatus::FAIL_ORPHANS;
3003b9ea32eSMitch Phillips
3013b9ea32eSMitch Phillips for (const auto &BranchNode : Graph.ConditionalBranchNodes) {
3023b9ea32eSMitch Phillips if (!BranchNode.CFIProtection)
3033b9ea32eSMitch Phillips return CFIProtectionStatus::FAIL_BAD_CONDITIONAL_BRANCH;
3043b9ea32eSMitch Phillips }
3053b9ea32eSMitch Phillips
3062e7be2a6SMitch Phillips if (indirectCFOperandClobber(Graph) != Graph.BaseAddress)
3072e7be2a6SMitch Phillips return CFIProtectionStatus::FAIL_REGISTER_CLOBBERED;
3082e7be2a6SMitch Phillips
3093b9ea32eSMitch Phillips return CFIProtectionStatus::PROTECTED;
3103b9ea32eSMitch Phillips }
311c15bdf55SMitch Phillips
indirectCFOperandClobber(const GraphResult & Graph) const3122e7be2a6SMitch Phillips uint64_t FileAnalysis::indirectCFOperandClobber(const GraphResult &Graph) const {
3132e7be2a6SMitch Phillips assert(Graph.OrphanedNodes.empty() && "Orphaned nodes should be empty.");
3142e7be2a6SMitch Phillips
3152e7be2a6SMitch Phillips // Get the set of registers we must check to ensure they're not clobbered.
3162e7be2a6SMitch Phillips const Instr &IndirectCF = getInstructionOrDie(Graph.BaseAddress);
3172e7be2a6SMitch Phillips DenseSet<unsigned> RegisterNumbers;
3182e7be2a6SMitch Phillips for (const auto &Operand : IndirectCF.Instruction) {
3192e7be2a6SMitch Phillips if (Operand.isReg())
3202e7be2a6SMitch Phillips RegisterNumbers.insert(Operand.getReg());
3212e7be2a6SMitch Phillips }
3222e7be2a6SMitch Phillips assert(RegisterNumbers.size() && "Zero register operands on indirect CF.");
3232e7be2a6SMitch Phillips
3242e7be2a6SMitch Phillips // Now check all branches to indirect CFs and ensure no clobbering happens.
3252e7be2a6SMitch Phillips for (const auto &Branch : Graph.ConditionalBranchNodes) {
3262e7be2a6SMitch Phillips uint64_t Node;
3272e7be2a6SMitch Phillips if (Branch.IndirectCFIsOnTargetPath)
3282e7be2a6SMitch Phillips Node = Branch.Target;
3292e7be2a6SMitch Phillips else
3302e7be2a6SMitch Phillips Node = Branch.Fallthrough;
3312e7be2a6SMitch Phillips
33206e7e579SJoel Galenson // Some architectures (e.g., AArch64) cannot load in an indirect branch, so
33306e7e579SJoel Galenson // we allow them one load.
33406e7e579SJoel Galenson bool canLoad = !MII->get(IndirectCF.Instruction.getOpcode()).mayLoad();
33506e7e579SJoel Galenson
33606e7e579SJoel Galenson // We walk backwards from the indirect CF. It is the last node returned by
33706e7e579SJoel Galenson // Graph.flattenAddress, so we skip it since we already handled it.
33806e7e579SJoel Galenson DenseSet<unsigned> CurRegisterNumbers = RegisterNumbers;
33906e7e579SJoel Galenson std::vector<uint64_t> Nodes = Graph.flattenAddress(Node);
34006e7e579SJoel Galenson for (auto I = Nodes.rbegin() + 1, E = Nodes.rend(); I != E; ++I) {
34106e7e579SJoel Galenson Node = *I;
3422e7be2a6SMitch Phillips const Instr &NodeInstr = getInstructionOrDie(Node);
3432e7be2a6SMitch Phillips const auto &InstrDesc = MII->get(NodeInstr.Instruction.getOpcode());
3442e7be2a6SMitch Phillips
34506e7e579SJoel Galenson for (auto RI = CurRegisterNumbers.begin(), RE = CurRegisterNumbers.end();
34606e7e579SJoel Galenson RI != RE; ++RI) {
34706e7e579SJoel Galenson unsigned RegNum = *RI;
3482e7be2a6SMitch Phillips if (InstrDesc.hasDefOfPhysReg(NodeInstr.Instruction, RegNum,
34906e7e579SJoel Galenson *RegisterInfo)) {
35006e7e579SJoel Galenson if (!canLoad || !InstrDesc.mayLoad())
3512e7be2a6SMitch Phillips return Node;
35206e7e579SJoel Galenson canLoad = false;
35306e7e579SJoel Galenson CurRegisterNumbers.erase(RI);
35406e7e579SJoel Galenson // Add the registers this load reads to those we check for clobbers.
35506e7e579SJoel Galenson for (unsigned i = InstrDesc.getNumDefs(),
35606e7e579SJoel Galenson e = InstrDesc.getNumOperands(); i != e; i++) {
357dd073e08SNathan Sidwell const auto &Operand = NodeInstr.Instruction.getOperand(i);
35806e7e579SJoel Galenson if (Operand.isReg())
35906e7e579SJoel Galenson CurRegisterNumbers.insert(Operand.getReg());
3602e7be2a6SMitch Phillips }
36106e7e579SJoel Galenson break;
36206e7e579SJoel Galenson }
36306e7e579SJoel Galenson }
3642e7be2a6SMitch Phillips }
3652e7be2a6SMitch Phillips }
3662e7be2a6SMitch Phillips
3672e7be2a6SMitch Phillips return Graph.BaseAddress;
3682e7be2a6SMitch Phillips }
3692e7be2a6SMitch Phillips
printInstruction(const Instr & InstrMeta,raw_ostream & OS) const37002993892SMitch Phillips void FileAnalysis::printInstruction(const Instr &InstrMeta,
37102993892SMitch Phillips raw_ostream &OS) const {
372d22f050eSGregory Alfonso Printer->printInst(&InstrMeta.Instruction, 0, "", *SubtargetInfo, OS);
37302993892SMitch Phillips }
37402993892SMitch Phillips
initialiseDisassemblyMembers()37589c3c8c4SVlad Tsyrklevich Error FileAnalysis::initialiseDisassemblyMembers() {
37689c3c8c4SVlad Tsyrklevich std::string TripleName = ObjectTriple.getTriple();
37789c3c8c4SVlad Tsyrklevich ArchName = "";
37889c3c8c4SVlad Tsyrklevich MCPU = "";
37989c3c8c4SVlad Tsyrklevich std::string ErrorString;
38089c3c8c4SVlad Tsyrklevich
3814f30a3d3SFangrui Song LLVMSymbolizer::Options Opt;
3824f30a3d3SFangrui Song Opt.UseSymbolTable = false;
3834f30a3d3SFangrui Song Symbolizer.reset(new LLVMSymbolizer(Opt));
384c15bdf55SMitch Phillips
38589c3c8c4SVlad Tsyrklevich ObjectTarget =
38689c3c8c4SVlad Tsyrklevich TargetRegistry::lookupTarget(ArchName, ObjectTriple, ErrorString);
38789c3c8c4SVlad Tsyrklevich if (!ObjectTarget)
388d9af383dSMitch Phillips return make_error<UnsupportedDisassembly>(
389d9af383dSMitch Phillips (Twine("Couldn't find target \"") + ObjectTriple.getTriple() +
3905ff01cdcSMitch Phillips "\", failed with error: " + ErrorString)
3915ff01cdcSMitch Phillips .str());
39289c3c8c4SVlad Tsyrklevich
39389c3c8c4SVlad Tsyrklevich RegisterInfo.reset(ObjectTarget->createMCRegInfo(TripleName));
39489c3c8c4SVlad Tsyrklevich if (!RegisterInfo)
395d9af383dSMitch Phillips return make_error<UnsupportedDisassembly>(
396d9af383dSMitch Phillips "Failed to initialise RegisterInfo.");
39789c3c8c4SVlad Tsyrklevich
3984b63ca13SMirko Brkusanin MCTargetOptions MCOptions;
3994b63ca13SMirko Brkusanin AsmInfo.reset(
4004b63ca13SMirko Brkusanin ObjectTarget->createMCAsmInfo(*RegisterInfo, TripleName, MCOptions));
40189c3c8c4SVlad Tsyrklevich if (!AsmInfo)
402d9af383dSMitch Phillips return make_error<UnsupportedDisassembly>("Failed to initialise AsmInfo.");
40389c3c8c4SVlad Tsyrklevich
40489c3c8c4SVlad Tsyrklevich SubtargetInfo.reset(ObjectTarget->createMCSubtargetInfo(
40589c3c8c4SVlad Tsyrklevich TripleName, MCPU, Features.getString()));
40689c3c8c4SVlad Tsyrklevich if (!SubtargetInfo)
407d9af383dSMitch Phillips return make_error<UnsupportedDisassembly>(
408d9af383dSMitch Phillips "Failed to initialise SubtargetInfo.");
40989c3c8c4SVlad Tsyrklevich
41089c3c8c4SVlad Tsyrklevich MII.reset(ObjectTarget->createMCInstrInfo());
41189c3c8c4SVlad Tsyrklevich if (!MII)
412d9af383dSMitch Phillips return make_error<UnsupportedDisassembly>("Failed to initialise MII.");
41389c3c8c4SVlad Tsyrklevich
414632ebc4aSPhilipp Krones Context.reset(new MCContext(Triple(TripleName), AsmInfo.get(),
415c2f819afSPhilipp Krones RegisterInfo.get(), SubtargetInfo.get()));
41689c3c8c4SVlad Tsyrklevich
41789c3c8c4SVlad Tsyrklevich Disassembler.reset(
41889c3c8c4SVlad Tsyrklevich ObjectTarget->createMCDisassembler(*SubtargetInfo, *Context));
41989c3c8c4SVlad Tsyrklevich
42089c3c8c4SVlad Tsyrklevich if (!Disassembler)
421d9af383dSMitch Phillips return make_error<UnsupportedDisassembly>(
422d9af383dSMitch Phillips "No disassembler available for target");
42389c3c8c4SVlad Tsyrklevich
42489c3c8c4SVlad Tsyrklevich MIA.reset(ObjectTarget->createMCInstrAnalysis(MII.get()));
42589c3c8c4SVlad Tsyrklevich
42689c3c8c4SVlad Tsyrklevich Printer.reset(ObjectTarget->createMCInstPrinter(
42789c3c8c4SVlad Tsyrklevich ObjectTriple, AsmInfo->getAssemblerDialect(), *AsmInfo, *MII,
42889c3c8c4SVlad Tsyrklevich *RegisterInfo));
42989c3c8c4SVlad Tsyrklevich
43089c3c8c4SVlad Tsyrklevich return Error::success();
43189c3c8c4SVlad Tsyrklevich }
43289c3c8c4SVlad Tsyrklevich
parseCodeSections()43389c3c8c4SVlad Tsyrklevich Error FileAnalysis::parseCodeSections() {
434c15bdf55SMitch Phillips if (!IgnoreDWARFFlag) {
435c15bdf55SMitch Phillips std::unique_ptr<DWARFContext> DWARF = DWARFContext::create(*Object);
4367db6f7a3SMitch Phillips if (!DWARF)
4377db6f7a3SMitch Phillips return make_error<StringError>("Could not create DWARF information.",
4387db6f7a3SMitch Phillips inconvertibleErrorCode());
4397db6f7a3SMitch Phillips
4407db6f7a3SMitch Phillips bool LineInfoValid = false;
4417db6f7a3SMitch Phillips
4427db6f7a3SMitch Phillips for (auto &Unit : DWARF->compile_units()) {
4437db6f7a3SMitch Phillips const auto &LineTable = DWARF->getLineTableForUnit(Unit.get());
4447db6f7a3SMitch Phillips if (LineTable && !LineTable->Rows.empty()) {
4457db6f7a3SMitch Phillips LineInfoValid = true;
4467db6f7a3SMitch Phillips break;
4477db6f7a3SMitch Phillips }
4487db6f7a3SMitch Phillips }
4497db6f7a3SMitch Phillips
4507db6f7a3SMitch Phillips if (!LineInfoValid)
4517db6f7a3SMitch Phillips return make_error<StringError>(
4527db6f7a3SMitch Phillips "DWARF line information missing. Did you compile with '-g'?",
4537db6f7a3SMitch Phillips inconvertibleErrorCode());
4547db6f7a3SMitch Phillips }
4557db6f7a3SMitch Phillips
45689c3c8c4SVlad Tsyrklevich for (const object::SectionRef &Section : Object->sections()) {
45789c3c8c4SVlad Tsyrklevich // Ensure only executable sections get analysed.
45889c3c8c4SVlad Tsyrklevich if (!(object::ELFSectionRef(Section).getFlags() & ELF::SHF_EXECINSTR))
45989c3c8c4SVlad Tsyrklevich continue;
46089c3c8c4SVlad Tsyrklevich
4616cc0e63eSJoel Galenson // Avoid checking the PLT since it produces spurious failures on AArch64
4626cc0e63eSJoel Galenson // when ignoring DWARF data.
463bcc00e1aSGeorge Rimar Expected<StringRef> NameOrErr = Section.getName();
464bcc00e1aSGeorge Rimar if (NameOrErr && *NameOrErr == ".plt")
4656cc0e63eSJoel Galenson continue;
466bcc00e1aSGeorge Rimar consumeError(NameOrErr.takeError());
4676cc0e63eSJoel Galenson
468e183340cSFangrui Song Expected<StringRef> Contents = Section.getContents();
469e183340cSFangrui Song if (!Contents)
470e183340cSFangrui Song return Contents.takeError();
471e183340cSFangrui Song ArrayRef<uint8_t> SectionBytes = arrayRefFromStringRef(*Contents);
47289c3c8c4SVlad Tsyrklevich
47377fc1f60SAlexey Lapshin parseSectionContents(SectionBytes,
47477fc1f60SAlexey Lapshin {Section.getAddress(), Section.getIndex()});
47589c3c8c4SVlad Tsyrklevich }
47689c3c8c4SVlad Tsyrklevich return Error::success();
47789c3c8c4SVlad Tsyrklevich }
47889c3c8c4SVlad Tsyrklevich
parseSectionContents(ArrayRef<uint8_t> SectionBytes,object::SectionedAddress Address)47989c3c8c4SVlad Tsyrklevich void FileAnalysis::parseSectionContents(ArrayRef<uint8_t> SectionBytes,
48077fc1f60SAlexey Lapshin object::SectionedAddress Address) {
481c15bdf55SMitch Phillips assert(Symbolizer && "Symbolizer is uninitialised.");
48289c3c8c4SVlad Tsyrklevich MCInst Instruction;
48389c3c8c4SVlad Tsyrklevich Instr InstrMeta;
48489c3c8c4SVlad Tsyrklevich uint64_t InstructionSize;
48589c3c8c4SVlad Tsyrklevich
48689c3c8c4SVlad Tsyrklevich for (uint64_t Byte = 0; Byte < SectionBytes.size();) {
48789c3c8c4SVlad Tsyrklevich bool ValidInstruction =
48889c3c8c4SVlad Tsyrklevich Disassembler->getInstruction(Instruction, InstructionSize,
4896fdd6a7bSFangrui Song SectionBytes.drop_front(Byte), 0,
49089c3c8c4SVlad Tsyrklevich outs()) == MCDisassembler::Success;
49189c3c8c4SVlad Tsyrklevich
49289c3c8c4SVlad Tsyrklevich Byte += InstructionSize;
49389c3c8c4SVlad Tsyrklevich
49477fc1f60SAlexey Lapshin uint64_t VMAddress = Address.Address + Byte - InstructionSize;
49589c3c8c4SVlad Tsyrklevich InstrMeta.Instruction = Instruction;
49689c3c8c4SVlad Tsyrklevich InstrMeta.VMAddress = VMAddress;
49789c3c8c4SVlad Tsyrklevich InstrMeta.InstructionSize = InstructionSize;
49889c3c8c4SVlad Tsyrklevich InstrMeta.Valid = ValidInstruction;
4997db6f7a3SMitch Phillips
50089c3c8c4SVlad Tsyrklevich addInstruction(InstrMeta);
50189c3c8c4SVlad Tsyrklevich
50289c3c8c4SVlad Tsyrklevich if (!ValidInstruction)
50389c3c8c4SVlad Tsyrklevich continue;
50489c3c8c4SVlad Tsyrklevich
50589c3c8c4SVlad Tsyrklevich // Skip additional parsing for instructions that do not affect the control
50689c3c8c4SVlad Tsyrklevich // flow.
50789c3c8c4SVlad Tsyrklevich const auto &InstrDesc = MII->get(Instruction.getOpcode());
50889c3c8c4SVlad Tsyrklevich if (!InstrDesc.mayAffectControlFlow(Instruction, *RegisterInfo))
50989c3c8c4SVlad Tsyrklevich continue;
51089c3c8c4SVlad Tsyrklevich
51189c3c8c4SVlad Tsyrklevich uint64_t Target;
51289c3c8c4SVlad Tsyrklevich if (MIA->evaluateBranch(Instruction, VMAddress, InstructionSize, Target)) {
51389c3c8c4SVlad Tsyrklevich // If the target can be evaluated, it's not indirect.
51489c3c8c4SVlad Tsyrklevich StaticBranchTargetings[Target].push_back(VMAddress);
51589c3c8c4SVlad Tsyrklevich continue;
51689c3c8c4SVlad Tsyrklevich }
51789c3c8c4SVlad Tsyrklevich
51889c3c8c4SVlad Tsyrklevich if (!usesRegisterOperand(InstrMeta))
51989c3c8c4SVlad Tsyrklevich continue;
52089c3c8c4SVlad Tsyrklevich
52106e7e579SJoel Galenson if (InstrDesc.isReturn())
52206e7e579SJoel Galenson continue;
52306e7e579SJoel Galenson
524d64af525SMitch Phillips // Check if this instruction exists in the range of the DWARF metadata.
525d64af525SMitch Phillips if (!IgnoreDWARFFlag) {
526adcd0268SBenjamin Kramer auto LineInfo =
527adcd0268SBenjamin Kramer Symbolizer->symbolizeCode(std::string(Object->getFileName()),
528adcd0268SBenjamin Kramer {VMAddress, Address.SectionIndex});
529d64af525SMitch Phillips if (!LineInfo) {
530d64af525SMitch Phillips handleAllErrors(LineInfo.takeError(), [](const ErrorInfoBase &E) {
531d64af525SMitch Phillips errs() << "Symbolizer failed to get line: " << E.message() << "\n";
532d64af525SMitch Phillips });
533d64af525SMitch Phillips continue;
534d64af525SMitch Phillips }
535d64af525SMitch Phillips
5369abf668cSMichael Pozulp if (LineInfo->FileName == DILineInfo::BadString)
537d64af525SMitch Phillips continue;
538d64af525SMitch Phillips }
539d64af525SMitch Phillips
54077fc1f60SAlexey Lapshin IndirectInstructions.insert({VMAddress, Address.SectionIndex});
54189c3c8c4SVlad Tsyrklevich }
54289c3c8c4SVlad Tsyrklevich }
54389c3c8c4SVlad Tsyrklevich
addInstruction(const Instr & Instruction)54489c3c8c4SVlad Tsyrklevich void FileAnalysis::addInstruction(const Instr &Instruction) {
54589c3c8c4SVlad Tsyrklevich const auto &KV =
54689c3c8c4SVlad Tsyrklevich Instructions.insert(std::make_pair(Instruction.VMAddress, Instruction));
54789c3c8c4SVlad Tsyrklevich if (!KV.second) {
54889c3c8c4SVlad Tsyrklevich errs() << "Failed to add instruction at address "
54989c3c8c4SVlad Tsyrklevich << format_hex(Instruction.VMAddress, 2)
55089c3c8c4SVlad Tsyrklevich << ": Instruction at this address already exists.\n";
55189c3c8c4SVlad Tsyrklevich exit(EXIT_FAILURE);
55289c3c8c4SVlad Tsyrklevich }
55389c3c8c4SVlad Tsyrklevich }
55489c3c8c4SVlad Tsyrklevich
parseSymbolTable()5556cc0e63eSJoel Galenson Error FileAnalysis::parseSymbolTable() {
5566cc0e63eSJoel Galenson // Functions that will trap on CFI violations.
5576cc0e63eSJoel Galenson SmallSet<StringRef, 4> TrapOnFailFunctions;
5586cc0e63eSJoel Galenson TrapOnFailFunctions.insert("__cfi_slowpath");
5596cc0e63eSJoel Galenson TrapOnFailFunctions.insert("__cfi_slowpath_diag");
5606cc0e63eSJoel Galenson TrapOnFailFunctions.insert("abort");
5616cc0e63eSJoel Galenson
5626cc0e63eSJoel Galenson // Look through the list of symbols for functions that will trap on CFI
5636cc0e63eSJoel Galenson // violations.
5646cc0e63eSJoel Galenson for (auto &Sym : Object->symbols()) {
5656cc0e63eSJoel Galenson auto SymNameOrErr = Sym.getName();
5666cc0e63eSJoel Galenson if (!SymNameOrErr)
5676cc0e63eSJoel Galenson consumeError(SymNameOrErr.takeError());
5688590a3e3SKazu Hirata else if (TrapOnFailFunctions.contains(*SymNameOrErr)) {
5696cc0e63eSJoel Galenson auto AddrOrErr = Sym.getAddress();
5706cc0e63eSJoel Galenson if (!AddrOrErr)
5716cc0e63eSJoel Galenson consumeError(AddrOrErr.takeError());
5726cc0e63eSJoel Galenson else
5736cc0e63eSJoel Galenson TrapOnFailFunctionAddresses.insert(*AddrOrErr);
5746cc0e63eSJoel Galenson }
5756cc0e63eSJoel Galenson }
5766cc0e63eSJoel Galenson if (auto *ElfObject = dyn_cast<object::ELFObjectFileBase>(Object)) {
577*9e37a7bdSFangrui Song for (const auto &Plt : ElfObject->getPltEntries()) {
578*9e37a7bdSFangrui Song if (!Plt.Symbol)
5797f8c49b0SFangrui Song continue;
580*9e37a7bdSFangrui Song object::SymbolRef Sym(*Plt.Symbol, Object);
5816cc0e63eSJoel Galenson auto SymNameOrErr = Sym.getName();
5826cc0e63eSJoel Galenson if (!SymNameOrErr)
5836cc0e63eSJoel Galenson consumeError(SymNameOrErr.takeError());
5848590a3e3SKazu Hirata else if (TrapOnFailFunctions.contains(*SymNameOrErr))
585*9e37a7bdSFangrui Song TrapOnFailFunctionAddresses.insert(Plt.Address);
5866cc0e63eSJoel Galenson }
5876cc0e63eSJoel Galenson }
5886cc0e63eSJoel Galenson return Error::success();
5896cc0e63eSJoel Galenson }
5906cc0e63eSJoel Galenson
UnsupportedDisassembly(StringRef Text)591adcd0268SBenjamin Kramer UnsupportedDisassembly::UnsupportedDisassembly(StringRef Text)
592adcd0268SBenjamin Kramer : Text(std::string(Text)) {}
593d9af383dSMitch Phillips
59489c3c8c4SVlad Tsyrklevich char UnsupportedDisassembly::ID;
log(raw_ostream & OS) const59589c3c8c4SVlad Tsyrklevich void UnsupportedDisassembly::log(raw_ostream &OS) const {
596d9af383dSMitch Phillips OS << "Could not initialise disassembler: " << Text;
59789c3c8c4SVlad Tsyrklevich }
59889c3c8c4SVlad Tsyrklevich
convertToErrorCode() const59989c3c8c4SVlad Tsyrklevich std::error_code UnsupportedDisassembly::convertToErrorCode() const {
60089c3c8c4SVlad Tsyrklevich return std::error_code();
60189c3c8c4SVlad Tsyrklevich }
60289c3c8c4SVlad Tsyrklevich
60389c3c8c4SVlad Tsyrklevich } // namespace cfi_verify
60489c3c8c4SVlad Tsyrklevich } // namespace llvm
605