blob: 63dc6f128e19ae8bb2ed400d92a810c01862f6e6 [file] [log] [blame]
Vlad Tsyrklevich31b45312017-09-20 20:38:14 +00001//===-- llvm-cfi-verify.cpp - CFI Verification tool for LLVM --------------===//
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// This tool verifies Control Flow Integrity (CFI) instrumentation by static
11// binary anaylsis. See the design document in /docs/CFIVerify.rst for more
12// information.
13//
14// This tool is currently incomplete. It currently only does disassembly for
15// object files, and searches through the code for indirect control flow
16// instructions, printing them once found.
17//
18//===----------------------------------------------------------------------===//
19
Vlad Tsyrklevicha45919f2017-10-10 21:21:13 +000020#include "llvm/MC/MCAsmInfo.h"
21#include "llvm/MC/MCContext.h"
22#include "llvm/MC/MCDisassembler/MCDisassembler.h"
23#include "llvm/MC/MCInst.h"
24#include "llvm/MC/MCInstPrinter.h"
25#include "llvm/MC/MCInstrAnalysis.h"
26#include "llvm/MC/MCInstrDesc.h"
27#include "llvm/MC/MCInstrInfo.h"
28#include "llvm/MC/MCObjectFileInfo.h"
29#include "llvm/MC/MCRegisterInfo.h"
30#include "llvm/MC/MCSubtargetInfo.h"
31#include "llvm/Object/Binary.h"
32#include "llvm/Object/COFF.h"
33#include "llvm/Object/ObjectFile.h"
34#include "llvm/Support/Casting.h"
Vlad Tsyrklevichb5488a22017-10-10 20:59:08 +000035#include "llvm/Support/CommandLine.h"
Vlad Tsyrklevicha45919f2017-10-10 21:21:13 +000036#include "llvm/Support/MemoryBuffer.h"
37#include "llvm/Support/TargetRegistry.h"
38#include "llvm/Support/TargetSelect.h"
39#include "llvm/Support/raw_ostream.h"
Vlad Tsyrklevichb5488a22017-10-10 20:59:08 +000040
Vlad Tsyrklevicha45919f2017-10-10 21:21:13 +000041#include <cassert>
Vlad Tsyrklevich31b45312017-09-20 20:38:14 +000042#include <cstdlib>
43
44using namespace llvm;
45using namespace llvm::object;
46
Vlad Tsyrklevicha45919f2017-10-10 21:21:13 +000047cl::opt<bool> ArgDumpSymbols("sym", cl::desc("Dump the symbol table."));
Vlad Tsyrklevich31b45312017-09-20 20:38:14 +000048cl::opt<std::string> InputFilename(cl::Positional, cl::desc("<input file>"),
49 cl::Required);
50
Vlad Tsyrklevicha45919f2017-10-10 21:21:13 +000051static void printSymbols(const ObjectFile *Object) {
52 for (const SymbolRef &Symbol : Object->symbols()) {
53 outs() << "Symbol [" << format_hex_no_prefix(Symbol.getValue(), 2)
54 << "] = ";
Vlad Tsyrklevich31b45312017-09-20 20:38:14 +000055
Vlad Tsyrklevicha45919f2017-10-10 21:21:13 +000056 auto SymbolName = Symbol.getName();
57 if (SymbolName)
58 outs() << *SymbolName;
59 else
60 outs() << "UNKNOWN";
61
62 if (Symbol.getFlags() & SymbolRef::SF_Hidden)
63 outs() << " .hidden";
64
65 outs() << " (Section = ";
66
67 auto SymbolSection = Symbol.getSection();
68 if (SymbolSection) {
69 StringRef SymbolSectionName;
70 if ((*SymbolSection)->getName(SymbolSectionName))
71 outs() << "UNKNOWN)";
72 else
73 outs() << SymbolSectionName << ")";
74 } else {
75 outs() << "N/A)";
76 }
77
Vlad Tsyrklevich31b45312017-09-20 20:38:14 +000078 outs() << "\n";
79 }
80}
81
82int main(int argc, char **argv) {
83 cl::ParseCommandLineOptions(argc, argv);
84
85 InitializeAllTargetInfos();
86 InitializeAllTargetMCs();
87 InitializeAllAsmParsers();
88 InitializeAllDisassemblers();
89
Vlad Tsyrklevicha45919f2017-10-10 21:21:13 +000090 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(InputFilename);
91 if (!BinaryOrErr) {
92 errs() << "Failed to open file.\n";
93 return EXIT_FAILURE;
94 }
95
96 Binary &Binary = *BinaryOrErr.get().getBinary();
97 ObjectFile *Object = dyn_cast<ObjectFile>(&Binary);
98 if (!Object) {
99 errs() << "Disassembling of non-objects not currently supported.\n";
100 return EXIT_FAILURE;
101 }
102
103 Triple TheTriple = Object->makeTriple();
104 std::string TripleName = TheTriple.getTriple();
105 std::string ArchName = "";
106 std::string ErrorString;
107
108 const Target *TheTarget =
109 TargetRegistry::lookupTarget(ArchName, TheTriple, ErrorString);
110
111 if (!TheTarget) {
112 errs() << "Couldn't find target \"" << TheTriple.getTriple()
113 << "\", failed with error: " << ErrorString << ".\n";
114 return EXIT_FAILURE;
115 }
116
117 SubtargetFeatures Features = Object->getFeatures();
118
119 std::unique_ptr<const MCRegisterInfo> RegisterInfo(
120 TheTarget->createMCRegInfo(TripleName));
121 if (!RegisterInfo) {
122 errs() << "Failed to initialise RegisterInfo.\n";
123 return EXIT_FAILURE;
124 }
125
126 std::unique_ptr<const MCAsmInfo> AsmInfo(
127 TheTarget->createMCAsmInfo(*RegisterInfo, TripleName));
128 if (!AsmInfo) {
129 errs() << "Failed to initialise AsmInfo.\n";
130 return EXIT_FAILURE;
131 }
132
133 std::string MCPU = "";
134 std::unique_ptr<MCSubtargetInfo> SubtargetInfo(
135 TheTarget->createMCSubtargetInfo(TripleName, MCPU, Features.getString()));
136 if (!SubtargetInfo) {
137 errs() << "Failed to initialise SubtargetInfo.\n";
138 return EXIT_FAILURE;
139 }
140
141 std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());
142 if (!MII) {
143 errs() << "Failed to initialise MII.\n";
144 return EXIT_FAILURE;
145 }
146
147 MCObjectFileInfo MOFI;
148 MCContext Context(AsmInfo.get(), RegisterInfo.get(), &MOFI);
149
150 std::unique_ptr<const MCDisassembler> Disassembler(
151 TheTarget->createMCDisassembler(*SubtargetInfo, Context));
152
153 if (!Disassembler) {
154 errs() << "No disassembler available for target.";
155 return EXIT_FAILURE;
156 }
157
158 std::unique_ptr<const MCInstrAnalysis> MIA(
159 TheTarget->createMCInstrAnalysis(MII.get()));
160
161 std::unique_ptr<MCInstPrinter> Printer(
162 TheTarget->createMCInstPrinter(TheTriple, AsmInfo->getAssemblerDialect(),
163 *AsmInfo, *MII, *RegisterInfo));
164
165 if (ArgDumpSymbols)
166 printSymbols(Object);
167
168 for (const SectionRef &Section : Object->sections()) {
169 outs() << "Section [" << format_hex_no_prefix(Section.getAddress(), 2)
170 << "] = ";
171 StringRef SectionName;
172
173 if (Section.getName(SectionName))
174 outs() << "UNKNOWN.\n";
175 else
176 outs() << SectionName << "\n";
177
178 StringRef SectionContents;
179 if (Section.getContents(SectionContents)) {
180 errs() << "Failed to retrieve section contents.\n";
181 return EXIT_FAILURE;
182 }
183
184 MCInst Instruction;
185 uint64_t InstructionSize;
186
187 ArrayRef<uint8_t> SectionBytes((const uint8_t *)SectionContents.data(),
188 Section.getSize());
189
190 for (uint64_t Byte = 0; Byte < Section.getSize();) {
191 bool BadInstruction = false;
192
193 // Disassemble the instruction.
194 if (Disassembler->getInstruction(
195 Instruction, InstructionSize, SectionBytes.drop_front(Byte), 0,
196 nulls(), outs()) != MCDisassembler::Success) {
197 BadInstruction = true;
198 }
199
200 Byte += InstructionSize;
201
202 if (BadInstruction)
203 continue;
204
205 // Skip instructions that do not affect the control flow.
206 const auto &InstrDesc = MII->get(Instruction.getOpcode());
207 if (!InstrDesc.mayAffectControlFlow(Instruction, *RegisterInfo))
208 continue;
209
210 // Skip instructions that do not operate on register operands.
211 bool UsesRegisterOperand = false;
212 for (const auto &Operand : Instruction) {
213 if (Operand.isReg())
214 UsesRegisterOperand = true;
215 }
216
217 if (!UsesRegisterOperand)
218 continue;
219
220 // Print the instruction address.
221 outs() << " "
222 << format_hex(Section.getAddress() + Byte - InstructionSize, 2)
223 << ": ";
224
225 // Print the instruction bytes.
226 for (uint64_t i = 0; i < InstructionSize; ++i) {
227 outs() << format_hex_no_prefix(SectionBytes[Byte - InstructionSize + i],
228 2)
229 << " ";
230 }
231
232 // Print the instruction.
233 outs() << " | " << MII->getName(Instruction.getOpcode()) << " ";
234 Instruction.dump_pretty(outs(), Printer.get());
235
236 outs() << "\n";
237 }
238 }
Vlad Tsyrklevich31b45312017-09-20 20:38:14 +0000239
240 return EXIT_SUCCESS;
241}