xref: /freebsd/contrib/llvm-project/llvm/lib/Transforms/Utils/MetaRenamer.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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(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(',');
104     if (PrefixesSplit.first.empty())
105       break;
106     ExcludedPrefixes.push_back(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(RenameExcludeAliasPrefixes, ExcludedAliasesPrefixes);
147   parseExcludedPrefixes(RenameExcludeGlobalPrefixes, ExcludedGlobalsPrefixes);
148   parseExcludedPrefixes(RenameExcludeStructPrefixes, ExcludedStructsPrefixes);
149   parseExcludedPrefixes(RenameExcludeFunctionPrefixes, ExcludedFuncPrefixes);
150 
151   auto IsNameExcluded = [](StringRef &Name,
152                            SmallVectorImpl<StringRef> &ExcludedPrefixes) {
153     return any_of(ExcludedPrefixes,
154                   [&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("llvm.") || (!Name.empty() && Name[0] == 1) ||
163            GetTLI(F).getLibFunc(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("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("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, 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(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>(M).getManager();
230   auto GetTLI = [&FAM](Function &F) -> TargetLibraryInfo & {
231     return FAM.getResult<TargetLibraryAnalysis>(F);
232   };
233   MetaRename(M, GetTLI);
234 
235   return PreservedAnalyses::all();
236 }
237