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
39using Instr = llvm::cfi_verify::FileAnalysis::Instr;
40using LLVMSymbolizer = llvm::symbolize::LLVMSymbolizer;
41
42namespace llvm {
43namespace cfi_verify {
44
45bool IgnoreDWARFFlag;
46
47static 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(L&: IgnoreDWARFFlag), cl::init(Val: false));
54
55StringRef 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
73Expected<FileAnalysis> FileAnalysis::Create(StringRef Filename) {
74 // Open the filename provided.
75 Expected<object::OwningBinary<object::Binary>> BinaryOrErr =
76 object::createBinary(Path: 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>(Val: Analysis.Binary.getBinary());
85 if (!Analysis.Object)
86 return make_error<UnsupportedDisassembly>(Args: "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>(Args: "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
118FileAnalysis::FileAnalysis(object::OwningBinary<object::Binary> Binary)
119 : Binary(std::move(Binary)) {}
120
121FileAnalysis::FileAnalysis(const Triple &ObjectTriple,
122 const SubtargetFeatures &Features)
123 : ObjectTriple(ObjectTriple), Features(Features) {}
124
125const Instr *
126FileAnalysis::getPrevInstructionSequential(const Instr &InstrMeta) const {
127 std::map<uint64_t, Instr>::const_iterator KV =
128 Instructions.find(x: 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
138const Instr *
139FileAnalysis::getNextInstructionSequential(const Instr &InstrMeta) const {
140 std::map<uint64_t, Instr>::const_iterator KV =
141 Instructions.find(x: 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
151bool 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
159const Instr *FileAnalysis::getInstruction(uint64_t Address) const {
160 const auto &InstrKV = Instructions.find(x: Address);
161 if (InstrKV == Instructions.end())
162 return nullptr;
163
164 return &InstrKV->second;
165}
166
167const Instr &FileAnalysis::getInstructionOrDie(uint64_t Address) const {
168 const auto &InstrKV = Instructions.find(x: Address);
169 assert(InstrKV != Instructions.end() && "Address doesn't exist.");
170 return InstrKV->second;
171}
172
173bool FileAnalysis::isCFITrap(const Instr &InstrMeta) const {
174 const auto &InstrDesc = MII->get(Opcode: InstrMeta.Instruction.getOpcode());
175 return InstrDesc.isTrap() || willTrapOnCFIViolation(InstrMeta);
176}
177
178bool FileAnalysis::willTrapOnCFIViolation(const Instr &InstrMeta) const {
179 const auto &InstrDesc = MII->get(Opcode: InstrMeta.Instruction.getOpcode());
180 if (!InstrDesc.isCall())
181 return false;
182 uint64_t Target;
183 if (!MIA->evaluateBranch(Inst: InstrMeta.Instruction, Addr: InstrMeta.VMAddress,
184 Size: InstrMeta.InstructionSize, Target))
185 return false;
186 return TrapOnFailFunctionAddresses.contains(V: Target);
187}
188
189bool 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(Opcode: InstrMeta.Instruction.getOpcode());
197 if (InstrDesc.mayAffectControlFlow(MI: InstrMeta.Instruction, RI: *RegisterInfo))
198 return InstrDesc.isConditionalBranch();
199
200 return true;
201}
202
203const Instr *
204FileAnalysis::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(Opcode: InstrMeta.Instruction.getOpcode());
212 const Instr *NextMetaPtr;
213 if (InstrDesc.mayAffectControlFlow(MI: InstrMeta.Instruction, RI: *RegisterInfo)) {
214 if (InstrDesc.isConditionalBranch())
215 return nullptr;
216
217 uint64_t Target;
218 if (!MIA->evaluateBranch(Inst: InstrMeta.Instruction, Addr: InstrMeta.VMAddress,
219 Size: InstrMeta.InstructionSize, Target))
220 return nullptr;
221
222 NextMetaPtr = getInstruction(Address: Target);
223 } else {
224 NextMetaPtr =
225 getInstruction(Address: InstrMeta.VMAddress + InstrMeta.InstructionSize);
226 }
227
228 if (!NextMetaPtr || !NextMetaPtr->Valid)
229 return nullptr;
230
231 return NextMetaPtr;
232}
233
234std::set<const Instr *>
235FileAnalysis::getDirectControlFlowXRefs(const Instr &InstrMeta) const {
236 std::set<const Instr *> CFCrossReferences;
237 const Instr *PrevInstruction = getPrevInstructionSequential(InstrMeta);
238
239 if (PrevInstruction && canFallThrough(InstrMeta: *PrevInstruction))
240 CFCrossReferences.insert(x: PrevInstruction);
241
242 const auto &TargetRefsKV = StaticBranchTargetings.find(Val: InstrMeta.VMAddress);
243 if (TargetRefsKV == StaticBranchTargetings.end())
244 return CFCrossReferences;
245
246 for (uint64_t SourceInstrAddress : TargetRefsKV->second) {
247 const auto &SourceInstrKV = Instructions.find(x: SourceInstrAddress);
248 if (SourceInstrKV == Instructions.end()) {
249 errs() << "Failed to find source instruction at address "
250 << format_hex(N: SourceInstrAddress, Width: 2)
251 << " for the cross-reference to instruction at address "
252 << format_hex(N: InstrMeta.VMAddress, Width: 2) << ".\n";
253 continue;
254 }
255
256 CFCrossReferences.insert(x: &SourceInstrKV->second);
257 }
258
259 return CFCrossReferences;
260}
261
262const std::set<object::SectionedAddress> &
263FileAnalysis::getIndirectInstructions() const {
264 return IndirectInstructions;
265}
266
267const MCRegisterInfo *FileAnalysis::getRegisterInfo() const {
268 return RegisterInfo.get();
269}
270
271const MCInstrInfo *FileAnalysis::getMCInstrInfo() const { return MII.get(); }
272
273const MCInstrAnalysis *FileAnalysis::getMCInstrAnalysis() const {
274 return MIA.get();
275}
276
277Expected<DIInliningInfo>
278FileAnalysis::symbolizeInlinedCode(object::SectionedAddress Address) {
279 assert(Symbolizer != nullptr && "Symbolizer is invalid.");
280
281 return Symbolizer->symbolizeInlinedCode(ModuleName: std::string(Object->getFileName()),
282 ModuleOffset: Address);
283}
284
285CFIProtectionStatus
286FileAnalysis::validateCFIProtection(const GraphResult &Graph) const {
287 const Instr *InstrMetaPtr = getInstruction(Address: Graph.BaseAddress);
288 if (!InstrMetaPtr)
289 return CFIProtectionStatus::FAIL_INVALID_INSTRUCTION;
290
291 const auto &InstrDesc = MII->get(Opcode: InstrMetaPtr->Instruction.getOpcode());
292 if (!InstrDesc.mayAffectControlFlow(MI: InstrMetaPtr->Instruction, RI: *RegisterInfo))
293 return CFIProtectionStatus::FAIL_NOT_INDIRECT_CF;
294
295 if (!usesRegisterOperand(InstrMeta: *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
312uint64_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(Address: Graph.BaseAddress);
317 DenseSet<unsigned> RegisterNumbers;
318 for (const auto &Operand : IndirectCF.Instruction) {
319 if (Operand.isReg())
320 RegisterNumbers.insert(V: 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(Opcode: 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(Address: Node);
340 for (auto I = Nodes.rbegin() + 1, E = Nodes.rend(); I != E; ++I) {
341 Node = *I;
342 const Instr &NodeInstr = getInstructionOrDie(Address: Node);
343 const auto &InstrDesc = MII->get(Opcode: 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(MI: NodeInstr.Instruction, Reg: RegNum,
349 RI: *RegisterInfo)) {
350 if (!canLoad || !InstrDesc.mayLoad())
351 return Node;
352 canLoad = false;
353 CurRegisterNumbers.erase(I: 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(V: Operand.getReg());
360 }
361 break;
362 }
363 }
364 }
365 }
366
367 return Graph.BaseAddress;
368}
369
370void FileAnalysis::printInstruction(const Instr &InstrMeta,
371 raw_ostream &OS) const {
372 Printer->printInst(MI: &InstrMeta.Instruction, Address: 0, Annot: "", STI: *SubtargetInfo, OS);
373}
374
375Error 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(p: new LLVMSymbolizer(Opt));
384
385 ObjectTarget =
386 TargetRegistry::lookupTarget(ArchName, TheTriple&: ObjectTriple, Error&: ErrorString);
387 if (!ObjectTarget)
388 return make_error<UnsupportedDisassembly>(
389 Args: (Twine("Couldn't find target \"") + ObjectTriple.getTriple() +
390 "\", failed with error: " + ErrorString)
391 .str());
392
393 RegisterInfo.reset(p: ObjectTarget->createMCRegInfo(TT: TripleName));
394 if (!RegisterInfo)
395 return make_error<UnsupportedDisassembly>(
396 Args: "Failed to initialise RegisterInfo.");
397
398 MCTargetOptions MCOptions;
399 AsmInfo.reset(
400 p: ObjectTarget->createMCAsmInfo(MRI: *RegisterInfo, TheTriple: TripleName, Options: MCOptions));
401 if (!AsmInfo)
402 return make_error<UnsupportedDisassembly>(Args: "Failed to initialise AsmInfo.");
403
404 SubtargetInfo.reset(p: ObjectTarget->createMCSubtargetInfo(
405 TheTriple: TripleName, CPU: MCPU, Features: Features.getString()));
406 if (!SubtargetInfo)
407 return make_error<UnsupportedDisassembly>(
408 Args: "Failed to initialise SubtargetInfo.");
409
410 MII.reset(p: ObjectTarget->createMCInstrInfo());
411 if (!MII)
412 return make_error<UnsupportedDisassembly>(Args: "Failed to initialise MII.");
413
414 Context.reset(p: new MCContext(Triple(TripleName), AsmInfo.get(),
415 RegisterInfo.get(), SubtargetInfo.get()));
416
417 Disassembler.reset(
418 p: ObjectTarget->createMCDisassembler(STI: *SubtargetInfo, Ctx&: *Context));
419
420 if (!Disassembler)
421 return make_error<UnsupportedDisassembly>(
422 Args: "No disassembler available for target");
423
424 MIA.reset(p: ObjectTarget->createMCInstrAnalysis(Info: MII.get()));
425
426 Printer.reset(p: ObjectTarget->createMCInstPrinter(
427 T: ObjectTriple, SyntaxVariant: AsmInfo->getAssemblerDialect(), MAI: *AsmInfo, MII: *MII,
428 MRI: *RegisterInfo));
429
430 return Error::success();
431}
432
433Error FileAnalysis::parseCodeSections() {
434 if (!IgnoreDWARFFlag) {
435 std::unique_ptr<DWARFContext> DWARF = DWARFContext::create(Obj: *Object);
436 if (!DWARF)
437 return make_error<StringError>(Args: "Could not create DWARF information.",
438 Args: inconvertibleErrorCode());
439
440 bool LineInfoValid = false;
441
442 for (auto &Unit : DWARF->compile_units()) {
443 const auto &LineTable = DWARF->getLineTableForUnit(U: 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 Args: "DWARF line information missing. Did you compile with '-g'?",
453 Args: 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(Err: NameOrErr.takeError());
467
468 Expected<StringRef> Contents = Section.getContents();
469 if (!Contents)
470 return Contents.takeError();
471 ArrayRef<uint8_t> SectionBytes = arrayRefFromStringRef(Input: *Contents);
472
473 parseSectionContents(SectionBytes,
474 Address: {.Address: Section.getAddress(), .SectionIndex: Section.getIndex()});
475 }
476 return Error::success();
477}
478
479void 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(Instr&: Instruction, Size&: InstructionSize,
489 Bytes: SectionBytes.drop_front(N: Byte), Address: 0,
490 CStream&: 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(Instruction: 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(Opcode: Instruction.getOpcode());
508 if (!InstrDesc.mayAffectControlFlow(MI: Instruction, RI: *RegisterInfo))
509 continue;
510
511 uint64_t Target;
512 if (MIA->evaluateBranch(Inst: Instruction, Addr: VMAddress, Size: InstructionSize, Target)) {
513 // If the target can be evaluated, it's not indirect.
514 StaticBranchTargetings[Target].push_back(x: 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(ModuleName: std::string(Object->getFileName()),
528 ModuleOffset: {.Address: VMAddress, .SectionIndex: Address.SectionIndex});
529 if (!LineInfo) {
530 handleAllErrors(E: LineInfo.takeError(), Handlers: [](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(x: {.Address: VMAddress, .SectionIndex: Address.SectionIndex});
541 }
542}
543
544void FileAnalysis::addInstruction(const Instr &Instruction) {
545 const auto &KV =
546 Instructions.insert(x: std::make_pair(x: Instruction.VMAddress, y: Instruction));
547 if (!KV.second) {
548 errs() << "Failed to add instruction at address "
549 << format_hex(N: Instruction.VMAddress, Width: 2)
550 << ": Instruction at this address already exists.\n";
551 exit(EXIT_FAILURE);
552 }
553}
554
555Error FileAnalysis::parseSymbolTable() {
556 // Functions that will trap on CFI violations.
557 SmallSet<StringRef, 4> TrapOnFailFunctions;
558 TrapOnFailFunctions.insert(V: "__cfi_slowpath");
559 TrapOnFailFunctions.insert(V: "__cfi_slowpath_diag");
560 TrapOnFailFunctions.insert(V: "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(Err: SymNameOrErr.takeError());
568 else if (TrapOnFailFunctions.contains(V: *SymNameOrErr)) {
569 auto AddrOrErr = Sym.getAddress();
570 if (!AddrOrErr)
571 consumeError(Err: AddrOrErr.takeError());
572 else
573 TrapOnFailFunctionAddresses.insert(V: *AddrOrErr);
574 }
575 }
576 if (auto *ElfObject = dyn_cast<object::ELFObjectFileBase>(Val: 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(Err: SymNameOrErr.takeError());
584 else if (TrapOnFailFunctions.contains(V: *SymNameOrErr))
585 TrapOnFailFunctionAddresses.insert(V: Plt.Address);
586 }
587 }
588 return Error::success();
589}
590
591UnsupportedDisassembly::UnsupportedDisassembly(StringRef Text)
592 : Text(std::string(Text)) {}
593
594char UnsupportedDisassembly::ID;
595void UnsupportedDisassembly::log(raw_ostream &OS) const {
596 OS << "Could not initialise disassembler: " << Text;
597}
598
599std::error_code UnsupportedDisassembly::convertToErrorCode() const {
600 return std::error_code();
601}
602
603} // namespace cfi_verify
604} // namespace llvm
605