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