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