xref: /openbsd-src/gnu/llvm/llvm/tools/llvm-cfi-verify/lib/FileAnalysis.cpp (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
109467b48Spatrick //===- FileAnalysis.cpp -----------------------------------------*- C++ -*-===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick 
909467b48Spatrick #include "FileAnalysis.h"
1009467b48Spatrick #include "GraphBuilder.h"
1109467b48Spatrick 
1209467b48Spatrick #include "llvm/BinaryFormat/ELF.h"
1309467b48Spatrick #include "llvm/DebugInfo/DWARF/DWARFContext.h"
14*d415bd75Srobert #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
1509467b48Spatrick #include "llvm/MC/MCAsmInfo.h"
1609467b48Spatrick #include "llvm/MC/MCContext.h"
1709467b48Spatrick #include "llvm/MC/MCDisassembler/MCDisassembler.h"
1809467b48Spatrick #include "llvm/MC/MCInst.h"
1909467b48Spatrick #include "llvm/MC/MCInstPrinter.h"
2009467b48Spatrick #include "llvm/MC/MCInstrAnalysis.h"
2109467b48Spatrick #include "llvm/MC/MCInstrDesc.h"
2209467b48Spatrick #include "llvm/MC/MCInstrInfo.h"
2309467b48Spatrick #include "llvm/MC/MCObjectFileInfo.h"
2409467b48Spatrick #include "llvm/MC/MCRegisterInfo.h"
2509467b48Spatrick #include "llvm/MC/MCSubtargetInfo.h"
2609467b48Spatrick #include "llvm/MC/MCTargetOptions.h"
27*d415bd75Srobert #include "llvm/MC/TargetRegistry.h"
2809467b48Spatrick #include "llvm/Object/Binary.h"
2909467b48Spatrick #include "llvm/Object/COFF.h"
3009467b48Spatrick #include "llvm/Object/ELFObjectFile.h"
3109467b48Spatrick #include "llvm/Object/ObjectFile.h"
3209467b48Spatrick #include "llvm/Support/Casting.h"
3309467b48Spatrick #include "llvm/Support/CommandLine.h"
3409467b48Spatrick #include "llvm/Support/Error.h"
3509467b48Spatrick #include "llvm/Support/MemoryBuffer.h"
3609467b48Spatrick #include "llvm/Support/TargetSelect.h"
3709467b48Spatrick #include "llvm/Support/raw_ostream.h"
3809467b48Spatrick 
3909467b48Spatrick using Instr = llvm::cfi_verify::FileAnalysis::Instr;
4009467b48Spatrick using LLVMSymbolizer = llvm::symbolize::LLVMSymbolizer;
4109467b48Spatrick 
4209467b48Spatrick namespace llvm {
4309467b48Spatrick namespace cfi_verify {
4409467b48Spatrick 
4509467b48Spatrick bool IgnoreDWARFFlag;
4609467b48Spatrick 
4709467b48Spatrick static cl::opt<bool, true> IgnoreDWARFArg(
4809467b48Spatrick     "ignore-dwarf",
4909467b48Spatrick     cl::desc(
5009467b48Spatrick         "Ignore all DWARF data. This relaxes the requirements for all "
5109467b48Spatrick         "statically linked libraries to have been compiled with '-g', but "
5209467b48Spatrick         "will result in false positives for 'CFI unprotected' instructions."),
5309467b48Spatrick     cl::location(IgnoreDWARFFlag), cl::init(false));
5409467b48Spatrick 
stringCFIProtectionStatus(CFIProtectionStatus Status)5509467b48Spatrick StringRef stringCFIProtectionStatus(CFIProtectionStatus Status) {
5609467b48Spatrick   switch (Status) {
5709467b48Spatrick   case CFIProtectionStatus::PROTECTED:
5809467b48Spatrick     return "PROTECTED";
5909467b48Spatrick   case CFIProtectionStatus::FAIL_NOT_INDIRECT_CF:
6009467b48Spatrick     return "FAIL_NOT_INDIRECT_CF";
6109467b48Spatrick   case CFIProtectionStatus::FAIL_ORPHANS:
6209467b48Spatrick     return "FAIL_ORPHANS";
6309467b48Spatrick   case CFIProtectionStatus::FAIL_BAD_CONDITIONAL_BRANCH:
6409467b48Spatrick     return "FAIL_BAD_CONDITIONAL_BRANCH";
6509467b48Spatrick   case CFIProtectionStatus::FAIL_REGISTER_CLOBBERED:
6609467b48Spatrick     return "FAIL_REGISTER_CLOBBERED";
6709467b48Spatrick   case CFIProtectionStatus::FAIL_INVALID_INSTRUCTION:
6809467b48Spatrick     return "FAIL_INVALID_INSTRUCTION";
6909467b48Spatrick   }
7009467b48Spatrick   llvm_unreachable("Attempted to stringify an unknown enum value.");
7109467b48Spatrick }
7209467b48Spatrick 
Create(StringRef Filename)7309467b48Spatrick Expected<FileAnalysis> FileAnalysis::Create(StringRef Filename) {
7409467b48Spatrick   // Open the filename provided.
7509467b48Spatrick   Expected<object::OwningBinary<object::Binary>> BinaryOrErr =
7609467b48Spatrick       object::createBinary(Filename);
7709467b48Spatrick   if (!BinaryOrErr)
7809467b48Spatrick     return BinaryOrErr.takeError();
7909467b48Spatrick 
8009467b48Spatrick   // Construct the object and allow it to take ownership of the binary.
8109467b48Spatrick   object::OwningBinary<object::Binary> Binary = std::move(BinaryOrErr.get());
8209467b48Spatrick   FileAnalysis Analysis(std::move(Binary));
8309467b48Spatrick 
8409467b48Spatrick   Analysis.Object = dyn_cast<object::ObjectFile>(Analysis.Binary.getBinary());
8509467b48Spatrick   if (!Analysis.Object)
8609467b48Spatrick     return make_error<UnsupportedDisassembly>("Failed to cast object");
8709467b48Spatrick 
8809467b48Spatrick   switch (Analysis.Object->getArch()) {
8909467b48Spatrick     case Triple::x86:
9009467b48Spatrick     case Triple::x86_64:
9109467b48Spatrick     case Triple::aarch64:
9209467b48Spatrick     case Triple::aarch64_be:
9309467b48Spatrick       break;
9409467b48Spatrick     default:
9509467b48Spatrick       return make_error<UnsupportedDisassembly>("Unsupported architecture.");
9609467b48Spatrick   }
9709467b48Spatrick 
9809467b48Spatrick   Analysis.ObjectTriple = Analysis.Object->makeTriple();
99*d415bd75Srobert   Expected<SubtargetFeatures> Features = Analysis.Object->getFeatures();
100*d415bd75Srobert   if (!Features)
101*d415bd75Srobert     return Features.takeError();
102*d415bd75Srobert 
103*d415bd75Srobert   Analysis.Features = *Features;
10409467b48Spatrick 
10509467b48Spatrick   // Init the rest of the object.
10609467b48Spatrick   if (auto InitResponse = Analysis.initialiseDisassemblyMembers())
10709467b48Spatrick     return std::move(InitResponse);
10809467b48Spatrick 
10909467b48Spatrick   if (auto SectionParseResponse = Analysis.parseCodeSections())
11009467b48Spatrick     return std::move(SectionParseResponse);
11109467b48Spatrick 
11209467b48Spatrick   if (auto SymbolTableParseResponse = Analysis.parseSymbolTable())
11309467b48Spatrick     return std::move(SymbolTableParseResponse);
11409467b48Spatrick 
11509467b48Spatrick   return std::move(Analysis);
11609467b48Spatrick }
11709467b48Spatrick 
FileAnalysis(object::OwningBinary<object::Binary> Binary)11809467b48Spatrick FileAnalysis::FileAnalysis(object::OwningBinary<object::Binary> Binary)
11909467b48Spatrick     : Binary(std::move(Binary)) {}
12009467b48Spatrick 
FileAnalysis(const Triple & ObjectTriple,const SubtargetFeatures & Features)12109467b48Spatrick FileAnalysis::FileAnalysis(const Triple &ObjectTriple,
12209467b48Spatrick                            const SubtargetFeatures &Features)
12309467b48Spatrick     : ObjectTriple(ObjectTriple), Features(Features) {}
12409467b48Spatrick 
12509467b48Spatrick const Instr *
getPrevInstructionSequential(const Instr & InstrMeta) const12609467b48Spatrick FileAnalysis::getPrevInstructionSequential(const Instr &InstrMeta) const {
12709467b48Spatrick   std::map<uint64_t, Instr>::const_iterator KV =
12809467b48Spatrick       Instructions.find(InstrMeta.VMAddress);
12909467b48Spatrick   if (KV == Instructions.end() || KV == Instructions.begin())
13009467b48Spatrick     return nullptr;
13109467b48Spatrick 
13209467b48Spatrick   if (!(--KV)->second.Valid)
13309467b48Spatrick     return nullptr;
13409467b48Spatrick 
13509467b48Spatrick   return &KV->second;
13609467b48Spatrick }
13709467b48Spatrick 
13809467b48Spatrick const Instr *
getNextInstructionSequential(const Instr & InstrMeta) const13909467b48Spatrick FileAnalysis::getNextInstructionSequential(const Instr &InstrMeta) const {
14009467b48Spatrick   std::map<uint64_t, Instr>::const_iterator KV =
14109467b48Spatrick       Instructions.find(InstrMeta.VMAddress);
14209467b48Spatrick   if (KV == Instructions.end() || ++KV == Instructions.end())
14309467b48Spatrick     return nullptr;
14409467b48Spatrick 
14509467b48Spatrick   if (!KV->second.Valid)
14609467b48Spatrick     return nullptr;
14709467b48Spatrick 
14809467b48Spatrick   return &KV->second;
14909467b48Spatrick }
15009467b48Spatrick 
usesRegisterOperand(const Instr & InstrMeta) const15109467b48Spatrick bool FileAnalysis::usesRegisterOperand(const Instr &InstrMeta) const {
15209467b48Spatrick   for (const auto &Operand : InstrMeta.Instruction) {
15309467b48Spatrick     if (Operand.isReg())
15409467b48Spatrick       return true;
15509467b48Spatrick   }
15609467b48Spatrick   return false;
15709467b48Spatrick }
15809467b48Spatrick 
getInstruction(uint64_t Address) const15909467b48Spatrick const Instr *FileAnalysis::getInstruction(uint64_t Address) const {
16009467b48Spatrick   const auto &InstrKV = Instructions.find(Address);
16109467b48Spatrick   if (InstrKV == Instructions.end())
16209467b48Spatrick     return nullptr;
16309467b48Spatrick 
16409467b48Spatrick   return &InstrKV->second;
16509467b48Spatrick }
16609467b48Spatrick 
getInstructionOrDie(uint64_t Address) const16709467b48Spatrick const Instr &FileAnalysis::getInstructionOrDie(uint64_t Address) const {
16809467b48Spatrick   const auto &InstrKV = Instructions.find(Address);
16909467b48Spatrick   assert(InstrKV != Instructions.end() && "Address doesn't exist.");
17009467b48Spatrick   return InstrKV->second;
17109467b48Spatrick }
17209467b48Spatrick 
isCFITrap(const Instr & InstrMeta) const17309467b48Spatrick bool FileAnalysis::isCFITrap(const Instr &InstrMeta) const {
17409467b48Spatrick   const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
17509467b48Spatrick   return InstrDesc.isTrap() || willTrapOnCFIViolation(InstrMeta);
17609467b48Spatrick }
17709467b48Spatrick 
willTrapOnCFIViolation(const Instr & InstrMeta) const17809467b48Spatrick bool FileAnalysis::willTrapOnCFIViolation(const Instr &InstrMeta) const {
17909467b48Spatrick   const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
18009467b48Spatrick   if (!InstrDesc.isCall())
18109467b48Spatrick     return false;
18209467b48Spatrick   uint64_t Target;
18309467b48Spatrick   if (!MIA->evaluateBranch(InstrMeta.Instruction, InstrMeta.VMAddress,
18409467b48Spatrick                            InstrMeta.InstructionSize, Target))
18509467b48Spatrick     return false;
18673471bf0Spatrick   return TrapOnFailFunctionAddresses.contains(Target);
18709467b48Spatrick }
18809467b48Spatrick 
canFallThrough(const Instr & InstrMeta) const18909467b48Spatrick bool FileAnalysis::canFallThrough(const Instr &InstrMeta) const {
19009467b48Spatrick   if (!InstrMeta.Valid)
19109467b48Spatrick     return false;
19209467b48Spatrick 
19309467b48Spatrick   if (isCFITrap(InstrMeta))
19409467b48Spatrick     return false;
19509467b48Spatrick 
19609467b48Spatrick   const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
19709467b48Spatrick   if (InstrDesc.mayAffectControlFlow(InstrMeta.Instruction, *RegisterInfo))
19809467b48Spatrick     return InstrDesc.isConditionalBranch();
19909467b48Spatrick 
20009467b48Spatrick   return true;
20109467b48Spatrick }
20209467b48Spatrick 
20309467b48Spatrick const Instr *
getDefiniteNextInstruction(const Instr & InstrMeta) const20409467b48Spatrick FileAnalysis::getDefiniteNextInstruction(const Instr &InstrMeta) const {
20509467b48Spatrick   if (!InstrMeta.Valid)
20609467b48Spatrick     return nullptr;
20709467b48Spatrick 
20809467b48Spatrick   if (isCFITrap(InstrMeta))
20909467b48Spatrick     return nullptr;
21009467b48Spatrick 
21109467b48Spatrick   const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
21209467b48Spatrick   const Instr *NextMetaPtr;
21309467b48Spatrick   if (InstrDesc.mayAffectControlFlow(InstrMeta.Instruction, *RegisterInfo)) {
21409467b48Spatrick     if (InstrDesc.isConditionalBranch())
21509467b48Spatrick       return nullptr;
21609467b48Spatrick 
21709467b48Spatrick     uint64_t Target;
21809467b48Spatrick     if (!MIA->evaluateBranch(InstrMeta.Instruction, InstrMeta.VMAddress,
21909467b48Spatrick                              InstrMeta.InstructionSize, Target))
22009467b48Spatrick       return nullptr;
22109467b48Spatrick 
22209467b48Spatrick     NextMetaPtr = getInstruction(Target);
22309467b48Spatrick   } else {
22409467b48Spatrick     NextMetaPtr =
22509467b48Spatrick         getInstruction(InstrMeta.VMAddress + InstrMeta.InstructionSize);
22609467b48Spatrick   }
22709467b48Spatrick 
22809467b48Spatrick   if (!NextMetaPtr || !NextMetaPtr->Valid)
22909467b48Spatrick     return nullptr;
23009467b48Spatrick 
23109467b48Spatrick   return NextMetaPtr;
23209467b48Spatrick }
23309467b48Spatrick 
23409467b48Spatrick std::set<const Instr *>
getDirectControlFlowXRefs(const Instr & InstrMeta) const23509467b48Spatrick FileAnalysis::getDirectControlFlowXRefs(const Instr &InstrMeta) const {
23609467b48Spatrick   std::set<const Instr *> CFCrossReferences;
23709467b48Spatrick   const Instr *PrevInstruction = getPrevInstructionSequential(InstrMeta);
23809467b48Spatrick 
23909467b48Spatrick   if (PrevInstruction && canFallThrough(*PrevInstruction))
24009467b48Spatrick     CFCrossReferences.insert(PrevInstruction);
24109467b48Spatrick 
24209467b48Spatrick   const auto &TargetRefsKV = StaticBranchTargetings.find(InstrMeta.VMAddress);
24309467b48Spatrick   if (TargetRefsKV == StaticBranchTargetings.end())
24409467b48Spatrick     return CFCrossReferences;
24509467b48Spatrick 
24609467b48Spatrick   for (uint64_t SourceInstrAddress : TargetRefsKV->second) {
24709467b48Spatrick     const auto &SourceInstrKV = Instructions.find(SourceInstrAddress);
24809467b48Spatrick     if (SourceInstrKV == Instructions.end()) {
24909467b48Spatrick       errs() << "Failed to find source instruction at address "
25009467b48Spatrick              << format_hex(SourceInstrAddress, 2)
25109467b48Spatrick              << " for the cross-reference to instruction at address "
25209467b48Spatrick              << format_hex(InstrMeta.VMAddress, 2) << ".\n";
25309467b48Spatrick       continue;
25409467b48Spatrick     }
25509467b48Spatrick 
25609467b48Spatrick     CFCrossReferences.insert(&SourceInstrKV->second);
25709467b48Spatrick   }
25809467b48Spatrick 
25909467b48Spatrick   return CFCrossReferences;
26009467b48Spatrick }
26109467b48Spatrick 
26209467b48Spatrick const std::set<object::SectionedAddress> &
getIndirectInstructions() const26309467b48Spatrick FileAnalysis::getIndirectInstructions() const {
26409467b48Spatrick   return IndirectInstructions;
26509467b48Spatrick }
26609467b48Spatrick 
getRegisterInfo() const26709467b48Spatrick const MCRegisterInfo *FileAnalysis::getRegisterInfo() const {
26809467b48Spatrick   return RegisterInfo.get();
26909467b48Spatrick }
27009467b48Spatrick 
getMCInstrInfo() const27109467b48Spatrick const MCInstrInfo *FileAnalysis::getMCInstrInfo() const { return MII.get(); }
27209467b48Spatrick 
getMCInstrAnalysis() const27309467b48Spatrick const MCInstrAnalysis *FileAnalysis::getMCInstrAnalysis() const {
27409467b48Spatrick   return MIA.get();
27509467b48Spatrick }
27609467b48Spatrick 
27709467b48Spatrick Expected<DIInliningInfo>
symbolizeInlinedCode(object::SectionedAddress Address)27809467b48Spatrick FileAnalysis::symbolizeInlinedCode(object::SectionedAddress Address) {
27909467b48Spatrick   assert(Symbolizer != nullptr && "Symbolizer is invalid.");
28009467b48Spatrick 
281097a140dSpatrick   return Symbolizer->symbolizeInlinedCode(std::string(Object->getFileName()),
282097a140dSpatrick                                           Address);
28309467b48Spatrick }
28409467b48Spatrick 
28509467b48Spatrick CFIProtectionStatus
validateCFIProtection(const GraphResult & Graph) const28609467b48Spatrick FileAnalysis::validateCFIProtection(const GraphResult &Graph) const {
28709467b48Spatrick   const Instr *InstrMetaPtr = getInstruction(Graph.BaseAddress);
28809467b48Spatrick   if (!InstrMetaPtr)
28909467b48Spatrick     return CFIProtectionStatus::FAIL_INVALID_INSTRUCTION;
29009467b48Spatrick 
29109467b48Spatrick   const auto &InstrDesc = MII->get(InstrMetaPtr->Instruction.getOpcode());
29209467b48Spatrick   if (!InstrDesc.mayAffectControlFlow(InstrMetaPtr->Instruction, *RegisterInfo))
29309467b48Spatrick     return CFIProtectionStatus::FAIL_NOT_INDIRECT_CF;
29409467b48Spatrick 
29509467b48Spatrick   if (!usesRegisterOperand(*InstrMetaPtr))
29609467b48Spatrick     return CFIProtectionStatus::FAIL_NOT_INDIRECT_CF;
29709467b48Spatrick 
29809467b48Spatrick   if (!Graph.OrphanedNodes.empty())
29909467b48Spatrick     return CFIProtectionStatus::FAIL_ORPHANS;
30009467b48Spatrick 
30109467b48Spatrick   for (const auto &BranchNode : Graph.ConditionalBranchNodes) {
30209467b48Spatrick     if (!BranchNode.CFIProtection)
30309467b48Spatrick       return CFIProtectionStatus::FAIL_BAD_CONDITIONAL_BRANCH;
30409467b48Spatrick   }
30509467b48Spatrick 
30609467b48Spatrick   if (indirectCFOperandClobber(Graph) != Graph.BaseAddress)
30709467b48Spatrick     return CFIProtectionStatus::FAIL_REGISTER_CLOBBERED;
30809467b48Spatrick 
30909467b48Spatrick   return CFIProtectionStatus::PROTECTED;
31009467b48Spatrick }
31109467b48Spatrick 
indirectCFOperandClobber(const GraphResult & Graph) const31209467b48Spatrick uint64_t FileAnalysis::indirectCFOperandClobber(const GraphResult &Graph) const {
31309467b48Spatrick   assert(Graph.OrphanedNodes.empty() && "Orphaned nodes should be empty.");
31409467b48Spatrick 
31509467b48Spatrick   // Get the set of registers we must check to ensure they're not clobbered.
31609467b48Spatrick   const Instr &IndirectCF = getInstructionOrDie(Graph.BaseAddress);
31709467b48Spatrick   DenseSet<unsigned> RegisterNumbers;
31809467b48Spatrick   for (const auto &Operand : IndirectCF.Instruction) {
31909467b48Spatrick     if (Operand.isReg())
32009467b48Spatrick       RegisterNumbers.insert(Operand.getReg());
32109467b48Spatrick   }
32209467b48Spatrick   assert(RegisterNumbers.size() && "Zero register operands on indirect CF.");
32309467b48Spatrick 
32409467b48Spatrick   // Now check all branches to indirect CFs and ensure no clobbering happens.
32509467b48Spatrick   for (const auto &Branch : Graph.ConditionalBranchNodes) {
32609467b48Spatrick     uint64_t Node;
32709467b48Spatrick     if (Branch.IndirectCFIsOnTargetPath)
32809467b48Spatrick       Node = Branch.Target;
32909467b48Spatrick     else
33009467b48Spatrick       Node = Branch.Fallthrough;
33109467b48Spatrick 
33209467b48Spatrick     // Some architectures (e.g., AArch64) cannot load in an indirect branch, so
33309467b48Spatrick     // we allow them one load.
33409467b48Spatrick     bool canLoad = !MII->get(IndirectCF.Instruction.getOpcode()).mayLoad();
33509467b48Spatrick 
33609467b48Spatrick     // We walk backwards from the indirect CF.  It is the last node returned by
33709467b48Spatrick     // Graph.flattenAddress, so we skip it since we already handled it.
33809467b48Spatrick     DenseSet<unsigned> CurRegisterNumbers = RegisterNumbers;
33909467b48Spatrick     std::vector<uint64_t> Nodes = Graph.flattenAddress(Node);
34009467b48Spatrick     for (auto I = Nodes.rbegin() + 1, E = Nodes.rend(); I != E; ++I) {
34109467b48Spatrick       Node = *I;
34209467b48Spatrick       const Instr &NodeInstr = getInstructionOrDie(Node);
34309467b48Spatrick       const auto &InstrDesc = MII->get(NodeInstr.Instruction.getOpcode());
34409467b48Spatrick 
34509467b48Spatrick       for (auto RI = CurRegisterNumbers.begin(), RE = CurRegisterNumbers.end();
34609467b48Spatrick            RI != RE; ++RI) {
34709467b48Spatrick         unsigned RegNum = *RI;
34809467b48Spatrick         if (InstrDesc.hasDefOfPhysReg(NodeInstr.Instruction, RegNum,
34909467b48Spatrick                                       *RegisterInfo)) {
35009467b48Spatrick           if (!canLoad || !InstrDesc.mayLoad())
35109467b48Spatrick             return Node;
35209467b48Spatrick           canLoad = false;
35309467b48Spatrick           CurRegisterNumbers.erase(RI);
35409467b48Spatrick           // Add the registers this load reads to those we check for clobbers.
35509467b48Spatrick           for (unsigned i = InstrDesc.getNumDefs(),
35609467b48Spatrick                         e = InstrDesc.getNumOperands(); i != e; i++) {
357*d415bd75Srobert             const auto &Operand = NodeInstr.Instruction.getOperand(i);
35809467b48Spatrick             if (Operand.isReg())
35909467b48Spatrick               CurRegisterNumbers.insert(Operand.getReg());
36009467b48Spatrick           }
36109467b48Spatrick           break;
36209467b48Spatrick         }
36309467b48Spatrick       }
36409467b48Spatrick     }
36509467b48Spatrick   }
36609467b48Spatrick 
36709467b48Spatrick   return Graph.BaseAddress;
36809467b48Spatrick }
36909467b48Spatrick 
printInstruction(const Instr & InstrMeta,raw_ostream & OS) const37009467b48Spatrick void FileAnalysis::printInstruction(const Instr &InstrMeta,
37109467b48Spatrick                                     raw_ostream &OS) const {
372*d415bd75Srobert   Printer->printInst(&InstrMeta.Instruction, 0, "", *SubtargetInfo, OS);
37309467b48Spatrick }
37409467b48Spatrick 
initialiseDisassemblyMembers()37509467b48Spatrick Error FileAnalysis::initialiseDisassemblyMembers() {
37609467b48Spatrick   std::string TripleName = ObjectTriple.getTriple();
37709467b48Spatrick   ArchName = "";
37809467b48Spatrick   MCPU = "";
37909467b48Spatrick   std::string ErrorString;
38009467b48Spatrick 
38173471bf0Spatrick   LLVMSymbolizer::Options Opt;
38273471bf0Spatrick   Opt.UseSymbolTable = false;
38373471bf0Spatrick   Symbolizer.reset(new LLVMSymbolizer(Opt));
38409467b48Spatrick 
38509467b48Spatrick   ObjectTarget =
38609467b48Spatrick       TargetRegistry::lookupTarget(ArchName, ObjectTriple, ErrorString);
38709467b48Spatrick   if (!ObjectTarget)
38809467b48Spatrick     return make_error<UnsupportedDisassembly>(
38909467b48Spatrick         (Twine("Couldn't find target \"") + ObjectTriple.getTriple() +
39009467b48Spatrick          "\", failed with error: " + ErrorString)
39109467b48Spatrick             .str());
39209467b48Spatrick 
39309467b48Spatrick   RegisterInfo.reset(ObjectTarget->createMCRegInfo(TripleName));
39409467b48Spatrick   if (!RegisterInfo)
39509467b48Spatrick     return make_error<UnsupportedDisassembly>(
39609467b48Spatrick         "Failed to initialise RegisterInfo.");
39709467b48Spatrick 
39809467b48Spatrick   MCTargetOptions MCOptions;
39909467b48Spatrick   AsmInfo.reset(
40009467b48Spatrick       ObjectTarget->createMCAsmInfo(*RegisterInfo, TripleName, MCOptions));
40109467b48Spatrick   if (!AsmInfo)
40209467b48Spatrick     return make_error<UnsupportedDisassembly>("Failed to initialise AsmInfo.");
40309467b48Spatrick 
40409467b48Spatrick   SubtargetInfo.reset(ObjectTarget->createMCSubtargetInfo(
40509467b48Spatrick       TripleName, MCPU, Features.getString()));
40609467b48Spatrick   if (!SubtargetInfo)
40709467b48Spatrick     return make_error<UnsupportedDisassembly>(
40809467b48Spatrick         "Failed to initialise SubtargetInfo.");
40909467b48Spatrick 
41009467b48Spatrick   MII.reset(ObjectTarget->createMCInstrInfo());
41109467b48Spatrick   if (!MII)
41209467b48Spatrick     return make_error<UnsupportedDisassembly>("Failed to initialise MII.");
41309467b48Spatrick 
41473471bf0Spatrick   Context.reset(new MCContext(Triple(TripleName), AsmInfo.get(),
41573471bf0Spatrick                               RegisterInfo.get(), SubtargetInfo.get()));
41609467b48Spatrick 
41709467b48Spatrick   Disassembler.reset(
41809467b48Spatrick       ObjectTarget->createMCDisassembler(*SubtargetInfo, *Context));
41909467b48Spatrick 
42009467b48Spatrick   if (!Disassembler)
42109467b48Spatrick     return make_error<UnsupportedDisassembly>(
42209467b48Spatrick         "No disassembler available for target");
42309467b48Spatrick 
42409467b48Spatrick   MIA.reset(ObjectTarget->createMCInstrAnalysis(MII.get()));
42509467b48Spatrick 
42609467b48Spatrick   Printer.reset(ObjectTarget->createMCInstPrinter(
42709467b48Spatrick       ObjectTriple, AsmInfo->getAssemblerDialect(), *AsmInfo, *MII,
42809467b48Spatrick       *RegisterInfo));
42909467b48Spatrick 
43009467b48Spatrick   return Error::success();
43109467b48Spatrick }
43209467b48Spatrick 
parseCodeSections()43309467b48Spatrick Error FileAnalysis::parseCodeSections() {
43409467b48Spatrick   if (!IgnoreDWARFFlag) {
43509467b48Spatrick     std::unique_ptr<DWARFContext> DWARF = DWARFContext::create(*Object);
43609467b48Spatrick     if (!DWARF)
43709467b48Spatrick       return make_error<StringError>("Could not create DWARF information.",
43809467b48Spatrick                                      inconvertibleErrorCode());
43909467b48Spatrick 
44009467b48Spatrick     bool LineInfoValid = false;
44109467b48Spatrick 
44209467b48Spatrick     for (auto &Unit : DWARF->compile_units()) {
44309467b48Spatrick       const auto &LineTable = DWARF->getLineTableForUnit(Unit.get());
44409467b48Spatrick       if (LineTable && !LineTable->Rows.empty()) {
44509467b48Spatrick         LineInfoValid = true;
44609467b48Spatrick         break;
44709467b48Spatrick       }
44809467b48Spatrick     }
44909467b48Spatrick 
45009467b48Spatrick     if (!LineInfoValid)
45109467b48Spatrick       return make_error<StringError>(
45209467b48Spatrick           "DWARF line information missing. Did you compile with '-g'?",
45309467b48Spatrick           inconvertibleErrorCode());
45409467b48Spatrick   }
45509467b48Spatrick 
45609467b48Spatrick   for (const object::SectionRef &Section : Object->sections()) {
45709467b48Spatrick     // Ensure only executable sections get analysed.
45809467b48Spatrick     if (!(object::ELFSectionRef(Section).getFlags() & ELF::SHF_EXECINSTR))
45909467b48Spatrick       continue;
46009467b48Spatrick 
46109467b48Spatrick     // Avoid checking the PLT since it produces spurious failures on AArch64
46209467b48Spatrick     // when ignoring DWARF data.
46309467b48Spatrick     Expected<StringRef> NameOrErr = Section.getName();
46409467b48Spatrick     if (NameOrErr && *NameOrErr == ".plt")
46509467b48Spatrick       continue;
46609467b48Spatrick     consumeError(NameOrErr.takeError());
46709467b48Spatrick 
46809467b48Spatrick     Expected<StringRef> Contents = Section.getContents();
46909467b48Spatrick     if (!Contents)
47009467b48Spatrick       return Contents.takeError();
47109467b48Spatrick     ArrayRef<uint8_t> SectionBytes = arrayRefFromStringRef(*Contents);
47209467b48Spatrick 
47309467b48Spatrick     parseSectionContents(SectionBytes,
47409467b48Spatrick                          {Section.getAddress(), Section.getIndex()});
47509467b48Spatrick   }
47609467b48Spatrick   return Error::success();
47709467b48Spatrick }
47809467b48Spatrick 
parseSectionContents(ArrayRef<uint8_t> SectionBytes,object::SectionedAddress Address)47909467b48Spatrick void FileAnalysis::parseSectionContents(ArrayRef<uint8_t> SectionBytes,
48009467b48Spatrick                                         object::SectionedAddress Address) {
48109467b48Spatrick   assert(Symbolizer && "Symbolizer is uninitialised.");
48209467b48Spatrick   MCInst Instruction;
48309467b48Spatrick   Instr InstrMeta;
48409467b48Spatrick   uint64_t InstructionSize;
48509467b48Spatrick 
48609467b48Spatrick   for (uint64_t Byte = 0; Byte < SectionBytes.size();) {
48709467b48Spatrick     bool ValidInstruction =
48809467b48Spatrick         Disassembler->getInstruction(Instruction, InstructionSize,
48909467b48Spatrick                                      SectionBytes.drop_front(Byte), 0,
49009467b48Spatrick                                      outs()) == MCDisassembler::Success;
49109467b48Spatrick 
49209467b48Spatrick     Byte += InstructionSize;
49309467b48Spatrick 
49409467b48Spatrick     uint64_t VMAddress = Address.Address + Byte - InstructionSize;
49509467b48Spatrick     InstrMeta.Instruction = Instruction;
49609467b48Spatrick     InstrMeta.VMAddress = VMAddress;
49709467b48Spatrick     InstrMeta.InstructionSize = InstructionSize;
49809467b48Spatrick     InstrMeta.Valid = ValidInstruction;
49909467b48Spatrick 
50009467b48Spatrick     addInstruction(InstrMeta);
50109467b48Spatrick 
50209467b48Spatrick     if (!ValidInstruction)
50309467b48Spatrick       continue;
50409467b48Spatrick 
50509467b48Spatrick     // Skip additional parsing for instructions that do not affect the control
50609467b48Spatrick     // flow.
50709467b48Spatrick     const auto &InstrDesc = MII->get(Instruction.getOpcode());
50809467b48Spatrick     if (!InstrDesc.mayAffectControlFlow(Instruction, *RegisterInfo))
50909467b48Spatrick       continue;
51009467b48Spatrick 
51109467b48Spatrick     uint64_t Target;
51209467b48Spatrick     if (MIA->evaluateBranch(Instruction, VMAddress, InstructionSize, Target)) {
51309467b48Spatrick       // If the target can be evaluated, it's not indirect.
51409467b48Spatrick       StaticBranchTargetings[Target].push_back(VMAddress);
51509467b48Spatrick       continue;
51609467b48Spatrick     }
51709467b48Spatrick 
51809467b48Spatrick     if (!usesRegisterOperand(InstrMeta))
51909467b48Spatrick       continue;
52009467b48Spatrick 
52109467b48Spatrick     if (InstrDesc.isReturn())
52209467b48Spatrick       continue;
52309467b48Spatrick 
52409467b48Spatrick     // Check if this instruction exists in the range of the DWARF metadata.
52509467b48Spatrick     if (!IgnoreDWARFFlag) {
526097a140dSpatrick       auto LineInfo =
527097a140dSpatrick           Symbolizer->symbolizeCode(std::string(Object->getFileName()),
528097a140dSpatrick                                     {VMAddress, Address.SectionIndex});
52909467b48Spatrick       if (!LineInfo) {
53009467b48Spatrick         handleAllErrors(LineInfo.takeError(), [](const ErrorInfoBase &E) {
53109467b48Spatrick           errs() << "Symbolizer failed to get line: " << E.message() << "\n";
53209467b48Spatrick         });
53309467b48Spatrick         continue;
53409467b48Spatrick       }
53509467b48Spatrick 
53609467b48Spatrick       if (LineInfo->FileName == DILineInfo::BadString)
53709467b48Spatrick         continue;
53809467b48Spatrick     }
53909467b48Spatrick 
54009467b48Spatrick     IndirectInstructions.insert({VMAddress, Address.SectionIndex});
54109467b48Spatrick   }
54209467b48Spatrick }
54309467b48Spatrick 
addInstruction(const Instr & Instruction)54409467b48Spatrick void FileAnalysis::addInstruction(const Instr &Instruction) {
54509467b48Spatrick   const auto &KV =
54609467b48Spatrick       Instructions.insert(std::make_pair(Instruction.VMAddress, Instruction));
54709467b48Spatrick   if (!KV.second) {
54809467b48Spatrick     errs() << "Failed to add instruction at address "
54909467b48Spatrick            << format_hex(Instruction.VMAddress, 2)
55009467b48Spatrick            << ": Instruction at this address already exists.\n";
55109467b48Spatrick     exit(EXIT_FAILURE);
55209467b48Spatrick   }
55309467b48Spatrick }
55409467b48Spatrick 
parseSymbolTable()55509467b48Spatrick Error FileAnalysis::parseSymbolTable() {
55609467b48Spatrick   // Functions that will trap on CFI violations.
55709467b48Spatrick   SmallSet<StringRef, 4> TrapOnFailFunctions;
55809467b48Spatrick   TrapOnFailFunctions.insert("__cfi_slowpath");
55909467b48Spatrick   TrapOnFailFunctions.insert("__cfi_slowpath_diag");
56009467b48Spatrick   TrapOnFailFunctions.insert("abort");
56109467b48Spatrick 
56209467b48Spatrick   // Look through the list of symbols for functions that will trap on CFI
56309467b48Spatrick   // violations.
56409467b48Spatrick   for (auto &Sym : Object->symbols()) {
56509467b48Spatrick     auto SymNameOrErr = Sym.getName();
56609467b48Spatrick     if (!SymNameOrErr)
56709467b48Spatrick       consumeError(SymNameOrErr.takeError());
56873471bf0Spatrick     else if (TrapOnFailFunctions.contains(*SymNameOrErr)) {
56909467b48Spatrick       auto AddrOrErr = Sym.getAddress();
57009467b48Spatrick       if (!AddrOrErr)
57109467b48Spatrick         consumeError(AddrOrErr.takeError());
57209467b48Spatrick       else
57309467b48Spatrick         TrapOnFailFunctionAddresses.insert(*AddrOrErr);
57409467b48Spatrick     }
57509467b48Spatrick   }
57609467b48Spatrick   if (auto *ElfObject = dyn_cast<object::ELFObjectFileBase>(Object)) {
57709467b48Spatrick     for (const auto &Addr : ElfObject->getPltAddresses()) {
57873471bf0Spatrick       if (!Addr.first)
57973471bf0Spatrick         continue;
58073471bf0Spatrick       object::SymbolRef Sym(*Addr.first, Object);
58109467b48Spatrick       auto SymNameOrErr = Sym.getName();
58209467b48Spatrick       if (!SymNameOrErr)
58309467b48Spatrick         consumeError(SymNameOrErr.takeError());
58473471bf0Spatrick       else if (TrapOnFailFunctions.contains(*SymNameOrErr))
58509467b48Spatrick         TrapOnFailFunctionAddresses.insert(Addr.second);
58609467b48Spatrick     }
58709467b48Spatrick   }
58809467b48Spatrick   return Error::success();
58909467b48Spatrick }
59009467b48Spatrick 
UnsupportedDisassembly(StringRef Text)591097a140dSpatrick UnsupportedDisassembly::UnsupportedDisassembly(StringRef Text)
592097a140dSpatrick     : Text(std::string(Text)) {}
59309467b48Spatrick 
59409467b48Spatrick char UnsupportedDisassembly::ID;
log(raw_ostream & OS) const59509467b48Spatrick void UnsupportedDisassembly::log(raw_ostream &OS) const {
59609467b48Spatrick   OS << "Could not initialise disassembler: " << Text;
59709467b48Spatrick }
59809467b48Spatrick 
convertToErrorCode() const59909467b48Spatrick std::error_code UnsupportedDisassembly::convertToErrorCode() const {
60009467b48Spatrick   return std::error_code();
60109467b48Spatrick }
60209467b48Spatrick 
60309467b48Spatrick } // namespace cfi_verify
60409467b48Spatrick } // namespace llvm
605