Files
clang-p2996/llvm/lib/Transforms/Utils/MetaRenamer.cpp
Dmitry Makogon 0b533c1833 [MetaRenamer] Add command line options to disable renaming name with specified prefixes
This patch adds 4 options for specifying functions, aliases, globals and
structs name prefixes hat don't need to be renamed by MetaRenamer pass.
This is useful if one has some downstream logic that depends directly
on an entity name. MetaRenamer can break this logic, but with the patch
you can tell it not to rename certain names.

Reviewed By: nikic

Differential Revision: https://reviews.llvm.org/D115323
2021-12-09 18:45:06 +07:00

252 lines
7.8 KiB
C++

//===- MetaRenamer.cpp - Rename everything with metasyntatic names --------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This pass renames everything with metasyntatic names. The intent is to use
// this pass after bugpoint reduction to conceal the nature of the original
// program.
//
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/Utils/MetaRenamer.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/Argument.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalAlias.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/TypeFinder.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Transforms/Utils.h"
using namespace llvm;
static cl::opt<std::string> RenameExcludeFunctionPrefixes(
"rename-exclude-function-prefixes",
cl::desc("Prefixes for functions that don't need to be renamed, separated "
"by a comma"),
cl::Hidden);
static cl::opt<std::string> RenameExcludeAliasPrefixes(
"rename-exclude-alias-prefixes",
cl::desc("Prefixes for aliases that don't need to be renamed, separated "
"by a comma"),
cl::Hidden);
static cl::opt<std::string> RenameExcludeGlobalPrefixes(
"rename-exclude-global-prefixes",
cl::desc(
"Prefixes for global values that don't need to be renamed, separated "
"by a comma"),
cl::Hidden);
static cl::opt<std::string> RenameExcludeStructPrefixes(
"rename-exclude-struct-prefixes",
cl::desc("Prefixes for structs that don't need to be renamed, separated "
"by a comma"),
cl::Hidden);
static const char *const metaNames[] = {
// See http://en.wikipedia.org/wiki/Metasyntactic_variable
"foo", "bar", "baz", "quux", "barney", "snork", "zot", "blam", "hoge",
"wibble", "wobble", "widget", "wombat", "ham", "eggs", "pluto", "spam"
};
namespace {
// This PRNG is from the ISO C spec. It is intentionally simple and
// unsuitable for cryptographic use. We're just looking for enough
// variety to surprise and delight users.
struct PRNG {
unsigned long next;
void srand(unsigned int seed) { next = seed; }
int rand() {
next = next * 1103515245 + 12345;
return (unsigned int)(next / 65536) % 32768;
}
};
struct Renamer {
Renamer(unsigned int seed) { prng.srand(seed); }
const char *newName() {
return metaNames[prng.rand() % array_lengthof(metaNames)];
}
PRNG prng;
};
static void
parseExcludedPrefixes(StringRef PrefixesStr,
SmallVectorImpl<StringRef> &ExcludedPrefixes) {
for (;;) {
auto PrefixesSplit = PrefixesStr.split(',');
if (PrefixesSplit.first.empty())
break;
ExcludedPrefixes.push_back(PrefixesSplit.first);
PrefixesStr = PrefixesSplit.second;
}
}
void MetaRename(Function &F) {
for (Argument &Arg : F.args())
if (!Arg.getType()->isVoidTy())
Arg.setName("arg");
for (auto &BB : F) {
BB.setName("bb");
for (auto &I : BB)
if (!I.getType()->isVoidTy())
I.setName("tmp");
}
}
void MetaRename(Module &M,
function_ref<TargetLibraryInfo &(Function &)> GetTLI) {
// Seed our PRNG with simple additive sum of ModuleID. We're looking to
// simply avoid always having the same function names, and we need to
// remain deterministic.
unsigned int randSeed = 0;
for (auto C : M.getModuleIdentifier())
randSeed += C;
Renamer renamer(randSeed);
SmallVector<StringRef, 8> ExcludedAliasesPrefixes;
SmallVector<StringRef, 8> ExcludedGlobalsPrefixes;
SmallVector<StringRef, 8> ExcludedStructsPrefixes;
SmallVector<StringRef, 8> ExcludedFuncPrefixes;
parseExcludedPrefixes(RenameExcludeAliasPrefixes, ExcludedAliasesPrefixes);
parseExcludedPrefixes(RenameExcludeGlobalPrefixes, ExcludedGlobalsPrefixes);
parseExcludedPrefixes(RenameExcludeStructPrefixes, ExcludedStructsPrefixes);
parseExcludedPrefixes(RenameExcludeFunctionPrefixes, ExcludedFuncPrefixes);
auto IsNameExcluded = [](StringRef &Name,
SmallVectorImpl<StringRef> &ExcludedPrefixes) {
return any_of(ExcludedPrefixes,
[&Name](auto &Prefix) { return Name.startswith(Prefix); });
};
// Rename all aliases
for (GlobalAlias &GA : M.aliases()) {
StringRef Name = GA.getName();
if (Name.startswith("llvm.") || (!Name.empty() && Name[0] == 1) ||
IsNameExcluded(Name, ExcludedAliasesPrefixes))
continue;
GA.setName("alias");
}
// Rename all global variables
for (GlobalVariable &GV : M.globals()) {
StringRef Name = GV.getName();
if (Name.startswith("llvm.") || (!Name.empty() && Name[0] == 1) ||
IsNameExcluded(Name, ExcludedGlobalsPrefixes))
continue;
GV.setName("global");
}
// Rename all struct types
TypeFinder StructTypes;
StructTypes.run(M, true);
for (StructType *STy : StructTypes) {
StringRef Name = STy->getName();
if (STy->isLiteral() || Name.empty() ||
IsNameExcluded(Name, ExcludedStructsPrefixes))
continue;
SmallString<128> NameStorage;
STy->setName(
(Twine("struct.") + renamer.newName()).toStringRef(NameStorage));
}
// Rename all functions
for (auto &F : M) {
StringRef Name = F.getName();
LibFunc Tmp;
// Leave library functions alone because their presence or absence could
// affect the behavior of other passes.
if (Name.startswith("llvm.") || (!Name.empty() && Name[0] == 1) ||
GetTLI(F).getLibFunc(F, Tmp) ||
IsNameExcluded(Name, ExcludedFuncPrefixes))
continue;
// Leave @main alone. The output of -metarenamer might be passed to
// lli for execution and the latter needs a main entry point.
if (Name != "main")
F.setName(renamer.newName());
MetaRename(F);
}
}
struct MetaRenamer : public ModulePass {
// Pass identification, replacement for typeid
static char ID;
MetaRenamer() : ModulePass(ID) {
initializeMetaRenamerPass(*PassRegistry::getPassRegistry());
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<TargetLibraryInfoWrapperPass>();
AU.setPreservesAll();
}
bool runOnModule(Module &M) override {
auto GetTLI = [this](Function &F) -> TargetLibraryInfo & {
return this->getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
};
MetaRename(M, GetTLI);
return true;
}
};
} // end anonymous namespace
char MetaRenamer::ID = 0;
INITIALIZE_PASS_BEGIN(MetaRenamer, "metarenamer",
"Assign new names to everything", false, false)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
INITIALIZE_PASS_END(MetaRenamer, "metarenamer",
"Assign new names to everything", false, false)
//===----------------------------------------------------------------------===//
//
// MetaRenamer - Rename everything with metasyntactic names.
//
ModulePass *llvm::createMetaRenamerPass() {
return new MetaRenamer();
}
PreservedAnalyses MetaRenamerPass::run(Module &M, ModuleAnalysisManager &AM) {
FunctionAnalysisManager &FAM =
AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
auto GetTLI = [&FAM](Function &F) -> TargetLibraryInfo & {
return FAM.getResult<TargetLibraryAnalysis>(F);
};
MetaRename(M, GetTLI);
return PreservedAnalyses::all();
}