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 | |
36 | using namespace llvm; |
37 | |
38 | static 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 | |
44 | static 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 | |
50 | static 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 | |
57 | static 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 | |
63 | static 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 | |
68 | static 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 | |
74 | namespace { |
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. |
78 | struct 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 | |
89 | struct 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 | |
99 | static void |
100 | parseExcludedPrefixes(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 | |
111 | void MetaRenameOnlyInstructions(Function &F) { |
112 | for (auto &I : instructions(F)) |
113 | if (!I.getType()->isVoidTy() && I.getName().empty()) |
114 | I.setName(I.getOpcodeName()); |
115 | } |
116 | |
117 | void 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 | |
131 | void 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 | |
227 | PreservedAnalyses 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 | |