brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.3 KiB · ec701b6 Raw
319 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// The StripSymbols transformation implements code stripping. Specifically, it10// can delete:11//12//   * names for virtual registers13//   * symbols for internal globals and functions14//   * debug information15//16// Note that this transformation makes code much less readable, so it should17// only be used in situations where the 'strip' utility would be used, such as18// 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 39using namespace llvm;40 41static cl::opt<bool>42    StripGlobalConstants("strip-global-constants", cl::init(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.47static 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 55static 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(Op, C))60      Operands.insert(cast<Constant>(Op));61  if (GlobalVariable *GV = dyn_cast<GlobalVariable>(C)) {62    if (!GV->hasLocalLinkage()) return;   // Don't delete non-static globals.63    GV->eraseFromParent();64  } else if (!isa<Function>(C)) {65    // FIXME: Why does the type of the constant matter here?66    if (isa<StructType>(C->getType()) || isa<ArrayType>(C->getType()) ||67        isa<VectorType>(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(O);74}75 76// Strip the symbol table of its names.77//78static 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>(V) || cast<GlobalValue>(V)->hasLocalLinkage()) {83      if (!PreserveDbgInfo || !V->getName().starts_with("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.91static void StripTypeNames(Module &M, bool PreserveDbgInfo) {92  TypeFinder StructTypes;93  StructTypes.run(M, false);94 95  for (StructType *STy : StructTypes) {96    if (STy->isLiteral() || STy->getName().empty()) continue;97 98    if (PreserveDbgInfo && STy->getName().starts_with("llvm.dbg"))99      continue;100 101    STy->setName("");102  }103}104 105/// Find values that are marked as llvm.used.106static void findUsedValues(GlobalVariable *LLVMUsed,107                           SmallPtrSetImpl<const GlobalValue*> &UsedValues) {108  if (!LLVMUsed) return;109  UsedValues.insert(LLVMUsed);110 111  ConstantArray *Inits = cast<ConstantArray>(LLVMUsed->getInitializer());112 113  for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i)114    if (GlobalValue *GV =115          dyn_cast<GlobalValue>(Inits->getOperand(i)->stripPointerCasts()))116      UsedValues.insert(GV);117}118 119/// StripSymbolNames - Strip symbol names.120static bool StripSymbolNames(Module &M, bool PreserveDbgInfo) {121 122  SmallPtrSet<const GlobalValue*, 8> llvmUsedValues;123  findUsedValues(M.getGlobalVariable("llvm.used"), llvmUsedValues);124  findUsedValues(M.getGlobalVariable("llvm.compiler.used"), llvmUsedValues);125 126  for (GlobalVariable &GV : M.globals()) {127    if (GV.hasLocalLinkage() && !llvmUsedValues.contains(&GV))128      if (!PreserveDbgInfo || !GV.getName().starts_with("llvm.dbg"))129        GV.setName(""); // Internal symbols can't participate in linkage130  }131 132  for (Function &I : M) {133    if (I.hasLocalLinkage() && !llvmUsedValues.contains(&I))134      if (!PreserveDbgInfo || !I.getName().starts_with("llvm.dbg"))135        I.setName(""); // Internal symbols can't participate in linkage136    if (auto *Symtab = I.getValueSymbolTable())137      StripSymtab(*Symtab, PreserveDbgInfo);138  }139 140  // Remove all names from types.141  StripTypeNames(M, PreserveDbgInfo);142 143  return true;144}145 146static bool stripDebugDeclareImpl(Module &M) {147  Function *Declare =148      Intrinsic::getDeclarationIfExists(&M, Intrinsic::dbg_declare);149  std::vector<Constant*> DeadConstants;150 151  if (Declare) {152    while (!Declare->use_empty()) {153      CallInst *CI = cast<CallInst>(Declare->user_back());154      Value *Arg1 = CI->getArgOperand(0);155      Value *Arg2 = CI->getArgOperand(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>(Arg1))160          DeadConstants.push_back(C);161        else162          RecursivelyDeleteTriviallyDeadInstructions(Arg1);163      }164      if (Arg2->use_empty())165        if (Constant *C = dyn_cast<Constant>(Arg2))166          DeadConstants.push_back(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>(C)) {175      if (GV->hasLocalLinkage())176        RemoveDeadConstant(GV);177    } else178      RemoveDeadConstant(C);179  }180 181  return true;182}183 184static 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 we190  // want to do, but we want to try and be as resilient as possible in the face191  // of potential debug info changes by using the formal interfaces given to us192  // 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 and197  // replace the current list of potentially dead global variables/functions198  // 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(GVEs);206    for (auto *GVE : GVEs)207      LiveGVs.insert(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>(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(FoundCUs.begin(), 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(DIG);229 230      // Make sure we only visit each global variable only once.231      if (!VisitedSet.insert(DIG).second)232        continue;233 234      // If a global variable references DIG, the global variable is live.235      if (LiveGVs.count(DIG))236        LiveGlobalVariables.push_back(DIG);237      else238        GlobalVariableChange = true;239    }240 241    if (!LiveGlobalVariables.empty())242      LiveCUs.insert(DIC);243    else if (!LiveCUs.count(DIC))244      HasDeadCUs = true;245 246    // If we found dead global variables, replace the current global247    // variable list with our new live global variable list.248    if (GlobalVariableChange) {249      DIC->replaceGlobalVariables(MDTuple::get(C, 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 one259    NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.cu");260    NMD->clearOperands();261    if (!LiveCUs.empty()) {262      for (DICompileUnit *CU : LiveCUs)263        NMD->addOperand(CU);264    }265    Changed = true;266  }267 268  return Changed;269}270 271PreservedAnalyses StripSymbolsPass::run(Module &M, ModuleAnalysisManager &AM) {272  StripDebugInfo(M);273  StripSymbolNames(M, false);274  PreservedAnalyses PA;275  PA.preserveSet<CFGAnalyses>();276  return PA;277}278 279PreservedAnalyses StripNonDebugSymbolsPass::run(Module &M,280                                                ModuleAnalysisManager &AM) {281  StripSymbolNames(M, true);282  PreservedAnalyses PA;283  PA.preserveSet<CFGAnalyses>();284  return PA;285}286 287PreservedAnalyses StripDebugDeclarePass::run(Module &M,288                                             ModuleAnalysisManager &AM) {289  stripDebugDeclareImpl(M);290  PreservedAnalyses PA;291  PA.preserveSet<CFGAnalyses>();292  return PA;293}294 295PreservedAnalyses StripDeadDebugInfoPass::run(Module &M,296                                              ModuleAnalysisManager &AM) {297  stripDeadDebugInfoImpl(M);298  PreservedAnalyses PA;299  PA.preserveSet<CFGAnalyses>();300  return PA;301}302 303PreservedAnalyses StripDeadCGProfilePass::run(Module &M,304                                              ModuleAnalysisManager &AM) {305  auto *CGProf = dyn_cast_or_null<MDTuple>(M.getModuleFlag("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>(Edge))312      if (!llvm::is_contained(EdgeAsNode->operands(), nullptr))313        ValidCGEdges.push_back(Edge);314  }315  M.setModuleFlag(Module::Append, "CG Profile",316                  MDTuple::getDistinct(M.getContext(), ValidCGEdges));317  return PreservedAnalyses::none();318}319