diff options
Diffstat (limited to 'lib/Transforms/Instrumentation')
-rw-r--r-- | lib/Transforms/Instrumentation/AddressSanitizer.cpp | 14 | ||||
-rw-r--r-- | lib/Transforms/Instrumentation/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/Transforms/Instrumentation/DebugIR.cpp | 310 | ||||
-rw-r--r-- | lib/Transforms/Instrumentation/GCOVProfiling.cpp | 2 | ||||
-rw-r--r-- | lib/Transforms/Instrumentation/MemorySanitizer.cpp | 66 | ||||
-rw-r--r-- | lib/Transforms/Instrumentation/ThreadSanitizer.cpp | 2 |
6 files changed, 372 insertions, 23 deletions
diff --git a/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/lib/Transforms/Instrumentation/AddressSanitizer.cpp index 623c470..22851b4 100644 --- a/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -39,9 +39,9 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/Endian.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" -#include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/BlackList.h" #include "llvm/Transforms/Utils/Local.h" @@ -56,6 +56,7 @@ static const uint64_t kDefaultShadowOffset32 = 1ULL << 29; static const uint64_t kDefaultShadowOffset64 = 1ULL << 44; static const uint64_t kDefaultShort64bitShadowOffset = 0x7FFF8000; // < 2G. static const uint64_t kPPC64_ShadowOffset64 = 1ULL << 41; +static const uint64_t kMIPS32_ShadowOffset32 = 0x0aaa8000; static const size_t kMaxStackMallocSize = 1 << 16; // 64K static const uintptr_t kCurrentStackFrameMagic = 0x41B58AB3; @@ -208,6 +209,8 @@ static ShadowMapping getShadowMapping(const Module &M, int LongSize, bool IsMacOSX = TargetTriple.getOS() == llvm::Triple::MacOSX; bool IsPPC64 = TargetTriple.getArch() == llvm::Triple::ppc64; bool IsX86_64 = TargetTriple.getArch() == llvm::Triple::x86_64; + bool IsMIPS32 = TargetTriple.getArch() == llvm::Triple::mips || + TargetTriple.getArch() == llvm::Triple::mipsel; ShadowMapping Mapping; @@ -217,7 +220,8 @@ static ShadowMapping getShadowMapping(const Module &M, int LongSize, Mapping.OrShadowOffset = !IsPPC64 && !ClShort64BitOffset; Mapping.Offset = (IsAndroid || ZeroBaseShadow) ? 0 : - (LongSize == 32 ? kDefaultShadowOffset32 : + (LongSize == 32 ? + (IsMIPS32 ? kMIPS32_ShadowOffset32 : kDefaultShadowOffset32) : IsPPC64 ? kPPC64_ShadowOffset64 : kDefaultShadowOffset64); if (!ZeroBaseShadow && ClShort64BitOffset && IsX86_64 && !IsMacOSX) { assert(LongSize == 64); @@ -520,7 +524,7 @@ ModulePass *llvm::createAddressSanitizerModulePass( } static size_t TypeSizeToSizeIndex(uint32_t TypeSize) { - size_t Res = CountTrailingZeros_32(TypeSize / 8); + size_t Res = countTrailingZeros(TypeSize / 8); assert(Res < kNumberOfAccessSizes); return Res; } @@ -1270,6 +1274,10 @@ void FunctionStackPoisoner::poisonRedZones( RedzoneSize(), 1ULL << Mapping.Scale, kAsanStackPartialRedzoneMagic); + Poison = + ASan.TD->isLittleEndian() + ? support::endian::byte_swap<uint32_t, support::little>(Poison) + : support::endian::byte_swap<uint32_t, support::big>(Poison); } Value *PartialPoison = ConstantInt::get(RZTy, Poison); IRB.CreateStore(PartialPoison, IRB.CreateIntToPtr(Ptr, RZPtrTy)); diff --git a/lib/Transforms/Instrumentation/CMakeLists.txt b/lib/Transforms/Instrumentation/CMakeLists.txt index 1c9e053..aa265a4 100644 --- a/lib/Transforms/Instrumentation/CMakeLists.txt +++ b/lib/Transforms/Instrumentation/CMakeLists.txt @@ -2,6 +2,7 @@ add_llvm_library(LLVMInstrumentation AddressSanitizer.cpp BlackList.cpp BoundsChecking.cpp + DebugIR.cpp EdgeProfiling.cpp GCOVProfiling.cpp MemorySanitizer.cpp diff --git a/lib/Transforms/Instrumentation/DebugIR.cpp b/lib/Transforms/Instrumentation/DebugIR.cpp new file mode 100644 index 0000000..020804f --- /dev/null +++ b/lib/Transforms/Instrumentation/DebugIR.cpp @@ -0,0 +1,310 @@ +//===--- DebugIR.cpp - Transform debug metadata to allow debugging IR -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// A Module transform pass that emits a succinct version of the IR and replaces +// the source file metadata to allow debuggers to step through the IR. +// +// The location where the IR file is emitted is the same as the directory +// operand of the !llvm.dbg.cu metadata node present in the input module. The +// file name is constructed from the original file name by stripping the +// extension and replacing it with "-debug-ll" or the Postfix string specified +// at construction. +// +// FIXME: instead of replacing debug metadata, additional metadata should be +// used to point capable debuggers to the IR file without destroying the +// mapping to the original source file. +// +// FIXME: this pass should not depend on the existance of debug metadata in +// the module as it does now. Instead, it should use DIBuilder to create the +// required metadata. +// +//===----------------------------------------------------------------------===// + +#include <string> + +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/ValueMap.h" +#include "llvm/Assembly/AssemblyAnnotationWriter.h" +#include "llvm/DebugInfo.h" +#include "llvm/DIBuilder.h" +#include "llvm/InstVisitor.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Module.h" +#include "llvm/Pass.h" +#include "llvm/Transforms/Instrumentation.h" +#include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/FormattedStream.h" +using namespace llvm; + +namespace { + +/// Builds a map of Value* to line numbers on which the Value appears in a +/// textual representation of the IR by plugging into the AssemblyWriter by +/// masquerading as an AssemblyAnnotationWriter. +class ValueToLineMap : public AssemblyAnnotationWriter { + ValueMap<const Value *, unsigned int> Lines; + typedef ValueMap<const Value *, unsigned int>::const_iterator LineIter; + +public: + + /// Prints Module to a null buffer in order to build the map of Value pointers + /// to line numbers. + ValueToLineMap(Module *M) { + raw_null_ostream ThrowAway; + M->print(ThrowAway, this); + } + + // This function is called after an Instruction, GlobalValue, or GlobalAlias + // is printed. + void printInfoComment(const Value &V, formatted_raw_ostream &Out) { + Out.flush(); + Lines.insert(std::make_pair(&V, Out.getLine() + 1)); + } + + /// If V appears on a line in the textual IR representation, sets Line to the + /// line number and returns true, otherwise returns false. + bool getLine(const Value *V, unsigned int &Line) const { + LineIter i = Lines.find(V); + if (i != Lines.end()) { + Line = i->second; + return true; + } + return false; + } +}; + +/// Removes debug intrisncs like llvm.dbg.declare and llvm.dbg.value. +class DebugIntrinsicsRemover : public InstVisitor<DebugIntrinsicsRemover> { + void remove(Instruction &I) { I.eraseFromParent(); } + +public: + void visitDbgDeclareInst(DbgDeclareInst &I) { remove(I); } + void visitDbgValueInst(DbgValueInst &I) { remove(I); } + void visitDbgInfoIntrinsic(DbgInfoIntrinsic &I) { remove(I); } +}; + +/// Removes debug metadata (!dbg) nodes from all instructions as well as +/// metadata named "llvm.dbg.cu" in the Module. +class DebugMetadataRemover : public InstVisitor<DebugMetadataRemover> { +public: + void visitInstruction(Instruction &I) { + if (I.getMetadata(LLVMContext::MD_dbg)) + I.setMetadata(LLVMContext::MD_dbg, 0); + } + + void run(Module *M) { + // Remove debug metadata attached to instructions + visit(M); + + // Remove CU named metadata (and all children nodes) + NamedMDNode *Node = M->getNamedMetadata("llvm.dbg.cu"); + M->eraseNamedMetadata(Node); + } +}; + +/// Replaces line number metadata attached to Instruction nodes with new line +/// numbers provided by the ValueToLineMap. +class LineNumberReplacer : public InstVisitor<LineNumberReplacer> { + /// Table of line numbers + const ValueToLineMap &LineTable; + + /// Table of cloned values + const ValueToValueMapTy &VMap; + + /// Directory of debug metadata + const DebugInfoFinder &Finder; + +public: + LineNumberReplacer(const ValueToLineMap &VLM, const DebugInfoFinder &Finder, + const ValueToValueMapTy &VMap) + : LineTable(VLM), VMap(VMap), Finder(Finder) {} + + void visitInstruction(Instruction &I) { + DebugLoc Loc(I.getDebugLoc()); + + unsigned Col = 0; // FIXME: support columns + unsigned Line; + if (!LineTable.getLine(VMap.lookup(&I), Line)) + // Instruction has no line, it may have been removed (in the module that + // will be passed to the debugger) so there is nothing to do here. + return; + + DebugLoc NewLoc; + if (!Loc.isUnknown()) + // I had a previous debug location: re-use the DebugLoc + NewLoc = DebugLoc::get(Line, Col, Loc.getScope(I.getContext()), + Loc.getInlinedAt(I.getContext())); + else if (MDNode *scope = findFunctionMD(I.getParent()->getParent())) + // I had no previous debug location, but M has some debug information + NewLoc = + DebugLoc::get(Line, Col, scope, /*FIXME: inlined instructions*/ 0); + else + // Neither I nor M has any debug information -- nothing to do here. + // FIXME: support debugging of undecorated IR (generated by clang without + // the -g option) + return; + + addDebugLocation(const_cast<Instruction &>(I), NewLoc); + } + +private: + + /// Returns the MDNode that corresponds with F + MDNode *findFunctionMD(const Function *F) { + for (DebugInfoFinder::iterator i = Finder.subprogram_begin(), + e = Finder.subprogram_end(); + i != e; ++i) { + DISubprogram S(*i); + if (S.getFunction() == F) + return *i; + } + // cannot find F -- likely means there is no debug information + return 0; + } + + void addDebugLocation(Instruction &I, DebugLoc Loc) { + MDNode *MD = Loc.getAsMDNode(I.getContext()); + I.setMetadata(LLVMContext::MD_dbg, MD); + } +}; + +class DebugIR : public ModulePass { + std::string Postfix; + std::string Filename; + + /// Flags to control the verbosity of the generated IR file + bool hideDebugIntrinsics; + bool hideDebugMetadata; + +public: + static char ID; + + const char *getPassName() const { return "DebugIR"; } + + // FIXME: figure out if we are compiling something that already exists on disk + // in text IR form, in which case we can omit outputting a new IR file, or if + // we're building something from memory where we actually need to emit a new + // IR file for the debugger. + + /// Output a file with the same base name as the original, but with the + /// postfix "-debug-ll" appended. + DebugIR() + : ModulePass(ID), Postfix("-debug-ll"), hideDebugIntrinsics(true), + hideDebugMetadata(true) {} + + /// Customize the postfix string used to replace the extension of the + /// original filename that appears in the !llvm.dbg.cu metadata node. + DebugIR(StringRef postfix, bool hideDebugIntrinsics, bool hideDebugMetadata) + : ModulePass(ID), Postfix(postfix), + hideDebugIntrinsics(hideDebugIntrinsics), + hideDebugMetadata(hideDebugMetadata) {} + +private: + // Modify the filename embedded in the Compilation-Unit debug information of M + bool replaceFilename(Module &M, const DebugInfoFinder &Finder) { + bool changed = false; + + // Sanity check -- if llvm.dbg.cu node exists, the DebugInfoFinder + // better have found at least one CU! + if (M.getNamedMetadata("llvm.dbg.cu")) + assert(Finder.compile_unit_count() > 0 && + "Found no compile units but llvm.dbg.cu node exists"); + + for (DebugInfoFinder::iterator i = Finder.compile_unit_begin(), + e = Finder.compile_unit_end(); + i != e; ++i) { + DICompileUnit CU(*i); + Filename = CU.getFilename(); + + // Replace extension with postfix + size_t dot = Filename.find_last_of("."); + if (dot != std::string::npos) + Filename.erase(dot); + Filename += Postfix; + + CU.setFilename(Filename, M.getContext()); + changed = true; + } + return changed; + } + + /// Replace existing line number metadata with line numbers that correspond + /// with the IR file that is seen by the debugger. + void addLineNumberMetadata(Module *M, const ValueToLineMap &VLM, + const ValueToValueMapTy &VMap, + const DebugInfoFinder &Finder) { + LineNumberReplacer Replacer(VLM, Finder, VMap); + Replacer.visit(M); + } + + void writeDebugBitcode(Module *M) { + std::string error; + tool_output_file OutFile(Filename.c_str(), error); + OutFile.keep(); + formatted_raw_ostream OS; + OS.setStream(OutFile.os()); + M->print(OS, 0); + } + + void removeDebugIntrinsics(Module *M) { + DebugIntrinsicsRemover Remover; + Remover.visit(M); + } + + void removeDebugMetadata(Module *M) { + DebugMetadataRemover Remover; + Remover.run(M); + } + + void updateAndWriteDebugIRFile(Module *M, const DebugInfoFinder &Finder) { + // The module we output in text form for a debugger to open is stripped of + // 'extras' like debug intrinsics that end up in DWARF anyways and just + // clutter the debug experience. + + ValueToValueMapTy VMap; + Module *DebuggerM = CloneModule(M, VMap); + + if (hideDebugIntrinsics) + removeDebugIntrinsics(DebuggerM); + + if (hideDebugMetadata) + removeDebugMetadata(DebuggerM); + + // FIXME: remove all debug metadata from M once we support generating DWARF + // subprogram attributes. + + ValueToLineMap LineTable(DebuggerM); + addLineNumberMetadata(M, LineTable, VMap, Finder); + writeDebugBitcode(DebuggerM); + } + + bool runOnModule(Module &M) { + // Stores existing debug info needed when creating new line number entries. + DebugInfoFinder Finder; + Finder.processModule(M); + + bool changed = replaceFilename(M, Finder); + if (changed) + updateAndWriteDebugIRFile(&M, Finder); + return changed; + } +}; + +} // anonymous namespace + +char DebugIR::ID = 0; +INITIALIZE_PASS(DebugIR, "debug-ir", "Enable debugging IR", false, false) + +ModulePass *llvm::createDebugIRPass(StringRef FilenamePostfix, + bool hideDebugIntrinsics, + bool hideDebugMetadata) { + return new DebugIR(FilenamePostfix, hideDebugIntrinsics, hideDebugMetadata); +} diff --git a/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/lib/Transforms/Instrumentation/GCOVProfiling.cpp index 2edd151..3ce9cf6 100644 --- a/lib/Transforms/Instrumentation/GCOVProfiling.cpp +++ b/lib/Transforms/Instrumentation/GCOVProfiling.cpp @@ -34,7 +34,7 @@ #include "llvm/Support/DebugLoc.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/InstIterator.h" -#include "llvm/Support/PathV2.h" +#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/ModuleUtils.h" #include <string> diff --git a/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/lib/Transforms/Instrumentation/MemorySanitizer.cpp index 4e75904..a3a688d 100644 --- a/lib/Transforms/Instrumentation/MemorySanitizer.cpp +++ b/lib/Transforms/Instrumentation/MemorySanitizer.cpp @@ -74,6 +74,7 @@ #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Triple.h" #include "llvm/ADT/ValueMap.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" @@ -228,7 +229,7 @@ class MemorySanitizer : public FunctionPass { MDNode *ColdCallWeights; /// \brief Branch weights for origin store. MDNode *OriginStoreWeights; - /// \bried Path to blacklist file. + /// \brief Path to blacklist file. SmallString<64> BlacklistFile; /// \brief The blacklist. OwningPtr<BlackList> BL; @@ -299,30 +300,30 @@ void MemorySanitizer::initializeCallbacks(Module &M) { RetvalTLS = new GlobalVariable( M, ArrayType::get(IRB.getInt64Ty(), 8), false, GlobalVariable::ExternalLinkage, 0, "__msan_retval_tls", 0, - GlobalVariable::GeneralDynamicTLSModel); + GlobalVariable::InitialExecTLSModel); RetvalOriginTLS = new GlobalVariable( M, OriginTy, false, GlobalVariable::ExternalLinkage, 0, - "__msan_retval_origin_tls", 0, GlobalVariable::GeneralDynamicTLSModel); + "__msan_retval_origin_tls", 0, GlobalVariable::InitialExecTLSModel); ParamTLS = new GlobalVariable( M, ArrayType::get(IRB.getInt64Ty(), 1000), false, GlobalVariable::ExternalLinkage, 0, "__msan_param_tls", 0, - GlobalVariable::GeneralDynamicTLSModel); + GlobalVariable::InitialExecTLSModel); ParamOriginTLS = new GlobalVariable( M, ArrayType::get(OriginTy, 1000), false, GlobalVariable::ExternalLinkage, - 0, "__msan_param_origin_tls", 0, GlobalVariable::GeneralDynamicTLSModel); + 0, "__msan_param_origin_tls", 0, GlobalVariable::InitialExecTLSModel); VAArgTLS = new GlobalVariable( M, ArrayType::get(IRB.getInt64Ty(), 1000), false, GlobalVariable::ExternalLinkage, 0, "__msan_va_arg_tls", 0, - GlobalVariable::GeneralDynamicTLSModel); + GlobalVariable::InitialExecTLSModel); VAArgOverflowSizeTLS = new GlobalVariable( M, IRB.getInt64Ty(), false, GlobalVariable::ExternalLinkage, 0, "__msan_va_arg_overflow_size_tls", 0, - GlobalVariable::GeneralDynamicTLSModel); + GlobalVariable::InitialExecTLSModel); OriginTLS = new GlobalVariable( M, IRB.getInt32Ty(), false, GlobalVariable::ExternalLinkage, 0, - "__msan_origin_tls", 0, GlobalVariable::GeneralDynamicTLSModel); + "__msan_origin_tls", 0, GlobalVariable::InitialExecTLSModel); // We insert an empty inline asm after __msan_report* to avoid callback merge. EmptyAsm = InlineAsm::get(FunctionType::get(IRB.getVoidTy(), false), @@ -365,11 +366,13 @@ bool MemorySanitizer::doInitialization(Module &M) { appendToGlobalCtors(M, cast<Function>(M.getOrInsertFunction( "__msan_init", IRB.getVoidTy(), NULL)), 0); - new GlobalVariable(M, IRB.getInt32Ty(), true, GlobalValue::WeakODRLinkage, - IRB.getInt32(TrackOrigins), "__msan_track_origins"); + if (TrackOrigins) + new GlobalVariable(M, IRB.getInt32Ty(), true, GlobalValue::WeakODRLinkage, + IRB.getInt32(TrackOrigins), "__msan_track_origins"); - new GlobalVariable(M, IRB.getInt32Ty(), true, GlobalValue::WeakODRLinkage, - IRB.getInt32(ClKeepGoing), "__msan_keep_going"); + if (ClKeepGoing) + new GlobalVariable(M, IRB.getInt32Ty(), true, GlobalValue::WeakODRLinkage, + IRB.getInt32(ClKeepGoing), "__msan_keep_going"); return true; } @@ -768,14 +771,21 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { if (AI->hasByValAttr()) { // ByVal pointer itself has clean shadow. We copy the actual // argument shadow to the underlying memory. + // Figure out maximal valid memcpy alignment. + unsigned ArgAlign = AI->getParamAlignment(); + if (ArgAlign == 0) { + Type *EltType = A->getType()->getPointerElementType(); + ArgAlign = MS.TD->getABITypeAlignment(EltType); + } + unsigned CopyAlign = std::min(ArgAlign, kShadowTLSAlignment); Value *Cpy = EntryIRB.CreateMemCpy( - getShadowPtr(V, EntryIRB.getInt8Ty(), EntryIRB), - Base, Size, AI->getParamAlignment()); + getShadowPtr(V, EntryIRB.getInt8Ty(), EntryIRB), Base, Size, + CopyAlign); DEBUG(dbgs() << " ByValCpy: " << *Cpy << "\n"); (void)Cpy; *ShadowPtr = getCleanShadow(V); } else { - *ShadowPtr = EntryIRB.CreateLoad(Base); + *ShadowPtr = EntryIRB.CreateAlignedLoad(Base, kShadowTLSAlignment); } DEBUG(dbgs() << " ARG: " << *AI << " ==> " << **ShadowPtr << "\n"); @@ -784,7 +794,7 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { setOrigin(A, EntryIRB.CreateLoad(OriginPtr)); } } - ArgOffset += DataLayout::RoundUpAlignment(Size, 8); + ArgOffset += DataLayout::RoundUpAlignment(Size, kShadowTLSAlignment); } assert(*ShadowPtr && "Could not find shadow for an argument"); return *ShadowPtr; @@ -1963,9 +1973,29 @@ struct VarArgAMD64Helper : public VarArgHelper { } }; -VarArgHelper* CreateVarArgHelper(Function &Func, MemorySanitizer &Msan, +/// \brief A no-op implementation of VarArgHelper. +struct VarArgNoOpHelper : public VarArgHelper { + VarArgNoOpHelper(Function &F, MemorySanitizer &MS, + MemorySanitizerVisitor &MSV) {} + + void visitCallSite(CallSite &CS, IRBuilder<> &IRB) {} + + void visitVAStartInst(VAStartInst &I) {} + + void visitVACopyInst(VACopyInst &I) {} + + void finalizeInstrumentation() {} +}; + +VarArgHelper *CreateVarArgHelper(Function &Func, MemorySanitizer &Msan, MemorySanitizerVisitor &Visitor) { - return new VarArgAMD64Helper(Func, Msan, Visitor); + // VarArg handling is only implemented on AMD64. False positives are possible + // on other platforms. + llvm::Triple TargetTriple(Func.getParent()->getTargetTriple()); + if (TargetTriple.getArch() == llvm::Triple::x86_64) + return new VarArgAMD64Helper(Func, Msan, Visitor); + else + return new VarArgNoOpHelper(Func, Msan, Visitor); } } // namespace diff --git a/lib/Transforms/Instrumentation/ThreadSanitizer.cpp b/lib/Transforms/Instrumentation/ThreadSanitizer.cpp index 299060a..318fa3f 100644 --- a/lib/Transforms/Instrumentation/ThreadSanitizer.cpp +++ b/lib/Transforms/Instrumentation/ThreadSanitizer.cpp @@ -579,7 +579,7 @@ int ThreadSanitizer::getMemoryAccessFuncIndex(Value *Addr) { // Ignore all unusual sizes. return -1; } - size_t Idx = CountTrailingZeros_32(TypeSize / 8); + size_t Idx = countTrailingZeros(TypeSize / 8); assert(Idx < kNumberOfAccessSizes); return Idx; } |