10b57cec5SDimitry Andric //===- StripSymbols.cpp - Strip symbols and debug info from a module ------===//
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 // The StripSymbols transformation implements code stripping. Specifically, it
100b57cec5SDimitry Andric // can delete:
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric // * names for virtual registers
130b57cec5SDimitry Andric // * symbols for internal globals and functions
140b57cec5SDimitry Andric // * debug information
150b57cec5SDimitry Andric //
160b57cec5SDimitry Andric // Note that this transformation makes code much less readable, so it should
170b57cec5SDimitry Andric // only be used in situations where the 'strip' utility would be used, such as
180b57cec5SDimitry Andric // reducing code size or making it harder to reverse engineer code.
190b57cec5SDimitry Andric //
200b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
210b57cec5SDimitry Andric
22e8d8bef9SDimitry Andric #include "llvm/Transforms/IPO/StripSymbols.h"
230b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
240b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
250b57cec5SDimitry Andric #include "llvm/IR/DebugInfo.h"
260b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h"
27bdd1243dSDimitry Andric #include "llvm/IR/InstIterator.h"
280b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
290b57cec5SDimitry Andric #include "llvm/IR/Module.h"
30e8d8bef9SDimitry Andric #include "llvm/IR/PassManager.h"
310b57cec5SDimitry Andric #include "llvm/IR/TypeFinder.h"
320b57cec5SDimitry Andric #include "llvm/IR/ValueSymbolTable.h"
33*5f757f3fSDimitry Andric #include "llvm/Support/CommandLine.h"
340b57cec5SDimitry Andric #include "llvm/Transforms/IPO.h"
35bdd1243dSDimitry Andric #include "llvm/Transforms/IPO/StripSymbols.h"
36480093f4SDimitry Andric #include "llvm/Transforms/Utils/Local.h"
37e8d8bef9SDimitry Andric
380b57cec5SDimitry Andric using namespace llvm;
390b57cec5SDimitry Andric
40*5f757f3fSDimitry Andric static cl::opt<bool>
41*5f757f3fSDimitry Andric StripGlobalConstants("strip-global-constants", cl::init(false), cl::Hidden,
42*5f757f3fSDimitry Andric cl::desc("Removes debug compile units which reference "
43*5f757f3fSDimitry Andric "to non-existing global constants"));
44*5f757f3fSDimitry Andric
450b57cec5SDimitry Andric /// OnlyUsedBy - Return true if V is only used by Usr.
OnlyUsedBy(Value * V,Value * Usr)460b57cec5SDimitry Andric static bool OnlyUsedBy(Value *V, Value *Usr) {
470b57cec5SDimitry Andric for (User *U : V->users())
480b57cec5SDimitry Andric if (U != Usr)
490b57cec5SDimitry Andric return false;
500b57cec5SDimitry Andric
510b57cec5SDimitry Andric return true;
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric
RemoveDeadConstant(Constant * C)540b57cec5SDimitry Andric static void RemoveDeadConstant(Constant *C) {
550b57cec5SDimitry Andric assert(C->use_empty() && "Constant is not dead!");
560b57cec5SDimitry Andric SmallPtrSet<Constant*, 4> Operands;
570b57cec5SDimitry Andric for (Value *Op : C->operands())
580b57cec5SDimitry Andric if (OnlyUsedBy(Op, C))
590b57cec5SDimitry Andric Operands.insert(cast<Constant>(Op));
600b57cec5SDimitry Andric if (GlobalVariable *GV = dyn_cast<GlobalVariable>(C)) {
610b57cec5SDimitry Andric if (!GV->hasLocalLinkage()) return; // Don't delete non-static globals.
620b57cec5SDimitry Andric GV->eraseFromParent();
635ffd83dbSDimitry Andric } else if (!isa<Function>(C)) {
645ffd83dbSDimitry Andric // FIXME: Why does the type of the constant matter here?
655ffd83dbSDimitry Andric if (isa<StructType>(C->getType()) || isa<ArrayType>(C->getType()) ||
665ffd83dbSDimitry Andric isa<VectorType>(C->getType()))
670b57cec5SDimitry Andric C->destroyConstant();
685ffd83dbSDimitry Andric }
690b57cec5SDimitry Andric
700b57cec5SDimitry Andric // If the constant referenced anything, see if we can delete it as well.
710b57cec5SDimitry Andric for (Constant *O : Operands)
720b57cec5SDimitry Andric RemoveDeadConstant(O);
730b57cec5SDimitry Andric }
740b57cec5SDimitry Andric
750b57cec5SDimitry Andric // Strip the symbol table of its names.
760b57cec5SDimitry Andric //
StripSymtab(ValueSymbolTable & ST,bool PreserveDbgInfo)770b57cec5SDimitry Andric static void StripSymtab(ValueSymbolTable &ST, bool PreserveDbgInfo) {
780b57cec5SDimitry Andric for (ValueSymbolTable::iterator VI = ST.begin(), VE = ST.end(); VI != VE; ) {
790b57cec5SDimitry Andric Value *V = VI->getValue();
800b57cec5SDimitry Andric ++VI;
810b57cec5SDimitry Andric if (!isa<GlobalValue>(V) || cast<GlobalValue>(V)->hasLocalLinkage()) {
82*5f757f3fSDimitry Andric if (!PreserveDbgInfo || !V->getName().starts_with("llvm.dbg"))
830b57cec5SDimitry Andric // Set name to "", removing from symbol table!
840b57cec5SDimitry Andric V->setName("");
850b57cec5SDimitry Andric }
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric }
880b57cec5SDimitry Andric
890b57cec5SDimitry Andric // Strip any named types of their names.
StripTypeNames(Module & M,bool PreserveDbgInfo)900b57cec5SDimitry Andric static void StripTypeNames(Module &M, bool PreserveDbgInfo) {
910b57cec5SDimitry Andric TypeFinder StructTypes;
920b57cec5SDimitry Andric StructTypes.run(M, false);
930b57cec5SDimitry Andric
94bdd1243dSDimitry Andric for (StructType *STy : StructTypes) {
950b57cec5SDimitry Andric if (STy->isLiteral() || STy->getName().empty()) continue;
960b57cec5SDimitry Andric
97*5f757f3fSDimitry Andric if (PreserveDbgInfo && STy->getName().starts_with("llvm.dbg"))
980b57cec5SDimitry Andric continue;
990b57cec5SDimitry Andric
1000b57cec5SDimitry Andric STy->setName("");
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric }
1030b57cec5SDimitry Andric
1040b57cec5SDimitry Andric /// Find values that are marked as llvm.used.
findUsedValues(GlobalVariable * LLVMUsed,SmallPtrSetImpl<const GlobalValue * > & UsedValues)1050b57cec5SDimitry Andric static void findUsedValues(GlobalVariable *LLVMUsed,
1060b57cec5SDimitry Andric SmallPtrSetImpl<const GlobalValue*> &UsedValues) {
1070b57cec5SDimitry Andric if (!LLVMUsed) return;
1080b57cec5SDimitry Andric UsedValues.insert(LLVMUsed);
1090b57cec5SDimitry Andric
1100b57cec5SDimitry Andric ConstantArray *Inits = cast<ConstantArray>(LLVMUsed->getInitializer());
1110b57cec5SDimitry Andric
1120b57cec5SDimitry Andric for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i)
1130b57cec5SDimitry Andric if (GlobalValue *GV =
1140b57cec5SDimitry Andric dyn_cast<GlobalValue>(Inits->getOperand(i)->stripPointerCasts()))
1150b57cec5SDimitry Andric UsedValues.insert(GV);
1160b57cec5SDimitry Andric }
1170b57cec5SDimitry Andric
1180b57cec5SDimitry Andric /// StripSymbolNames - Strip symbol names.
StripSymbolNames(Module & M,bool PreserveDbgInfo)1190b57cec5SDimitry Andric static bool StripSymbolNames(Module &M, bool PreserveDbgInfo) {
1200b57cec5SDimitry Andric
1210b57cec5SDimitry Andric SmallPtrSet<const GlobalValue*, 8> llvmUsedValues;
1220b57cec5SDimitry Andric findUsedValues(M.getGlobalVariable("llvm.used"), llvmUsedValues);
1230b57cec5SDimitry Andric findUsedValues(M.getGlobalVariable("llvm.compiler.used"), llvmUsedValues);
1240b57cec5SDimitry Andric
125fe6060f1SDimitry Andric for (GlobalVariable &GV : M.globals()) {
126349cc55cSDimitry Andric if (GV.hasLocalLinkage() && !llvmUsedValues.contains(&GV))
127*5f757f3fSDimitry Andric if (!PreserveDbgInfo || !GV.getName().starts_with("llvm.dbg"))
128fe6060f1SDimitry Andric GV.setName(""); // Internal symbols can't participate in linkage
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric
1310b57cec5SDimitry Andric for (Function &I : M) {
132349cc55cSDimitry Andric if (I.hasLocalLinkage() && !llvmUsedValues.contains(&I))
133*5f757f3fSDimitry Andric if (!PreserveDbgInfo || !I.getName().starts_with("llvm.dbg"))
1340b57cec5SDimitry Andric I.setName(""); // Internal symbols can't participate in linkage
1350b57cec5SDimitry Andric if (auto *Symtab = I.getValueSymbolTable())
1360b57cec5SDimitry Andric StripSymtab(*Symtab, PreserveDbgInfo);
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric
1390b57cec5SDimitry Andric // Remove all names from types.
1400b57cec5SDimitry Andric StripTypeNames(M, PreserveDbgInfo);
1410b57cec5SDimitry Andric
1420b57cec5SDimitry Andric return true;
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric
stripDebugDeclareImpl(Module & M)145e8d8bef9SDimitry Andric static bool stripDebugDeclareImpl(Module &M) {
1460b57cec5SDimitry Andric
1470b57cec5SDimitry Andric Function *Declare = M.getFunction("llvm.dbg.declare");
1480b57cec5SDimitry Andric std::vector<Constant*> DeadConstants;
1490b57cec5SDimitry Andric
1500b57cec5SDimitry Andric if (Declare) {
1510b57cec5SDimitry Andric while (!Declare->use_empty()) {
1520b57cec5SDimitry Andric CallInst *CI = cast<CallInst>(Declare->user_back());
1530b57cec5SDimitry Andric Value *Arg1 = CI->getArgOperand(0);
1540b57cec5SDimitry Andric Value *Arg2 = CI->getArgOperand(1);
1550b57cec5SDimitry Andric assert(CI->use_empty() && "llvm.dbg intrinsic should have void result");
1560b57cec5SDimitry Andric CI->eraseFromParent();
1570b57cec5SDimitry Andric if (Arg1->use_empty()) {
1580b57cec5SDimitry Andric if (Constant *C = dyn_cast<Constant>(Arg1))
1590b57cec5SDimitry Andric DeadConstants.push_back(C);
1600b57cec5SDimitry Andric else
1610b57cec5SDimitry Andric RecursivelyDeleteTriviallyDeadInstructions(Arg1);
1620b57cec5SDimitry Andric }
1630b57cec5SDimitry Andric if (Arg2->use_empty())
1640b57cec5SDimitry Andric if (Constant *C = dyn_cast<Constant>(Arg2))
1650b57cec5SDimitry Andric DeadConstants.push_back(C);
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric Declare->eraseFromParent();
1680b57cec5SDimitry Andric }
1690b57cec5SDimitry Andric
1700b57cec5SDimitry Andric while (!DeadConstants.empty()) {
1710b57cec5SDimitry Andric Constant *C = DeadConstants.back();
1720b57cec5SDimitry Andric DeadConstants.pop_back();
1730b57cec5SDimitry Andric if (GlobalVariable *GV = dyn_cast<GlobalVariable>(C)) {
1740b57cec5SDimitry Andric if (GV->hasLocalLinkage())
1750b57cec5SDimitry Andric RemoveDeadConstant(GV);
1760b57cec5SDimitry Andric } else
1770b57cec5SDimitry Andric RemoveDeadConstant(C);
1780b57cec5SDimitry Andric }
1790b57cec5SDimitry Andric
1800b57cec5SDimitry Andric return true;
1810b57cec5SDimitry Andric }
1820b57cec5SDimitry Andric
stripDeadDebugInfoImpl(Module & M)183e8d8bef9SDimitry Andric static bool stripDeadDebugInfoImpl(Module &M) {
1840b57cec5SDimitry Andric bool Changed = false;
1850b57cec5SDimitry Andric
1860b57cec5SDimitry Andric LLVMContext &C = M.getContext();
1870b57cec5SDimitry Andric
1880b57cec5SDimitry Andric // Find all debug info in F. This is actually overkill in terms of what we
1890b57cec5SDimitry Andric // want to do, but we want to try and be as resilient as possible in the face
1900b57cec5SDimitry Andric // of potential debug info changes by using the formal interfaces given to us
1910b57cec5SDimitry Andric // as much as possible.
1920b57cec5SDimitry Andric DebugInfoFinder F;
1930b57cec5SDimitry Andric F.processModule(M);
1940b57cec5SDimitry Andric
1950b57cec5SDimitry Andric // For each compile unit, find the live set of global variables/functions and
1960b57cec5SDimitry Andric // replace the current list of potentially dead global variables/functions
1970b57cec5SDimitry Andric // with the live list.
1980b57cec5SDimitry Andric SmallVector<Metadata *, 64> LiveGlobalVariables;
1990b57cec5SDimitry Andric DenseSet<DIGlobalVariableExpression *> VisitedSet;
2000b57cec5SDimitry Andric
2010b57cec5SDimitry Andric std::set<DIGlobalVariableExpression *> LiveGVs;
2020b57cec5SDimitry Andric for (GlobalVariable &GV : M.globals()) {
2030b57cec5SDimitry Andric SmallVector<DIGlobalVariableExpression *, 1> GVEs;
2040b57cec5SDimitry Andric GV.getDebugInfo(GVEs);
2050b57cec5SDimitry Andric for (auto *GVE : GVEs)
2060b57cec5SDimitry Andric LiveGVs.insert(GVE);
2070b57cec5SDimitry Andric }
2080b57cec5SDimitry Andric
2090b57cec5SDimitry Andric std::set<DICompileUnit *> LiveCUs;
21006c3fb27SDimitry Andric DebugInfoFinder LiveCUFinder;
21106c3fb27SDimitry Andric for (const Function &F : M.functions()) {
21206c3fb27SDimitry Andric if (auto *SP = cast_or_null<DISubprogram>(F.getSubprogram()))
21306c3fb27SDimitry Andric LiveCUFinder.processSubprogram(SP);
21406c3fb27SDimitry Andric for (const Instruction &I : instructions(F))
21506c3fb27SDimitry Andric LiveCUFinder.processInstruction(M, I);
216bdd1243dSDimitry Andric }
21706c3fb27SDimitry Andric auto FoundCUs = LiveCUFinder.compile_units();
21806c3fb27SDimitry Andric LiveCUs.insert(FoundCUs.begin(), FoundCUs.end());
2190b57cec5SDimitry Andric
2200b57cec5SDimitry Andric bool HasDeadCUs = false;
2210b57cec5SDimitry Andric for (DICompileUnit *DIC : F.compile_units()) {
2220b57cec5SDimitry Andric // Create our live global variable list.
2230b57cec5SDimitry Andric bool GlobalVariableChange = false;
2240b57cec5SDimitry Andric for (auto *DIG : DIC->getGlobalVariables()) {
225*5f757f3fSDimitry Andric if (DIG->getExpression() && DIG->getExpression()->isConstant() &&
226*5f757f3fSDimitry Andric !StripGlobalConstants)
2270b57cec5SDimitry Andric LiveGVs.insert(DIG);
2280b57cec5SDimitry Andric
2290b57cec5SDimitry Andric // Make sure we only visit each global variable only once.
2300b57cec5SDimitry Andric if (!VisitedSet.insert(DIG).second)
2310b57cec5SDimitry Andric continue;
2320b57cec5SDimitry Andric
2330b57cec5SDimitry Andric // If a global variable references DIG, the global variable is live.
2340b57cec5SDimitry Andric if (LiveGVs.count(DIG))
2350b57cec5SDimitry Andric LiveGlobalVariables.push_back(DIG);
2360b57cec5SDimitry Andric else
2370b57cec5SDimitry Andric GlobalVariableChange = true;
2380b57cec5SDimitry Andric }
2390b57cec5SDimitry Andric
2400b57cec5SDimitry Andric if (!LiveGlobalVariables.empty())
2410b57cec5SDimitry Andric LiveCUs.insert(DIC);
2420b57cec5SDimitry Andric else if (!LiveCUs.count(DIC))
2430b57cec5SDimitry Andric HasDeadCUs = true;
2440b57cec5SDimitry Andric
2450b57cec5SDimitry Andric // If we found dead global variables, replace the current global
2460b57cec5SDimitry Andric // variable list with our new live global variable list.
2470b57cec5SDimitry Andric if (GlobalVariableChange) {
2480b57cec5SDimitry Andric DIC->replaceGlobalVariables(MDTuple::get(C, LiveGlobalVariables));
2490b57cec5SDimitry Andric Changed = true;
2500b57cec5SDimitry Andric }
2510b57cec5SDimitry Andric
2520b57cec5SDimitry Andric // Reset lists for the next iteration.
2530b57cec5SDimitry Andric LiveGlobalVariables.clear();
2540b57cec5SDimitry Andric }
2550b57cec5SDimitry Andric
2560b57cec5SDimitry Andric if (HasDeadCUs) {
2570b57cec5SDimitry Andric // Delete the old node and replace it with a new one
2580b57cec5SDimitry Andric NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.cu");
2590b57cec5SDimitry Andric NMD->clearOperands();
2600b57cec5SDimitry Andric if (!LiveCUs.empty()) {
2610b57cec5SDimitry Andric for (DICompileUnit *CU : LiveCUs)
2620b57cec5SDimitry Andric NMD->addOperand(CU);
2630b57cec5SDimitry Andric }
2640b57cec5SDimitry Andric Changed = true;
2650b57cec5SDimitry Andric }
2660b57cec5SDimitry Andric
2670b57cec5SDimitry Andric return Changed;
2680b57cec5SDimitry Andric }
269e8d8bef9SDimitry Andric
run(Module & M,ModuleAnalysisManager & AM)270e8d8bef9SDimitry Andric PreservedAnalyses StripSymbolsPass::run(Module &M, ModuleAnalysisManager &AM) {
271e8d8bef9SDimitry Andric StripDebugInfo(M);
272e8d8bef9SDimitry Andric StripSymbolNames(M, false);
27306c3fb27SDimitry Andric PreservedAnalyses PA;
27406c3fb27SDimitry Andric PA.preserveSet<CFGAnalyses>();
27506c3fb27SDimitry Andric return PA;
276e8d8bef9SDimitry Andric }
277e8d8bef9SDimitry Andric
run(Module & M,ModuleAnalysisManager & AM)278e8d8bef9SDimitry Andric PreservedAnalyses StripNonDebugSymbolsPass::run(Module &M,
279e8d8bef9SDimitry Andric ModuleAnalysisManager &AM) {
280e8d8bef9SDimitry Andric StripSymbolNames(M, true);
28106c3fb27SDimitry Andric PreservedAnalyses PA;
28206c3fb27SDimitry Andric PA.preserveSet<CFGAnalyses>();
28306c3fb27SDimitry Andric return PA;
284e8d8bef9SDimitry Andric }
285e8d8bef9SDimitry Andric
run(Module & M,ModuleAnalysisManager & AM)286e8d8bef9SDimitry Andric PreservedAnalyses StripDebugDeclarePass::run(Module &M,
287e8d8bef9SDimitry Andric ModuleAnalysisManager &AM) {
288e8d8bef9SDimitry Andric stripDebugDeclareImpl(M);
28906c3fb27SDimitry Andric PreservedAnalyses PA;
29006c3fb27SDimitry Andric PA.preserveSet<CFGAnalyses>();
29106c3fb27SDimitry Andric return PA;
292e8d8bef9SDimitry Andric }
293e8d8bef9SDimitry Andric
run(Module & M,ModuleAnalysisManager & AM)294e8d8bef9SDimitry Andric PreservedAnalyses StripDeadDebugInfoPass::run(Module &M,
295e8d8bef9SDimitry Andric ModuleAnalysisManager &AM) {
296e8d8bef9SDimitry Andric stripDeadDebugInfoImpl(M);
29706c3fb27SDimitry Andric PreservedAnalyses PA;
29806c3fb27SDimitry Andric PA.preserveSet<CFGAnalyses>();
29906c3fb27SDimitry Andric return PA;
300e8d8bef9SDimitry Andric }
301