//===--- DebugInfo.cpp - Debug Information Helper Classes -----------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the helper classes used to build and interpret debug // information in LLVM IR form. // //===----------------------------------------------------------------------===// #include "llvm/IR/DebugInfo.h" #include "LLVMContextImpl.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DIBuilder.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/GVMaterializer.h" #include "llvm/IR/Module.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; using namespace llvm::dwarf; DISubprogram *llvm::getDISubprogram(const MDNode *Scope) { if (auto *LocalScope = dyn_cast_or_null<DILocalScope>(Scope)) return LocalScope->getSubprogram(); return nullptr; } DISubprogram *llvm::getDISubprogram(const Function *F) { // We look for the first instr that has a debug annotation leading back to F. for (auto &BB : *F) { auto Inst = std::find_if(BB.begin(), BB.end(), [](const Instruction &Inst) { return Inst.getDebugLoc(); }); if (Inst == BB.end()) continue; DebugLoc DLoc = Inst->getDebugLoc(); const MDNode *Scope = DLoc.getInlinedAtScope(); auto *Subprogram = getDISubprogram(Scope); return Subprogram->describes(F) ? Subprogram : nullptr; } return nullptr; } DITypeIdentifierMap llvm::generateDITypeIdentifierMap(const NamedMDNode *CU_Nodes) { DITypeIdentifierMap Map; for (unsigned CUi = 0, CUe = CU_Nodes->getNumOperands(); CUi != CUe; ++CUi) { auto *CU = cast<DICompileUnit>(CU_Nodes->getOperand(CUi)); DINodeArray Retain = CU->getRetainedTypes(); for (unsigned Ti = 0, Te = Retain.size(); Ti != Te; ++Ti) { if (!isa<DICompositeType>(Retain[Ti])) continue; auto *Ty = cast<DICompositeType>(Retain[Ti]); if (MDString *TypeId = Ty->getRawIdentifier()) { // Definition has priority over declaration. // Try to insert (TypeId, Ty) to Map. std::pair<DITypeIdentifierMap::iterator, bool> P = Map.insert(std::make_pair(TypeId, Ty)); // If TypeId already exists in Map and this is a definition, replace // whatever we had (declaration or definition) with the definition. if (!P.second && !Ty->isForwardDecl()) P.first->second = Ty; } } } return Map; } //===----------------------------------------------------------------------===// // DebugInfoFinder implementations. //===----------------------------------------------------------------------===// void DebugInfoFinder::reset() { CUs.clear(); SPs.clear(); GVs.clear(); TYs.clear(); Scopes.clear(); NodesSeen.clear(); TypeIdentifierMap.clear(); TypeMapInitialized = false; } void DebugInfoFinder::InitializeTypeMap(const Module &M) { if (!TypeMapInitialized) if (NamedMDNode *CU_Nodes = M.getNamedMetadata("llvm.dbg.cu")) { TypeIdentifierMap = generateDITypeIdentifierMap(CU_Nodes); TypeMapInitialized = true; } } void DebugInfoFinder::processModule(const Module &M) { InitializeTypeMap(M); if (NamedMDNode *CU_Nodes = M.getNamedMetadata("llvm.dbg.cu")) { for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) { auto *CU = cast<DICompileUnit>(CU_Nodes->getOperand(i)); addCompileUnit(CU); for (auto *DIG : CU->getGlobalVariables()) { if (addGlobalVariable(DIG)) { processScope(DIG->getScope()); processType(DIG->getType().resolve(TypeIdentifierMap)); } } for (auto *SP : CU->getSubprograms()) processSubprogram(SP); for (auto *ET : CU->getEnumTypes()) processType(ET); for (auto *RT : CU->getRetainedTypes()) processType(RT); for (auto *Import : CU->getImportedEntities()) { auto *Entity = Import->getEntity().resolve(TypeIdentifierMap); if (auto *T = dyn_cast<DIType>(Entity)) processType(T); else if (auto *SP = dyn_cast<DISubprogram>(Entity)) processSubprogram(SP); else if (auto *NS = dyn_cast<DINamespace>(Entity)) processScope(NS->getScope()); else if (auto *M = dyn_cast<DIModule>(Entity)) processScope(M->getScope()); } } } } void DebugInfoFinder::processLocation(const Module &M, const DILocation *Loc) { if (!Loc) return; InitializeTypeMap(M); processScope(Loc->getScope()); processLocation(M, Loc->getInlinedAt()); } void DebugInfoFinder::processType(DIType *DT) { if (!addType(DT)) return; processScope(DT->getScope().resolve(TypeIdentifierMap)); if (auto *ST = dyn_cast<DISubroutineType>(DT)) { for (DITypeRef Ref : ST->getTypeArray()) processType(Ref.resolve(TypeIdentifierMap)); return; } if (auto *DCT = dyn_cast<DICompositeType>(DT)) { processType(DCT->getBaseType().resolve(TypeIdentifierMap)); for (Metadata *D : DCT->getElements()) { if (auto *T = dyn_cast<DIType>(D)) processType(T); else if (auto *SP = dyn_cast<DISubprogram>(D)) processSubprogram(SP); } return; } if (auto *DDT = dyn_cast<DIDerivedType>(DT)) { processType(DDT->getBaseType().resolve(TypeIdentifierMap)); } } void DebugInfoFinder::processScope(DIScope *Scope) { if (!Scope) return; if (auto *Ty = dyn_cast<DIType>(Scope)) { processType(Ty); return; } if (auto *CU = dyn_cast<DICompileUnit>(Scope)) { addCompileUnit(CU); return; } if (auto *SP = dyn_cast<DISubprogram>(Scope)) { processSubprogram(SP); return; } if (!addScope(Scope)) return; if (auto *LB = dyn_cast<DILexicalBlockBase>(Scope)) { processScope(LB->getScope()); } else if (auto *NS = dyn_cast<DINamespace>(Scope)) { processScope(NS->getScope()); } else if (auto *M = dyn_cast<DIModule>(Scope)) { processScope(M->getScope()); } } void DebugInfoFinder::processSubprogram(DISubprogram *SP) { if (!addSubprogram(SP)) return; processScope(SP->getScope().resolve(TypeIdentifierMap)); processType(SP->getType()); for (auto *Element : SP->getTemplateParams()) { if (auto *TType = dyn_cast<DITemplateTypeParameter>(Element)) { processType(TType->getType().resolve(TypeIdentifierMap)); } else if (auto *TVal = dyn_cast<DITemplateValueParameter>(Element)) { processType(TVal->getType().resolve(TypeIdentifierMap)); } } } void DebugInfoFinder::processDeclare(const Module &M, const DbgDeclareInst *DDI) { auto *N = dyn_cast<MDNode>(DDI->getVariable()); if (!N) return; InitializeTypeMap(M); auto *DV = dyn_cast<DILocalVariable>(N); if (!DV) return; if (!NodesSeen.insert(DV).second) return; processScope(DV->getScope()); processType(DV->getType().resolve(TypeIdentifierMap)); } void DebugInfoFinder::processValue(const Module &M, const DbgValueInst *DVI) { auto *N = dyn_cast<MDNode>(DVI->getVariable()); if (!N) return; InitializeTypeMap(M); auto *DV = dyn_cast<DILocalVariable>(N); if (!DV) return; if (!NodesSeen.insert(DV).second) return; processScope(DV->getScope()); processType(DV->getType().resolve(TypeIdentifierMap)); } bool DebugInfoFinder::addType(DIType *DT) { if (!DT) return false; if (!NodesSeen.insert(DT).second) return false; TYs.push_back(const_cast<DIType *>(DT)); return true; } bool DebugInfoFinder::addCompileUnit(DICompileUnit *CU) { if (!CU) return false; if (!NodesSeen.insert(CU).second) return false; CUs.push_back(CU); return true; } bool DebugInfoFinder::addGlobalVariable(DIGlobalVariable *DIG) { if (!DIG) return false; if (!NodesSeen.insert(DIG).second) return false; GVs.push_back(DIG); return true; } bool DebugInfoFinder::addSubprogram(DISubprogram *SP) { if (!SP) return false; if (!NodesSeen.insert(SP).second) return false; SPs.push_back(SP); return true; } bool DebugInfoFinder::addScope(DIScope *Scope) { if (!Scope) return false; // FIXME: Ocaml binding generates a scope with no content, we treat it // as null for now. if (Scope->getNumOperands() == 0) return false; if (!NodesSeen.insert(Scope).second) return false; Scopes.push_back(Scope); return true; } bool llvm::stripDebugInfo(Function &F) { bool Changed = false; if (F.getSubprogram()) { Changed = true; F.setSubprogram(nullptr); } for (BasicBlock &BB : F) { for (Instruction &I : BB) { if (I.getDebugLoc()) { Changed = true; I.setDebugLoc(DebugLoc()); } } } return Changed; } bool llvm::StripDebugInfo(Module &M) { bool Changed = false; // Remove all of the calls to the debugger intrinsics, and remove them from // the module. if (Function *Declare = M.getFunction("llvm.dbg.declare")) { while (!Declare->use_empty()) { CallInst *CI = cast<CallInst>(Declare->user_back()); CI->eraseFromParent(); } Declare->eraseFromParent(); Changed = true; } if (Function *DbgVal = M.getFunction("llvm.dbg.value")) { while (!DbgVal->use_empty()) { CallInst *CI = cast<CallInst>(DbgVal->user_back()); CI->eraseFromParent(); } DbgVal->eraseFromParent(); Changed = true; } for (Module::named_metadata_iterator NMI = M.named_metadata_begin(), NME = M.named_metadata_end(); NMI != NME;) { NamedMDNode *NMD = &*NMI; ++NMI; if (NMD->getName().startswith("llvm.dbg.")) { NMD->eraseFromParent(); Changed = true; } } for (Function &F : M) Changed |= stripDebugInfo(F); if (GVMaterializer *Materializer = M.getMaterializer()) Materializer->setStripDebugInfo(); return Changed; } unsigned llvm::getDebugMetadataVersionFromModule(const Module &M) { if (auto *Val = mdconst::dyn_extract_or_null<ConstantInt>( M.getModuleFlag("Debug Info Version"))) return Val->getZExtValue(); return 0; }