| Index: lib/Analysis/NaCl/PNaClABIVerifyModule.cpp
|
| diff --git a/lib/Analysis/NaCl/PNaClABIVerifyModule.cpp b/lib/Analysis/NaCl/PNaClABIVerifyModule.cpp
|
| index efb40cf43a7d90747ae4ae081e47a468e8318c9b..515dbbcc1eb59ba13239d4ad635f91d8b21b1d39 100644
|
| --- a/lib/Analysis/NaCl/PNaClABIVerifyModule.cpp
|
| +++ b/lib/Analysis/NaCl/PNaClABIVerifyModule.cpp
|
| @@ -17,7 +17,9 @@
|
| #include "llvm/ADT/Twine.h"
|
| #include "llvm/Analysis/NaCl.h"
|
| #include "llvm/IR/DerivedTypes.h"
|
| +#include "llvm/IR/Intrinsics.h"
|
| #include "llvm/IR/Module.h"
|
| +#include "llvm/Support/Debug.h"
|
| #include "llvm/Support/raw_ostream.h"
|
|
|
| #include "PNaClABITypeChecker.h"
|
| @@ -28,8 +30,14 @@ cl::opt<bool>
|
| PNaClABIAllowDebugMetadata("pnaclabi-allow-debug-metadata",
|
| cl::desc("Allow debug metadata during PNaCl ABI verification."),
|
| cl::init(false));
|
| +
|
| }
|
|
|
| +static cl::opt<bool>
|
| +PNaClABIAllowDevIntrinsics("pnaclabi-allow-dev-intrinsics",
|
| + cl::desc("Allow all LLVM intrinsics during PNaCl ABI verification."),
|
| + cl::init(true)); // TODO(jvoung): Make this false by default.
|
| +
|
| namespace {
|
| // This pass should not touch function bodies, to stay streaming-friendly
|
| class PNaClABIVerifyModule : public ModulePass {
|
| @@ -55,6 +63,7 @@ class PNaClABIVerifyModule : public ModulePass {
|
| virtual void print(raw_ostream &O, const Module *M) const;
|
| private:
|
| void CheckGlobalValueCommon(const GlobalValue *GV);
|
| + bool IsWhitelistedIntrinsic(const Function* F, unsigned ID);
|
| bool IsWhitelistedMetadata(const NamedMDNode *MD);
|
| PNaClABITypeChecker TC;
|
| PNaClABIErrorReporter *Reporter;
|
| @@ -113,6 +122,76 @@ void PNaClABIVerifyModule::CheckGlobalValueCommon(const GlobalValue *GV) {
|
| }
|
| }
|
|
|
| +bool PNaClABIVerifyModule::IsWhitelistedIntrinsic(const Function* F,
|
| + unsigned ID) {
|
| + // Keep 3 categories of intrinsics for now.
|
| + // (1) Allowed always
|
| + // (2) Never allowed
|
| + // (3) "Dev" intrinsics, which may or may not be allowed.
|
| + // "Dev" intrinsics are controlled by the PNaClABIAllowDevIntrinsics flag.
|
| + // Please keep these sorted within each category.
|
| + switch(ID) {
|
| + // Disallow by default.
|
| + default: return false;
|
| + // (1) Always allowed.
|
| + case Intrinsic::invariant_end:
|
| + case Intrinsic::invariant_start:
|
| + case Intrinsic::lifetime_end:
|
| + case Intrinsic::lifetime_start:
|
| + case Intrinsic::memcpy:
|
| + case Intrinsic::memmove:
|
| + case Intrinsic::memset:
|
| + case Intrinsic::nacl_read_tp:
|
| + case Intrinsic::trap:
|
| + return true;
|
| +
|
| + // (2) Known to be never allowed.
|
| + case Intrinsic::not_intrinsic:
|
| + case Intrinsic::adjust_trampoline:
|
| + case Intrinsic::init_trampoline:
|
| + case Intrinsic::stackprotector:
|
| + case Intrinsic::vacopy:
|
| + case Intrinsic::vaend:
|
| + case Intrinsic::vastart:
|
| + return false;
|
| +
|
| + // (3) Dev intrinsics.
|
| + case Intrinsic::dbg_declare:
|
| + case Intrinsic::dbg_value:
|
| + return PNaClABIAllowDevIntrinsics || PNaClABIAllowDebugMetadata;
|
| + case Intrinsic::bswap: // Support via compiler_rt if arch doesn't have it?
|
| + case Intrinsic::cos: // Rounding not defined: support with fast-math?
|
| + case Intrinsic::ctlz: // Support via compiler_rt if arch doesn't have it?
|
| + case Intrinsic::ctpop: // Support via compiler_rt if arch doesn't have it?
|
| + case Intrinsic::cttz: // Support via compiler_rt if arch doesn't have it?
|
| + case Intrinsic::eh_dwarf_cfa: // For EH tests.
|
| + case Intrinsic::exp: // Rounding not defined: support with fast-math?
|
| + case Intrinsic::exp2: // Rounding not defined: support with fast-math?
|
| + case Intrinsic::expect: // From __builtin_expect.
|
| + case Intrinsic::flt_rounds:
|
| + case Intrinsic::frameaddress: // Support for 0-level or not?
|
| + case Intrinsic::log: // Rounding not defined: support with fast-math?
|
| + case Intrinsic::log2: // Rounding not defined: support with fast-math?
|
| + case Intrinsic::log10: // Rounding not defined: support with fast-math?
|
| + case Intrinsic::nacl_target_arch: // Used by translator self-build.
|
| + case Intrinsic::pow: // Rounding not defined: support with fast-math?
|
| + case Intrinsic::prefetch: // Could ignore if target doesn't support?
|
| + case Intrinsic::returnaddress: // Support for 0-level or not?
|
| + case Intrinsic::sin: // Rounding not defined: support with fast-math?
|
| + case Intrinsic::sqrt:
|
| + case Intrinsic::stackrestore: // Used to support C99 VLAs.
|
| + case Intrinsic::stacksave:
|
| + // the *_with_overflow return struct types, so we'll need to fix these.
|
| + case Intrinsic::sadd_with_overflow: // Introduced by -ftrapv
|
| + case Intrinsic::ssub_with_overflow:
|
| + case Intrinsic::uadd_with_overflow:
|
| + case Intrinsic::usub_with_overflow:
|
| + case Intrinsic::smul_with_overflow:
|
| + case Intrinsic::umul_with_overflow: // Introduced by c++ new[x * y].
|
| + return PNaClABIAllowDevIntrinsics;
|
| + }
|
| +}
|
| +
|
| bool PNaClABIVerifyModule::IsWhitelistedMetadata(const NamedMDNode* MD) {
|
| return MD->getName().startswith("llvm.dbg.") && PNaClABIAllowDebugMetadata;
|
| }
|
| @@ -153,6 +232,13 @@ bool PNaClABIVerifyModule::runOnModule(Module &M) {
|
| }
|
|
|
| for (Module::const_iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) {
|
| + // Check intrinsics.
|
| + if (MI->isIntrinsic()
|
| + && !IsWhitelistedIntrinsic(MI, MI->getIntrinsicID())) {
|
| + Reporter->addError() << "Function " << MI->getName()
|
| + << " is a disallowed LLVM intrinsic\n";
|
| + }
|
| +
|
| // Check types of functions and their arguments
|
| FunctionType *FT = MI->getFunctionType();
|
| if (!TC.isValidType(FT->getReturnType())) {
|
|
|