blob: 928571bfd0a49a5689074204a7f0a8ec66c9c84e [file] [log] [blame]
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +00001//===- FileAnalysis.cpp -----------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "FileAnalysis.h"
Mitch Phillips5ff01cd2017-10-25 21:21:16 +000011#include "GraphBuilder.h"
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000012
13#include "llvm/BinaryFormat/ELF.h"
14#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"
32#include "llvm/Support/FormatVariadic.h"
33#include "llvm/Support/MemoryBuffer.h"
34#include "llvm/Support/TargetRegistry.h"
35#include "llvm/Support/TargetSelect.h"
36#include "llvm/Support/raw_ostream.h"
37
38#include <functional>
39
40using Instr = llvm::cfi_verify::FileAnalysis::Instr;
41
42namespace llvm {
43namespace cfi_verify {
44
45Expected<FileAnalysis> FileAnalysis::Create(StringRef Filename) {
46 // Open the filename provided.
47 Expected<object::OwningBinary<object::Binary>> BinaryOrErr =
48 object::createBinary(Filename);
49 if (!BinaryOrErr)
50 return BinaryOrErr.takeError();
51
52 // Construct the object and allow it to take ownership of the binary.
53 object::OwningBinary<object::Binary> Binary = std::move(BinaryOrErr.get());
54 FileAnalysis Analysis(std::move(Binary));
55
56 Analysis.Object = dyn_cast<object::ObjectFile>(Analysis.Binary.getBinary());
57 if (!Analysis.Object)
Mitch Phillipsd9af3832017-10-23 20:54:01 +000058 return make_error<UnsupportedDisassembly>("Failed to cast object");
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +000059
60 Analysis.ObjectTriple = Analysis.Object->makeTriple();
61 Analysis.Features = Analysis.Object->getFeatures();
62
63 // Init the rest of the object.
64 if (auto InitResponse = Analysis.initialiseDisassemblyMembers())
65 return std::move(InitResponse);
66
67 if (auto SectionParseResponse = Analysis.parseCodeSections())
68 return std::move(SectionParseResponse);
69
70 return std::move(Analysis);
71}
72
73FileAnalysis::FileAnalysis(object::OwningBinary<object::Binary> Binary)
74 : Binary(std::move(Binary)) {}
75
76FileAnalysis::FileAnalysis(const Triple &ObjectTriple,
77 const SubtargetFeatures &Features)
78 : ObjectTriple(ObjectTriple), Features(Features) {}
79
Mitch Phillips5ff01cd2017-10-25 21:21:16 +000080bool FileAnalysis::isIndirectInstructionCFIProtected(uint64_t Address) const {
81 const Instr *InstrMetaPtr = getInstruction(Address);
82 if (!InstrMetaPtr)
83 return false;
84
85 const auto &InstrDesc = MII->get(InstrMetaPtr->Instruction.getOpcode());
86
87 if (!InstrDesc.mayAffectControlFlow(InstrMetaPtr->Instruction, *RegisterInfo))
88 return false;
89
90 if (!usesRegisterOperand(*InstrMetaPtr))
91 return false;
92
93 auto Flows = GraphBuilder::buildFlowGraph(*this, Address);
94
95 if (!Flows.OrphanedNodes.empty())
96 return false;
97
98 for (const auto &BranchNode : Flows.ConditionalBranchNodes) {
99 if (!BranchNode.CFIProtection)
100 return false;
101 }
102
103 return true;
104}
105
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000106const Instr *
107FileAnalysis::getPrevInstructionSequential(const Instr &InstrMeta) const {
108 std::map<uint64_t, Instr>::const_iterator KV =
109 Instructions.find(InstrMeta.VMAddress);
110 if (KV == Instructions.end() || KV == Instructions.begin())
111 return nullptr;
112
113 if (!(--KV)->second.Valid)
114 return nullptr;
115
116 return &KV->second;
117}
118
119const Instr *
120FileAnalysis::getNextInstructionSequential(const Instr &InstrMeta) const {
121 std::map<uint64_t, Instr>::const_iterator KV =
122 Instructions.find(InstrMeta.VMAddress);
123 if (KV == Instructions.end() || ++KV == Instructions.end())
124 return nullptr;
125
126 if (!KV->second.Valid)
127 return nullptr;
128
129 return &KV->second;
130}
131
132bool FileAnalysis::usesRegisterOperand(const Instr &InstrMeta) const {
133 for (const auto &Operand : InstrMeta.Instruction) {
134 if (Operand.isReg())
135 return true;
136 }
137 return false;
138}
139
140const Instr *FileAnalysis::getInstruction(uint64_t Address) const {
141 const auto &InstrKV = Instructions.find(Address);
142 if (InstrKV == Instructions.end())
143 return nullptr;
144
145 return &InstrKV->second;
146}
147
148const Instr &FileAnalysis::getInstructionOrDie(uint64_t Address) const {
149 const auto &InstrKV = Instructions.find(Address);
150 assert(InstrKV != Instructions.end() && "Address doesn't exist.");
151 return InstrKV->second;
152}
153
Vlad Tsyrklevich0ee26322017-10-11 23:17:29 +0000154bool FileAnalysis::isCFITrap(const Instr &InstrMeta) const {
155 return MII->getName(InstrMeta.Instruction.getOpcode()) == "TRAP";
156}
157
158bool FileAnalysis::canFallThrough(const Instr &InstrMeta) const {
159 if (!InstrMeta.Valid)
160 return false;
161
162 if (isCFITrap(InstrMeta))
163 return false;
164
165 const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
166 if (InstrDesc.mayAffectControlFlow(InstrMeta.Instruction, *RegisterInfo))
167 return InstrDesc.isConditionalBranch();
168
169 return true;
170}
171
172const Instr *
173FileAnalysis::getDefiniteNextInstruction(const Instr &InstrMeta) const {
174 if (!InstrMeta.Valid)
175 return nullptr;
176
177 if (isCFITrap(InstrMeta))
178 return nullptr;
179
180 const auto &InstrDesc = MII->get(InstrMeta.Instruction.getOpcode());
181 const Instr *NextMetaPtr;
182 if (InstrDesc.mayAffectControlFlow(InstrMeta.Instruction, *RegisterInfo)) {
183 if (InstrDesc.isConditionalBranch())
184 return nullptr;
185
186 uint64_t Target;
187 if (!MIA->evaluateBranch(InstrMeta.Instruction, InstrMeta.VMAddress,
188 InstrMeta.InstructionSize, Target))
189 return nullptr;
190
191 NextMetaPtr = getInstruction(Target);
192 } else {
193 NextMetaPtr =
194 getInstruction(InstrMeta.VMAddress + InstrMeta.InstructionSize);
195 }
196
197 if (!NextMetaPtr || !NextMetaPtr->Valid)
198 return nullptr;
199
200 return NextMetaPtr;
201}
202
203std::set<const Instr *>
204FileAnalysis::getDirectControlFlowXRefs(const Instr &InstrMeta) const {
205 std::set<const Instr *> CFCrossReferences;
206 const Instr *PrevInstruction = getPrevInstructionSequential(InstrMeta);
207
208 if (PrevInstruction && canFallThrough(*PrevInstruction))
209 CFCrossReferences.insert(PrevInstruction);
210
211 const auto &TargetRefsKV = StaticBranchTargetings.find(InstrMeta.VMAddress);
212 if (TargetRefsKV == StaticBranchTargetings.end())
213 return CFCrossReferences;
214
215 for (uint64_t SourceInstrAddress : TargetRefsKV->second) {
216 const auto &SourceInstrKV = Instructions.find(SourceInstrAddress);
217 if (SourceInstrKV == Instructions.end()) {
218 errs() << "Failed to find source instruction at address "
219 << format_hex(SourceInstrAddress, 2)
220 << " for the cross-reference to instruction at address "
221 << format_hex(InstrMeta.VMAddress, 2) << ".\n";
222 continue;
223 }
224
225 CFCrossReferences.insert(&SourceInstrKV->second);
226 }
227
228 return CFCrossReferences;
229}
230
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000231const std::set<uint64_t> &FileAnalysis::getIndirectInstructions() const {
232 return IndirectInstructions;
233}
234
235const MCRegisterInfo *FileAnalysis::getRegisterInfo() const {
236 return RegisterInfo.get();
237}
238
239const MCInstrInfo *FileAnalysis::getMCInstrInfo() const { return MII.get(); }
240
241const MCInstrAnalysis *FileAnalysis::getMCInstrAnalysis() const {
242 return MIA.get();
243}
244
245Error FileAnalysis::initialiseDisassemblyMembers() {
246 std::string TripleName = ObjectTriple.getTriple();
247 ArchName = "";
248 MCPU = "";
249 std::string ErrorString;
250
251 ObjectTarget =
252 TargetRegistry::lookupTarget(ArchName, ObjectTriple, ErrorString);
253 if (!ObjectTarget)
Mitch Phillipsd9af3832017-10-23 20:54:01 +0000254 return make_error<UnsupportedDisassembly>(
255 (Twine("Couldn't find target \"") + ObjectTriple.getTriple() +
Mitch Phillips5ff01cd2017-10-25 21:21:16 +0000256 "\", failed with error: " + ErrorString)
257 .str());
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000258
259 RegisterInfo.reset(ObjectTarget->createMCRegInfo(TripleName));
260 if (!RegisterInfo)
Mitch Phillipsd9af3832017-10-23 20:54:01 +0000261 return make_error<UnsupportedDisassembly>(
262 "Failed to initialise RegisterInfo.");
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000263
264 AsmInfo.reset(ObjectTarget->createMCAsmInfo(*RegisterInfo, TripleName));
265 if (!AsmInfo)
Mitch Phillipsd9af3832017-10-23 20:54:01 +0000266 return make_error<UnsupportedDisassembly>("Failed to initialise AsmInfo.");
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000267
268 SubtargetInfo.reset(ObjectTarget->createMCSubtargetInfo(
269 TripleName, MCPU, Features.getString()));
270 if (!SubtargetInfo)
Mitch Phillipsd9af3832017-10-23 20:54:01 +0000271 return make_error<UnsupportedDisassembly>(
272 "Failed to initialise SubtargetInfo.");
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000273
274 MII.reset(ObjectTarget->createMCInstrInfo());
275 if (!MII)
Mitch Phillipsd9af3832017-10-23 20:54:01 +0000276 return make_error<UnsupportedDisassembly>("Failed to initialise MII.");
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000277
278 Context.reset(new MCContext(AsmInfo.get(), RegisterInfo.get(), &MOFI));
279
280 Disassembler.reset(
281 ObjectTarget->createMCDisassembler(*SubtargetInfo, *Context));
282
283 if (!Disassembler)
Mitch Phillipsd9af3832017-10-23 20:54:01 +0000284 return make_error<UnsupportedDisassembly>(
285 "No disassembler available for target");
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000286
287 MIA.reset(ObjectTarget->createMCInstrAnalysis(MII.get()));
288
289 Printer.reset(ObjectTarget->createMCInstPrinter(
290 ObjectTriple, AsmInfo->getAssemblerDialect(), *AsmInfo, *MII,
291 *RegisterInfo));
292
293 return Error::success();
294}
295
296Error FileAnalysis::parseCodeSections() {
297 for (const object::SectionRef &Section : Object->sections()) {
298 // Ensure only executable sections get analysed.
299 if (!(object::ELFSectionRef(Section).getFlags() & ELF::SHF_EXECINSTR))
300 continue;
301
302 StringRef SectionContents;
303 if (Section.getContents(SectionContents))
304 return make_error<StringError>("Failed to retrieve section contents",
305 inconvertibleErrorCode());
306
307 ArrayRef<uint8_t> SectionBytes((const uint8_t *)SectionContents.data(),
308 Section.getSize());
309 parseSectionContents(SectionBytes, Section.getAddress());
310 }
311 return Error::success();
312}
313
314void FileAnalysis::parseSectionContents(ArrayRef<uint8_t> SectionBytes,
315 uint64_t SectionAddress) {
316 MCInst Instruction;
317 Instr InstrMeta;
318 uint64_t InstructionSize;
319
320 for (uint64_t Byte = 0; Byte < SectionBytes.size();) {
321 bool ValidInstruction =
322 Disassembler->getInstruction(Instruction, InstructionSize,
323 SectionBytes.drop_front(Byte), 0, nulls(),
324 outs()) == MCDisassembler::Success;
325
326 Byte += InstructionSize;
327
328 uint64_t VMAddress = SectionAddress + Byte - InstructionSize;
329 InstrMeta.Instruction = Instruction;
330 InstrMeta.VMAddress = VMAddress;
331 InstrMeta.InstructionSize = InstructionSize;
332 InstrMeta.Valid = ValidInstruction;
333 addInstruction(InstrMeta);
334
335 if (!ValidInstruction)
336 continue;
337
338 // Skip additional parsing for instructions that do not affect the control
339 // flow.
340 const auto &InstrDesc = MII->get(Instruction.getOpcode());
341 if (!InstrDesc.mayAffectControlFlow(Instruction, *RegisterInfo))
342 continue;
343
344 uint64_t Target;
345 if (MIA->evaluateBranch(Instruction, VMAddress, InstructionSize, Target)) {
346 // If the target can be evaluated, it's not indirect.
347 StaticBranchTargetings[Target].push_back(VMAddress);
348 continue;
349 }
350
351 if (!usesRegisterOperand(InstrMeta))
352 continue;
353
354 IndirectInstructions.insert(VMAddress);
355 }
356}
357
358void FileAnalysis::addInstruction(const Instr &Instruction) {
359 const auto &KV =
360 Instructions.insert(std::make_pair(Instruction.VMAddress, Instruction));
361 if (!KV.second) {
362 errs() << "Failed to add instruction at address "
363 << format_hex(Instruction.VMAddress, 2)
364 << ": Instruction at this address already exists.\n";
365 exit(EXIT_FAILURE);
366 }
367}
368
Mitch Phillipsd9af3832017-10-23 20:54:01 +0000369UnsupportedDisassembly::UnsupportedDisassembly(StringRef Text) : Text(Text) {}
370
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000371char UnsupportedDisassembly::ID;
372void UnsupportedDisassembly::log(raw_ostream &OS) const {
Mitch Phillipsd9af3832017-10-23 20:54:01 +0000373 OS << "Could not initialise disassembler: " << Text;
Vlad Tsyrklevich89c3c8c2017-10-11 20:35:01 +0000374}
375
376std::error_code UnsupportedDisassembly::convertToErrorCode() const {
377 return std::error_code();
378}
379
380} // namespace cfi_verify
381} // namespace llvm