1243789Sdim//===-- BlackList.cpp - blacklist for sanitizers --------------------------===//
2243789Sdim//
3243789Sdim//                     The LLVM Compiler Infrastructure
4243789Sdim//
5243789Sdim// This file is distributed under the University of Illinois Open Source
6243789Sdim// License. See LICENSE.TXT for details.
7243789Sdim//
8243789Sdim//===----------------------------------------------------------------------===//
9243789Sdim//
10243789Sdim// This is a utility class for instrumentation passes (like AddressSanitizer
11243789Sdim// or ThreadSanitizer) to avoid instrumenting some functions or global
12243789Sdim// variables based on a user-supplied blacklist.
13243789Sdim//
14243789Sdim//===----------------------------------------------------------------------===//
15243789Sdim
16249423Sdim#include "llvm/Transforms/Utils/BlackList.h"
17243789Sdim#include "llvm/ADT/OwningPtr.h"
18243789Sdim#include "llvm/ADT/SmallVector.h"
19243789Sdim#include "llvm/ADT/StringExtras.h"
20249423Sdim#include "llvm/IR/DerivedTypes.h"
21249423Sdim#include "llvm/IR/Function.h"
22249423Sdim#include "llvm/IR/GlobalVariable.h"
23249423Sdim#include "llvm/IR/Module.h"
24243789Sdim#include "llvm/Support/MemoryBuffer.h"
25243789Sdim#include "llvm/Support/Regex.h"
26243789Sdim#include "llvm/Support/raw_ostream.h"
27243789Sdim#include "llvm/Support/system_error.h"
28249423Sdim#include <string>
29249423Sdim#include <utility>
30243789Sdim
31243789Sdimnamespace llvm {
32243789Sdim
33243789SdimBlackList::BlackList(const StringRef Path) {
34243789Sdim  // Validate and open blacklist file.
35249423Sdim  if (Path.empty()) return;
36243789Sdim  OwningPtr<MemoryBuffer> File;
37243789Sdim  if (error_code EC = MemoryBuffer::getFile(Path, File)) {
38243789Sdim    report_fatal_error("Can't open blacklist file: " + Path + ": " +
39243789Sdim                       EC.message());
40243789Sdim  }
41243789Sdim
42243789Sdim  // Iterate through each line in the blacklist file.
43243789Sdim  SmallVector<StringRef, 16> Lines;
44243789Sdim  SplitString(File.take()->getBuffer(), Lines, "\n\r");
45243789Sdim  StringMap<std::string> Regexps;
46243789Sdim  for (SmallVector<StringRef, 16>::iterator I = Lines.begin(), E = Lines.end();
47243789Sdim       I != E; ++I) {
48243789Sdim    // Ignore empty lines and lines starting with "#"
49243789Sdim    if (I->empty() || I->startswith("#"))
50243789Sdim      continue;
51243789Sdim    // Get our prefix and unparsed regexp.
52243789Sdim    std::pair<StringRef, StringRef> SplitLine = I->split(":");
53243789Sdim    StringRef Prefix = SplitLine.first;
54243789Sdim    std::string Regexp = SplitLine.second;
55249423Sdim    if (Regexp.empty()) {
56249423Sdim      // Missing ':' in the line.
57249423Sdim      report_fatal_error("malformed blacklist line: " + SplitLine.first);
58249423Sdim    }
59243789Sdim
60243789Sdim    // Replace * with .*
61243789Sdim    for (size_t pos = 0; (pos = Regexp.find("*", pos)) != std::string::npos;
62243789Sdim         pos += strlen(".*")) {
63243789Sdim      Regexp.replace(pos, strlen("*"), ".*");
64243789Sdim    }
65243789Sdim
66243789Sdim    // Check that the regexp is valid.
67243789Sdim    Regex CheckRE(Regexp);
68243789Sdim    std::string Error;
69243789Sdim    if (!CheckRE.isValid(Error)) {
70243789Sdim      report_fatal_error("malformed blacklist regex: " + SplitLine.second +
71243789Sdim          ": " + Error);
72243789Sdim    }
73243789Sdim
74243789Sdim    // Add this regexp into the proper group by its prefix.
75249423Sdim    if (!Regexps[Prefix].empty())
76243789Sdim      Regexps[Prefix] += "|";
77243789Sdim    Regexps[Prefix] += Regexp;
78243789Sdim  }
79243789Sdim
80243789Sdim  // Iterate through each of the prefixes, and create Regexs for them.
81249423Sdim  for (StringMap<std::string>::const_iterator I = Regexps.begin(),
82249423Sdim       E = Regexps.end(); I != E; ++I) {
83243789Sdim    Entries[I->getKey()] = new Regex(I->getValue());
84243789Sdim  }
85243789Sdim}
86243789Sdim
87249423Sdimbool BlackList::isIn(const Function &F) const {
88243789Sdim  return isIn(*F.getParent()) || inSection("fun", F.getName());
89243789Sdim}
90243789Sdim
91249423Sdimbool BlackList::isIn(const GlobalVariable &G) const {
92243789Sdim  return isIn(*G.getParent()) || inSection("global", G.getName());
93243789Sdim}
94243789Sdim
95249423Sdimbool BlackList::isIn(const Module &M) const {
96243789Sdim  return inSection("src", M.getModuleIdentifier());
97243789Sdim}
98243789Sdim
99249423Sdimstatic StringRef GetGVTypeString(const GlobalVariable &G) {
100249423Sdim  // Types of GlobalVariables are always pointer types.
101249423Sdim  Type *GType = G.getType()->getElementType();
102249423Sdim  // For now we support blacklisting struct types only.
103249423Sdim  if (StructType *SGType = dyn_cast<StructType>(GType)) {
104249423Sdim    if (!SGType->isLiteral())
105249423Sdim      return SGType->getName();
106249423Sdim  }
107249423Sdim  return "<unknown type>";
108243789Sdim}
109243789Sdim
110249423Sdimbool BlackList::isInInit(const GlobalVariable &G) const {
111249423Sdim  return (isIn(*G.getParent()) ||
112249423Sdim          inSection("global-init", G.getName()) ||
113251662Sdim          inSection("global-init-type", GetGVTypeString(G)) ||
114251662Sdim          inSection("global-init-src", G.getParent()->getModuleIdentifier()));
115249423Sdim}
116249423Sdim
117243789Sdimbool BlackList::inSection(const StringRef Section,
118249423Sdim                          const StringRef Query) const {
119249423Sdim  StringMap<Regex*>::const_iterator I = Entries.find(Section);
120249423Sdim  if (I == Entries.end()) return false;
121249423Sdim
122249423Sdim  Regex *FunctionRegex = I->getValue();
123249423Sdim  return FunctionRegex->match(Query);
124243789Sdim}
125243789Sdim
126243789Sdim}  // namespace llvm
127