10b57cec5SDimitry Andric //===- MetaRenamer.cpp - Rename everything with metasyntatic names --------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This pass renames everything with metasyntatic names. The intent is to use 100b57cec5SDimitry Andric // this pass after bugpoint reduction to conceal the nature of the original 110b57cec5SDimitry Andric // program. 120b57cec5SDimitry Andric // 130b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 140b57cec5SDimitry Andric 15e8d8bef9SDimitry Andric #include "llvm/Transforms/Utils/MetaRenamer.h" 160b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 170b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h" 180eae32dcSDimitry Andric #include "llvm/ADT/SmallVector.h" 190b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 200b57cec5SDimitry Andric #include "llvm/ADT/Twine.h" 210b57cec5SDimitry Andric #include "llvm/Analysis/TargetLibraryInfo.h" 220b57cec5SDimitry Andric #include "llvm/IR/Argument.h" 230b57cec5SDimitry Andric #include "llvm/IR/BasicBlock.h" 240b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h" 250b57cec5SDimitry Andric #include "llvm/IR/Function.h" 260b57cec5SDimitry Andric #include "llvm/IR/GlobalAlias.h" 270b57cec5SDimitry Andric #include "llvm/IR/GlobalVariable.h" 280b57cec5SDimitry Andric #include "llvm/IR/Instruction.h" 2906c3fb27SDimitry Andric #include "llvm/IR/InstIterator.h" 300b57cec5SDimitry Andric #include "llvm/IR/Module.h" 31e8d8bef9SDimitry Andric #include "llvm/IR/PassManager.h" 320b57cec5SDimitry Andric #include "llvm/IR/Type.h" 330b57cec5SDimitry Andric #include "llvm/IR/TypeFinder.h" 340eae32dcSDimitry Andric #include "llvm/Support/CommandLine.h" 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric using namespace llvm; 370b57cec5SDimitry Andric 380eae32dcSDimitry Andric static cl::opt<std::string> RenameExcludeFunctionPrefixes( 390eae32dcSDimitry Andric "rename-exclude-function-prefixes", 400eae32dcSDimitry Andric cl::desc("Prefixes for functions that don't need to be renamed, separated " 410eae32dcSDimitry Andric "by a comma"), 420eae32dcSDimitry Andric cl::Hidden); 430eae32dcSDimitry Andric 440eae32dcSDimitry Andric static cl::opt<std::string> RenameExcludeAliasPrefixes( 450eae32dcSDimitry Andric "rename-exclude-alias-prefixes", 460eae32dcSDimitry Andric cl::desc("Prefixes for aliases that don't need to be renamed, separated " 470eae32dcSDimitry Andric "by a comma"), 480eae32dcSDimitry Andric cl::Hidden); 490eae32dcSDimitry Andric 500eae32dcSDimitry Andric static cl::opt<std::string> RenameExcludeGlobalPrefixes( 510eae32dcSDimitry Andric "rename-exclude-global-prefixes", 520eae32dcSDimitry Andric cl::desc( 530eae32dcSDimitry Andric "Prefixes for global values that don't need to be renamed, separated " 540eae32dcSDimitry Andric "by a comma"), 550eae32dcSDimitry Andric cl::Hidden); 560eae32dcSDimitry Andric 570eae32dcSDimitry Andric static cl::opt<std::string> RenameExcludeStructPrefixes( 580eae32dcSDimitry Andric "rename-exclude-struct-prefixes", 590eae32dcSDimitry Andric cl::desc("Prefixes for structs that don't need to be renamed, separated " 600eae32dcSDimitry Andric "by a comma"), 610eae32dcSDimitry Andric cl::Hidden); 620eae32dcSDimitry Andric 6306c3fb27SDimitry Andric static cl::opt<bool> 6406c3fb27SDimitry Andric RenameOnlyInst("rename-only-inst", cl::init(false), 6506c3fb27SDimitry Andric cl::desc("only rename the instructions in the function"), 6606c3fb27SDimitry Andric cl::Hidden); 6706c3fb27SDimitry Andric 680b57cec5SDimitry Andric static const char *const metaNames[] = { 690b57cec5SDimitry Andric // See http://en.wikipedia.org/wiki/Metasyntactic_variable 700b57cec5SDimitry Andric "foo", "bar", "baz", "quux", "barney", "snork", "zot", "blam", "hoge", 710b57cec5SDimitry Andric "wibble", "wobble", "widget", "wombat", "ham", "eggs", "pluto", "spam" 720b57cec5SDimitry Andric }; 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric namespace { 750b57cec5SDimitry Andric // This PRNG is from the ISO C spec. It is intentionally simple and 760b57cec5SDimitry Andric // unsuitable for cryptographic use. We're just looking for enough 770b57cec5SDimitry Andric // variety to surprise and delight users. 780b57cec5SDimitry Andric struct PRNG { 790b57cec5SDimitry Andric unsigned long next; 800b57cec5SDimitry Andric 81e8d8bef9SDimitry Andric void srand(unsigned int seed) { next = seed; } 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric int rand() { 840b57cec5SDimitry Andric next = next * 1103515245 + 12345; 850b57cec5SDimitry Andric return (unsigned int)(next / 65536) % 32768; 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric }; 880b57cec5SDimitry Andric 890b57cec5SDimitry Andric struct Renamer { 90e8d8bef9SDimitry Andric Renamer(unsigned int seed) { prng.srand(seed); } 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric const char *newName() { 93bdd1243dSDimitry Andric return metaNames[prng.rand() % std::size(metaNames)]; 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric PRNG prng; 970b57cec5SDimitry Andric }; 980b57cec5SDimitry Andric 990eae32dcSDimitry Andric static void 1000eae32dcSDimitry Andric parseExcludedPrefixes(StringRef PrefixesStr, 1010eae32dcSDimitry Andric SmallVectorImpl<StringRef> &ExcludedPrefixes) { 1020eae32dcSDimitry Andric for (;;) { 1030eae32dcSDimitry Andric auto PrefixesSplit = PrefixesStr.split(','); 1040eae32dcSDimitry Andric if (PrefixesSplit.first.empty()) 1050eae32dcSDimitry Andric break; 1060eae32dcSDimitry Andric ExcludedPrefixes.push_back(PrefixesSplit.first); 1070eae32dcSDimitry Andric PrefixesStr = PrefixesSplit.second; 1080eae32dcSDimitry Andric } 1090eae32dcSDimitry Andric } 1100eae32dcSDimitry Andric 11106c3fb27SDimitry Andric void MetaRenameOnlyInstructions(Function &F) { 11206c3fb27SDimitry Andric for (auto &I : instructions(F)) 11306c3fb27SDimitry Andric if (!I.getType()->isVoidTy() && I.getName().empty()) 11406c3fb27SDimitry Andric I.setName(I.getOpcodeName()); 11506c3fb27SDimitry Andric } 11606c3fb27SDimitry Andric 117e8d8bef9SDimitry Andric void MetaRename(Function &F) { 118fe6060f1SDimitry Andric for (Argument &Arg : F.args()) 119fe6060f1SDimitry Andric if (!Arg.getType()->isVoidTy()) 120fe6060f1SDimitry Andric Arg.setName("arg"); 1210b57cec5SDimitry Andric 122e8d8bef9SDimitry Andric for (auto &BB : F) { 123e8d8bef9SDimitry Andric BB.setName("bb"); 124e8d8bef9SDimitry Andric 125e8d8bef9SDimitry Andric for (auto &I : BB) 126e8d8bef9SDimitry Andric if (!I.getType()->isVoidTy()) 12706c3fb27SDimitry Andric I.setName(I.getOpcodeName()); 128e8d8bef9SDimitry Andric } 1290b57cec5SDimitry Andric } 1300b57cec5SDimitry Andric 131e8d8bef9SDimitry Andric void MetaRename(Module &M, 132e8d8bef9SDimitry Andric function_ref<TargetLibraryInfo &(Function &)> GetTLI) { 1330b57cec5SDimitry Andric // Seed our PRNG with simple additive sum of ModuleID. We're looking to 1340b57cec5SDimitry Andric // simply avoid always having the same function names, and we need to 1350b57cec5SDimitry Andric // remain deterministic. 1360b57cec5SDimitry Andric unsigned int randSeed = 0; 1370b57cec5SDimitry Andric for (auto C : M.getModuleIdentifier()) 1380b57cec5SDimitry Andric randSeed += C; 1390b57cec5SDimitry Andric 1400b57cec5SDimitry Andric Renamer renamer(randSeed); 1410b57cec5SDimitry Andric 1420eae32dcSDimitry Andric SmallVector<StringRef, 8> ExcludedAliasesPrefixes; 1430eae32dcSDimitry Andric SmallVector<StringRef, 8> ExcludedGlobalsPrefixes; 1440eae32dcSDimitry Andric SmallVector<StringRef, 8> ExcludedStructsPrefixes; 1450eae32dcSDimitry Andric SmallVector<StringRef, 8> ExcludedFuncPrefixes; 1460eae32dcSDimitry Andric parseExcludedPrefixes(RenameExcludeAliasPrefixes, ExcludedAliasesPrefixes); 1470eae32dcSDimitry Andric parseExcludedPrefixes(RenameExcludeGlobalPrefixes, ExcludedGlobalsPrefixes); 1480eae32dcSDimitry Andric parseExcludedPrefixes(RenameExcludeStructPrefixes, ExcludedStructsPrefixes); 1490eae32dcSDimitry Andric parseExcludedPrefixes(RenameExcludeFunctionPrefixes, ExcludedFuncPrefixes); 1500eae32dcSDimitry Andric 1510eae32dcSDimitry Andric auto IsNameExcluded = [](StringRef &Name, 1520eae32dcSDimitry Andric SmallVectorImpl<StringRef> &ExcludedPrefixes) { 1530eae32dcSDimitry Andric return any_of(ExcludedPrefixes, 154*5f757f3fSDimitry Andric [&Name](auto &Prefix) { return Name.starts_with(Prefix); }); 1550eae32dcSDimitry Andric }; 1560eae32dcSDimitry Andric 15706c3fb27SDimitry Andric // Leave library functions alone because their presence or absence could 15806c3fb27SDimitry Andric // affect the behavior of other passes. 15906c3fb27SDimitry Andric auto ExcludeLibFuncs = [&](Function &F) { 16006c3fb27SDimitry Andric LibFunc Tmp; 16106c3fb27SDimitry Andric StringRef Name = F.getName(); 162*5f757f3fSDimitry Andric return Name.starts_with("llvm.") || (!Name.empty() && Name[0] == 1) || 16306c3fb27SDimitry Andric GetTLI(F).getLibFunc(F, Tmp) || 16406c3fb27SDimitry Andric IsNameExcluded(Name, ExcludedFuncPrefixes); 16506c3fb27SDimitry Andric }; 16606c3fb27SDimitry Andric 16706c3fb27SDimitry Andric if (RenameOnlyInst) { 16806c3fb27SDimitry Andric // Rename all functions 16906c3fb27SDimitry Andric for (auto &F : M) { 17006c3fb27SDimitry Andric if (ExcludeLibFuncs(F)) 17106c3fb27SDimitry Andric continue; 17206c3fb27SDimitry Andric MetaRenameOnlyInstructions(F); 17306c3fb27SDimitry Andric } 17406c3fb27SDimitry Andric return; 17506c3fb27SDimitry Andric } 17606c3fb27SDimitry Andric 1770b57cec5SDimitry Andric // Rename all aliases 1785e801ac6SDimitry Andric for (GlobalAlias &GA : M.aliases()) { 1795e801ac6SDimitry Andric StringRef Name = GA.getName(); 180*5f757f3fSDimitry Andric if (Name.starts_with("llvm.") || (!Name.empty() && Name[0] == 1) || 1810eae32dcSDimitry Andric IsNameExcluded(Name, ExcludedAliasesPrefixes)) 1820b57cec5SDimitry Andric continue; 1830b57cec5SDimitry Andric 1845e801ac6SDimitry Andric GA.setName("alias"); 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric // Rename all global variables 188fe6060f1SDimitry Andric for (GlobalVariable &GV : M.globals()) { 189fe6060f1SDimitry Andric StringRef Name = GV.getName(); 190*5f757f3fSDimitry Andric if (Name.starts_with("llvm.") || (!Name.empty() && Name[0] == 1) || 1910eae32dcSDimitry Andric IsNameExcluded(Name, ExcludedGlobalsPrefixes)) 1920b57cec5SDimitry Andric continue; 1930b57cec5SDimitry Andric 194fe6060f1SDimitry Andric GV.setName("global"); 1950b57cec5SDimitry Andric } 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric // Rename all struct types 1980b57cec5SDimitry Andric TypeFinder StructTypes; 1990b57cec5SDimitry Andric StructTypes.run(M, true); 2000b57cec5SDimitry Andric for (StructType *STy : StructTypes) { 2010eae32dcSDimitry Andric StringRef Name = STy->getName(); 2020eae32dcSDimitry Andric if (STy->isLiteral() || Name.empty() || 2030eae32dcSDimitry Andric IsNameExcluded(Name, ExcludedStructsPrefixes)) 204e8d8bef9SDimitry Andric continue; 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric SmallString<128> NameStorage; 207e8d8bef9SDimitry Andric STy->setName( 208e8d8bef9SDimitry Andric (Twine("struct.") + renamer.newName()).toStringRef(NameStorage)); 2090b57cec5SDimitry Andric } 2100b57cec5SDimitry Andric 2110b57cec5SDimitry Andric // Rename all functions 2120b57cec5SDimitry Andric for (auto &F : M) { 21306c3fb27SDimitry Andric if (ExcludeLibFuncs(F)) 2140b57cec5SDimitry Andric continue; 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric // Leave @main alone. The output of -metarenamer might be passed to 2170b57cec5SDimitry Andric // lli for execution and the latter needs a main entry point. 21806c3fb27SDimitry Andric if (F.getName() != "main") 2190b57cec5SDimitry Andric F.setName(renamer.newName()); 2200b57cec5SDimitry Andric 221e8d8bef9SDimitry Andric MetaRename(F); 2220b57cec5SDimitry Andric } 2230b57cec5SDimitry Andric } 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric } // end anonymous namespace 2260b57cec5SDimitry Andric 227e8d8bef9SDimitry Andric PreservedAnalyses MetaRenamerPass::run(Module &M, ModuleAnalysisManager &AM) { 228e8d8bef9SDimitry Andric FunctionAnalysisManager &FAM = 229e8d8bef9SDimitry Andric AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); 230e8d8bef9SDimitry Andric auto GetTLI = [&FAM](Function &F) -> TargetLibraryInfo & { 231e8d8bef9SDimitry Andric return FAM.getResult<TargetLibraryAnalysis>(F); 232e8d8bef9SDimitry Andric }; 233e8d8bef9SDimitry Andric MetaRename(M, GetTLI); 234e8d8bef9SDimitry Andric 235e8d8bef9SDimitry Andric return PreservedAnalyses::all(); 236e8d8bef9SDimitry Andric } 237