xref: /llvm-project/llvm/tools/llvm-cfi-verify/lib/FileAnalysis.cpp (revision 9e37a7bd1f38fed4e00704d561b3897fe8915c4c)
1 //===- FileAnalysis.cpp -----------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "FileAnalysis.h"
10 #include "GraphBuilder.h"
11 
12 #include "llvm/BinaryFormat/ELF.h"
13 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
14 #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
15 #include "llvm/MC/MCAsmInfo.h"
16 #include "llvm/MC/MCContext.h"
17 #include "llvm/MC/MCDisassembler/MCDisassembler.h"
18 #include "llvm/MC/MCInst.h"
19 #include "llvm/MC/MCInstPrinter.h"
20 #include "llvm/MC/MCInstrAnalysis.h"
21 #include "llvm/MC/MCInstrDesc.h"
22 #include "llvm/MC/MCInstrInfo.h"
23 #include "llvm/MC/MCObjectFileInfo.h"
24 #include "llvm/MC/MCRegisterInfo.h"
25 #include "llvm/MC/MCSubtargetInfo.h"
26 #include "llvm/MC/MCTargetOptions.h"
27 #include "llvm/MC/TargetRegistry.h"
28 #include "llvm/Object/Binary.h"
29 #include "llvm/Object/COFF.h"
30 #include "llvm/Object/ELFObjectFile.h"
31 #include "llvm/Object/ObjectFile.h"
32 #include "llvm/Support/Casting.h"
33 #include "llvm/Support/CommandLine.h"
34 #include "llvm/Support/Error.h"
35 #include "llvm/Support/MemoryBuffer.h"
36 #include "llvm/Support/TargetSelect.h"
37 #include "llvm/Support/raw_ostream.h"
38 
39 using Instr = llvm::cfi_verify::FileAnalysis::Instr;
40 using LLVMSymbolizer = llvm::symbolize::LLVMSymbolizer;
41 
42 namespace llvm {
43 namespace cfi_verify {
44 
45 bool IgnoreDWARFFlag;
46 
47 static cl::opt<bool, true> IgnoreDWARFArg(
48     "ignore-dwarf",
49     cl::desc(
50         "Ignore all DWARF data. This relaxes the requirements for all "
51         "statically linked libraries to have been compiled with '-g', but "
52         "will result in false positives for 'CFI unprotected' instructions."),
53     cl::location(IgnoreDWARFFlag), cl::init(false));
54 
stringCFIProtectionStatus(CFIProtectionStatus Status)55 StringRef stringCFIProtectionStatus(CFIProtectionStatus Status) {
56   switch (Status) {
57   case CFIProtectionStatus::PROTECTED:
58     return "PROTECTED";
59   case CFIProtectionStatus::FAIL_NOT_INDIRECT_CF:
60     return "FAIL_NOT_INDIRECT_CF";
61   case CFIProtectionStatus::FAIL_ORPHANS:
62     return "FAIL_ORPHANS";
63   case CFIProtectionStatus::FAIL_BAD_CONDITIONAL_BRANCH:
64     return "FAIL_BAD_CONDITIONAL_BRANCH";
65   case CFIProtectionStatus::FAIL_REGISTER_CLOBBERED:
66     return "FAIL_REGISTER_CLOBBERED";
67   case CFIProtectionStatus::FAIL_INVALID_INSTRUCTION:
68     return "FAIL_INVALID_INSTRUCTION";
69   }
70   llvm_unreachable("Attempted to stringify an unknown enum value.");
71 }
72 
Create(StringRef Filename)73 Expected<FileAnalysis> FileAnalysis::Create(StringRef Filename) {
74   // Open the filename provided.
75   Expected<object::OwningBinary<object::Binary>> BinaryOrErr =
76       object::createBinary(Filename);
77   if (!BinaryOrErr)
78     return BinaryOrErr.takeError();
79 
80   // Construct the object and allow it to take ownership of the binary.
81   object::OwningBinary<object::Binary> Binary = std::move(BinaryOrErr.get());
82   FileAnalysis Analysis(std::move(Binary));
83 
84   Analysis.Object = dyn_cast<object::ObjectFile>(Analysis.Binary.getBinary());
85   if (!Analysis.Object)
86     return make_error<UnsupportedDisassembly>("Failed to cast object");
87 
88   switch (Analysis.Object->getArch()) {
89     case Triple::x86:
90     case Triple::x86_64:
91     case Triple::aarch64:
92     case Triple::aarch64_be:
93       break;
94     default:
95       return make_error<UnsupportedDisassembly>("Unsupported architecture.");
96   }
97 
98   Analysis.ObjectTriple = Analysis.Object->makeTriple();
99   Expected<SubtargetFeatures> Features = Analysis.Object->getFeatures();
100   if (!Features)
101     return Features.takeError();
102 
103   Analysis.Features = *Features;
104 
105   // Init the rest of the object.
106   if (auto InitResponse = Analysis.initialiseDisassemblyMembers())
107     return std::move(InitResponse);
108 
109   if (auto SectionParseResponse = Analysis.parseCodeSections())
110     return std::move(SectionParseResponse);
111 
112   if (auto SymbolTableParseResponse = Analysis.parseSymbolTable())
113     return std::move(SymbolTableParseResponse);
114 
115   return std::move(Analysis);
116 }
117 
FileAnalysis(object::OwningBinary<object::Binary> Binary)118 FileAnalysis::FileAnalysis(object::OwningBinary<object::Binary> Binary)
119     : Binary(std::move(Binary)) {}
120 
FileAnalysis(const Triple & ObjectTriple,const SubtargetFeatures & Features)121 FileAnalysis::FileAnalysis(const Triple &ObjectTriple,
122                            const SubtargetFeatures &Features)
123     : ObjectTriple(ObjectTriple), Features(Features) {}
124 
125 const Instr *
getPrevInstructionSequential(const Instr & InstrMeta) const126 FileAnalysis::getPrevInstructionSequential(const Instr &InstrMeta) const {
127   std::map<uint64_t, Instr>::const_iterator KV =
128       Instructions.find(InstrMeta.VMAddress);
129   if (KV == Instructions.end() || KV == Instructions.begin())
130     return nullptr;
131 
132   if (!(--KV)->second.Valid)
133     return nullptr;
134 
135   return &KV->second;
136 }
137 
138 const Instr *
getNextInstructionSequential(const Instr & InstrMeta) const139 FileAnalysis::getNextInstructionSequential(const Instr &InstrMeta) const {
140   std::map<uint64_t, Instr>::const_iterator KV =
141       Instructions.find(InstrMeta.VMAddress);
142   if (KV == Instructions.end() || ++KV == Instructions.end())
143     return nullptr;
144 
145   if (!KV->second.Valid)
146     return nullptr;
147 
148   return &KV->second;
149 }
150 
usesRegisterOperand(const Instr & InstrMeta) const151 bool FileAnalysis::usesRegisterOperand(const Instr &InstrMeta) const {
152   for (const auto &Operand : InstrMeta.Instruction) {
153     if (Operand.isReg())
154       return true;
155   }
156   return false;
157 }
158 
getInstruction(uint64_t Address) const159 const Instr *FileAnalysis::getInstruction(uint64_t Address) const {
160   const auto &InstrKV = Instructions.find(Address);
161   if (InstrKV == Instructions.end())
162     return nullptr;
163 
164   return &InstrKV->second;
165 }
166 
getInstructionOrDie(uint64_t Address) const167 const Instr &FileAnalysis::getInstructionOrDie(uint64_t Address) const {
168   const auto &InstrKV = Instructions.find(Address);
169   assert(InstrKV != Instructions.end() && "Address doesn't exist.");
170   return InstrKV->second;
171 }
172 
isCFITrap(const Instr & InstrMeta) const173 bool FileAnalysis::isCFITrap(const Instr &InstrMeta) const {
174   const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
175   return InstrDesc.isTrap() || willTrapOnCFIViolation(InstrMeta);
176 }
177 
willTrapOnCFIViolation(const Instr & InstrMeta) const178 bool FileAnalysis::willTrapOnCFIViolation(const Instr &InstrMeta) const {
179   const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
180   if (!InstrDesc.isCall())
181     return false;
182   uint64_t Target;
183   if (!MIA->evaluateBranch(InstrMeta.Instruction, InstrMeta.VMAddress,
184                            InstrMeta.InstructionSize, Target))
185     return false;
186   return TrapOnFailFunctionAddresses.contains(Target);
187 }
188 
canFallThrough(const Instr & InstrMeta) const189 bool FileAnalysis::canFallThrough(const Instr &InstrMeta) const {
190   if (!InstrMeta.Valid)
191     return false;
192 
193   if (isCFITrap(InstrMeta))
194     return false;
195 
196   const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
197   if (InstrDesc.mayAffectControlFlow(InstrMeta.Instruction, *RegisterInfo))
198     return InstrDesc.isConditionalBranch();
199 
200   return true;
201 }
202 
203 const Instr *
getDefiniteNextInstruction(const Instr & InstrMeta) const204 FileAnalysis::getDefiniteNextInstruction(const Instr &InstrMeta) const {
205   if (!InstrMeta.Valid)
206     return nullptr;
207 
208   if (isCFITrap(InstrMeta))
209     return nullptr;
210 
211   const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
212   const Instr *NextMetaPtr;
213   if (InstrDesc.mayAffectControlFlow(InstrMeta.Instruction, *RegisterInfo)) {
214     if (InstrDesc.isConditionalBranch())
215       return nullptr;
216 
217     uint64_t Target;
218     if (!MIA->evaluateBranch(InstrMeta.Instruction, InstrMeta.VMAddress,
219                              InstrMeta.InstructionSize, Target))
220       return nullptr;
221 
222     NextMetaPtr = getInstruction(Target);
223   } else {
224     NextMetaPtr =
225         getInstruction(InstrMeta.VMAddress + InstrMeta.InstructionSize);
226   }
227 
228   if (!NextMetaPtr || !NextMetaPtr->Valid)
229     return nullptr;
230 
231   return NextMetaPtr;
232 }
233 
234 std::set<const Instr *>
getDirectControlFlowXRefs(const Instr & InstrMeta) const235 FileAnalysis::getDirectControlFlowXRefs(const Instr &InstrMeta) const {
236   std::set<const Instr *> CFCrossReferences;
237   const Instr *PrevInstruction = getPrevInstructionSequential(InstrMeta);
238 
239   if (PrevInstruction && canFallThrough(*PrevInstruction))
240     CFCrossReferences.insert(PrevInstruction);
241 
242   const auto &TargetRefsKV = StaticBranchTargetings.find(InstrMeta.VMAddress);
243   if (TargetRefsKV == StaticBranchTargetings.end())
244     return CFCrossReferences;
245 
246   for (uint64_t SourceInstrAddress : TargetRefsKV->second) {
247     const auto &SourceInstrKV = Instructions.find(SourceInstrAddress);
248     if (SourceInstrKV == Instructions.end()) {
249       errs() << "Failed to find source instruction at address "
250              << format_hex(SourceInstrAddress, 2)
251              << " for the cross-reference to instruction at address "
252              << format_hex(InstrMeta.VMAddress, 2) << ".\n";
253       continue;
254     }
255 
256     CFCrossReferences.insert(&SourceInstrKV->second);
257   }
258 
259   return CFCrossReferences;
260 }
261 
262 const std::set<object::SectionedAddress> &
getIndirectInstructions() const263 FileAnalysis::getIndirectInstructions() const {
264   return IndirectInstructions;
265 }
266 
getRegisterInfo() const267 const MCRegisterInfo *FileAnalysis::getRegisterInfo() const {
268   return RegisterInfo.get();
269 }
270 
getMCInstrInfo() const271 const MCInstrInfo *FileAnalysis::getMCInstrInfo() const { return MII.get(); }
272 
getMCInstrAnalysis() const273 const MCInstrAnalysis *FileAnalysis::getMCInstrAnalysis() const {
274   return MIA.get();
275 }
276 
277 Expected<DIInliningInfo>
symbolizeInlinedCode(object::SectionedAddress Address)278 FileAnalysis::symbolizeInlinedCode(object::SectionedAddress Address) {
279   assert(Symbolizer != nullptr && "Symbolizer is invalid.");
280 
281   return Symbolizer->symbolizeInlinedCode(std::string(Object->getFileName()),
282                                           Address);
283 }
284 
285 CFIProtectionStatus
validateCFIProtection(const GraphResult & Graph) const286 FileAnalysis::validateCFIProtection(const GraphResult &Graph) const {
287   const Instr *InstrMetaPtr = getInstruction(Graph.BaseAddress);
288   if (!InstrMetaPtr)
289     return CFIProtectionStatus::FAIL_INVALID_INSTRUCTION;
290 
291   const auto &InstrDesc = MII->get(InstrMetaPtr->Instruction.getOpcode());
292   if (!InstrDesc.mayAffectControlFlow(InstrMetaPtr->Instruction, *RegisterInfo))
293     return CFIProtectionStatus::FAIL_NOT_INDIRECT_CF;
294 
295   if (!usesRegisterOperand(*InstrMetaPtr))
296     return CFIProtectionStatus::FAIL_NOT_INDIRECT_CF;
297 
298   if (!Graph.OrphanedNodes.empty())
299     return CFIProtectionStatus::FAIL_ORPHANS;
300 
301   for (const auto &BranchNode : Graph.ConditionalBranchNodes) {
302     if (!BranchNode.CFIProtection)
303       return CFIProtectionStatus::FAIL_BAD_CONDITIONAL_BRANCH;
304   }
305 
306   if (indirectCFOperandClobber(Graph) != Graph.BaseAddress)
307     return CFIProtectionStatus::FAIL_REGISTER_CLOBBERED;
308 
309   return CFIProtectionStatus::PROTECTED;
310 }
311 
indirectCFOperandClobber(const GraphResult & Graph) const312 uint64_t FileAnalysis::indirectCFOperandClobber(const GraphResult &Graph) const {
313   assert(Graph.OrphanedNodes.empty() && "Orphaned nodes should be empty.");
314 
315   // Get the set of registers we must check to ensure they're not clobbered.
316   const Instr &IndirectCF = getInstructionOrDie(Graph.BaseAddress);
317   DenseSet<unsigned> RegisterNumbers;
318   for (const auto &Operand : IndirectCF.Instruction) {
319     if (Operand.isReg())
320       RegisterNumbers.insert(Operand.getReg());
321   }
322   assert(RegisterNumbers.size() && "Zero register operands on indirect CF.");
323 
324   // Now check all branches to indirect CFs and ensure no clobbering happens.
325   for (const auto &Branch : Graph.ConditionalBranchNodes) {
326     uint64_t Node;
327     if (Branch.IndirectCFIsOnTargetPath)
328       Node = Branch.Target;
329     else
330       Node = Branch.Fallthrough;
331 
332     // Some architectures (e.g., AArch64) cannot load in an indirect branch, so
333     // we allow them one load.
334     bool canLoad = !MII->get(IndirectCF.Instruction.getOpcode()).mayLoad();
335 
336     // We walk backwards from the indirect CF.  It is the last node returned by
337     // Graph.flattenAddress, so we skip it since we already handled it.
338     DenseSet<unsigned> CurRegisterNumbers = RegisterNumbers;
339     std::vector<uint64_t> Nodes = Graph.flattenAddress(Node);
340     for (auto I = Nodes.rbegin() + 1, E = Nodes.rend(); I != E; ++I) {
341       Node = *I;
342       const Instr &NodeInstr = getInstructionOrDie(Node);
343       const auto &InstrDesc = MII->get(NodeInstr.Instruction.getOpcode());
344 
345       for (auto RI = CurRegisterNumbers.begin(), RE = CurRegisterNumbers.end();
346            RI != RE; ++RI) {
347         unsigned RegNum = *RI;
348         if (InstrDesc.hasDefOfPhysReg(NodeInstr.Instruction, RegNum,
349                                       *RegisterInfo)) {
350           if (!canLoad || !InstrDesc.mayLoad())
351             return Node;
352           canLoad = false;
353           CurRegisterNumbers.erase(RI);
354           // Add the registers this load reads to those we check for clobbers.
355           for (unsigned i = InstrDesc.getNumDefs(),
356                         e = InstrDesc.getNumOperands(); i != e; i++) {
357             const auto &Operand = NodeInstr.Instruction.getOperand(i);
358             if (Operand.isReg())
359               CurRegisterNumbers.insert(Operand.getReg());
360           }
361           break;
362         }
363       }
364     }
365   }
366 
367   return Graph.BaseAddress;
368 }
369 
printInstruction(const Instr & InstrMeta,raw_ostream & OS) const370 void FileAnalysis::printInstruction(const Instr &InstrMeta,
371                                     raw_ostream &OS) const {
372   Printer->printInst(&InstrMeta.Instruction, 0, "", *SubtargetInfo, OS);
373 }
374 
initialiseDisassemblyMembers()375 Error FileAnalysis::initialiseDisassemblyMembers() {
376   std::string TripleName = ObjectTriple.getTriple();
377   ArchName = "";
378   MCPU = "";
379   std::string ErrorString;
380 
381   LLVMSymbolizer::Options Opt;
382   Opt.UseSymbolTable = false;
383   Symbolizer.reset(new LLVMSymbolizer(Opt));
384 
385   ObjectTarget =
386       TargetRegistry::lookupTarget(ArchName, ObjectTriple, ErrorString);
387   if (!ObjectTarget)
388     return make_error<UnsupportedDisassembly>(
389         (Twine("Couldn't find target \"") + ObjectTriple.getTriple() +
390          "\", failed with error: " + ErrorString)
391             .str());
392 
393   RegisterInfo.reset(ObjectTarget->createMCRegInfo(TripleName));
394   if (!RegisterInfo)
395     return make_error<UnsupportedDisassembly>(
396         "Failed to initialise RegisterInfo.");
397 
398   MCTargetOptions MCOptions;
399   AsmInfo.reset(
400       ObjectTarget->createMCAsmInfo(*RegisterInfo, TripleName, MCOptions));
401   if (!AsmInfo)
402     return make_error<UnsupportedDisassembly>("Failed to initialise AsmInfo.");
403 
404   SubtargetInfo.reset(ObjectTarget->createMCSubtargetInfo(
405       TripleName, MCPU, Features.getString()));
406   if (!SubtargetInfo)
407     return make_error<UnsupportedDisassembly>(
408         "Failed to initialise SubtargetInfo.");
409 
410   MII.reset(ObjectTarget->createMCInstrInfo());
411   if (!MII)
412     return make_error<UnsupportedDisassembly>("Failed to initialise MII.");
413 
414   Context.reset(new MCContext(Triple(TripleName), AsmInfo.get(),
415                               RegisterInfo.get(), SubtargetInfo.get()));
416 
417   Disassembler.reset(
418       ObjectTarget->createMCDisassembler(*SubtargetInfo, *Context));
419 
420   if (!Disassembler)
421     return make_error<UnsupportedDisassembly>(
422         "No disassembler available for target");
423 
424   MIA.reset(ObjectTarget->createMCInstrAnalysis(MII.get()));
425 
426   Printer.reset(ObjectTarget->createMCInstPrinter(
427       ObjectTriple, AsmInfo->getAssemblerDialect(), *AsmInfo, *MII,
428       *RegisterInfo));
429 
430   return Error::success();
431 }
432 
parseCodeSections()433 Error FileAnalysis::parseCodeSections() {
434   if (!IgnoreDWARFFlag) {
435     std::unique_ptr<DWARFContext> DWARF = DWARFContext::create(*Object);
436     if (!DWARF)
437       return make_error<StringError>("Could not create DWARF information.",
438                                      inconvertibleErrorCode());
439 
440     bool LineInfoValid = false;
441 
442     for (auto &Unit : DWARF->compile_units()) {
443       const auto &LineTable = DWARF->getLineTableForUnit(Unit.get());
444       if (LineTable && !LineTable->Rows.empty()) {
445         LineInfoValid = true;
446         break;
447       }
448     }
449 
450     if (!LineInfoValid)
451       return make_error<StringError>(
452           "DWARF line information missing. Did you compile with '-g'?",
453           inconvertibleErrorCode());
454   }
455 
456   for (const object::SectionRef &Section : Object->sections()) {
457     // Ensure only executable sections get analysed.
458     if (!(object::ELFSectionRef(Section).getFlags() & ELF::SHF_EXECINSTR))
459       continue;
460 
461     // Avoid checking the PLT since it produces spurious failures on AArch64
462     // when ignoring DWARF data.
463     Expected<StringRef> NameOrErr = Section.getName();
464     if (NameOrErr && *NameOrErr == ".plt")
465       continue;
466     consumeError(NameOrErr.takeError());
467 
468     Expected<StringRef> Contents = Section.getContents();
469     if (!Contents)
470       return Contents.takeError();
471     ArrayRef<uint8_t> SectionBytes = arrayRefFromStringRef(*Contents);
472 
473     parseSectionContents(SectionBytes,
474                          {Section.getAddress(), Section.getIndex()});
475   }
476   return Error::success();
477 }
478 
parseSectionContents(ArrayRef<uint8_t> SectionBytes,object::SectionedAddress Address)479 void FileAnalysis::parseSectionContents(ArrayRef<uint8_t> SectionBytes,
480                                         object::SectionedAddress Address) {
481   assert(Symbolizer && "Symbolizer is uninitialised.");
482   MCInst Instruction;
483   Instr InstrMeta;
484   uint64_t InstructionSize;
485 
486   for (uint64_t Byte = 0; Byte < SectionBytes.size();) {
487     bool ValidInstruction =
488         Disassembler->getInstruction(Instruction, InstructionSize,
489                                      SectionBytes.drop_front(Byte), 0,
490                                      outs()) == MCDisassembler::Success;
491 
492     Byte += InstructionSize;
493 
494     uint64_t VMAddress = Address.Address + Byte - InstructionSize;
495     InstrMeta.Instruction = Instruction;
496     InstrMeta.VMAddress = VMAddress;
497     InstrMeta.InstructionSize = InstructionSize;
498     InstrMeta.Valid = ValidInstruction;
499 
500     addInstruction(InstrMeta);
501 
502     if (!ValidInstruction)
503       continue;
504 
505     // Skip additional parsing for instructions that do not affect the control
506     // flow.
507     const auto &InstrDesc = MII->get(Instruction.getOpcode());
508     if (!InstrDesc.mayAffectControlFlow(Instruction, *RegisterInfo))
509       continue;
510 
511     uint64_t Target;
512     if (MIA->evaluateBranch(Instruction, VMAddress, InstructionSize, Target)) {
513       // If the target can be evaluated, it's not indirect.
514       StaticBranchTargetings[Target].push_back(VMAddress);
515       continue;
516     }
517 
518     if (!usesRegisterOperand(InstrMeta))
519       continue;
520 
521     if (InstrDesc.isReturn())
522       continue;
523 
524     // Check if this instruction exists in the range of the DWARF metadata.
525     if (!IgnoreDWARFFlag) {
526       auto LineInfo =
527           Symbolizer->symbolizeCode(std::string(Object->getFileName()),
528                                     {VMAddress, Address.SectionIndex});
529       if (!LineInfo) {
530         handleAllErrors(LineInfo.takeError(), [](const ErrorInfoBase &E) {
531           errs() << "Symbolizer failed to get line: " << E.message() << "\n";
532         });
533         continue;
534       }
535 
536       if (LineInfo->FileName == DILineInfo::BadString)
537         continue;
538     }
539 
540     IndirectInstructions.insert({VMAddress, Address.SectionIndex});
541   }
542 }
543 
addInstruction(const Instr & Instruction)544 void FileAnalysis::addInstruction(const Instr &Instruction) {
545   const auto &KV =
546       Instructions.insert(std::make_pair(Instruction.VMAddress, Instruction));
547   if (!KV.second) {
548     errs() << "Failed to add instruction at address "
549            << format_hex(Instruction.VMAddress, 2)
550            << ": Instruction at this address already exists.\n";
551     exit(EXIT_FAILURE);
552   }
553 }
554 
parseSymbolTable()555 Error FileAnalysis::parseSymbolTable() {
556   // Functions that will trap on CFI violations.
557   SmallSet<StringRef, 4> TrapOnFailFunctions;
558   TrapOnFailFunctions.insert("__cfi_slowpath");
559   TrapOnFailFunctions.insert("__cfi_slowpath_diag");
560   TrapOnFailFunctions.insert("abort");
561 
562   // Look through the list of symbols for functions that will trap on CFI
563   // violations.
564   for (auto &Sym : Object->symbols()) {
565     auto SymNameOrErr = Sym.getName();
566     if (!SymNameOrErr)
567       consumeError(SymNameOrErr.takeError());
568     else if (TrapOnFailFunctions.contains(*SymNameOrErr)) {
569       auto AddrOrErr = Sym.getAddress();
570       if (!AddrOrErr)
571         consumeError(AddrOrErr.takeError());
572       else
573         TrapOnFailFunctionAddresses.insert(*AddrOrErr);
574     }
575   }
576   if (auto *ElfObject = dyn_cast<object::ELFObjectFileBase>(Object)) {
577     for (const auto &Plt : ElfObject->getPltEntries()) {
578       if (!Plt.Symbol)
579         continue;
580       object::SymbolRef Sym(*Plt.Symbol, Object);
581       auto SymNameOrErr = Sym.getName();
582       if (!SymNameOrErr)
583         consumeError(SymNameOrErr.takeError());
584       else if (TrapOnFailFunctions.contains(*SymNameOrErr))
585         TrapOnFailFunctionAddresses.insert(Plt.Address);
586     }
587   }
588   return Error::success();
589 }
590 
UnsupportedDisassembly(StringRef Text)591 UnsupportedDisassembly::UnsupportedDisassembly(StringRef Text)
592     : Text(std::string(Text)) {}
593 
594 char UnsupportedDisassembly::ID;
log(raw_ostream & OS) const595 void UnsupportedDisassembly::log(raw_ostream &OS) const {
596   OS << "Could not initialise disassembler: " << Text;
597 }
598 
convertToErrorCode() const599 std::error_code UnsupportedDisassembly::convertToErrorCode() const {
600   return std::error_code();
601 }
602 
603 } // namespace cfi_verify
604 } // namespace llvm
605