1//===-- BlackList.cpp - blacklist for sanitizers --------------------------===//
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// This is a utility class for instrumentation passes (like AddressSanitizer
11// or ThreadSanitizer) to avoid instrumenting some functions or global
12// variables based on a user-supplied blacklist.
13//
14//===----------------------------------------------------------------------===//
15
16#include "llvm/Transforms/Utils/BlackList.h"
17#include "llvm/ADT/OwningPtr.h"
18#include "llvm/ADT/SmallVector.h"
19#include "llvm/ADT/StringExtras.h"
20#include "llvm/IR/DerivedTypes.h"
21#include "llvm/IR/Function.h"
22#include "llvm/IR/GlobalVariable.h"
23#include "llvm/IR/Module.h"
24#include "llvm/Support/MemoryBuffer.h"
25#include "llvm/Support/Regex.h"
26#include "llvm/Support/raw_ostream.h"
27#include "llvm/Support/system_error.h"
28#include <string>
29#include <utility>
30
31namespace llvm {
32
33BlackList::BlackList(const StringRef Path) {
34  // Validate and open blacklist file.
35  if (Path.empty()) return;
36  OwningPtr<MemoryBuffer> File;
37  if (error_code EC = MemoryBuffer::getFile(Path, File)) {
38    report_fatal_error("Can't open blacklist file: " + Path + ": " +
39                       EC.message());
40  }
41
42  // Iterate through each line in the blacklist file.
43  SmallVector<StringRef, 16> Lines;
44  SplitString(File.take()->getBuffer(), Lines, "\n\r");
45  StringMap<std::string> Regexps;
46  for (SmallVector<StringRef, 16>::iterator I = Lines.begin(), E = Lines.end();
47       I != E; ++I) {
48    // Ignore empty lines and lines starting with "#"
49    if (I->empty() || I->startswith("#"))
50      continue;
51    // Get our prefix and unparsed regexp.
52    std::pair<StringRef, StringRef> SplitLine = I->split(":");
53    StringRef Prefix = SplitLine.first;
54    std::string Regexp = SplitLine.second;
55    if (Regexp.empty()) {
56      // Missing ':' in the line.
57      report_fatal_error("malformed blacklist line: " + SplitLine.first);
58    }
59
60    // Replace * with .*
61    for (size_t pos = 0; (pos = Regexp.find("*", pos)) != std::string::npos;
62         pos += strlen(".*")) {
63      Regexp.replace(pos, strlen("*"), ".*");
64    }
65
66    // Check that the regexp is valid.
67    Regex CheckRE(Regexp);
68    std::string Error;
69    if (!CheckRE.isValid(Error)) {
70      report_fatal_error("malformed blacklist regex: " + SplitLine.second +
71          ": " + Error);
72    }
73
74    // Add this regexp into the proper group by its prefix.
75    if (!Regexps[Prefix].empty())
76      Regexps[Prefix] += "|";
77    Regexps[Prefix] += Regexp;
78  }
79
80  // Iterate through each of the prefixes, and create Regexs for them.
81  for (StringMap<std::string>::const_iterator I = Regexps.begin(),
82       E = Regexps.end(); I != E; ++I) {
83    Entries[I->getKey()] = new Regex(I->getValue());
84  }
85}
86
87bool BlackList::isIn(const Function &F) const {
88  return isIn(*F.getParent()) || inSection("fun", F.getName());
89}
90
91bool BlackList::isIn(const GlobalVariable &G) const {
92  return isIn(*G.getParent()) || inSection("global", G.getName());
93}
94
95bool BlackList::isIn(const Module &M) const {
96  return inSection("src", M.getModuleIdentifier());
97}
98
99static StringRef GetGVTypeString(const GlobalVariable &G) {
100  // Types of GlobalVariables are always pointer types.
101  Type *GType = G.getType()->getElementType();
102  // For now we support blacklisting struct types only.
103  if (StructType *SGType = dyn_cast<StructType>(GType)) {
104    if (!SGType->isLiteral())
105      return SGType->getName();
106  }
107  return "<unknown type>";
108}
109
110bool BlackList::isInInit(const GlobalVariable &G) const {
111  return (isIn(*G.getParent()) ||
112          inSection("global-init", G.getName()) ||
113          inSection("global-init-type", GetGVTypeString(G)) ||
114          inSection("global-init-src", G.getParent()->getModuleIdentifier()));
115}
116
117bool BlackList::inSection(const StringRef Section,
118                          const StringRef Query) const {
119  StringMap<Regex*>::const_iterator I = Entries.find(Section);
120  if (I == Entries.end()) return false;
121
122  Regex *FunctionRegex = I->getValue();
123  return FunctionRegex->match(Query);
124}
125
126}  // namespace llvm
127