OLD | NEW |
1 //===- PNaClABIVerifyModule.cpp - Verify PNaCl ABI rules --------===// | 1 //===- PNaClABIVerifyModule.cpp - Verify PNaCl ABI rules --------===// |
2 // | 2 // |
3 // The LLVM Compiler Infrastructure | 3 // The LLVM Compiler Infrastructure |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 // | 9 // |
10 // Verify module-level PNaCl ABI requirements (specifically those that do not | 10 // Verify module-level PNaCl ABI requirements (specifically those that do not |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
55 ReporterIsOwned(false) { | 55 ReporterIsOwned(false) { |
56 initializePNaClABIVerifyModulePass(*PassRegistry::getPassRegistry()); | 56 initializePNaClABIVerifyModulePass(*PassRegistry::getPassRegistry()); |
57 } | 57 } |
58 ~PNaClABIVerifyModule() { | 58 ~PNaClABIVerifyModule() { |
59 if (ReporterIsOwned) | 59 if (ReporterIsOwned) |
60 delete Reporter; | 60 delete Reporter; |
61 } | 61 } |
62 bool runOnModule(Module &M); | 62 bool runOnModule(Module &M); |
63 virtual void print(raw_ostream &O, const Module *M) const; | 63 virtual void print(raw_ostream &O, const Module *M) const; |
64 private: | 64 private: |
65 void CheckGlobalValueCommon(const GlobalValue *GV); | 65 void checkGlobalValueCommon(const GlobalValue *GV); |
66 bool IsWhitelistedIntrinsic(const Function* F, unsigned ID); | 66 bool isWhitelistedIntrinsic(const Function *F, unsigned ID); |
67 bool IsWhitelistedMetadata(const NamedMDNode *MD); | 67 bool isWhitelistedMetadata(const NamedMDNode *MD); |
68 PNaClABITypeChecker TC; | 68 PNaClABITypeChecker TC; |
69 PNaClABIErrorReporter *Reporter; | 69 PNaClABIErrorReporter *Reporter; |
70 bool ReporterIsOwned; | 70 bool ReporterIsOwned; |
71 }; | 71 }; |
72 | 72 |
73 static const char *linkageName(GlobalValue::LinkageTypes LT) { | 73 static const char *linkageName(GlobalValue::LinkageTypes LT) { |
74 // This logic is taken from PrintLinkage in lib/VMCore/AsmWriter.cpp | 74 // This logic is taken from PrintLinkage in lib/VMCore/AsmWriter.cpp |
75 switch (LT) { | 75 switch (LT) { |
76 case GlobalValue::ExternalLinkage: return "external"; | 76 case GlobalValue::ExternalLinkage: return "external"; |
77 case GlobalValue::PrivateLinkage: return "private "; | 77 case GlobalValue::PrivateLinkage: return "private "; |
(...skipping 15 matching lines...) Expand all Loading... |
93 return "available_externally "; | 93 return "available_externally "; |
94 default: | 94 default: |
95 return "unknown"; | 95 return "unknown"; |
96 } | 96 } |
97 } | 97 } |
98 | 98 |
99 } // end anonymous namespace | 99 } // end anonymous namespace |
100 | 100 |
101 // Check linkage type and section attributes, which are the same for | 101 // Check linkage type and section attributes, which are the same for |
102 // GlobalVariables and Functions. | 102 // GlobalVariables and Functions. |
103 void PNaClABIVerifyModule::CheckGlobalValueCommon(const GlobalValue *GV) { | 103 void PNaClABIVerifyModule::checkGlobalValueCommon(const GlobalValue *GV) { |
104 assert(!isa<GlobalAlias>(GV)); | 104 assert(!isa<GlobalAlias>(GV)); |
105 const char *GVTypeName = isa<GlobalVariable>(GV) ? | 105 const char *GVTypeName = isa<GlobalVariable>(GV) ? |
106 "Variable " : "Function "; | 106 "Variable " : "Function "; |
107 switch (GV->getLinkage()) { | 107 switch (GV->getLinkage()) { |
108 // TODO(dschuff): Disallow external linkage | 108 // TODO(dschuff): Disallow external linkage |
109 case GlobalValue::ExternalLinkage: | 109 case GlobalValue::ExternalLinkage: |
110 case GlobalValue::AvailableExternallyLinkage: | 110 case GlobalValue::AvailableExternallyLinkage: |
111 case GlobalValue::InternalLinkage: | 111 case GlobalValue::InternalLinkage: |
112 case GlobalValue::PrivateLinkage: | 112 case GlobalValue::PrivateLinkage: |
113 break; | 113 break; |
114 default: | 114 default: |
115 Reporter->addError() << GVTypeName << GV->getName() | 115 Reporter->addError() << GVTypeName << GV->getName() |
116 << " has disallowed linkage type: " | 116 << " has disallowed linkage type: " |
117 << linkageName(GV->getLinkage()) << "\n"; | 117 << linkageName(GV->getLinkage()) << "\n"; |
118 } | 118 } |
119 if (GV->hasSection()) { | 119 if (GV->hasSection()) { |
120 Reporter->addError() << GVTypeName << GV->getName() << | 120 Reporter->addError() << GVTypeName << GV->getName() << |
121 " has disallowed \"section\" attribute\n"; | 121 " has disallowed \"section\" attribute\n"; |
122 } | 122 } |
123 } | 123 } |
124 | 124 |
125 bool PNaClABIVerifyModule::IsWhitelistedIntrinsic(const Function* F, | 125 static bool TypeAcceptable(const Type *T, |
| 126 const ArrayRef<Type*> &AcceptableTypes) { |
| 127 for (ArrayRef<Type*>::iterator I = AcceptableTypes.begin(), |
| 128 E = AcceptableTypes.end(); I != E; ++I) |
| 129 if (*I == T) |
| 130 return true; |
| 131 return false; |
| 132 } |
| 133 |
| 134 // We accept bswap for a limited set of types (i16, i32, i64). |
| 135 // The various backends are able to generate instructions to |
| 136 // implement the intrinsic. Also, i16 and i64 are easy to |
| 137 // implement as along as there is a way to do i32. |
| 138 static bool isWhitelistedBswap(const Function *F) { |
| 139 FunctionType *FT = F->getFunctionType(); |
| 140 if (FT->getNumParams() != 1) |
| 141 return false; |
| 142 Type *ParamType = FT->getParamType(0); |
| 143 LLVMContext &C = F->getContext(); |
| 144 Type *AcceptableTypes[] = { Type::getInt16Ty(C), |
| 145 Type::getInt32Ty(C), |
| 146 Type::getInt64Ty(C) }; |
| 147 return TypeAcceptable(ParamType, AcceptableTypes); |
| 148 } |
| 149 |
| 150 bool PNaClABIVerifyModule::isWhitelistedIntrinsic(const Function *F, |
126 unsigned ID) { | 151 unsigned ID) { |
127 // Keep 3 categories of intrinsics for now. | 152 // Keep 3 categories of intrinsics for now. |
128 // (1) Allowed always | 153 // (1) Allowed always |
129 // (2) Never allowed | 154 // (2) Never allowed |
130 // (3) "Dev" intrinsics, which may or may not be allowed. | 155 // (3) "Dev" intrinsics, which may or may not be allowed. |
131 // "Dev" intrinsics are controlled by the PNaClABIAllowDevIntrinsics flag. | 156 // "Dev" intrinsics are controlled by the PNaClABIAllowDevIntrinsics flag. |
132 // Please keep these sorted or grouped in a sensible way, within | 157 // Please keep these sorted or grouped in a sensible way, within |
133 // each category. | 158 // each category. |
134 switch(ID) { | 159 switch(ID) { |
135 // Disallow by default. | 160 // Disallow by default. |
136 default: return false; | 161 default: return false; |
137 // (1) Always allowed. | 162 // (1) Always allowed. |
| 163 case Intrinsic::bswap: return isWhitelistedBswap(F); |
138 case Intrinsic::invariant_end: | 164 case Intrinsic::invariant_end: |
139 case Intrinsic::invariant_start: | 165 case Intrinsic::invariant_start: |
140 case Intrinsic::lifetime_end: | 166 case Intrinsic::lifetime_end: |
141 case Intrinsic::lifetime_start: | 167 case Intrinsic::lifetime_start: |
142 case Intrinsic::memcpy: | 168 case Intrinsic::memcpy: |
143 case Intrinsic::memmove: | 169 case Intrinsic::memmove: |
144 case Intrinsic::memset: | 170 case Intrinsic::memset: |
145 case Intrinsic::nacl_read_tp: | 171 case Intrinsic::nacl_read_tp: |
146 case Intrinsic::nacl_setjmp: | 172 case Intrinsic::nacl_setjmp: |
147 case Intrinsic::nacl_longjmp: | 173 case Intrinsic::nacl_longjmp: |
(...skipping 24 matching lines...) Expand all Loading... |
172 // Var-args handling is done w/out intrinsics. | 198 // Var-args handling is done w/out intrinsics. |
173 case Intrinsic::vacopy: | 199 case Intrinsic::vacopy: |
174 case Intrinsic::vaend: | 200 case Intrinsic::vaend: |
175 case Intrinsic::vastart: | 201 case Intrinsic::vastart: |
176 return false; | 202 return false; |
177 | 203 |
178 // (3) Dev intrinsics. | 204 // (3) Dev intrinsics. |
179 case Intrinsic::dbg_declare: | 205 case Intrinsic::dbg_declare: |
180 case Intrinsic::dbg_value: | 206 case Intrinsic::dbg_value: |
181 return PNaClABIAllowDevIntrinsics || PNaClABIAllowDebugMetadata; | 207 return PNaClABIAllowDevIntrinsics || PNaClABIAllowDebugMetadata; |
182 case Intrinsic::bswap: // Support via compiler_rt if arch doesn't have it? | |
183 case Intrinsic::cos: // Rounding not defined: support with fast-math? | 208 case Intrinsic::cos: // Rounding not defined: support with fast-math? |
184 case Intrinsic::ctlz: // Support via compiler_rt if arch doesn't have it? | 209 case Intrinsic::ctlz: // Support via compiler_rt if arch doesn't have it? |
185 case Intrinsic::ctpop: // Support via compiler_rt if arch doesn't have it? | 210 case Intrinsic::ctpop: // Support via compiler_rt if arch doesn't have it? |
186 case Intrinsic::cttz: // Support via compiler_rt if arch doesn't have it? | 211 case Intrinsic::cttz: // Support via compiler_rt if arch doesn't have it? |
187 case Intrinsic::exp: // Rounding not defined: support with fast-math? | 212 case Intrinsic::exp: // Rounding not defined: support with fast-math? |
188 case Intrinsic::exp2: // Rounding not defined: support with fast-math? | 213 case Intrinsic::exp2: // Rounding not defined: support with fast-math? |
189 case Intrinsic::expect: // From __builtin_expect. | 214 case Intrinsic::expect: // From __builtin_expect. |
190 case Intrinsic::flt_rounds: | 215 case Intrinsic::flt_rounds: // For FLT_ROUNDS macro from float.h. |
| 216 // We do not have fesetround() in newlib, can we return a |
| 217 // consistent rounding mode though? |
191 case Intrinsic::log: // Rounding not defined: support with fast-math? | 218 case Intrinsic::log: // Rounding not defined: support with fast-math? |
192 case Intrinsic::log2: // Rounding not defined: support with fast-math? | 219 case Intrinsic::log2: // Rounding not defined: support with fast-math? |
193 case Intrinsic::log10: // Rounding not defined: support with fast-math? | 220 case Intrinsic::log10: // Rounding not defined: support with fast-math? |
194 case Intrinsic::nacl_target_arch: // Used by translator self-build. | 221 case Intrinsic::nacl_target_arch: // Used by translator self-build. |
195 case Intrinsic::pow: // Rounding is supposed to be the same as libm. | 222 case Intrinsic::pow: // Rounding is supposed to be the same as libm. |
196 case Intrinsic::powi: // Rounding not defined: support with fast-math? | 223 case Intrinsic::powi: // Rounding not defined: support with fast-math? |
197 case Intrinsic::prefetch: // Could ignore if target doesn't support? | 224 case Intrinsic::prefetch: // Could ignore if target doesn't support? |
198 case Intrinsic::sin: // Rounding not defined: support with fast-math? | 225 case Intrinsic::sin: // Rounding not defined: support with fast-math? |
199 case Intrinsic::sqrt: | 226 case Intrinsic::sqrt: // Rounding is defined, but setting errno up to libm. |
200 case Intrinsic::stackrestore: // Used to support C99 VLAs. | 227 case Intrinsic::stackrestore: // Used to support C99 VLAs. |
201 case Intrinsic::stacksave: | 228 case Intrinsic::stacksave: // Used to support C99 VLAs. |
202 // the *_with_overflow return struct types, so we'll need to fix these. | 229 // the *_with_overflow return struct types, so we'll need to fix these. |
203 case Intrinsic::sadd_with_overflow: // Introduced by -ftrapv | 230 case Intrinsic::sadd_with_overflow: // Introduced by -ftrapv |
204 case Intrinsic::ssub_with_overflow: | 231 case Intrinsic::ssub_with_overflow: |
205 case Intrinsic::uadd_with_overflow: | 232 case Intrinsic::uadd_with_overflow: |
206 case Intrinsic::usub_with_overflow: | 233 case Intrinsic::usub_with_overflow: |
207 case Intrinsic::smul_with_overflow: | 234 case Intrinsic::smul_with_overflow: |
208 case Intrinsic::umul_with_overflow: // Introduced by c++ new[x * y]. | 235 case Intrinsic::umul_with_overflow: // Introduced by c++ new[x * y]. |
209 return PNaClABIAllowDevIntrinsics; | 236 return PNaClABIAllowDevIntrinsics; |
210 } | 237 } |
211 } | 238 } |
212 | 239 |
213 bool PNaClABIVerifyModule::IsWhitelistedMetadata(const NamedMDNode* MD) { | 240 bool PNaClABIVerifyModule::isWhitelistedMetadata(const NamedMDNode *MD) { |
214 return MD->getName().startswith("llvm.dbg.") && PNaClABIAllowDebugMetadata; | 241 return MD->getName().startswith("llvm.dbg.") && PNaClABIAllowDebugMetadata; |
215 } | 242 } |
216 | 243 |
217 bool PNaClABIVerifyModule::runOnModule(Module &M) { | 244 bool PNaClABIVerifyModule::runOnModule(Module &M) { |
218 for (Module::const_global_iterator MI = M.global_begin(), ME = M.global_end(); | 245 for (Module::const_global_iterator MI = M.global_begin(), ME = M.global_end(); |
219 MI != ME; ++MI) { | 246 MI != ME; ++MI) { |
220 // Check types of global variables and their initializers | 247 // Check types of global variables and their initializers |
221 if (!TC.isValidType(MI->getType())) { | 248 if (!TC.isValidType(MI->getType())) { |
222 // GVs are pointers, so print the pointed-to type for clarity | 249 // GVs are pointers, so print the pointed-to type for clarity |
223 Reporter->addError() << "Variable " << MI->getName() << | 250 Reporter->addError() << "Variable " << MI->getName() << |
224 " has disallowed type: " << | 251 " has disallowed type: " << |
225 PNaClABITypeChecker::getTypeName(MI->getType()->getContainedType(0)) | 252 PNaClABITypeChecker::getTypeName(MI->getType()->getContainedType(0)) |
226 + "\n"; | 253 + "\n"; |
227 } else if (MI->hasInitializer()) { | 254 } else if (MI->hasInitializer()) { |
228 // If the type of the global is bad, no point in checking its initializer | 255 // If the type of the global is bad, no point in checking its initializer |
229 Type *T = TC.checkTypesInConstant(MI->getInitializer()); | 256 Type *T = TC.checkTypesInConstant(MI->getInitializer()); |
230 if (T) { | 257 if (T) { |
231 Reporter->addError() << "Initializer for " << MI->getName() << | 258 Reporter->addError() << "Initializer for " << MI->getName() << |
232 " has disallowed type: " << | 259 " has disallowed type: " << |
233 PNaClABITypeChecker::getTypeName(T) << "\n"; | 260 PNaClABITypeChecker::getTypeName(T) << "\n"; |
234 } | 261 } |
235 } | 262 } |
236 | 263 |
237 CheckGlobalValueCommon(MI); | 264 checkGlobalValueCommon(MI); |
238 | 265 |
239 if (MI->isThreadLocal()) { | 266 if (MI->isThreadLocal()) { |
240 Reporter->addError() << "Variable " << MI->getName() << | 267 Reporter->addError() << "Variable " << MI->getName() << |
241 " has disallowed \"thread_local\" attribute\n"; | 268 " has disallowed \"thread_local\" attribute\n"; |
242 } | 269 } |
243 } | 270 } |
244 | 271 |
245 // No aliases allowed for now. | 272 // No aliases allowed for now. |
246 for (Module::alias_iterator MI = M.alias_begin(), | 273 for (Module::alias_iterator MI = M.alias_begin(), |
247 E = M.alias_end(); MI != E; ++MI) { | 274 E = M.alias_end(); MI != E; ++MI) { |
248 Reporter->addError() << "Variable " << MI->getName() << | 275 Reporter->addError() << "Variable " << MI->getName() << |
249 " is an alias (disallowed)\n"; | 276 " is an alias (disallowed)\n"; |
250 } | 277 } |
251 | 278 |
252 for (Module::const_iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) { | 279 for (Module::const_iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) { |
253 // Check intrinsics. | 280 // Check intrinsics. |
254 if (MI->isIntrinsic() | 281 if (MI->isIntrinsic() |
255 && !IsWhitelistedIntrinsic(MI, MI->getIntrinsicID())) { | 282 && !isWhitelistedIntrinsic(MI, MI->getIntrinsicID())) { |
256 Reporter->addError() << "Function " << MI->getName() | 283 Reporter->addError() << "Function " << MI->getName() |
257 << " is a disallowed LLVM intrinsic\n"; | 284 << " is a disallowed LLVM intrinsic\n"; |
258 } | 285 } |
259 | 286 |
260 // Check types of functions and their arguments | 287 // Check types of functions and their arguments |
261 FunctionType *FT = MI->getFunctionType(); | 288 FunctionType *FT = MI->getFunctionType(); |
262 if (!TC.isValidType(FT->getReturnType())) { | 289 if (!TC.isValidType(FT->getReturnType())) { |
263 Reporter->addError() << "Function " << MI->getName() << | 290 Reporter->addError() << "Function " << MI->getName() << |
264 " has disallowed return type: " << | 291 " has disallowed return type: " << |
265 PNaClABITypeChecker::getTypeName(FT->getReturnType()) << "\n"; | 292 PNaClABITypeChecker::getTypeName(FT->getReturnType()) << "\n"; |
266 } | 293 } |
267 for (unsigned I = 0, E = FT->getNumParams(); I < E; ++I) { | 294 for (unsigned I = 0, E = FT->getNumParams(); I < E; ++I) { |
268 Type *PT = FT->getParamType(I); | 295 Type *PT = FT->getParamType(I); |
269 if (!TC.isValidType(PT)) { | 296 if (!TC.isValidType(PT)) { |
270 Reporter->addError() << "Function " << MI->getName() << " argument " << | 297 Reporter->addError() << "Function " << MI->getName() << " argument " << |
271 I + 1 << " has disallowed type: " << | 298 I + 1 << " has disallowed type: " << |
272 PNaClABITypeChecker::getTypeName(PT) << "\n"; | 299 PNaClABITypeChecker::getTypeName(PT) << "\n"; |
273 } | 300 } |
274 } | 301 } |
275 // Pointers to varargs function types are not yet disallowed, but | 302 // Pointers to varargs function types are not yet disallowed, but |
276 // we do disallow defining or calling functions of varargs types. | 303 // we do disallow defining or calling functions of varargs types. |
277 if (MI->isVarArg()) { | 304 if (MI->isVarArg()) { |
278 Reporter->addError() << "Function " << MI->getName() << | 305 Reporter->addError() << "Function " << MI->getName() << |
279 " is a variable-argument function (disallowed)\n"; | 306 " is a variable-argument function (disallowed)\n"; |
280 } | 307 } |
281 | 308 |
282 CheckGlobalValueCommon(MI); | 309 checkGlobalValueCommon(MI); |
283 | 310 |
284 if (MI->hasGC()) { | 311 if (MI->hasGC()) { |
285 Reporter->addError() << "Function " << MI->getName() << | 312 Reporter->addError() << "Function " << MI->getName() << |
286 " has disallowed \"gc\" attribute\n"; | 313 " has disallowed \"gc\" attribute\n"; |
287 } | 314 } |
288 } | 315 } |
289 | 316 |
290 // Check named metadata nodes | 317 // Check named metadata nodes |
291 for (Module::const_named_metadata_iterator I = M.named_metadata_begin(), | 318 for (Module::const_named_metadata_iterator I = M.named_metadata_begin(), |
292 E = M.named_metadata_end(); I != E; ++I) { | 319 E = M.named_metadata_end(); I != E; ++I) { |
293 if (!IsWhitelistedMetadata(I)) { | 320 if (!isWhitelistedMetadata(I)) { |
294 Reporter->addError() << "Named metadata node " << I->getName() | 321 Reporter->addError() << "Named metadata node " << I->getName() |
295 << " is disallowed\n"; | 322 << " is disallowed\n"; |
296 } else { | 323 } else { |
297 // Check the types in the metadata. | 324 // Check the types in the metadata. |
298 for (unsigned i = 0, e = I->getNumOperands(); i != e; i++) { | 325 for (unsigned i = 0, e = I->getNumOperands(); i != e; i++) { |
299 if (Type *T = TC.checkTypesInMDNode(I->getOperand(i))) { | 326 if (Type *T = TC.checkTypesInMDNode(I->getOperand(i))) { |
300 Reporter->addError() << "Named metadata node " << I->getName() | 327 Reporter->addError() << "Named metadata node " << I->getName() |
301 << " refers to disallowed type: " | 328 << " refers to disallowed type: " |
302 << PNaClABITypeChecker::getTypeName(T) << "\n"; | 329 << PNaClABITypeChecker::getTypeName(T) << "\n"; |
303 } | 330 } |
(...skipping 15 matching lines...) Expand all Loading... |
319 } | 346 } |
320 | 347 |
321 char PNaClABIVerifyModule::ID = 0; | 348 char PNaClABIVerifyModule::ID = 0; |
322 INITIALIZE_PASS(PNaClABIVerifyModule, "verify-pnaclabi-module", | 349 INITIALIZE_PASS(PNaClABIVerifyModule, "verify-pnaclabi-module", |
323 "Verify module for PNaCl", false, true) | 350 "Verify module for PNaCl", false, true) |
324 | 351 |
325 ModulePass *llvm::createPNaClABIVerifyModulePass( | 352 ModulePass *llvm::createPNaClABIVerifyModulePass( |
326 PNaClABIErrorReporter *Reporter) { | 353 PNaClABIErrorReporter *Reporter) { |
327 return new PNaClABIVerifyModule(Reporter); | 354 return new PNaClABIVerifyModule(Reporter); |
328 } | 355 } |
OLD | NEW |