1//===- MetaRenamer.cpp - Rename everything with metasyntatic names --------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This pass renames everything with metasyntatic names. The intent is to use
10// this pass after bugpoint reduction to conceal the nature of the original
11// program.
12//
13//===----------------------------------------------------------------------===//
14
15#include "llvm/Transforms/Utils/MetaRenamer.h"
16#include "llvm/ADT/STLExtras.h"
17#include "llvm/ADT/SmallString.h"
18#include "llvm/ADT/SmallVector.h"
19#include "llvm/ADT/StringRef.h"
20#include "llvm/ADT/Twine.h"
21#include "llvm/Analysis/TargetLibraryInfo.h"
22#include "llvm/IR/Argument.h"
23#include "llvm/IR/BasicBlock.h"
24#include "llvm/IR/DerivedTypes.h"
25#include "llvm/IR/Function.h"
26#include "llvm/IR/GlobalAlias.h"
27#include "llvm/IR/GlobalVariable.h"
28#include "llvm/IR/Instruction.h"
29#include "llvm/IR/InstIterator.h"
30#include "llvm/IR/Module.h"
31#include "llvm/IR/PassManager.h"
32#include "llvm/IR/Type.h"
33#include "llvm/IR/TypeFinder.h"
34#include "llvm/Support/CommandLine.h"
35
36using namespace llvm;
37
38static cl::opt<std::string> RenameExcludeFunctionPrefixes(
39 "rename-exclude-function-prefixes",
40 cl::desc("Prefixes for functions that don't need to be renamed, separated "
41 "by a comma"),
42 cl::Hidden);
43
44static cl::opt<std::string> RenameExcludeAliasPrefixes(
45 "rename-exclude-alias-prefixes",
46 cl::desc("Prefixes for aliases that don't need to be renamed, separated "
47 "by a comma"),
48 cl::Hidden);
49
50static cl::opt<std::string> RenameExcludeGlobalPrefixes(
51 "rename-exclude-global-prefixes",
52 cl::desc(
53 "Prefixes for global values that don't need to be renamed, separated "
54 "by a comma"),
55 cl::Hidden);
56
57static cl::opt<std::string> RenameExcludeStructPrefixes(
58 "rename-exclude-struct-prefixes",
59 cl::desc("Prefixes for structs that don't need to be renamed, separated "
60 "by a comma"),
61 cl::Hidden);
62
63static cl::opt<bool>
64 RenameOnlyInst("rename-only-inst", cl::init(Val: false),
65 cl::desc("only rename the instructions in the function"),
66 cl::Hidden);
67
68static const char *const metaNames[] = {
69 // See http://en.wikipedia.org/wiki/Metasyntactic_variable
70 "foo", "bar", "baz", "quux", "barney", "snork", "zot", "blam", "hoge",
71 "wibble", "wobble", "widget", "wombat", "ham", "eggs", "pluto", "spam"
72};
73
74namespace {
75// This PRNG is from the ISO C spec. It is intentionally simple and
76// unsuitable for cryptographic use. We're just looking for enough
77// variety to surprise and delight users.
78struct PRNG {
79 unsigned long next;
80
81 void srand(unsigned int seed) { next = seed; }
82
83 int rand() {
84 next = next * 1103515245 + 12345;
85 return (unsigned int)(next / 65536) % 32768;
86 }
87};
88
89struct Renamer {
90 Renamer(unsigned int seed) { prng.srand(seed); }
91
92 const char *newName() {
93 return metaNames[prng.rand() % std::size(metaNames)];
94 }
95
96 PRNG prng;
97};
98
99static void
100parseExcludedPrefixes(StringRef PrefixesStr,
101 SmallVectorImpl<StringRef> &ExcludedPrefixes) {
102 for (;;) {
103 auto PrefixesSplit = PrefixesStr.split(Separator: ',');
104 if (PrefixesSplit.first.empty())
105 break;
106 ExcludedPrefixes.push_back(Elt: PrefixesSplit.first);
107 PrefixesStr = PrefixesSplit.second;
108 }
109}
110
111void MetaRenameOnlyInstructions(Function &F) {
112 for (auto &I : instructions(F))
113 if (!I.getType()->isVoidTy() && I.getName().empty())
114 I.setName(I.getOpcodeName());
115}
116
117void MetaRename(Function &F) {
118 for (Argument &Arg : F.args())
119 if (!Arg.getType()->isVoidTy())
120 Arg.setName("arg");
121
122 for (auto &BB : F) {
123 BB.setName("bb");
124
125 for (auto &I : BB)
126 if (!I.getType()->isVoidTy())
127 I.setName(I.getOpcodeName());
128 }
129}
130
131void MetaRename(Module &M,
132 function_ref<TargetLibraryInfo &(Function &)> GetTLI) {
133 // Seed our PRNG with simple additive sum of ModuleID. We're looking to
134 // simply avoid always having the same function names, and we need to
135 // remain deterministic.
136 unsigned int randSeed = 0;
137 for (auto C : M.getModuleIdentifier())
138 randSeed += C;
139
140 Renamer renamer(randSeed);
141
142 SmallVector<StringRef, 8> ExcludedAliasesPrefixes;
143 SmallVector<StringRef, 8> ExcludedGlobalsPrefixes;
144 SmallVector<StringRef, 8> ExcludedStructsPrefixes;
145 SmallVector<StringRef, 8> ExcludedFuncPrefixes;
146 parseExcludedPrefixes(PrefixesStr: RenameExcludeAliasPrefixes, ExcludedPrefixes&: ExcludedAliasesPrefixes);
147 parseExcludedPrefixes(PrefixesStr: RenameExcludeGlobalPrefixes, ExcludedPrefixes&: ExcludedGlobalsPrefixes);
148 parseExcludedPrefixes(PrefixesStr: RenameExcludeStructPrefixes, ExcludedPrefixes&: ExcludedStructsPrefixes);
149 parseExcludedPrefixes(PrefixesStr: RenameExcludeFunctionPrefixes, ExcludedPrefixes&: ExcludedFuncPrefixes);
150
151 auto IsNameExcluded = [](StringRef &Name,
152 SmallVectorImpl<StringRef> &ExcludedPrefixes) {
153 return any_of(Range&: ExcludedPrefixes,
154 P: [&Name](auto &Prefix) { return Name.starts_with(Prefix); });
155 };
156
157 // Leave library functions alone because their presence or absence could
158 // affect the behavior of other passes.
159 auto ExcludeLibFuncs = [&](Function &F) {
160 LibFunc Tmp;
161 StringRef Name = F.getName();
162 return Name.starts_with(Prefix: "llvm.") || (!Name.empty() && Name[0] == 1) ||
163 GetTLI(F).getLibFunc(FDecl: F, F&: Tmp) ||
164 IsNameExcluded(Name, ExcludedFuncPrefixes);
165 };
166
167 if (RenameOnlyInst) {
168 // Rename all functions
169 for (auto &F : M) {
170 if (ExcludeLibFuncs(F))
171 continue;
172 MetaRenameOnlyInstructions(F);
173 }
174 return;
175 }
176
177 // Rename all aliases
178 for (GlobalAlias &GA : M.aliases()) {
179 StringRef Name = GA.getName();
180 if (Name.starts_with(Prefix: "llvm.") || (!Name.empty() && Name[0] == 1) ||
181 IsNameExcluded(Name, ExcludedAliasesPrefixes))
182 continue;
183
184 GA.setName("alias");
185 }
186
187 // Rename all global variables
188 for (GlobalVariable &GV : M.globals()) {
189 StringRef Name = GV.getName();
190 if (Name.starts_with(Prefix: "llvm.") || (!Name.empty() && Name[0] == 1) ||
191 IsNameExcluded(Name, ExcludedGlobalsPrefixes))
192 continue;
193
194 GV.setName("global");
195 }
196
197 // Rename all struct types
198 TypeFinder StructTypes;
199 StructTypes.run(M, onlyNamed: true);
200 for (StructType *STy : StructTypes) {
201 StringRef Name = STy->getName();
202 if (STy->isLiteral() || Name.empty() ||
203 IsNameExcluded(Name, ExcludedStructsPrefixes))
204 continue;
205
206 SmallString<128> NameStorage;
207 STy->setName(
208 (Twine("struct.") + renamer.newName()).toStringRef(Out&: NameStorage));
209 }
210
211 // Rename all functions
212 for (auto &F : M) {
213 if (ExcludeLibFuncs(F))
214 continue;
215
216 // Leave @main alone. The output of -metarenamer might be passed to
217 // lli for execution and the latter needs a main entry point.
218 if (F.getName() != "main")
219 F.setName(renamer.newName());
220
221 MetaRename(F);
222 }
223}
224
225} // end anonymous namespace
226
227PreservedAnalyses MetaRenamerPass::run(Module &M, ModuleAnalysisManager &AM) {
228 FunctionAnalysisManager &FAM =
229 AM.getResult<FunctionAnalysisManagerModuleProxy>(IR&: M).getManager();
230 auto GetTLI = [&FAM](Function &F) -> TargetLibraryInfo & {
231 return FAM.getResult<TargetLibraryAnalysis>(IR&: F);
232 };
233 MetaRename(M, GetTLI);
234
235 return PreservedAnalyses::all();
236}
237