Implement categories for special case lists.
[oota-llvm.git] / lib / Transforms / Utils / SpecialCaseList.cpp
1 //===-- SpecialCaseList.cpp - special case list 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, or to instrument some functions or global variables in a specific
13 // way, based on a user-supplied list.
14 //
15 //===----------------------------------------------------------------------===//
16
17 #include "llvm/Transforms/Utils/SpecialCaseList.h"
18 #include "llvm/ADT/OwningPtr.h"
19 #include "llvm/ADT/SmallVector.h"
20 #include "llvm/ADT/STLExtras.h"
21 #include "llvm/ADT/StringExtras.h"
22 #include "llvm/IR/DerivedTypes.h"
23 #include "llvm/IR/Function.h"
24 #include "llvm/IR/GlobalVariable.h"
25 #include "llvm/IR/Module.h"
26 #include "llvm/Support/MemoryBuffer.h"
27 #include "llvm/Support/Regex.h"
28 #include "llvm/Support/raw_ostream.h"
29 #include "llvm/Support/system_error.h"
30 #include <string>
31 #include <utility>
32
33 namespace llvm {
34
35 SpecialCaseList::SpecialCaseList(const StringRef Path) {
36   // Validate and open blacklist file.
37   if (Path.empty()) return;
38   OwningPtr<MemoryBuffer> File;
39   if (error_code EC = MemoryBuffer::getFile(Path, File)) {
40     report_fatal_error("Can't open blacklist file: " + Path + ": " +
41                        EC.message());
42   }
43
44   init(File.get());
45 }
46
47 SpecialCaseList::SpecialCaseList(const MemoryBuffer *MB) {
48   init(MB);
49 }
50
51 void SpecialCaseList::init(const MemoryBuffer *MB) {
52   // Iterate through each line in the blacklist file.
53   SmallVector<StringRef, 16> Lines;
54   SplitString(MB->getBuffer(), Lines, "\n\r");
55   StringMap<StringMap<std::string> > Regexps;
56   for (SmallVectorImpl<StringRef>::iterator I = Lines.begin(), E = Lines.end();
57        I != E; ++I) {
58     // Ignore empty lines and lines starting with "#"
59     if (I->empty() || I->startswith("#"))
60       continue;
61     // Get our prefix and unparsed regexp.
62     std::pair<StringRef, StringRef> SplitLine = I->split(":");
63     StringRef Prefix = SplitLine.first;
64     if (SplitLine.second.empty()) {
65       // Missing ':' in the line.
66       report_fatal_error("malformed blacklist line: " + SplitLine.first);
67     }
68
69     std::pair<StringRef, StringRef> SplitRegexp = SplitLine.second.split("=");
70     std::string Regexp = SplitRegexp.first;
71     StringRef Category = SplitRegexp.second;
72
73     // Backwards compatibility.
74     if (Prefix == "global-init") {
75       Prefix = "global";
76       Category = "init";
77     } else if (Prefix == "global-init-type") {
78       Prefix = "type";
79       Category = "init";
80     } else if (Prefix == "global-init-src") {
81       Prefix = "src";
82       Category = "init";
83     }
84
85     // Replace * with .*
86     for (size_t pos = 0; (pos = Regexp.find("*", pos)) != std::string::npos;
87          pos += strlen(".*")) {
88       Regexp.replace(pos, strlen("*"), ".*");
89     }
90
91     // Check that the regexp is valid.
92     Regex CheckRE(Regexp);
93     std::string Error;
94     if (!CheckRE.isValid(Error)) {
95       report_fatal_error("malformed blacklist regex: " + SplitLine.second +
96           ": " + Error);
97     }
98
99     // Add this regexp into the proper group by its prefix.
100     if (!Regexps[Prefix][Category].empty())
101       Regexps[Prefix][Category] += "|";
102     Regexps[Prefix][Category] += Regexp;
103   }
104
105   // Iterate through each of the prefixes, and create Regexs for them.
106   for (StringMap<StringMap<std::string> >::const_iterator I = Regexps.begin(),
107                                                           E = Regexps.end();
108        I != E; ++I) {
109     for (StringMap<std::string>::const_iterator II = I->second.begin(),
110                                                 IE = I->second.end();
111          II != IE; ++II) {
112       Entries[I->getKey()][II->getKey()] = new Regex(II->getValue());
113     }
114   }
115 }
116
117 SpecialCaseList::~SpecialCaseList() {
118   for (StringMap<StringMap<Regex*> >::iterator I = Entries.begin(),
119                                                E = Entries.end();
120        I != E; ++I) {
121     DeleteContainerSeconds(I->second);
122   }
123 }
124
125 bool SpecialCaseList::findCategory(const Function &F,
126                                    StringRef &Category) const {
127   return findCategory(*F.getParent(), Category) ||
128          findCategory("fun", F.getName(), Category);
129 }
130
131 bool SpecialCaseList::isIn(const Function& F, const StringRef Category) const {
132   return isIn(*F.getParent(), Category) ||
133          inSectionCategory("fun", F.getName(), Category);
134 }
135
136 static StringRef GetGVTypeString(const GlobalVariable &G) {
137   // Types of GlobalVariables are always pointer types.
138   Type *GType = G.getType()->getElementType();
139   // For now we support blacklisting struct types only.
140   if (StructType *SGType = dyn_cast<StructType>(GType)) {
141     if (!SGType->isLiteral())
142       return SGType->getName();
143   }
144   return "<unknown type>";
145 }
146
147 bool SpecialCaseList::findCategory(const GlobalVariable &G,
148                                    StringRef &Category) const {
149   return findCategory(*G.getParent(), Category) ||
150          findCategory("global", G.getName(), Category) ||
151          findCategory("type", GetGVTypeString(G), Category);
152 }
153
154 bool SpecialCaseList::isIn(const GlobalVariable &G,
155                            const StringRef Category) const {
156   return isIn(*G.getParent(), Category) ||
157          inSectionCategory("global", G.getName(), Category) ||
158          inSectionCategory("type", GetGVTypeString(G), Category);
159 }
160
161 bool SpecialCaseList::findCategory(const Module &M, StringRef &Category) const {
162   return findCategory("src", M.getModuleIdentifier(), Category);
163 }
164
165 bool SpecialCaseList::isIn(const Module &M, const StringRef Category) const {
166   return inSectionCategory("src", M.getModuleIdentifier(), Category);
167 }
168
169 bool SpecialCaseList::findCategory(const StringRef Section,
170                                    const StringRef Query,
171                                    StringRef &Category) const {
172   StringMap<StringMap<Regex *> >::const_iterator I = Entries.find(Section);
173   if (I == Entries.end()) return false;
174
175   for (StringMap<Regex *>::const_iterator II = I->second.begin(),
176                                           IE = I->second.end();
177        II != IE; ++II) {
178     Regex *FunctionRegex = II->getValue();
179     if (FunctionRegex->match(Query)) {
180       Category = II->first();
181       return true;
182     }
183   }
184
185   return false;
186 }
187
188 bool SpecialCaseList::inSectionCategory(const StringRef Section,
189                                         const StringRef Query,
190                                         const StringRef Category) const {
191   StringMap<StringMap<Regex *> >::const_iterator I = Entries.find(Section);
192   if (I == Entries.end()) return false;
193   StringMap<Regex *>::const_iterator II = I->second.find(Category);
194   if (II == I->second.end()) return false;
195
196   Regex *FunctionRegex = II->getValue();
197   return FunctionRegex->match(Query);
198 }
199
200 }  // namespace llvm