text: //===- PNaClABIVerifyModule.cpp - Verify PNaCl ABI rules ------------------===//
  //
  //                     The LLVM Compiler Infrastructure
  //
  // This file is distributed under the University of Illinois Open Source
  // License. See LICENSE.TXT for details.
  //
  //===----------------------------------------------------------------------===//
  //
  // Verify module-level PNaCl ABI requirements (specifically those that do not
  // require looking at the function bodies)
  //
  //
  //===----------------------------------------------------------------------===//
  
  #include "llvm/Analysis/NaCl/PNaClABIVerifyModule.h"
  #include "llvm/ADT/Twine.h"
  #include "llvm/Analysis/NaCl/PNaClABIProps.h"
  #include "llvm/Analysis/NaCl/PNaClABITypeChecker.h"
  #include "llvm/Analysis/NaCl/PNaClAllowedIntrinsics.h"
  #include "llvm/IR/Constants.h"
  #include "llvm/IR/DerivedTypes.h"
  #include "llvm/IR/Instructions.h"
  #include "llvm/Support/Debug.h"
  #include "llvm/Support/raw_ostream.h"
  
  using namespace llvm;
  
  namespace llvm {
  cl::opt<bool>
  PNaClABIAllowDebugMetadata("pnaclabi-allow-debug-metadata",
    cl::desc("Allow debug metadata during PNaCl ABI verification."),
    cl::init(false));
  
  cl::opt<bool>
  PNaClABIAllowMinsfiSyscalls("pnaclabi-allow-minsfi-syscalls",
    cl::desc("Allow undefined references to MinSFI syscall functions."),
    cl::init(false));
  
  }
  
  PNaClABIVerifyModule::~PNaClABIVerifyModule() {
    if (ReporterIsOwned)
      delete Reporter;
  }
  
  // MinSFI syscalls are functions with a given prefix which are left undefined
  // and later linked against their implementation inside the trusted runtime.
  // If the corresponding flag is set, do allow these external symbols in the
  // module.
  //
  // We also require the syscall declarations to have an i32 return type. This
  // is meant to prevent abusing syscalls to obtain an undefined value, e.g. by
  // invoking a syscall whose trusted implementation returns void as a function
  // which returns an integer, leaking the value of a register (see comments in
  // the SubstituteUndefs pass for more information on undef values).
  static bool isAllowedMinsfiSyscall(const Function *Func) {
    return PNaClABIAllowMinsfiSyscalls &&
           Func->getName().startswith("__minsfi_syscall_") &&
           Func->getReturnType()->isIntegerTy(32);
  }
  
  // Check linkage type and section attributes, which are the same for
  // GlobalVariables and Functions.
  void PNaClABIVerifyModule::checkGlobalValue(const GlobalValue *GV) {
    assert(!isa<GlobalAlias>(GV));
    const char *GVTypeName = PNaClABIProps::GVTypeName(isa<Function>(GV));
    GlobalValue::LinkageTypes Linkage = GV->getLinkage();
    if (!PNaClABIProps::isValidGlobalLinkage(Linkage)) {
      Reporter->addError() << GVTypeName << " " << GV->getName()
                           << " has disallowed linkage type: "
                           << PNaClABIProps::LinkageName(Linkage) << "\n";
    }
    if (Linkage == GlobalValue::ExternalLinkage) checkExternalSymbol(GV);
    if (GV->getVisibility() != GlobalValue::DefaultVisibility) {
      std::string Text = "unknown";
      if (GV->getVisibility() == GlobalValue::HiddenVisibility) {
        Text = "hidden";
      } else if (GV->getVisibility() == GlobalValue::ProtectedVisibility) {
        Text = "protected";
      }
      Reporter->addError() << GVTypeName << " " << GV->getName()
                           << " has disallowed visibility: " << Text << "\n";
    }
    if (GV->hasSection()) {
      Reporter->addError() << GVTypeName << " " << GV->getName() <<
          " has disallowed \"section\" attribute\n";
    }
    if (GV->getType()->getAddressSpace() != 0) {
      Reporter->addError() << GVTypeName << " " << GV->getName()
                           << " has addrspace attribute (disallowed)\n";
    }
    // The "unnamed_addr" attribute can be used to merge duplicate
    // definitions, but that should be done by user-toolchain
    // optimization passes, not by the PNaCl translator.
    if (GV->hasUnnamedAddr()) {
      Reporter->addError() << GVTypeName << " " << GV->getName()
                           << " has disallowed \"unnamed_addr\" attribute\n";
    }
  }
  
  void PNaClABIVerifyModule::checkExternalSymbol(const GlobalValue *GV) {
    if (const Function *Func = dyn_cast<const Function>(GV)) {
      if (Func->isIntrinsic() || isAllowedMinsfiSyscall(Func))
        return;
    }
  
    // We only allow __pnacl_pso_root to be a variable, not a function, to
    // reduce the number of cases that the translator needs to handle.
    bool ValidEntry =
        (isa<Function>(GV) && GV->getName().equals("_start")) ||
        (isa<GlobalVariable>(GV) && GV->getName().equals("__pnacl_pso_root"));
    if (!ValidEntry) {
      Reporter->addError()
          << GV->getName()
          << " is not a valid external symbol (disallowed)\n";
    } else {
      if (SeenEntryPoint) {
        Reporter->addError() <<
            "Module has multiple entry points (disallowed)\n";
      }
      SeenEntryPoint = true;
    }
  }
  
  static bool isPtrToIntOfGlobal(const Constant *C) {
    if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) {
      return CE->getOpcode() == Instruction::PtrToInt &&
             isa<GlobalValue>(CE->getOperand(0));
    }
    return false;
  }
  
  // This checks for part of the normal form produced by FlattenGlobals.
  static bool isSimpleElement(const Constant *C) {
    // A SimpleElement is one of the following:
    // 1) An i8 array literal or zeroinitializer:
    //      [SIZE x i8] c"DATA"
    //      [SIZE x i8] zeroinitializer
    if (ArrayType *Ty = dyn_cast<ArrayType>(C->getType())) {
      return Ty->getElementType()->isIntegerTy(8) &&
             (isa<ConstantAggregateZero>(C) ||
              isa<ConstantDataArray>(C));
    }
    // 2) A reference to a GlobalValue (a function or global variable)
    //    with an optional byte offset added to it (the addend).
    if (C->getType()->isIntegerTy(32)) {
      const ConstantExpr *CE = dyn_cast<ConstantExpr>(C);
      if (!CE)
        return false;
      // Without addend:  ptrtoint (TYPE* @GLOBAL to i32)
      if (isPtrToIntOfGlobal(CE))
        return true;
      // With addend:  add (i32 ptrtoint (TYPE* @GLOBAL to i32), i32 ADDEND)
      if (CE->getOpcode() == Instruction::Add &&
          isPtrToIntOfGlobal(CE->getOperand(0)) &&
          isa<ConstantInt>(CE->getOperand(1)))
        return true;
    }
    return false;
  }
  
  // This checks for part of the normal form produced by FlattenGlobals.
  static bool isCompoundElement(const Constant *C) {
    const ConstantStruct *CS = dyn_cast<ConstantStruct>(C);
    if (!CS || !CS->getType()->isPacked() || CS->getType()->hasName() ||
        CS->getNumOperands() <= 1)
      return false;
    for (unsigned I = 0; I < CS->getNumOperands(); ++I) {
      if (!isSimpleElement(CS->getOperand(I)))
        return false;
    }
    return true;
  }
  
  static std::string getAttributesAsString(AttributeSet Attrs) {
    std::string AttrsAsString;
    for (unsigned Slot = 0; Slot < Attrs.getNumSlots(); ++Slot) {
      for (AttributeSet::iterator Attr = Attrs.begin(Slot),
             E = Attrs.end(Slot); Attr != E; ++Attr) {
        AttrsAsString += " ";
        AttrsAsString += Attr->getAsString();
      }
    }
    return AttrsAsString;
  }
  
  // This checks that the GlobalVariable has the normal form produced by
  // the FlattenGlobals pass.
  void PNaClABIVerifyModule::checkGlobalIsFlattened(const GlobalVariable *GV) {
    if (!GV->hasInitializer()) {
      Reporter->addError() << "Global variable " << GV->getName()
                           << " has no initializer (disallowed)\n";
      return;
    }
    const Constant *InitVal = GV->getInitializer();
    if (isSimpleElement(InitVal) || isCompoundElement(InitVal))
      return;
    Reporter->addError() << "Global variable " << GV->getName()
                         << " has non-flattened initializer (disallowed): "
                         << *InitVal << "\n";
  }
  
  void PNaClABIVerifyModule::checkFunction(const Function *F,
                                           const StringRef &Name,
                                           PNaClAllowedIntrinsics &Intrinsics) {
    if (F->isIntrinsic()) {
      // Check intrinsics.
      if (!Intrinsics.isAllowed(F)) {
        Reporter->addError() << "Function " << F->getName()
                             << " is a disallowed LLVM intrinsic\n";
      }
    } else {
      // Check types of functions and their arguments.  Not necessary
      // for intrinsics, whose types are fixed anyway, and which have
      // argument types that we disallow such as i8.
      if (!PNaClABITypeChecker::isValidFunctionType(F->getFunctionType())) {
        Reporter->addError()
            << "Function " << Name << " has disallowed type: "
            << PNaClABITypeChecker::getTypeName(F->getFunctionType())
            << "\n";
      }
      // This check is disabled in streaming mode because it would
      // reject a function that is defined but not read in yet.
      // Unfortunately this means we simply don't check this property
      // when translating a pexe in the browser.
      // TODO(mseaborn): Enforce this property in the bitcode reader.
      if (!StreamingMode && F->isDeclaration() && !isAllowedMinsfiSyscall(F)) {
        Reporter->addError() << "Function " << Name
                             << " is declared but not defined (disallowed)\n";
      }
      if (!F->getAttributes().isEmpty()) {
        Reporter->addError()
            << "Function " << Name << " has disallowed attributes:"
            << getAttributesAsString(F->getAttributes()) << "\n";
      }
      if (!PNaClABIProps::isValidCallingConv(F->getCallingConv())) {
        Reporter->addError()
            << "Function " << Name << " has disallowed calling convention: "
            << PNaClABIProps::CallingConvName(F->getCallingConv()) << " ("
            << F->getCallingConv() << ")\n";
      }
    }
  
    checkGlobalValue(F);
  
    if (F->hasGC()) {
      Reporter->addError() << "Function " << Name <<
          " has disallowed \"gc\" attribute\n";
    }
    // Knowledge of what function alignments are useful is
    // architecture-specific and sandbox-specific, so PNaCl pexes
    // should not be able to specify function alignment.
    if (F->getAlignment() != 0) {
      Reporter->addError() << "Function " << Name <<
          " has disallowed \"align\" attribute\n";
    }
  }
  
  bool PNaClABIVerifyModule::runOnModule(Module &M) {
    SeenEntryPoint = false;
    PNaClAllowedIntrinsics Intrinsics(&M.getContext());
  
    if (!M.getModuleInlineAsm().empty()) {
      Reporter->addError() <<
          "Module contains disallowed top-level inline assembly\n";
    }
  
    for (Module::const_global_iterator MI = M.global_begin(), ME = M.global_end();
         MI != ME; ++MI) {
      checkGlobalIsFlattened(MI);
      checkGlobalVariable(MI);
  
      if (MI->isThreadLocal()) {
        Reporter->addError() << "Variable " << MI->getName() <<
            " has disallowed \"thread_local\" attribute\n";
      }
      if (MI->isExternallyInitialized()) {
        Reporter->addError() << "Variable " << MI->getName() <<
            " has disallowed \"externally_initialized\" attribute\n";
      }
    }
  
    // No aliases allowed for now.
    for (Module::alias_iterator MI = M.alias_begin(),
             E = M.alias_end(); MI != E; ++MI) {
      Reporter->addError() << "Variable " << MI->getName() <<
          " is an alias (disallowed)\n";
    }
  
    for (Module::const_iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) {
      checkFunction(MI, MI->getName(), Intrinsics);
    }
  
    // Check named metadata nodes
    for (Module::const_named_metadata_iterator I = M.named_metadata_begin(),
             E = M.named_metadata_end(); I != E; ++I) {
      if (!PNaClABIProps::isWhitelistedMetadata(I)) {
        Reporter->addError() << "Named metadata node " << I->getName()
                             << " is disallowed\n";
      }
    }
  
    if (!SeenEntryPoint) {
      Reporter->addError() << "Module has no entry point (disallowed)\n";
    }
    Reporter->checkForFatalErrors();
    return false;
  }
  
  // This method exists so that the passes can easily be run with opt -analyze.
  // In this case the default constructor is used and we want to reset the error
  // messages after each print (this is more of an issue for the FunctionPass
  // than the ModulePass)
  void PNaClABIVerifyModule::print(llvm::raw_ostream &O, const Module *M) const {
    Reporter->printErrors(O);
    Reporter->reset();
  }
  
  char PNaClABIVerifyModule::ID = 0;
  INITIALIZE_PASS(PNaClABIVerifyModule, "verify-pnaclabi-module",
                  "Verify module for PNaCl", false, true)
  
  ModulePass *llvm::createPNaClABIVerifyModulePass(
      PNaClABIErrorReporter *Reporter, bool StreamingMode) {
    return new PNaClABIVerifyModule(Reporter, StreamingMode);
  }
  