xref: /llvm-project/llvm/tools/llvm-cfi-verify/lib/FileAnalysis.cpp (revision 9e37a7bd1f38fed4e00704d561b3897fe8915c4c)
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