blob: ff2ce46a01db168f486794b318c46d708419f6b8 [file] [log] [blame]
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +00001//===- FileAnalysis.cpp -----------------------------------------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "FileAnalysis.h"
Mitch Phillips5ff01cd2017-10-25 21:21:16 +000010#include "GraphBuilder.h"
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000011
12#include "llvm/BinaryFormat/ELF.h"
Mitch Phillips7db6f7a2017-10-31 23:20:05 +000013#include "llvm/DebugInfo/DWARF/DWARFContext.h"
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000014#include "llvm/MC/MCAsmInfo.h"
15#include "llvm/MC/MCContext.h"
16#include "llvm/MC/MCDisassembler/MCDisassembler.h"
17#include "llvm/MC/MCInst.h"
18#include "llvm/MC/MCInstPrinter.h"
19#include "llvm/MC/MCInstrAnalysis.h"
20#include "llvm/MC/MCInstrDesc.h"
21#include "llvm/MC/MCInstrInfo.h"
22#include "llvm/MC/MCObjectFileInfo.h"
23#include "llvm/MC/MCRegisterInfo.h"
24#include "llvm/MC/MCSubtargetInfo.h"
25#include "llvm/Object/Binary.h"
26#include "llvm/Object/COFF.h"
27#include "llvm/Object/ELFObjectFile.h"
28#include "llvm/Object/ObjectFile.h"
29#include "llvm/Support/Casting.h"
30#include "llvm/Support/CommandLine.h"
31#include "llvm/Support/Error.h"
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000032#include "llvm/Support/MemoryBuffer.h"
33#include "llvm/Support/TargetRegistry.h"
34#include "llvm/Support/TargetSelect.h"
35#include "llvm/Support/raw_ostream.h"
36
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000037
38using Instr = llvm::cfi_verify::FileAnalysis::Instr;
Mitch Phillipsc15bdf52017-11-03 20:54:26 +000039using LLVMSymbolizer = llvm::symbolize::LLVMSymbolizer;
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000040
41namespace llvm {
42namespace cfi_verify {
43
Mitch Phillipsc15bdf52017-11-03 20:54:26 +000044bool IgnoreDWARFFlag;
45
46static cl::opt<bool, true> IgnoreDWARFArg(
Mitch Phillips7db6f7a2017-10-31 23:20:05 +000047 "ignore-dwarf",
48 cl::desc(
49 "Ignore all DWARF data. This relaxes the requirements for all "
50 "statically linked libraries to have been compiled with '-g', but "
51 "will result in false positives for 'CFI unprotected' instructions."),
Mitch Phillipsc15bdf52017-11-03 20:54:26 +000052 cl::location(IgnoreDWARFFlag), cl::init(false));
Mitch Phillips7db6f7a2017-10-31 23:20:05 +000053
Mitch Phillips3b9ea322017-11-10 21:00:22 +000054StringRef stringCFIProtectionStatus(CFIProtectionStatus Status) {
55 switch (Status) {
56 case CFIProtectionStatus::PROTECTED:
57 return "PROTECTED";
58 case CFIProtectionStatus::FAIL_NOT_INDIRECT_CF:
59 return "FAIL_NOT_INDIRECT_CF";
60 case CFIProtectionStatus::FAIL_ORPHANS:
61 return "FAIL_ORPHANS";
62 case CFIProtectionStatus::FAIL_BAD_CONDITIONAL_BRANCH:
63 return "FAIL_BAD_CONDITIONAL_BRANCH";
Mitch Phillips2e7be2a2017-11-15 00:35:26 +000064 case CFIProtectionStatus::FAIL_REGISTER_CLOBBERED:
65 return "FAIL_REGISTER_CLOBBERED";
Mitch Phillips3b9ea322017-11-10 21:00:22 +000066 case CFIProtectionStatus::FAIL_INVALID_INSTRUCTION:
67 return "FAIL_INVALID_INSTRUCTION";
68 }
69 llvm_unreachable("Attempted to stringify an unknown enum value.");
70}
71
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000072Expected<FileAnalysis> FileAnalysis::Create(StringRef Filename) {
73 // Open the filename provided.
74 Expected<object::OwningBinary<object::Binary>> BinaryOrErr =
75 object::createBinary(Filename);
76 if (!BinaryOrErr)
77 return BinaryOrErr.takeError();
78
79 // Construct the object and allow it to take ownership of the binary.
80 object::OwningBinary<object::Binary> Binary = std::move(BinaryOrErr.get());
81 FileAnalysis Analysis(std::move(Binary));
82
83 Analysis.Object = dyn_cast<object::ObjectFile>(Analysis.Binary.getBinary());
84 if (!Analysis.Object)
Mitch Phillipsd9af3832017-10-23 20:54:01 +000085 return make_error<UnsupportedDisassembly>("Failed to cast object");
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000086
Joel Galenson4099b242018-07-16 15:26:44 +000087 switch (Analysis.Object->getArch()) {
88 case Triple::x86:
89 case Triple::x86_64:
90 case Triple::aarch64:
91 case Triple::aarch64_be:
92 break;
93 default:
94 return make_error<UnsupportedDisassembly>("Unsupported architecture.");
95 }
96
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000097 Analysis.ObjectTriple = Analysis.Object->makeTriple();
98 Analysis.Features = Analysis.Object->getFeatures();
99
100 // Init the rest of the object.
101 if (auto InitResponse = Analysis.initialiseDisassemblyMembers())
102 return std::move(InitResponse);
103
104 if (auto SectionParseResponse = Analysis.parseCodeSections())
105 return std::move(SectionParseResponse);
106
Joel Galenson6cc0e632018-08-24 15:21:58 +0000107 if (auto SymbolTableParseResponse = Analysis.parseSymbolTable())
108 return std::move(SymbolTableParseResponse);
109
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000110 return std::move(Analysis);
111}
112
113FileAnalysis::FileAnalysis(object::OwningBinary<object::Binary> Binary)
114 : Binary(std::move(Binary)) {}
115
116FileAnalysis::FileAnalysis(const Triple &ObjectTriple,
117 const SubtargetFeatures &Features)
118 : ObjectTriple(ObjectTriple), Features(Features) {}
119
120const Instr *
121FileAnalysis::getPrevInstructionSequential(const Instr &InstrMeta) const {
122 std::map<uint64_t, Instr>::const_iterator KV =
123 Instructions.find(InstrMeta.VMAddress);
124 if (KV == Instructions.end() || KV == Instructions.begin())
125 return nullptr;
126
127 if (!(--KV)->second.Valid)
128 return nullptr;
129
130 return &KV->second;
131}
132
133const Instr *
134FileAnalysis::getNextInstructionSequential(const Instr &InstrMeta) const {
135 std::map<uint64_t, Instr>::const_iterator KV =
136 Instructions.find(InstrMeta.VMAddress);
137 if (KV == Instructions.end() || ++KV == Instructions.end())
138 return nullptr;
139
140 if (!KV->second.Valid)
141 return nullptr;
142
143 return &KV->second;
144}
145
146bool FileAnalysis::usesRegisterOperand(const Instr &InstrMeta) const {
147 for (const auto &Operand : InstrMeta.Instruction) {
148 if (Operand.isReg())
149 return true;
150 }
151 return false;
152}
153
154const Instr *FileAnalysis::getInstruction(uint64_t Address) const {
155 const auto &InstrKV = Instructions.find(Address);
156 if (InstrKV == Instructions.end())
157 return nullptr;
158
159 return &InstrKV->second;
160}
161
162const Instr &FileAnalysis::getInstructionOrDie(uint64_t Address) const {
163 const auto &InstrKV = Instructions.find(Address);
164 assert(InstrKV != Instructions.end() && "Address doesn't exist.");
165 return InstrKV->second;
166}
167
Vlad Tsyrklevich0ee26322017-10-11 23:17:29 +0000168bool FileAnalysis::isCFITrap(const Instr &InstrMeta) const {
Joel Galenson06e7e572018-07-13 15:19:33 +0000169 const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
Joel Galenson6cc0e632018-08-24 15:21:58 +0000170 return InstrDesc.isTrap() || willTrapOnCFIViolation(InstrMeta);
171}
172
173bool FileAnalysis::willTrapOnCFIViolation(const Instr &InstrMeta) const {
174 const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
175 if (!InstrDesc.isCall())
176 return false;
177 uint64_t Target;
178 if (!MIA->evaluateBranch(InstrMeta.Instruction, InstrMeta.VMAddress,
179 InstrMeta.InstructionSize, Target))
180 return false;
181 return TrapOnFailFunctionAddresses.count(Target) > 0;
Vlad Tsyrklevich0ee26322017-10-11 23:17:29 +0000182}
183
184bool FileAnalysis::canFallThrough(const Instr &InstrMeta) const {
185 if (!InstrMeta.Valid)
186 return false;
187
188 if (isCFITrap(InstrMeta))
189 return false;
190
191 const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
192 if (InstrDesc.mayAffectControlFlow(InstrMeta.Instruction, *RegisterInfo))
193 return InstrDesc.isConditionalBranch();
194
195 return true;
196}
197
198const Instr *
199FileAnalysis::getDefiniteNextInstruction(const Instr &InstrMeta) const {
200 if (!InstrMeta.Valid)
201 return nullptr;
202
203 if (isCFITrap(InstrMeta))
204 return nullptr;
205
206 const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
207 const Instr *NextMetaPtr;
208 if (InstrDesc.mayAffectControlFlow(InstrMeta.Instruction, *RegisterInfo)) {
209 if (InstrDesc.isConditionalBranch())
210 return nullptr;
211
212 uint64_t Target;
213 if (!MIA->evaluateBranch(InstrMeta.Instruction, InstrMeta.VMAddress,
214 InstrMeta.InstructionSize, Target))
215 return nullptr;
216
217 NextMetaPtr = getInstruction(Target);
218 } else {
219 NextMetaPtr =
220 getInstruction(InstrMeta.VMAddress + InstrMeta.InstructionSize);
221 }
222
223 if (!NextMetaPtr || !NextMetaPtr->Valid)
224 return nullptr;
225
226 return NextMetaPtr;
227}
228
229std::set<const Instr *>
230FileAnalysis::getDirectControlFlowXRefs(const Instr &InstrMeta) const {
231 std::set<const Instr *> CFCrossReferences;
232 const Instr *PrevInstruction = getPrevInstructionSequential(InstrMeta);
233
234 if (PrevInstruction && canFallThrough(*PrevInstruction))
235 CFCrossReferences.insert(PrevInstruction);
236
237 const auto &TargetRefsKV = StaticBranchTargetings.find(InstrMeta.VMAddress);
238 if (TargetRefsKV == StaticBranchTargetings.end())
239 return CFCrossReferences;
240
241 for (uint64_t SourceInstrAddress : TargetRefsKV->second) {
242 const auto &SourceInstrKV = Instructions.find(SourceInstrAddress);
243 if (SourceInstrKV == Instructions.end()) {
244 errs() << "Failed to find source instruction at address "
245 << format_hex(SourceInstrAddress, 2)
246 << " for the cross-reference to instruction at address "
247 << format_hex(InstrMeta.VMAddress, 2) << ".\n";
248 continue;
249 }
250
251 CFCrossReferences.insert(&SourceInstrKV->second);
252 }
253
254 return CFCrossReferences;
255}
256
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000257const std::set<object::SectionedAddress> &
258FileAnalysis::getIndirectInstructions() const {
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000259 return IndirectInstructions;
260}
261
262const MCRegisterInfo *FileAnalysis::getRegisterInfo() const {
263 return RegisterInfo.get();
264}
265
266const MCInstrInfo *FileAnalysis::getMCInstrInfo() const { return MII.get(); }
267
268const MCInstrAnalysis *FileAnalysis::getMCInstrAnalysis() const {
269 return MIA.get();
270}
271
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000272Expected<DIInliningInfo>
273FileAnalysis::symbolizeInlinedCode(object::SectionedAddress Address) {
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000274 assert(Symbolizer != nullptr && "Symbolizer is invalid.");
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000275
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000276 return Symbolizer->symbolizeInlinedCode(Object->getFileName(), Address);
277}
278
279CFIProtectionStatus
280FileAnalysis::validateCFIProtection(const GraphResult &Graph) const {
281 const Instr *InstrMetaPtr = getInstruction(Graph.BaseAddress);
282 if (!InstrMetaPtr)
283 return CFIProtectionStatus::FAIL_INVALID_INSTRUCTION;
284
285 const auto &InstrDesc = MII->get(InstrMetaPtr->Instruction.getOpcode());
286 if (!InstrDesc.mayAffectControlFlow(InstrMetaPtr->Instruction, *RegisterInfo))
287 return CFIProtectionStatus::FAIL_NOT_INDIRECT_CF;
288
289 if (!usesRegisterOperand(*InstrMetaPtr))
290 return CFIProtectionStatus::FAIL_NOT_INDIRECT_CF;
291
292 if (!Graph.OrphanedNodes.empty())
293 return CFIProtectionStatus::FAIL_ORPHANS;
294
295 for (const auto &BranchNode : Graph.ConditionalBranchNodes) {
296 if (!BranchNode.CFIProtection)
297 return CFIProtectionStatus::FAIL_BAD_CONDITIONAL_BRANCH;
298 }
299
Mitch Phillips2e7be2a2017-11-15 00:35:26 +0000300 if (indirectCFOperandClobber(Graph) != Graph.BaseAddress)
301 return CFIProtectionStatus::FAIL_REGISTER_CLOBBERED;
302
Mitch Phillips3b9ea322017-11-10 21:00:22 +0000303 return CFIProtectionStatus::PROTECTED;
304}
Mitch Phillipsc15bdf52017-11-03 20:54:26 +0000305
Mitch Phillips2e7be2a2017-11-15 00:35:26 +0000306uint64_t FileAnalysis::indirectCFOperandClobber(const GraphResult &Graph) const {
307 assert(Graph.OrphanedNodes.empty() && "Orphaned nodes should be empty.");
308
309 // Get the set of registers we must check to ensure they're not clobbered.
310 const Instr &IndirectCF = getInstructionOrDie(Graph.BaseAddress);
311 DenseSet<unsigned> RegisterNumbers;
312 for (const auto &Operand : IndirectCF.Instruction) {
313 if (Operand.isReg())
314 RegisterNumbers.insert(Operand.getReg());
315 }
316 assert(RegisterNumbers.size() && "Zero register operands on indirect CF.");
317
318 // Now check all branches to indirect CFs and ensure no clobbering happens.
319 for (const auto &Branch : Graph.ConditionalBranchNodes) {
320 uint64_t Node;
321 if (Branch.IndirectCFIsOnTargetPath)
322 Node = Branch.Target;
323 else
324 Node = Branch.Fallthrough;
325
Joel Galenson06e7e572018-07-13 15:19:33 +0000326 // Some architectures (e.g., AArch64) cannot load in an indirect branch, so
327 // we allow them one load.
328 bool canLoad = !MII->get(IndirectCF.Instruction.getOpcode()).mayLoad();
329
330 // We walk backwards from the indirect CF. It is the last node returned by
331 // Graph.flattenAddress, so we skip it since we already handled it.
332 DenseSet<unsigned> CurRegisterNumbers = RegisterNumbers;
333 std::vector<uint64_t> Nodes = Graph.flattenAddress(Node);
334 for (auto I = Nodes.rbegin() + 1, E = Nodes.rend(); I != E; ++I) {
335 Node = *I;
Mitch Phillips2e7be2a2017-11-15 00:35:26 +0000336 const Instr &NodeInstr = getInstructionOrDie(Node);
337 const auto &InstrDesc = MII->get(NodeInstr.Instruction.getOpcode());
338
Joel Galenson06e7e572018-07-13 15:19:33 +0000339 for (auto RI = CurRegisterNumbers.begin(), RE = CurRegisterNumbers.end();
340 RI != RE; ++RI) {
341 unsigned RegNum = *RI;
Mitch Phillips2e7be2a2017-11-15 00:35:26 +0000342 if (InstrDesc.hasDefOfPhysReg(NodeInstr.Instruction, RegNum,
Joel Galenson06e7e572018-07-13 15:19:33 +0000343 *RegisterInfo)) {
344 if (!canLoad || !InstrDesc.mayLoad())
345 return Node;
346 canLoad = false;
347 CurRegisterNumbers.erase(RI);
348 // Add the registers this load reads to those we check for clobbers.
349 for (unsigned i = InstrDesc.getNumDefs(),
350 e = InstrDesc.getNumOperands(); i != e; i++) {
351 const auto Operand = NodeInstr.Instruction.getOperand(i);
352 if (Operand.isReg())
353 CurRegisterNumbers.insert(Operand.getReg());
354 }
355 break;
356 }
Mitch Phillips2e7be2a2017-11-15 00:35:26 +0000357 }
Mitch Phillips2e7be2a2017-11-15 00:35:26 +0000358 }
359 }
360
361 return Graph.BaseAddress;
362}
363
Mitch Phillips02993892017-11-14 22:43:13 +0000364void FileAnalysis::printInstruction(const Instr &InstrMeta,
365 raw_ostream &OS) const {
366 Printer->printInst(&InstrMeta.Instruction, OS, "", *SubtargetInfo.get());
367}
368
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000369Error FileAnalysis::initialiseDisassemblyMembers() {
370 std::string TripleName = ObjectTriple.getTriple();
371 ArchName = "";
372 MCPU = "";
373 std::string ErrorString;
374
Mitch Phillipsc15bdf52017-11-03 20:54:26 +0000375 Symbolizer.reset(new LLVMSymbolizer());
376
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000377 ObjectTarget =
378 TargetRegistry::lookupTarget(ArchName, ObjectTriple, ErrorString);
379 if (!ObjectTarget)
Mitch Phillipsd9af3832017-10-23 20:54:01 +0000380 return make_error<UnsupportedDisassembly>(
381 (Twine("Couldn't find target \"") + ObjectTriple.getTriple() +
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000382 "\", failed with error: " + ErrorString)
383 .str());
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000384
385 RegisterInfo.reset(ObjectTarget->createMCRegInfo(TripleName));
386 if (!RegisterInfo)
Mitch Phillipsd9af3832017-10-23 20:54:01 +0000387 return make_error<UnsupportedDisassembly>(
388 "Failed to initialise RegisterInfo.");
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000389
390 AsmInfo.reset(ObjectTarget->createMCAsmInfo(*RegisterInfo, TripleName));
391 if (!AsmInfo)
Mitch Phillipsd9af3832017-10-23 20:54:01 +0000392 return make_error<UnsupportedDisassembly>("Failed to initialise AsmInfo.");
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000393
394 SubtargetInfo.reset(ObjectTarget->createMCSubtargetInfo(
395 TripleName, MCPU, Features.getString()));
396 if (!SubtargetInfo)
Mitch Phillipsd9af3832017-10-23 20:54:01 +0000397 return make_error<UnsupportedDisassembly>(
398 "Failed to initialise SubtargetInfo.");
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000399
400 MII.reset(ObjectTarget->createMCInstrInfo());
401 if (!MII)
Mitch Phillipsd9af3832017-10-23 20:54:01 +0000402 return make_error<UnsupportedDisassembly>("Failed to initialise MII.");
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000403
404 Context.reset(new MCContext(AsmInfo.get(), RegisterInfo.get(), &MOFI));
405
406 Disassembler.reset(
407 ObjectTarget->createMCDisassembler(*SubtargetInfo, *Context));
408
409 if (!Disassembler)
Mitch Phillipsd9af3832017-10-23 20:54:01 +0000410 return make_error<UnsupportedDisassembly>(
411 "No disassembler available for target");
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000412
413 MIA.reset(ObjectTarget->createMCInstrAnalysis(MII.get()));
414
415 Printer.reset(ObjectTarget->createMCInstPrinter(
416 ObjectTriple, AsmInfo->getAssemblerDialect(), *AsmInfo, *MII,
417 *RegisterInfo));
418
419 return Error::success();
420}
421
422Error FileAnalysis::parseCodeSections() {
Mitch Phillipsc15bdf52017-11-03 20:54:26 +0000423 if (!IgnoreDWARFFlag) {
424 std::unique_ptr<DWARFContext> DWARF = DWARFContext::create(*Object);
Mitch Phillips7db6f7a2017-10-31 23:20:05 +0000425 if (!DWARF)
426 return make_error<StringError>("Could not create DWARF information.",
427 inconvertibleErrorCode());
428
429 bool LineInfoValid = false;
430
431 for (auto &Unit : DWARF->compile_units()) {
432 const auto &LineTable = DWARF->getLineTableForUnit(Unit.get());
433 if (LineTable && !LineTable->Rows.empty()) {
434 LineInfoValid = true;
435 break;
436 }
437 }
438
439 if (!LineInfoValid)
440 return make_error<StringError>(
441 "DWARF line information missing. Did you compile with '-g'?",
442 inconvertibleErrorCode());
443 }
444
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000445 for (const object::SectionRef &Section : Object->sections()) {
446 // Ensure only executable sections get analysed.
447 if (!(object::ELFSectionRef(Section).getFlags() & ELF::SHF_EXECINSTR))
448 continue;
449
Joel Galenson6cc0e632018-08-24 15:21:58 +0000450 // Avoid checking the PLT since it produces spurious failures on AArch64
451 // when ignoring DWARF data.
452 StringRef SectionName;
453 if (!Section.getName(SectionName) && SectionName == ".plt")
454 continue;
455
Hans Wennborg4da9ff92019-05-16 12:08:34 +0000456 StringRef SectionContents;
457 if (Section.getContents(SectionContents))
458 return make_error<StringError>("Failed to retrieve section contents",
459 inconvertibleErrorCode());
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000460
Hans Wennborg4da9ff92019-05-16 12:08:34 +0000461 ArrayRef<uint8_t> SectionBytes((const uint8_t *)SectionContents.data(),
462 Section.getSize());
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000463 parseSectionContents(SectionBytes,
464 {Section.getAddress(), Section.getIndex()});
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000465 }
466 return Error::success();
467}
468
469void FileAnalysis::parseSectionContents(ArrayRef<uint8_t> SectionBytes,
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000470 object::SectionedAddress Address) {
Mitch Phillipsc15bdf52017-11-03 20:54:26 +0000471 assert(Symbolizer && "Symbolizer is uninitialised.");
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000472 MCInst Instruction;
473 Instr InstrMeta;
474 uint64_t InstructionSize;
475
476 for (uint64_t Byte = 0; Byte < SectionBytes.size();) {
477 bool ValidInstruction =
478 Disassembler->getInstruction(Instruction, InstructionSize,
479 SectionBytes.drop_front(Byte), 0, nulls(),
480 outs()) == MCDisassembler::Success;
481
482 Byte += InstructionSize;
483
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000484 uint64_t VMAddress = Address.Address + Byte - InstructionSize;
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000485 InstrMeta.Instruction = Instruction;
486 InstrMeta.VMAddress = VMAddress;
487 InstrMeta.InstructionSize = InstructionSize;
488 InstrMeta.Valid = ValidInstruction;
Mitch Phillips7db6f7a2017-10-31 23:20:05 +0000489
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000490 addInstruction(InstrMeta);
491
492 if (!ValidInstruction)
493 continue;
494
495 // Skip additional parsing for instructions that do not affect the control
496 // flow.
497 const auto &InstrDesc = MII->get(Instruction.getOpcode());
498 if (!InstrDesc.mayAffectControlFlow(Instruction, *RegisterInfo))
499 continue;
500
501 uint64_t Target;
502 if (MIA->evaluateBranch(Instruction, VMAddress, InstructionSize, Target)) {
503 // If the target can be evaluated, it's not indirect.
504 StaticBranchTargetings[Target].push_back(VMAddress);
505 continue;
506 }
507
508 if (!usesRegisterOperand(InstrMeta))
509 continue;
510
Joel Galenson06e7e572018-07-13 15:19:33 +0000511 if (InstrDesc.isReturn())
512 continue;
513
Mitch Phillipsd64af522017-11-09 00:18:31 +0000514 // Check if this instruction exists in the range of the DWARF metadata.
515 if (!IgnoreDWARFFlag) {
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000516 auto LineInfo = Symbolizer->symbolizeCode(
517 Object->getFileName(), {VMAddress, Address.SectionIndex});
Mitch Phillipsd64af522017-11-09 00:18:31 +0000518 if (!LineInfo) {
519 handleAllErrors(LineInfo.takeError(), [](const ErrorInfoBase &E) {
520 errs() << "Symbolizer failed to get line: " << E.message() << "\n";
521 });
522 continue;
523 }
524
525 if (LineInfo->FileName == "<invalid>")
526 continue;
527 }
528
Alexey Lapshin77fc1f62019-02-27 13:17:36 +0000529 IndirectInstructions.insert({VMAddress, Address.SectionIndex});
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000530 }
531}
532
533void FileAnalysis::addInstruction(const Instr &Instruction) {
534 const auto &KV =
535 Instructions.insert(std::make_pair(Instruction.VMAddress, Instruction));
536 if (!KV.second) {
537 errs() << "Failed to add instruction at address "
538 << format_hex(Instruction.VMAddress, 2)
539 << ": Instruction at this address already exists.\n";
540 exit(EXIT_FAILURE);
541 }
542}
543
Joel Galenson6cc0e632018-08-24 15:21:58 +0000544Error FileAnalysis::parseSymbolTable() {
545 // Functions that will trap on CFI violations.
546 SmallSet<StringRef, 4> TrapOnFailFunctions;
547 TrapOnFailFunctions.insert("__cfi_slowpath");
548 TrapOnFailFunctions.insert("__cfi_slowpath_diag");
549 TrapOnFailFunctions.insert("abort");
550
551 // Look through the list of symbols for functions that will trap on CFI
552 // violations.
553 for (auto &Sym : Object->symbols()) {
554 auto SymNameOrErr = Sym.getName();
555 if (!SymNameOrErr)
556 consumeError(SymNameOrErr.takeError());
557 else if (TrapOnFailFunctions.count(*SymNameOrErr) > 0) {
558 auto AddrOrErr = Sym.getAddress();
559 if (!AddrOrErr)
560 consumeError(AddrOrErr.takeError());
561 else
562 TrapOnFailFunctionAddresses.insert(*AddrOrErr);
563 }
564 }
565 if (auto *ElfObject = dyn_cast<object::ELFObjectFileBase>(Object)) {
566 for (const auto &Addr : ElfObject->getPltAddresses()) {
567 object::SymbolRef Sym(Addr.first, Object);
568 auto SymNameOrErr = Sym.getName();
569 if (!SymNameOrErr)
570 consumeError(SymNameOrErr.takeError());
571 else if (TrapOnFailFunctions.count(*SymNameOrErr) > 0)
572 TrapOnFailFunctionAddresses.insert(Addr.second);
573 }
574 }
575 return Error::success();
576}
577
Mitch Phillipsd9af3832017-10-23 20:54:01 +0000578UnsupportedDisassembly::UnsupportedDisassembly(StringRef Text) : Text(Text) {}
579
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000580char UnsupportedDisassembly::ID;
581void UnsupportedDisassembly::log(raw_ostream &OS) const {
Mitch Phillipsd9af3832017-10-23 20:54:01 +0000582 OS << "Could not initialise disassembler: " << Text;
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000583}
584
585std::error_code UnsupportedDisassembly::convertToErrorCode() const {
586 return std::error_code();
587}
588
589} // namespace cfi_verify
590} // namespace llvm