xref: /llvm-project/llvm/lib/Transforms/Utils/MetaRenamer.cpp (revision 981ec1faeb508a364cc47c8246b72fc89dd8c1d8)
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/Module.h"
30 #include "llvm/IR/PassManager.h"
31 #include "llvm/IR/Type.h"
32 #include "llvm/IR/TypeFinder.h"
33 #include "llvm/Support/CommandLine.h"
34 
35 using namespace llvm;
36 
37 static cl::opt<std::string> RenameExcludeFunctionPrefixes(
38     "rename-exclude-function-prefixes",
39     cl::desc("Prefixes for functions that don't need to be renamed, separated "
40              "by a comma"),
41     cl::Hidden);
42 
43 static cl::opt<std::string> RenameExcludeAliasPrefixes(
44     "rename-exclude-alias-prefixes",
45     cl::desc("Prefixes for aliases that don't need to be renamed, separated "
46              "by a comma"),
47     cl::Hidden);
48 
49 static cl::opt<std::string> RenameExcludeGlobalPrefixes(
50     "rename-exclude-global-prefixes",
51     cl::desc(
52         "Prefixes for global values that don't need to be renamed, separated "
53         "by a comma"),
54     cl::Hidden);
55 
56 static cl::opt<std::string> RenameExcludeStructPrefixes(
57     "rename-exclude-struct-prefixes",
58     cl::desc("Prefixes for structs that don't need to be renamed, separated "
59              "by a comma"),
60     cl::Hidden);
61 
62 static const char *const metaNames[] = {
63   // See http://en.wikipedia.org/wiki/Metasyntactic_variable
64   "foo", "bar", "baz", "quux", "barney", "snork", "zot", "blam", "hoge",
65   "wibble", "wobble", "widget", "wombat", "ham", "eggs", "pluto", "spam"
66 };
67 
68 namespace {
69 // This PRNG is from the ISO C spec. It is intentionally simple and
70 // unsuitable for cryptographic use. We're just looking for enough
71 // variety to surprise and delight users.
72 struct PRNG {
73   unsigned long next;
74 
75   void srand(unsigned int seed) { next = seed; }
76 
77   int rand() {
78     next = next * 1103515245 + 12345;
79     return (unsigned int)(next / 65536) % 32768;
80   }
81 };
82 
83 struct Renamer {
84   Renamer(unsigned int seed) { prng.srand(seed); }
85 
86   const char *newName() {
87     return metaNames[prng.rand() % std::size(metaNames)];
88   }
89 
90   PRNG prng;
91 };
92 
93 static void
94 parseExcludedPrefixes(StringRef PrefixesStr,
95                       SmallVectorImpl<StringRef> &ExcludedPrefixes) {
96   for (;;) {
97     auto PrefixesSplit = PrefixesStr.split(',');
98     if (PrefixesSplit.first.empty())
99       break;
100     ExcludedPrefixes.push_back(PrefixesSplit.first);
101     PrefixesStr = PrefixesSplit.second;
102   }
103 }
104 
105 void MetaRename(Function &F) {
106   for (Argument &Arg : F.args())
107     if (!Arg.getType()->isVoidTy())
108       Arg.setName("arg");
109 
110   for (auto &BB : F) {
111     BB.setName("bb");
112 
113     for (auto &I : BB)
114       if (!I.getType()->isVoidTy())
115         I.setName(I.getOpcodeName());
116   }
117 }
118 
119 void MetaRename(Module &M,
120                 function_ref<TargetLibraryInfo &(Function &)> GetTLI) {
121   // Seed our PRNG with simple additive sum of ModuleID. We're looking to
122   // simply avoid always having the same function names, and we need to
123   // remain deterministic.
124   unsigned int randSeed = 0;
125   for (auto C : M.getModuleIdentifier())
126     randSeed += C;
127 
128   Renamer renamer(randSeed);
129 
130   SmallVector<StringRef, 8> ExcludedAliasesPrefixes;
131   SmallVector<StringRef, 8> ExcludedGlobalsPrefixes;
132   SmallVector<StringRef, 8> ExcludedStructsPrefixes;
133   SmallVector<StringRef, 8> ExcludedFuncPrefixes;
134   parseExcludedPrefixes(RenameExcludeAliasPrefixes, ExcludedAliasesPrefixes);
135   parseExcludedPrefixes(RenameExcludeGlobalPrefixes, ExcludedGlobalsPrefixes);
136   parseExcludedPrefixes(RenameExcludeStructPrefixes, ExcludedStructsPrefixes);
137   parseExcludedPrefixes(RenameExcludeFunctionPrefixes, ExcludedFuncPrefixes);
138 
139   auto IsNameExcluded = [](StringRef &Name,
140                            SmallVectorImpl<StringRef> &ExcludedPrefixes) {
141     return any_of(ExcludedPrefixes,
142                   [&Name](auto &Prefix) { return Name.startswith(Prefix); });
143   };
144 
145   // Rename all aliases
146   for (GlobalAlias &GA : M.aliases()) {
147     StringRef Name = GA.getName();
148     if (Name.startswith("llvm.") || (!Name.empty() && Name[0] == 1) ||
149         IsNameExcluded(Name, ExcludedAliasesPrefixes))
150       continue;
151 
152     GA.setName("alias");
153   }
154 
155   // Rename all global variables
156   for (GlobalVariable &GV : M.globals()) {
157     StringRef Name = GV.getName();
158     if (Name.startswith("llvm.") || (!Name.empty() && Name[0] == 1) ||
159         IsNameExcluded(Name, ExcludedGlobalsPrefixes))
160       continue;
161 
162     GV.setName("global");
163   }
164 
165   // Rename all struct types
166   TypeFinder StructTypes;
167   StructTypes.run(M, true);
168   for (StructType *STy : StructTypes) {
169     StringRef Name = STy->getName();
170     if (STy->isLiteral() || Name.empty() ||
171         IsNameExcluded(Name, ExcludedStructsPrefixes))
172       continue;
173 
174     SmallString<128> NameStorage;
175     STy->setName(
176         (Twine("struct.") + renamer.newName()).toStringRef(NameStorage));
177   }
178 
179   // Rename all functions
180   for (auto &F : M) {
181     StringRef Name = F.getName();
182     LibFunc Tmp;
183     // Leave library functions alone because their presence or absence could
184     // affect the behavior of other passes.
185     if (Name.startswith("llvm.") || (!Name.empty() && Name[0] == 1) ||
186         GetTLI(F).getLibFunc(F, Tmp) ||
187         IsNameExcluded(Name, ExcludedFuncPrefixes))
188       continue;
189 
190     // Leave @main alone. The output of -metarenamer might be passed to
191     // lli for execution and the latter needs a main entry point.
192     if (Name != "main")
193       F.setName(renamer.newName());
194 
195     MetaRename(F);
196   }
197 }
198 
199 } // end anonymous namespace
200 
201 PreservedAnalyses MetaRenamerPass::run(Module &M, ModuleAnalysisManager &AM) {
202   FunctionAnalysisManager &FAM =
203       AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
204   auto GetTLI = [&FAM](Function &F) -> TargetLibraryInfo & {
205     return FAM.getResult<TargetLibraryAnalysis>(F);
206   };
207   MetaRename(M, GetTLI);
208 
209   return PreservedAnalyses::all();
210 }
211