OLD | NEW |
(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 } |
OLD | NEW |