Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(482)

Side by Side Diff: lib/Analysis/NaCl/PNaClABIVerifyModule.cpp

Issue 939073008: Rebased PNaCl localmods in LLVM to 223109 (Closed)
Patch Set: undo localmod Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 //===- PNaClABIVerifyModule.cpp - Verify PNaCl ABI rules ------------------===//
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 // Verify module-level PNaCl ABI requirements (specifically those that do not
11 // require looking at the function bodies)
12 //
13 //
14 //===----------------------------------------------------------------------===//
15
16 #include "llvm/Analysis/NaCl/PNaClABIVerifyModule.h"
17 #include "llvm/ADT/Twine.h"
18 #include "llvm/Analysis/NaCl/PNaClABIProps.h"
19 #include "llvm/Analysis/NaCl/PNaClABITypeChecker.h"
20 #include "llvm/Analysis/NaCl/PNaClAllowedIntrinsics.h"
21 #include "llvm/IR/Constants.h"
22 #include "llvm/IR/DerivedTypes.h"
23 #include "llvm/IR/Instructions.h"
24 #include "llvm/Support/Debug.h"
25 #include "llvm/Support/raw_ostream.h"
26
27 using namespace llvm;
28
29 namespace llvm {
30 cl::opt<bool>
31 PNaClABIAllowDebugMetadata("pnaclabi-allow-debug-metadata",
32 cl::desc("Allow debug metadata during PNaCl ABI verification."),
33 cl::init(false));
34
35 cl::opt<bool>
36 PNaClABIAllowMinsfiSyscalls("pnaclabi-allow-minsfi-syscalls",
37 cl::desc("Allow undefined references to MinSFI syscall functions."),
38 cl::init(false));
39
40 }
41
42 PNaClABIVerifyModule::~PNaClABIVerifyModule() {
43 if (ReporterIsOwned)
44 delete Reporter;
45 }
46
47 // MinSFI syscalls are functions with a given prefix which are left undefined
48 // and later linked against their implementation inside the trusted runtime.
49 // If the corresponding flag is set, do allow these external symbols in the
50 // module.
51 //
52 // We also require the syscall declarations to have an i32 return type. This
53 // is meant to prevent abusing syscalls to obtain an undefined value, e.g. by
54 // invoking a syscall whose trusted implementation returns void as a function
55 // which returns an integer, leaking the value of a register (see comments in
56 // the SubstituteUndefs pass for more information on undef values).
57 static bool isAllowedMinsfiSyscall(const Function *Func) {
58 return PNaClABIAllowMinsfiSyscalls &&
59 Func->getName().startswith("__minsfi_syscall_") &&
60 Func->getReturnType()->isIntegerTy(32);
61 }
62
63 // Check linkage type and section attributes, which are the same for
64 // GlobalVariables and Functions.
65 void PNaClABIVerifyModule::checkGlobalValue(const GlobalValue *GV) {
66 assert(!isa<GlobalAlias>(GV));
67 const char *GVTypeName = PNaClABIProps::GVTypeName(isa<Function>(GV));
68 GlobalValue::LinkageTypes Linkage = GV->getLinkage();
69 if (!PNaClABIProps::isValidGlobalLinkage(Linkage)) {
70 Reporter->addError() << GVTypeName << " " << GV->getName()
71 << " has disallowed linkage type: "
72 << PNaClABIProps::LinkageName(Linkage) << "\n";
73 }
74 if (Linkage == GlobalValue::ExternalLinkage) checkExternalSymbol(GV);
75 if (GV->getVisibility() != GlobalValue::DefaultVisibility) {
76 std::string Text = "unknown";
77 if (GV->getVisibility() == GlobalValue::HiddenVisibility) {
78 Text = "hidden";
79 } else if (GV->getVisibility() == GlobalValue::ProtectedVisibility) {
80 Text = "protected";
81 }
82 Reporter->addError() << GVTypeName << " " << GV->getName()
83 << " has disallowed visibility: " << Text << "\n";
84 }
85 if (GV->hasSection()) {
86 Reporter->addError() << GVTypeName << " " << GV->getName() <<
87 " has disallowed \"section\" attribute\n";
88 }
89 if (GV->getType()->getAddressSpace() != 0) {
90 Reporter->addError() << GVTypeName << " " << GV->getName()
91 << " has addrspace attribute (disallowed)\n";
92 }
93 // The "unnamed_addr" attribute can be used to merge duplicate
94 // definitions, but that should be done by user-toolchain
95 // optimization passes, not by the PNaCl translator.
96 if (GV->hasUnnamedAddr()) {
97 Reporter->addError() << GVTypeName << " " << GV->getName()
98 << " has disallowed \"unnamed_addr\" attribute\n";
99 }
100 }
101
102 void PNaClABIVerifyModule::checkExternalSymbol(const GlobalValue *GV) {
103 if (const Function *Func = dyn_cast<const Function>(GV)) {
104 if (Func->isIntrinsic() || isAllowedMinsfiSyscall(Func))
105 return;
106 }
107
108 // We only allow __pnacl_pso_root to be a variable, not a function, to
109 // reduce the number of cases that the translator needs to handle.
110 bool ValidEntry =
111 (isa<Function>(GV) && GV->getName().equals("_start")) ||
112 (isa<GlobalVariable>(GV) && GV->getName().equals("__pnacl_pso_root"));
113 if (!ValidEntry) {
114 Reporter->addError()
115 << GV->getName()
116 << " is not a valid external symbol (disallowed)\n";
117 } else {
118 if (SeenEntryPoint) {
119 Reporter->addError() <<
120 "Module has multiple entry points (disallowed)\n";
121 }
122 SeenEntryPoint = true;
123 }
124 }
125
126 static bool isPtrToIntOfGlobal(const Constant *C) {
127 if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) {
128 return CE->getOpcode() == Instruction::PtrToInt &&
129 isa<GlobalValue>(CE->getOperand(0));
130 }
131 return false;
132 }
133
134 // This checks for part of the normal form produced by FlattenGlobals.
135 static bool isSimpleElement(const Constant *C) {
136 // A SimpleElement is one of the following:
137 // 1) An i8 array literal or zeroinitializer:
138 // [SIZE x i8] c"DATA"
139 // [SIZE x i8] zeroinitializer
140 if (ArrayType *Ty = dyn_cast<ArrayType>(C->getType())) {
141 return Ty->getElementType()->isIntegerTy(8) &&
142 (isa<ConstantAggregateZero>(C) ||
143 isa<ConstantDataArray>(C));
144 }
145 // 2) A reference to a GlobalValue (a function or global variable)
146 // with an optional byte offset added to it (the addend).
147 if (C->getType()->isIntegerTy(32)) {
148 const ConstantExpr *CE = dyn_cast<ConstantExpr>(C);
149 if (!CE)
150 return false;
151 // Without addend: ptrtoint (TYPE* @GLOBAL to i32)
152 if (isPtrToIntOfGlobal(CE))
153 return true;
154 // With addend: add (i32 ptrtoint (TYPE* @GLOBAL to i32), i32 ADDEND)
155 if (CE->getOpcode() == Instruction::Add &&
156 isPtrToIntOfGlobal(CE->getOperand(0)) &&
157 isa<ConstantInt>(CE->getOperand(1)))
158 return true;
159 }
160 return false;
161 }
162
163 // This checks for part of the normal form produced by FlattenGlobals.
164 static bool isCompoundElement(const Constant *C) {
165 const ConstantStruct *CS = dyn_cast<ConstantStruct>(C);
166 if (!CS || !CS->getType()->isPacked() || CS->getType()->hasName() ||
167 CS->getNumOperands() <= 1)
168 return false;
169 for (unsigned I = 0; I < CS->getNumOperands(); ++I) {
170 if (!isSimpleElement(CS->getOperand(I)))
171 return false;
172 }
173 return true;
174 }
175
176 static std::string getAttributesAsString(AttributeSet Attrs) {
177 std::string AttrsAsString;
178 for (unsigned Slot = 0; Slot < Attrs.getNumSlots(); ++Slot) {
179 for (AttributeSet::iterator Attr = Attrs.begin(Slot),
180 E = Attrs.end(Slot); Attr != E; ++Attr) {
181 AttrsAsString += " ";
182 AttrsAsString += Attr->getAsString();
183 }
184 }
185 return AttrsAsString;
186 }
187
188 // This checks that the GlobalVariable has the normal form produced by
189 // the FlattenGlobals pass.
190 void PNaClABIVerifyModule::checkGlobalIsFlattened(const GlobalVariable *GV) {
191 if (!GV->hasInitializer()) {
192 Reporter->addError() << "Global variable " << GV->getName()
193 << " has no initializer (disallowed)\n";
194 return;
195 }
196 const Constant *InitVal = GV->getInitializer();
197 if (isSimpleElement(InitVal) || isCompoundElement(InitVal))
198 return;
199 Reporter->addError() << "Global variable " << GV->getName()
200 << " has non-flattened initializer (disallowed): "
201 << *InitVal << "\n";
202 }
203
204 void PNaClABIVerifyModule::checkFunction(const Function *F,
205 const StringRef &Name,
206 PNaClAllowedIntrinsics &Intrinsics) {
207 if (F->isIntrinsic()) {
208 // Check intrinsics.
209 if (!Intrinsics.isAllowed(F)) {
210 Reporter->addError() << "Function " << F->getName()
211 << " is a disallowed LLVM intrinsic\n";
212 }
213 } else {
214 // Check types of functions and their arguments. Not necessary
215 // for intrinsics, whose types are fixed anyway, and which have
216 // argument types that we disallow such as i8.
217 if (!PNaClABITypeChecker::isValidFunctionType(F->getFunctionType())) {
218 Reporter->addError()
219 << "Function " << Name << " has disallowed type: "
220 << PNaClABITypeChecker::getTypeName(F->getFunctionType())
221 << "\n";
222 }
223 // This check is disabled in streaming mode because it would
224 // reject a function that is defined but not read in yet.
225 // Unfortunately this means we simply don't check this property
226 // when translating a pexe in the browser.
227 // TODO(mseaborn): Enforce this property in the bitcode reader.
228 if (!StreamingMode && F->isDeclaration() && !isAllowedMinsfiSyscall(F)) {
229 Reporter->addError() << "Function " << Name
230 << " is declared but not defined (disallowed)\n";
231 }
232 if (!F->getAttributes().isEmpty()) {
233 Reporter->addError()
234 << "Function " << Name << " has disallowed attributes:"
235 << getAttributesAsString(F->getAttributes()) << "\n";
236 }
237 if (!PNaClABIProps::isValidCallingConv(F->getCallingConv())) {
238 Reporter->addError()
239 << "Function " << Name << " has disallowed calling convention: "
240 << PNaClABIProps::CallingConvName(F->getCallingConv()) << " ("
241 << F->getCallingConv() << ")\n";
242 }
243 }
244
245 checkGlobalValue(F);
246
247 if (F->hasGC()) {
248 Reporter->addError() << "Function " << Name <<
249 " has disallowed \"gc\" attribute\n";
250 }
251 // Knowledge of what function alignments are useful is
252 // architecture-specific and sandbox-specific, so PNaCl pexes
253 // should not be able to specify function alignment.
254 if (F->getAlignment() != 0) {
255 Reporter->addError() << "Function " << Name <<
256 " has disallowed \"align\" attribute\n";
257 }
258 }
259
260 bool PNaClABIVerifyModule::runOnModule(Module &M) {
261 SeenEntryPoint = false;
262 PNaClAllowedIntrinsics Intrinsics(&M.getContext());
263
264 if (!M.getModuleInlineAsm().empty()) {
265 Reporter->addError() <<
266 "Module contains disallowed top-level inline assembly\n";
267 }
268
269 for (Module::const_global_iterator MI = M.global_begin(), ME = M.global_end();
270 MI != ME; ++MI) {
271 checkGlobalIsFlattened(MI);
272 checkGlobalVariable(MI);
273
274 if (MI->isThreadLocal()) {
275 Reporter->addError() << "Variable " << MI->getName() <<
276 " has disallowed \"thread_local\" attribute\n";
277 }
278 if (MI->isExternallyInitialized()) {
279 Reporter->addError() << "Variable " << MI->getName() <<
280 " has disallowed \"externally_initialized\" attribute\n";
281 }
282 }
283
284 // No aliases allowed for now.
285 for (Module::alias_iterator MI = M.alias_begin(),
286 E = M.alias_end(); MI != E; ++MI) {
287 Reporter->addError() << "Variable " << MI->getName() <<
288 " is an alias (disallowed)\n";
289 }
290
291 for (Module::const_iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) {
292 checkFunction(MI, MI->getName(), Intrinsics);
293 }
294
295 // Check named metadata nodes
296 for (Module::const_named_metadata_iterator I = M.named_metadata_begin(),
297 E = M.named_metadata_end(); I != E; ++I) {
298 if (!PNaClABIProps::isWhitelistedMetadata(I)) {
299 Reporter->addError() << "Named metadata node " << I->getName()
300 << " is disallowed\n";
301 }
302 }
303
304 if (!SeenEntryPoint) {
305 Reporter->addError() << "Module has no entry point (disallowed)\n";
306 }
307 Reporter->checkForFatalErrors();
308 return false;
309 }
310
311 // This method exists so that the passes can easily be run with opt -analyze.
312 // In this case the default constructor is used and we want to reset the error
313 // messages after each print (this is more of an issue for the FunctionPass
314 // than the ModulePass)
315 void PNaClABIVerifyModule::print(llvm::raw_ostream &O, const Module *M) const {
316 Reporter->printErrors(O);
317 Reporter->reset();
318 }
319
320 char PNaClABIVerifyModule::ID = 0;
321 INITIALIZE_PASS(PNaClABIVerifyModule, "verify-pnaclabi-module",
322 "Verify module for PNaCl", false, true)
323
324 ModulePass *llvm::createPNaClABIVerifyModulePass(
325 PNaClABIErrorReporter *Reporter, bool StreamingMode) {
326 return new PNaClABIVerifyModule(Reporter, StreamingMode);
327 }
OLDNEW
« no previous file with comments | « lib/Analysis/NaCl/PNaClABIVerifyFunctions.cpp ('k') | lib/Analysis/NaCl/PNaClAllowedIntrinsics.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698