Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/IPO/StripSymbols.cpp
35269 views
//===- StripSymbols.cpp - Strip symbols and debug info from a module ------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// The StripSymbols transformation implements code stripping. Specifically, it9// can delete:10//11// * names for virtual registers12// * symbols for internal globals and functions13// * debug information14//15// Note that this transformation makes code much less readable, so it should16// only be used in situations where the 'strip' utility would be used, such as17// reducing code size or making it harder to reverse engineer code.18//19//===----------------------------------------------------------------------===//2021#include "llvm/Transforms/IPO/StripSymbols.h"22#include "llvm/ADT/SmallPtrSet.h"23#include "llvm/IR/Constants.h"24#include "llvm/IR/DebugInfo.h"25#include "llvm/IR/DerivedTypes.h"26#include "llvm/IR/InstIterator.h"27#include "llvm/IR/Instructions.h"28#include "llvm/IR/Module.h"29#include "llvm/IR/PassManager.h"30#include "llvm/IR/TypeFinder.h"31#include "llvm/IR/ValueSymbolTable.h"32#include "llvm/Support/CommandLine.h"33#include "llvm/Transforms/IPO.h"34#include "llvm/Transforms/IPO/StripSymbols.h"35#include "llvm/Transforms/Utils/Local.h"3637using namespace llvm;3839static cl::opt<bool>40StripGlobalConstants("strip-global-constants", cl::init(false), cl::Hidden,41cl::desc("Removes debug compile units which reference "42"to non-existing global constants"));4344/// OnlyUsedBy - Return true if V is only used by Usr.45static bool OnlyUsedBy(Value *V, Value *Usr) {46for (User *U : V->users())47if (U != Usr)48return false;4950return true;51}5253static void RemoveDeadConstant(Constant *C) {54assert(C->use_empty() && "Constant is not dead!");55SmallPtrSet<Constant*, 4> Operands;56for (Value *Op : C->operands())57if (OnlyUsedBy(Op, C))58Operands.insert(cast<Constant>(Op));59if (GlobalVariable *GV = dyn_cast<GlobalVariable>(C)) {60if (!GV->hasLocalLinkage()) return; // Don't delete non-static globals.61GV->eraseFromParent();62} else if (!isa<Function>(C)) {63// FIXME: Why does the type of the constant matter here?64if (isa<StructType>(C->getType()) || isa<ArrayType>(C->getType()) ||65isa<VectorType>(C->getType()))66C->destroyConstant();67}6869// If the constant referenced anything, see if we can delete it as well.70for (Constant *O : Operands)71RemoveDeadConstant(O);72}7374// Strip the symbol table of its names.75//76static void StripSymtab(ValueSymbolTable &ST, bool PreserveDbgInfo) {77for (ValueSymbolTable::iterator VI = ST.begin(), VE = ST.end(); VI != VE; ) {78Value *V = VI->getValue();79++VI;80if (!isa<GlobalValue>(V) || cast<GlobalValue>(V)->hasLocalLinkage()) {81if (!PreserveDbgInfo || !V->getName().starts_with("llvm.dbg"))82// Set name to "", removing from symbol table!83V->setName("");84}85}86}8788// Strip any named types of their names.89static void StripTypeNames(Module &M, bool PreserveDbgInfo) {90TypeFinder StructTypes;91StructTypes.run(M, false);9293for (StructType *STy : StructTypes) {94if (STy->isLiteral() || STy->getName().empty()) continue;9596if (PreserveDbgInfo && STy->getName().starts_with("llvm.dbg"))97continue;9899STy->setName("");100}101}102103/// Find values that are marked as llvm.used.104static void findUsedValues(GlobalVariable *LLVMUsed,105SmallPtrSetImpl<const GlobalValue*> &UsedValues) {106if (!LLVMUsed) return;107UsedValues.insert(LLVMUsed);108109ConstantArray *Inits = cast<ConstantArray>(LLVMUsed->getInitializer());110111for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i)112if (GlobalValue *GV =113dyn_cast<GlobalValue>(Inits->getOperand(i)->stripPointerCasts()))114UsedValues.insert(GV);115}116117/// StripSymbolNames - Strip symbol names.118static bool StripSymbolNames(Module &M, bool PreserveDbgInfo) {119120SmallPtrSet<const GlobalValue*, 8> llvmUsedValues;121findUsedValues(M.getGlobalVariable("llvm.used"), llvmUsedValues);122findUsedValues(M.getGlobalVariable("llvm.compiler.used"), llvmUsedValues);123124for (GlobalVariable &GV : M.globals()) {125if (GV.hasLocalLinkage() && !llvmUsedValues.contains(&GV))126if (!PreserveDbgInfo || !GV.getName().starts_with("llvm.dbg"))127GV.setName(""); // Internal symbols can't participate in linkage128}129130for (Function &I : M) {131if (I.hasLocalLinkage() && !llvmUsedValues.contains(&I))132if (!PreserveDbgInfo || !I.getName().starts_with("llvm.dbg"))133I.setName(""); // Internal symbols can't participate in linkage134if (auto *Symtab = I.getValueSymbolTable())135StripSymtab(*Symtab, PreserveDbgInfo);136}137138// Remove all names from types.139StripTypeNames(M, PreserveDbgInfo);140141return true;142}143144static bool stripDebugDeclareImpl(Module &M) {145146Function *Declare = M.getFunction("llvm.dbg.declare");147std::vector<Constant*> DeadConstants;148149if (Declare) {150while (!Declare->use_empty()) {151CallInst *CI = cast<CallInst>(Declare->user_back());152Value *Arg1 = CI->getArgOperand(0);153Value *Arg2 = CI->getArgOperand(1);154assert(CI->use_empty() && "llvm.dbg intrinsic should have void result");155CI->eraseFromParent();156if (Arg1->use_empty()) {157if (Constant *C = dyn_cast<Constant>(Arg1))158DeadConstants.push_back(C);159else160RecursivelyDeleteTriviallyDeadInstructions(Arg1);161}162if (Arg2->use_empty())163if (Constant *C = dyn_cast<Constant>(Arg2))164DeadConstants.push_back(C);165}166Declare->eraseFromParent();167}168169while (!DeadConstants.empty()) {170Constant *C = DeadConstants.back();171DeadConstants.pop_back();172if (GlobalVariable *GV = dyn_cast<GlobalVariable>(C)) {173if (GV->hasLocalLinkage())174RemoveDeadConstant(GV);175} else176RemoveDeadConstant(C);177}178179return true;180}181182static bool stripDeadDebugInfoImpl(Module &M) {183bool Changed = false;184185LLVMContext &C = M.getContext();186187// Find all debug info in F. This is actually overkill in terms of what we188// want to do, but we want to try and be as resilient as possible in the face189// of potential debug info changes by using the formal interfaces given to us190// as much as possible.191DebugInfoFinder F;192F.processModule(M);193194// For each compile unit, find the live set of global variables/functions and195// replace the current list of potentially dead global variables/functions196// with the live list.197SmallVector<Metadata *, 64> LiveGlobalVariables;198DenseSet<DIGlobalVariableExpression *> VisitedSet;199200std::set<DIGlobalVariableExpression *> LiveGVs;201for (GlobalVariable &GV : M.globals()) {202SmallVector<DIGlobalVariableExpression *, 1> GVEs;203GV.getDebugInfo(GVEs);204for (auto *GVE : GVEs)205LiveGVs.insert(GVE);206}207208std::set<DICompileUnit *> LiveCUs;209DebugInfoFinder LiveCUFinder;210for (const Function &F : M.functions()) {211if (auto *SP = cast_or_null<DISubprogram>(F.getSubprogram()))212LiveCUFinder.processSubprogram(SP);213for (const Instruction &I : instructions(F))214LiveCUFinder.processInstruction(M, I);215}216auto FoundCUs = LiveCUFinder.compile_units();217LiveCUs.insert(FoundCUs.begin(), FoundCUs.end());218219bool HasDeadCUs = false;220for (DICompileUnit *DIC : F.compile_units()) {221// Create our live global variable list.222bool GlobalVariableChange = false;223for (auto *DIG : DIC->getGlobalVariables()) {224if (DIG->getExpression() && DIG->getExpression()->isConstant() &&225!StripGlobalConstants)226LiveGVs.insert(DIG);227228// Make sure we only visit each global variable only once.229if (!VisitedSet.insert(DIG).second)230continue;231232// If a global variable references DIG, the global variable is live.233if (LiveGVs.count(DIG))234LiveGlobalVariables.push_back(DIG);235else236GlobalVariableChange = true;237}238239if (!LiveGlobalVariables.empty())240LiveCUs.insert(DIC);241else if (!LiveCUs.count(DIC))242HasDeadCUs = true;243244// If we found dead global variables, replace the current global245// variable list with our new live global variable list.246if (GlobalVariableChange) {247DIC->replaceGlobalVariables(MDTuple::get(C, LiveGlobalVariables));248Changed = true;249}250251// Reset lists for the next iteration.252LiveGlobalVariables.clear();253}254255if (HasDeadCUs) {256// Delete the old node and replace it with a new one257NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.cu");258NMD->clearOperands();259if (!LiveCUs.empty()) {260for (DICompileUnit *CU : LiveCUs)261NMD->addOperand(CU);262}263Changed = true;264}265266return Changed;267}268269PreservedAnalyses StripSymbolsPass::run(Module &M, ModuleAnalysisManager &AM) {270StripDebugInfo(M);271StripSymbolNames(M, false);272PreservedAnalyses PA;273PA.preserveSet<CFGAnalyses>();274return PA;275}276277PreservedAnalyses StripNonDebugSymbolsPass::run(Module &M,278ModuleAnalysisManager &AM) {279StripSymbolNames(M, true);280PreservedAnalyses PA;281PA.preserveSet<CFGAnalyses>();282return PA;283}284285PreservedAnalyses StripDebugDeclarePass::run(Module &M,286ModuleAnalysisManager &AM) {287stripDebugDeclareImpl(M);288PreservedAnalyses PA;289PA.preserveSet<CFGAnalyses>();290return PA;291}292293PreservedAnalyses StripDeadDebugInfoPass::run(Module &M,294ModuleAnalysisManager &AM) {295stripDeadDebugInfoImpl(M);296PreservedAnalyses PA;297PA.preserveSet<CFGAnalyses>();298return PA;299}300301302