1 //===- StripSymbols.cpp - Strip symbols and debug info from a module ------===// 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 // The StripSymbols transformation implements code stripping. Specifically, it 10 // can delete: 11 // 12 // * names for virtual registers 13 // * symbols for internal globals and functions 14 // * debug information 15 // 16 // Note that this transformation makes code much less readable, so it should 17 // only be used in situations where the 'strip' utility would be used, such as 18 // reducing code size or making it harder to reverse engineer code. 19 // 20 //===----------------------------------------------------------------------===// 21 22 #include "llvm/Transforms/IPO/StripSymbols.h" 23 #include "llvm/ADT/SmallPtrSet.h" 24 #include "llvm/IR/Constants.h" 25 #include "llvm/IR/DebugInfo.h" 26 #include "llvm/IR/DerivedTypes.h" 27 #include "llvm/IR/InstIterator.h" 28 #include "llvm/IR/Instructions.h" 29 #include "llvm/IR/Module.h" 30 #include "llvm/IR/PassManager.h" 31 #include "llvm/IR/TypeFinder.h" 32 #include "llvm/IR/ValueSymbolTable.h" 33 #include "llvm/Support/CommandLine.h" 34 #include "llvm/Transforms/IPO/StripSymbols.h" 35 #include "llvm/Transforms/Utils/Local.h" 36 37 using namespace llvm; 38 39 static cl::opt<bool> 40 StripGlobalConstants("strip-global-constants", cl::init(false), cl::Hidden, 41 cl::desc("Removes debug compile units which reference " 42 "to non-existing global constants")); 43 44 /// OnlyUsedBy - Return true if V is only used by Usr. 45 static bool OnlyUsedBy(Value *V, Value *Usr) { 46 for (User *U : V->users()) 47 if (U != Usr) 48 return false; 49 50 return true; 51 } 52 53 static void RemoveDeadConstant(Constant *C) { 54 assert(C->use_empty() && "Constant is not dead!"); 55 SmallPtrSet<Constant*, 4> Operands; 56 for (Value *Op : C->operands()) 57 if (OnlyUsedBy(Op, C)) 58 Operands.insert(cast<Constant>(Op)); 59 if (GlobalVariable *GV = dyn_cast<GlobalVariable>(C)) { 60 if (!GV->hasLocalLinkage()) return; // Don't delete non-static globals. 61 GV->eraseFromParent(); 62 } else if (!isa<Function>(C)) { 63 // FIXME: Why does the type of the constant matter here? 64 if (isa<StructType>(C->getType()) || isa<ArrayType>(C->getType()) || 65 isa<VectorType>(C->getType())) 66 C->destroyConstant(); 67 } 68 69 // If the constant referenced anything, see if we can delete it as well. 70 for (Constant *O : Operands) 71 RemoveDeadConstant(O); 72 } 73 74 // Strip the symbol table of its names. 75 // 76 static void StripSymtab(ValueSymbolTable &ST, bool PreserveDbgInfo) { 77 for (ValueSymbolTable::iterator VI = ST.begin(), VE = ST.end(); VI != VE; ) { 78 Value *V = VI->getValue(); 79 ++VI; 80 if (!isa<GlobalValue>(V) || cast<GlobalValue>(V)->hasLocalLinkage()) { 81 if (!PreserveDbgInfo || !V->getName().starts_with("llvm.dbg")) 82 // Set name to "", removing from symbol table! 83 V->setName(""); 84 } 85 } 86 } 87 88 // Strip any named types of their names. 89 static void StripTypeNames(Module &M, bool PreserveDbgInfo) { 90 TypeFinder StructTypes; 91 StructTypes.run(M, false); 92 93 for (StructType *STy : StructTypes) { 94 if (STy->isLiteral() || STy->getName().empty()) continue; 95 96 if (PreserveDbgInfo && STy->getName().starts_with("llvm.dbg")) 97 continue; 98 99 STy->setName(""); 100 } 101 } 102 103 /// Find values that are marked as llvm.used. 104 static void findUsedValues(GlobalVariable *LLVMUsed, 105 SmallPtrSetImpl<const GlobalValue*> &UsedValues) { 106 if (!LLVMUsed) return; 107 UsedValues.insert(LLVMUsed); 108 109 ConstantArray *Inits = cast<ConstantArray>(LLVMUsed->getInitializer()); 110 111 for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i) 112 if (GlobalValue *GV = 113 dyn_cast<GlobalValue>(Inits->getOperand(i)->stripPointerCasts())) 114 UsedValues.insert(GV); 115 } 116 117 /// StripSymbolNames - Strip symbol names. 118 static bool StripSymbolNames(Module &M, bool PreserveDbgInfo) { 119 120 SmallPtrSet<const GlobalValue*, 8> llvmUsedValues; 121 findUsedValues(M.getGlobalVariable("llvm.used"), llvmUsedValues); 122 findUsedValues(M.getGlobalVariable("llvm.compiler.used"), llvmUsedValues); 123 124 for (GlobalVariable &GV : M.globals()) { 125 if (GV.hasLocalLinkage() && !llvmUsedValues.contains(&GV)) 126 if (!PreserveDbgInfo || !GV.getName().starts_with("llvm.dbg")) 127 GV.setName(""); // Internal symbols can't participate in linkage 128 } 129 130 for (Function &I : M) { 131 if (I.hasLocalLinkage() && !llvmUsedValues.contains(&I)) 132 if (!PreserveDbgInfo || !I.getName().starts_with("llvm.dbg")) 133 I.setName(""); // Internal symbols can't participate in linkage 134 if (auto *Symtab = I.getValueSymbolTable()) 135 StripSymtab(*Symtab, PreserveDbgInfo); 136 } 137 138 // Remove all names from types. 139 StripTypeNames(M, PreserveDbgInfo); 140 141 return true; 142 } 143 144 static bool stripDebugDeclareImpl(Module &M) { 145 Function *Declare = 146 Intrinsic::getDeclarationIfExists(&M, Intrinsic::dbg_declare); 147 std::vector<Constant*> DeadConstants; 148 149 if (Declare) { 150 while (!Declare->use_empty()) { 151 CallInst *CI = cast<CallInst>(Declare->user_back()); 152 Value *Arg1 = CI->getArgOperand(0); 153 Value *Arg2 = CI->getArgOperand(1); 154 assert(CI->use_empty() && "llvm.dbg intrinsic should have void result"); 155 CI->eraseFromParent(); 156 if (Arg1->use_empty()) { 157 if (Constant *C = dyn_cast<Constant>(Arg1)) 158 DeadConstants.push_back(C); 159 else 160 RecursivelyDeleteTriviallyDeadInstructions(Arg1); 161 } 162 if (Arg2->use_empty()) 163 if (Constant *C = dyn_cast<Constant>(Arg2)) 164 DeadConstants.push_back(C); 165 } 166 Declare->eraseFromParent(); 167 } 168 169 while (!DeadConstants.empty()) { 170 Constant *C = DeadConstants.back(); 171 DeadConstants.pop_back(); 172 if (GlobalVariable *GV = dyn_cast<GlobalVariable>(C)) { 173 if (GV->hasLocalLinkage()) 174 RemoveDeadConstant(GV); 175 } else 176 RemoveDeadConstant(C); 177 } 178 179 return true; 180 } 181 182 static bool stripDeadDebugInfoImpl(Module &M) { 183 bool Changed = false; 184 185 LLVMContext &C = M.getContext(); 186 187 // Find all debug info in F. This is actually overkill in terms of what we 188 // want to do, but we want to try and be as resilient as possible in the face 189 // of potential debug info changes by using the formal interfaces given to us 190 // as much as possible. 191 DebugInfoFinder F; 192 F.processModule(M); 193 194 // For each compile unit, find the live set of global variables/functions and 195 // replace the current list of potentially dead global variables/functions 196 // with the live list. 197 SmallVector<Metadata *, 64> LiveGlobalVariables; 198 DenseSet<DIGlobalVariableExpression *> VisitedSet; 199 200 std::set<DIGlobalVariableExpression *> LiveGVs; 201 for (GlobalVariable &GV : M.globals()) { 202 SmallVector<DIGlobalVariableExpression *, 1> GVEs; 203 GV.getDebugInfo(GVEs); 204 for (auto *GVE : GVEs) 205 LiveGVs.insert(GVE); 206 } 207 208 std::set<DICompileUnit *> LiveCUs; 209 DebugInfoFinder LiveCUFinder; 210 for (const Function &F : M.functions()) { 211 if (auto *SP = cast_or_null<DISubprogram>(F.getSubprogram())) 212 LiveCUFinder.processSubprogram(SP); 213 for (const Instruction &I : instructions(F)) 214 LiveCUFinder.processInstruction(M, I); 215 } 216 auto FoundCUs = LiveCUFinder.compile_units(); 217 LiveCUs.insert(FoundCUs.begin(), FoundCUs.end()); 218 219 bool HasDeadCUs = false; 220 for (DICompileUnit *DIC : F.compile_units()) { 221 // Create our live global variable list. 222 bool GlobalVariableChange = false; 223 for (auto *DIG : DIC->getGlobalVariables()) { 224 if (DIG->getExpression() && DIG->getExpression()->isConstant() && 225 !StripGlobalConstants) 226 LiveGVs.insert(DIG); 227 228 // Make sure we only visit each global variable only once. 229 if (!VisitedSet.insert(DIG).second) 230 continue; 231 232 // If a global variable references DIG, the global variable is live. 233 if (LiveGVs.count(DIG)) 234 LiveGlobalVariables.push_back(DIG); 235 else 236 GlobalVariableChange = true; 237 } 238 239 if (!LiveGlobalVariables.empty()) 240 LiveCUs.insert(DIC); 241 else if (!LiveCUs.count(DIC)) 242 HasDeadCUs = true; 243 244 // If we found dead global variables, replace the current global 245 // variable list with our new live global variable list. 246 if (GlobalVariableChange) { 247 DIC->replaceGlobalVariables(MDTuple::get(C, LiveGlobalVariables)); 248 Changed = true; 249 } 250 251 // Reset lists for the next iteration. 252 LiveGlobalVariables.clear(); 253 } 254 255 if (HasDeadCUs) { 256 // Delete the old node and replace it with a new one 257 NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.cu"); 258 NMD->clearOperands(); 259 if (!LiveCUs.empty()) { 260 for (DICompileUnit *CU : LiveCUs) 261 NMD->addOperand(CU); 262 } 263 Changed = true; 264 } 265 266 return Changed; 267 } 268 269 PreservedAnalyses StripSymbolsPass::run(Module &M, ModuleAnalysisManager &AM) { 270 StripDebugInfo(M); 271 StripSymbolNames(M, false); 272 PreservedAnalyses PA; 273 PA.preserveSet<CFGAnalyses>(); 274 return PA; 275 } 276 277 PreservedAnalyses StripNonDebugSymbolsPass::run(Module &M, 278 ModuleAnalysisManager &AM) { 279 StripSymbolNames(M, true); 280 PreservedAnalyses PA; 281 PA.preserveSet<CFGAnalyses>(); 282 return PA; 283 } 284 285 PreservedAnalyses StripDebugDeclarePass::run(Module &M, 286 ModuleAnalysisManager &AM) { 287 stripDebugDeclareImpl(M); 288 PreservedAnalyses PA; 289 PA.preserveSet<CFGAnalyses>(); 290 return PA; 291 } 292 293 PreservedAnalyses StripDeadDebugInfoPass::run(Module &M, 294 ModuleAnalysisManager &AM) { 295 stripDeadDebugInfoImpl(M); 296 PreservedAnalyses PA; 297 PA.preserveSet<CFGAnalyses>(); 298 return PA; 299 } 300