klee
FunctionAlias.cpp
Go to the documentation of this file.
1//===-- FunctionAliasPass.cpp -----------------------------------*- C++ -*-===//
2//
3// The KLEE Symbolic Virtual Machine
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "Passes.h"
11
15
16#include "llvm/IR/GlobalAlias.h"
17#include "llvm/Support/CommandLine.h"
18#include "llvm/Support/Regex.h"
19
20using namespace llvm;
21
22namespace {
23
24cl::list<std::string>
25 FunctionAlias("function-alias",
26 cl::desc("Replace functions that match name or regular "
27 "expression pattern with an alias to the function "
28 "whose name is given by replacement"),
29 cl::value_desc("name|pattern>:<replacement"),
30 cl::cat(klee::ModuleCat));
31
32} // namespace
33
34namespace klee {
35
37 bool modified = false;
38
39 assert((M.ifunc_size() == 0) && "Unexpected ifunc");
40
41 for (const auto &pair : FunctionAlias) {
42 bool matchFound = false;
43
44 // regex pattern can contain colons, e.g. in character classes,
45 // but replacement function name cannot
46 std::size_t lastColon = pair.rfind(':');
47 if (lastColon == std::string::npos) {
48 klee_error("function-alias: no replacement given");
49 }
50 std::string pattern = pair.substr(0, lastColon);
51 std::string replacement = pair.substr(lastColon + 1);
52
53 if (pattern.empty())
54 klee_error("function-alias: name or pattern cannot be empty");
55 if (replacement.empty())
56 klee_error("function-alias: replacement cannot be empty");
57
58 if (pattern == replacement) {
59 klee_error("function-alias: @%s cannot replace itself", pattern.c_str());
60 }
61
62 // check if replacement function exists
63 GlobalValue *replacementValue = M.getNamedValue(replacement);
64 if (!isFunctionOrGlobalFunctionAlias(replacementValue))
65 klee_error("function-alias: replacement function @%s could not be found",
66 replacement.c_str());
67
68 // directly replace if pattern is not a regex
69 GlobalValue *match = M.getNamedValue(pattern);
71 if (tryToReplace(match, replacementValue)) {
72 modified = true;
73 klee_message("function-alias: replaced @%s with @%s", pattern.c_str(),
74 replacement.c_str());
75 continue;
76 }
77 }
78 if (match != nullptr) {
79 // pattern is not a regex, but no replacement was found
80 klee_error("function-alias: no (replacable) match for '%s' found",
81 pattern.c_str());
82 }
83
84 Regex regex(pattern);
85 std::string error;
86 if (!regex.isValid(error)) {
87 klee_error("function-alias: '%s' is not a valid regex: %s",
88 pattern.c_str(), error.c_str());
89 }
90
91 std::vector<GlobalValue *> matches;
92
93 // find matches for regex
94 for (GlobalValue &global : M.global_values()) {
95 if (!global.hasName())
96 continue;
97
99 continue;
100
101 SmallVector<StringRef, 8> matchVec;
102 bool match = regex.match(global.getName(), &matchVec);
103 if (match && matchVec[0].str() == global.getName().str()) {
104 if (global.getName().str() == replacement) {
105 klee_warning("function-alias: do not replace @%s (matching '%s') "
106 "with @%s: cannot replace itself",
107 global.getName().str().c_str(), pattern.c_str(),
108 replacement.c_str());
109 continue;
110 }
111 matches.push_back(&global);
112 }
113 }
114
115 // replace all found regex matches
116 for (GlobalValue *global : matches) {
117 // name will be invalidated by tryToReplace
118 std::string name = global->getName().str();
119 if (tryToReplace(global, replacementValue)) {
120 modified = true;
121 matchFound = true;
122 klee_message("function-alias: replaced @%s (matching '%s') with @%s",
123 name.c_str(), pattern.c_str(), replacement.c_str());
124 }
125 }
126
127 if (!matchFound) {
128 klee_error("function-alias: no (replacable) match for '%s' found",
129 pattern.c_str());
130 }
131 }
132
133 return modified;
134}
135
136const FunctionType *FunctionAliasPass::getFunctionType(const GlobalValue *gv) {
137 const Type *type = gv->getType();
138 while (type->isPointerTy()) {
139 const PointerType *ptr = cast<PointerType>(type);
140 type = ptr->getElementType();
141 }
142 return cast<FunctionType>(type);
143}
144
145bool FunctionAliasPass::checkType(const GlobalValue *match,
146 const GlobalValue *replacement) {
147 const FunctionType *MFT = getFunctionType(match);
148 const FunctionType *RFT = getFunctionType(replacement);
149 assert(MFT != nullptr && RFT != nullptr);
150
151 if (MFT->getReturnType() != RFT->getReturnType()) {
152 klee_warning("function-alias: @%s could not be replaced with @%s: "
153 "return type differs",
154 match->getName().str().c_str(),
155 replacement->getName().str().c_str());
156 return false;
157 }
158
159 if (MFT->isVarArg() != RFT->isVarArg()) {
160 klee_warning("function-alias: @%s could not be replaced with @%s: "
161 "one has varargs while the other does not",
162 match->getName().str().c_str(),
163 replacement->getName().str().c_str());
164 return false;
165 }
166
167 if (MFT->getNumParams() != RFT->getNumParams()) {
168 klee_warning("function-alias: @%s could not be replaced with @%s: "
169 "number of parameters differs",
170 match->getName().str().c_str(),
171 replacement->getName().str().c_str());
172 return false;
173 }
174
175 std::size_t numParams = MFT->getNumParams();
176 for (std::size_t i = 0; i < numParams; ++i) {
177 if (MFT->getParamType(i) != RFT->getParamType(i)) {
178 klee_warning("function-alias: @%s could not be replaced with @%s: "
179 "parameter types differ",
180 match->getName().str().c_str(),
181 replacement->getName().str().c_str());
182 return false;
183 }
184 }
185 return true;
186}
187
188bool FunctionAliasPass::tryToReplace(GlobalValue *match,
189 GlobalValue *replacement) {
190 if (!checkType(match, replacement))
191 return false;
192
193 GlobalAlias *alias = GlobalAlias::create("", replacement);
194 match->replaceAllUsesWith(alias);
195 alias->takeName(match);
196 match->eraseFromParent();
197
198 return true;
199}
200
202 if (isa_and_nonnull<Function>(gv))
203 return true;
204
205 if (const auto *ga = dyn_cast_or_null<GlobalAlias>(gv)) {
206 const auto *aliasee = dyn_cast<GlobalValue>(ga->getAliasee());
207 if (!aliasee) {
208 // check if GlobalAlias is alias bitcast
209 const auto *cexpr = dyn_cast<ConstantExpr>(ga->getAliasee());
210 if (!cexpr || !cexpr->isCast())
211 return false;
212 aliasee = dyn_cast<GlobalValue>(cexpr->getOperand(0));
213 }
214 return isFunctionOrGlobalFunctionAlias(aliasee);
215 }
216
217 return false;
218}
219
220char FunctionAliasPass::ID = 0;
221
222} // namespace klee
static const llvm::FunctionType * getFunctionType(const llvm::GlobalValue *gv)
static bool checkType(const llvm::GlobalValue *match, const llvm::GlobalValue *replacement)
bool runOnModule(llvm::Module &M) override
static char ID
Definition: Passes.h:176
static bool isFunctionOrGlobalFunctionAlias(const llvm::GlobalValue *gv)
static bool tryToReplace(llvm::GlobalValue *match, llvm::GlobalValue *replacement)
Definition: main.cpp:291
void klee_message(const char *msg,...) __attribute__((format(printf
void klee_error(const char *msg,...) __attribute__((format(printf
llvm::cl::OptionCategory ModuleCat
void void void klee_warning(const char *msg,...) __attribute__((format(printf