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