diff --git a/llvm/include/llvm-c/DebugInfo.h b/llvm/include/llvm-c/DebugInfo.h new file mode 100644 index 000000000000..c84765b0dd7f --- /dev/null +++ b/llvm/include/llvm-c/DebugInfo.h @@ -0,0 +1,202 @@ +//===------------ DebugInfo.h - LLVM C API Debug Info API -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// This file declares the C API endpoints for generating DWARF Debug Info +/// +/// Note: This interface is experimental. It is *NOT* stable, and may be +/// changed without warning. +/// +//===----------------------------------------------------------------------===// + +#include "llvm-c/Core.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/// Debug info flags. +typedef enum { + LLVMDIFlagZero = 0, + LLVMDIFlagPrivate = 1, + LLVMDIFlagProtected = 2, + LLVMDIFlagPublic = 3, + LLVMDIFlagFwdDecl = 1 << 2, + LLVMDIFlagAppleBlock = 1 << 3, + LLVMDIFlagBlockByrefStruct = 1 << 4, + LLVMDIFlagVirtual = 1 << 5, + LLVMDIFlagArtificial = 1 << 6, + LLVMDIFlagExplicit = 1 << 7, + LLVMDIFlagPrototyped = 1 << 8, + LLVMDIFlagObjcClassComplete = 1 << 9, + LLVMDIFlagObjectPointer = 1 << 10, + LLVMDIFlagVector = 1 << 11, + LLVMDIFlagStaticMember = 1 << 12, + LLVMDIFlagLValueReference = 1 << 13, + LLVMDIFlagRValueReference = 1 << 14, + LLVMDIFlagReserved = 1 << 15, + LLVMDIFlagSingleInheritance = 1 << 16, + LLVMDIFlagMultipleInheritance = 2 << 16, + LLVMDIFlagVirtualInheritance = 3 << 16, + LLVMDIFlagIntroducedVirtual = 1 << 18, + LLVMDIFlagBitField = 1 << 19, + LLVMDIFlagNoReturn = 1 << 20, + LLVMDIFlagMainSubprogram = 1 << 21, + LLVMDIFlagIndirectVirtualBase = (1 << 2) | (1 << 5), + LLVMDIFlagAccessibility = LLVMDIFlagPrivate | LLVMDIFlagProtected | + LLVMDIFlagPublic, + LLVMDIFlagPtrToMemberRep = LLVMDIFlagSingleInheritance | + LLVMDIFlagMultipleInheritance | + LLVMDIFlagVirtualInheritance +} LLVMDIFlags; + +/// Source languages known by DWARF. +typedef enum { + LLVMDWARFSourceLanguageC89, + LLVMDWARFSourceLanguageC, + LLVMDWARFSourceLanguageAda83, + LLVMDWARFSourceLanguageC_plus_plus, + LLVMDWARFSourceLanguageCobol74, + LLVMDWARFSourceLanguageCobol85, + LLVMDWARFSourceLanguageFortran77, + LLVMDWARFSourceLanguageFortran90, + LLVMDWARFSourceLanguagePascal83, + LLVMDWARFSourceLanguageModula2, + // New in DWARF v3: + LLVMDWARFSourceLanguageJava, + LLVMDWARFSourceLanguageC99, + LLVMDWARFSourceLanguageAda95, + LLVMDWARFSourceLanguageFortran95, + LLVMDWARFSourceLanguagePLI, + LLVMDWARFSourceLanguageObjC, + LLVMDWARFSourceLanguageObjC_plus_plus, + LLVMDWARFSourceLanguageUPC, + LLVMDWARFSourceLanguageD, + // New in DWARF v4: + LLVMDWARFSourceLanguagePython, + // New in DWARF v5: + LLVMDWARFSourceLanguageOpenCL, + LLVMDWARFSourceLanguageGo, + LLVMDWARFSourceLanguageModula3, + LLVMDWARFSourceLanguageHaskell, + LLVMDWARFSourceLanguageC_plus_plus_03, + LLVMDWARFSourceLanguageC_plus_plus_11, + LLVMDWARFSourceLanguageOCaml, + LLVMDWARFSourceLanguageRust, + LLVMDWARFSourceLanguageC11, + LLVMDWARFSourceLanguageSwift, + LLVMDWARFSourceLanguageJulia, + LLVMDWARFSourceLanguageDylan, + LLVMDWARFSourceLanguageC_plus_plus_14, + LLVMDWARFSourceLanguageFortran03, + LLVMDWARFSourceLanguageFortran08, + LLVMDWARFSourceLanguageRenderScript, + LLVMDWARFSourceLanguageBLISS, + // Vendor extensions: + LLVMDWARFSourceLanguageMips_Assembler, + LLVMDWARFSourceLanguageGOOGLE_RenderScript, + LLVMDWARFSourceLanguageBORLAND_Delphi +} LLVMDWARFSourceLanguage; + +/// The amount of debug information to emit. +typedef enum { + LLVMDWARFEmissionNone = 0, + LLVMDWARFEmissionFull, + LLVMDWARFEmissionLineTablesOnly +} LLVMDWARFEmissionKind; + +/// The current debug metadata version number. +unsigned LLVMDebugMetadataVersion(void); + +/// The version of debug metadata that's present in the provided \c Module. +unsigned LLVMGetModuleDebugMetadataVersion(LLVMModuleRef Module); + +/// Strip debug info in the module if it exists. +/// +/// To do this, we remove all calls to the debugger intrinsics and any named +/// metadata for debugging. We also remove debug locations for instructions. +/// Return true if module is modified. +LLVMBool LLVMStripModuleDebugInfo(LLVMModuleRef Module); + +/// Construct a builder for a module, and do not allow for unresolved nodes +/// attached to the module. +LLVMDIBuilderRef LLVMCreateDIBuilderDisallowUnresolved(LLVMModuleRef M); + +/// Construct a builder for a module and collect unresolved nodes attached +/// to the module in order to resolve cycles during a call to +/// \c LLVMDIBuilderFinalize. +LLVMDIBuilderRef LLVMCreateDIBuilder(LLVMModuleRef M); + +/// Deallocates the DIBuilder and everything it owns. +/// @note You must call \c LLVMDIBuilderFinalize before this +void LLVMDisposeDIBuilder(LLVMDIBuilderRef Builder); + +/// Construct any deferred debug info descriptors. +void LLVMDIBuilderFinalize(LLVMDIBuilderRef Builder); + +/// A CompileUnit provides an anchor for all debugging +/// information generated during this instance of compilation. +/// \param Lang Source programming language, eg. +/// \c LLVMDWARFSourceLanguageC99 +/// \param File File info. +/// \param Producer Identify the producer of debugging information +/// and code. Usually this is a compiler +/// version string. +/// \param ProducerLen The length of the C string passed to \c Producer. +/// \param isOptimized A boolean flag which indicates whether optimization +/// is enabled or not. +/// \param Flags This string lists command line options. This +/// string is directly embedded in debug info +/// output which may be used by a tool +/// analyzing generated debugging information. +/// \param FlagsLen The length of the C string passed to \c Flags. +/// \param RuntimeVer This indicates runtime version for languages like +/// Objective-C. +/// \param SplitName The name of the file that we'll split debug info +/// out into. +/// \param SplitNameLen The length of the C string passed to \c SplitName. +/// \param Kind The kind of debug information to generate. +/// \param DWOId The DWOId if this is a split skeleton compile unit. +/// \param SplitDebugInlining Whether to emit inline debug info. +/// \param DebugInfoForProfiling Whether to emit extra debug info for +/// profile collection. +LLVMMetadataRef LLVMDIBuilderCreateCompileUnit( + LLVMDIBuilderRef Builder, LLVMDWARFSourceLanguage Lang, + LLVMMetadataRef FileRef, const char *Producer, size_t ProducerLen, + LLVMBool isOptimized, const char *Flags, size_t FlagsLen, + unsigned RuntimeVer, const char *SplitName, size_t SplitNameLen, + LLVMDWARFEmissionKind Kind, unsigned DWOId, LLVMBool SplitDebugInlining, + LLVMBool DebugInfoForProfiling); + +/// Create a file descriptor to hold debugging information for a file. +/// \param Builder The DIBuilder. +/// \param Filename File name. +/// \param FilenameLen The length of the C string passed to \c Filename. +/// \param Directory Directory. +/// \param DirectoryLen The length of the C string passed to \c Directory. +LLVMMetadataRef +LLVMDIBuilderCreateFile(LLVMDIBuilderRef Builder, const char *Filename, + size_t FilenameLen, const char *Directory, + size_t DirectoryLen); + +/// Creates a new DebugLocation that describes a source location. +/// \param Line The line in the source file. +/// \param Column The column in the source file. +/// \param Scope The scope in which the location resides. +/// \param InlinedAt The scope where this location was inlined, if at all. +/// (optional). +/// \note If the item to which this location is attached cannot be +/// attributed to a source line, pass 0 for the line and column. +LLVMMetadataRef +LLVMDIBuilderCreateDebugLocation(LLVMContextRef Ctx, unsigned Line, + unsigned Column, LLVMMetadataRef Scope, + LLVMMetadataRef InlinedAt); + +#ifdef __cplusplus +} // end extern "C" +#endif diff --git a/llvm/lib/IR/DebugInfo.cpp b/llvm/lib/IR/DebugInfo.cpp index ae044b3d2872..b34383f5ada9 100644 --- a/llvm/lib/IR/DebugInfo.cpp +++ b/llvm/lib/IR/DebugInfo.cpp @@ -1,694 +1,774 @@ //===- 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 "llvm-c/DebugInfo.h" +#include "LLVMContextImpl.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/None.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/IR/DIBuilder.h" #include "llvm/IR/Function.h" #include "llvm/IR/GVMaterializer.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/Support/Casting.h" #include #include #include using namespace llvm; using namespace llvm::dwarf; DISubprogram *llvm::getDISubprogram(const MDNode *Scope) { if (auto *LocalScope = dyn_cast_or_null(Scope)) return LocalScope->getSubprogram(); return nullptr; } //===----------------------------------------------------------------------===// // DebugInfoFinder implementations. //===----------------------------------------------------------------------===// void DebugInfoFinder::reset() { CUs.clear(); SPs.clear(); GVs.clear(); TYs.clear(); Scopes.clear(); NodesSeen.clear(); } void DebugInfoFinder::processModule(const Module &M) { for (auto *CU : M.debug_compile_units()) { addCompileUnit(CU); for (auto DIG : CU->getGlobalVariables()) { if (!addGlobalVariable(DIG)) continue; auto *GV = DIG->getVariable(); processScope(GV->getScope()); processType(GV->getType().resolve()); } for (auto *ET : CU->getEnumTypes()) processType(ET); for (auto *RT : CU->getRetainedTypes()) if (auto *T = dyn_cast(RT)) processType(T); else processSubprogram(cast(RT)); for (auto *Import : CU->getImportedEntities()) { auto *Entity = Import->getEntity().resolve(); if (auto *T = dyn_cast(Entity)) processType(T); else if (auto *SP = dyn_cast(Entity)) processSubprogram(SP); else if (auto *NS = dyn_cast(Entity)) processScope(NS->getScope()); else if (auto *M = dyn_cast(Entity)) processScope(M->getScope()); } } for (auto &F : M.functions()) { if (auto *SP = cast_or_null(F.getSubprogram())) processSubprogram(SP); // There could be subprograms from inlined functions referenced from // instructions only. Walk the function to find them. for (const BasicBlock &BB : F) { for (const Instruction &I : BB) { if (!I.getDebugLoc()) continue; processLocation(M, I.getDebugLoc().get()); } } } } void DebugInfoFinder::processLocation(const Module &M, const DILocation *Loc) { if (!Loc) return; processScope(Loc->getScope()); processLocation(M, Loc->getInlinedAt()); } void DebugInfoFinder::processType(DIType *DT) { if (!addType(DT)) return; processScope(DT->getScope().resolve()); if (auto *ST = dyn_cast(DT)) { for (DITypeRef Ref : ST->getTypeArray()) processType(Ref.resolve()); return; } if (auto *DCT = dyn_cast(DT)) { processType(DCT->getBaseType().resolve()); for (Metadata *D : DCT->getElements()) { if (auto *T = dyn_cast(D)) processType(T); else if (auto *SP = dyn_cast(D)) processSubprogram(SP); } return; } if (auto *DDT = dyn_cast(DT)) { processType(DDT->getBaseType().resolve()); } } void DebugInfoFinder::processScope(DIScope *Scope) { if (!Scope) return; if (auto *Ty = dyn_cast(Scope)) { processType(Ty); return; } if (auto *CU = dyn_cast(Scope)) { addCompileUnit(CU); return; } if (auto *SP = dyn_cast(Scope)) { processSubprogram(SP); return; } if (!addScope(Scope)) return; if (auto *LB = dyn_cast(Scope)) { processScope(LB->getScope()); } else if (auto *NS = dyn_cast(Scope)) { processScope(NS->getScope()); } else if (auto *M = dyn_cast(Scope)) { processScope(M->getScope()); } } void DebugInfoFinder::processSubprogram(DISubprogram *SP) { if (!addSubprogram(SP)) return; processScope(SP->getScope().resolve()); processType(SP->getType()); for (auto *Element : SP->getTemplateParams()) { if (auto *TType = dyn_cast(Element)) { processType(TType->getType().resolve()); } else if (auto *TVal = dyn_cast(Element)) { processType(TVal->getType().resolve()); } } } void DebugInfoFinder::processDeclare(const Module &M, const DbgDeclareInst *DDI) { auto *N = dyn_cast(DDI->getVariable()); if (!N) return; auto *DV = dyn_cast(N); if (!DV) return; if (!NodesSeen.insert(DV).second) return; processScope(DV->getScope()); processType(DV->getType().resolve()); } void DebugInfoFinder::processValue(const Module &M, const DbgValueInst *DVI) { auto *N = dyn_cast(DVI->getVariable()); if (!N) return; auto *DV = dyn_cast(N); if (!DV) return; if (!NodesSeen.insert(DV).second) return; processScope(DV->getScope()); processType(DV->getType().resolve()); } bool DebugInfoFinder::addType(DIType *DT) { if (!DT) return false; if (!NodesSeen.insert(DT).second) return false; TYs.push_back(const_cast(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(DIGlobalVariableExpression *DIG) { 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; } static MDNode *stripDebugLocFromLoopID(MDNode *N) { assert(N->op_begin() != N->op_end() && "Missing self reference?"); // if there is no debug location, we do not have to rewrite this MDNode. if (std::none_of(N->op_begin() + 1, N->op_end(), [](const MDOperand &Op) { return isa(Op.get()); })) return N; // If there is only the debug location without any actual loop metadata, we // can remove the metadata. if (std::none_of(N->op_begin() + 1, N->op_end(), [](const MDOperand &Op) { return !isa(Op.get()); })) return nullptr; SmallVector Args; // Reserve operand 0 for loop id self reference. auto TempNode = MDNode::getTemporary(N->getContext(), None); Args.push_back(TempNode.get()); // Add all non-debug location operands back. for (auto Op = N->op_begin() + 1; Op != N->op_end(); Op++) { if (!isa(*Op)) Args.push_back(*Op); } // Set the first operand to itself. MDNode *LoopID = MDNode::get(N->getContext(), Args); LoopID->replaceOperandWith(0, LoopID); return LoopID; } bool llvm::stripDebugInfo(Function &F) { bool Changed = false; if (F.getMetadata(LLVMContext::MD_dbg)) { Changed = true; F.setSubprogram(nullptr); } DenseMap LoopIDsMap; for (BasicBlock &BB : F) { for (auto II = BB.begin(), End = BB.end(); II != End;) { Instruction &I = *II++; // We may delete the instruction, increment now. if (isa(&I)) { I.eraseFromParent(); Changed = true; continue; } if (I.getDebugLoc()) { Changed = true; I.setDebugLoc(DebugLoc()); } } auto *TermInst = BB.getTerminator(); if (!TermInst) // This is invalid IR, but we may not have run the verifier yet continue; if (auto *LoopID = TermInst->getMetadata(LLVMContext::MD_loop)) { auto *NewLoopID = LoopIDsMap.lookup(LoopID); if (!NewLoopID) NewLoopID = LoopIDsMap[LoopID] = stripDebugLocFromLoopID(LoopID); if (NewLoopID != LoopID) TermInst->setMetadata(LLVMContext::MD_loop, NewLoopID); } } return Changed; } bool llvm::StripDebugInfo(Module &M) { bool Changed = false; for (Module::named_metadata_iterator NMI = M.named_metadata_begin(), NME = M.named_metadata_end(); NMI != NME;) { NamedMDNode *NMD = &*NMI; ++NMI; // We're stripping debug info, and without them, coverage information // doesn't quite make sense. if (NMD->getName().startswith("llvm.dbg.") || NMD->getName() == "llvm.gcov") { NMD->eraseFromParent(); Changed = true; } } for (Function &F : M) Changed |= stripDebugInfo(F); for (auto &GV : M.globals()) { SmallVector MDs; GV.getMetadata(LLVMContext::MD_dbg, MDs); if (!MDs.empty()) { GV.eraseMetadata(LLVMContext::MD_dbg); Changed = true; } } if (GVMaterializer *Materializer = M.getMaterializer()) Materializer->setStripDebugInfo(); return Changed; } namespace { /// Helper class to downgrade -g metadata to -gline-tables-only metadata. class DebugTypeInfoRemoval { DenseMap Replacements; public: /// The (void)() type. MDNode *EmptySubroutineType; private: /// Remember what linkage name we originally had before stripping. If we end /// up making two subprograms identical who originally had different linkage /// names, then we need to make one of them distinct, to avoid them getting /// uniqued. Maps the new node to the old linkage name. DenseMap NewToLinkageName; // TODO: Remember the distinct subprogram we created for a given linkage name, // so that we can continue to unique whenever possible. Map to the first (possibly distinct) mdsubprogram // created for that combination. This is not strictly needed for correctness, // but can cut down on the number of MDNodes and let us diff cleanly with the // output of -gline-tables-only. public: DebugTypeInfoRemoval(LLVMContext &C) : EmptySubroutineType(DISubroutineType::get(C, DINode::FlagZero, 0, MDNode::get(C, {}))) {} Metadata *map(Metadata *M) { if (!M) return nullptr; auto Replacement = Replacements.find(M); if (Replacement != Replacements.end()) return Replacement->second; return M; } MDNode *mapNode(Metadata *N) { return dyn_cast_or_null(map(N)); } /// Recursively remap N and all its referenced children. Does a DF post-order /// traversal, so as to remap bottoms up. void traverseAndRemap(MDNode *N) { traverse(N); } private: // Create a new DISubprogram, to replace the one given. DISubprogram *getReplacementSubprogram(DISubprogram *MDS) { auto *FileAndScope = cast_or_null(map(MDS->getFile())); StringRef LinkageName = MDS->getName().empty() ? MDS->getLinkageName() : ""; DISubprogram *Declaration = nullptr; auto *Type = cast_or_null(map(MDS->getType())); DITypeRef ContainingType(map(MDS->getContainingType())); auto *Unit = cast_or_null(map(MDS->getUnit())); auto Variables = nullptr; auto TemplateParams = nullptr; // Make a distinct DISubprogram, for situations that warrent it. auto distinctMDSubprogram = [&]() { return DISubprogram::getDistinct( MDS->getContext(), FileAndScope, MDS->getName(), LinkageName, FileAndScope, MDS->getLine(), Type, MDS->isLocalToUnit(), MDS->isDefinition(), MDS->getScopeLine(), ContainingType, MDS->getVirtuality(), MDS->getVirtualIndex(), MDS->getThisAdjustment(), MDS->getFlags(), MDS->isOptimized(), Unit, TemplateParams, Declaration, Variables); }; if (MDS->isDistinct()) return distinctMDSubprogram(); auto *NewMDS = DISubprogram::get( MDS->getContext(), FileAndScope, MDS->getName(), LinkageName, FileAndScope, MDS->getLine(), Type, MDS->isLocalToUnit(), MDS->isDefinition(), MDS->getScopeLine(), ContainingType, MDS->getVirtuality(), MDS->getVirtualIndex(), MDS->getThisAdjustment(), MDS->getFlags(), MDS->isOptimized(), Unit, TemplateParams, Declaration, Variables); StringRef OldLinkageName = MDS->getLinkageName(); // See if we need to make a distinct one. auto OrigLinkage = NewToLinkageName.find(NewMDS); if (OrigLinkage != NewToLinkageName.end()) { if (OrigLinkage->second == OldLinkageName) // We're good. return NewMDS; // Otherwise, need to make a distinct one. // TODO: Query the map to see if we already have one. return distinctMDSubprogram(); } NewToLinkageName.insert({NewMDS, MDS->getLinkageName()}); return NewMDS; } /// Create a new compile unit, to replace the one given DICompileUnit *getReplacementCU(DICompileUnit *CU) { // Drop skeleton CUs. if (CU->getDWOId()) return nullptr; auto *File = cast_or_null(map(CU->getFile())); MDTuple *EnumTypes = nullptr; MDTuple *RetainedTypes = nullptr; MDTuple *GlobalVariables = nullptr; MDTuple *ImportedEntities = nullptr; return DICompileUnit::getDistinct( CU->getContext(), CU->getSourceLanguage(), File, CU->getProducer(), CU->isOptimized(), CU->getFlags(), CU->getRuntimeVersion(), CU->getSplitDebugFilename(), DICompileUnit::LineTablesOnly, EnumTypes, RetainedTypes, GlobalVariables, ImportedEntities, CU->getMacros(), CU->getDWOId(), CU->getSplitDebugInlining(), CU->getDebugInfoForProfiling(), CU->getGnuPubnames()); } DILocation *getReplacementMDLocation(DILocation *MLD) { auto *Scope = map(MLD->getScope()); auto *InlinedAt = map(MLD->getInlinedAt()); if (MLD->isDistinct()) return DILocation::getDistinct(MLD->getContext(), MLD->getLine(), MLD->getColumn(), Scope, InlinedAt); return DILocation::get(MLD->getContext(), MLD->getLine(), MLD->getColumn(), Scope, InlinedAt); } /// Create a new generic MDNode, to replace the one given MDNode *getReplacementMDNode(MDNode *N) { SmallVector Ops; Ops.reserve(N->getNumOperands()); for (auto &I : N->operands()) if (I) Ops.push_back(map(I)); auto *Ret = MDNode::get(N->getContext(), Ops); return Ret; } /// Attempt to re-map N to a newly created node. void remap(MDNode *N) { if (Replacements.count(N)) return; auto doRemap = [&](MDNode *N) -> MDNode * { if (!N) return nullptr; if (auto *MDSub = dyn_cast(N)) { remap(MDSub->getUnit()); return getReplacementSubprogram(MDSub); } if (isa(N)) return EmptySubroutineType; if (auto *CU = dyn_cast(N)) return getReplacementCU(CU); if (isa(N)) return N; if (auto *MDLB = dyn_cast(N)) // Remap to our referenced scope (recursively). return mapNode(MDLB->getScope()); if (auto *MLD = dyn_cast(N)) return getReplacementMDLocation(MLD); // Otherwise, if we see these, just drop them now. Not strictly necessary, // but this speeds things up a little. if (isa(N)) return nullptr; return getReplacementMDNode(N); }; Replacements[N] = doRemap(N); } /// Do the remapping traversal. void traverse(MDNode *); }; } // end anonymous namespace void DebugTypeInfoRemoval::traverse(MDNode *N) { if (!N || Replacements.count(N)) return; // To avoid cycles, as well as for efficiency sake, we will sometimes prune // parts of the graph. auto prune = [](MDNode *Parent, MDNode *Child) { if (auto *MDS = dyn_cast(Parent)) return Child == MDS->getVariables().get(); return false; }; SmallVector ToVisit; DenseSet Opened; // Visit each node starting at N in post order, and map them. ToVisit.push_back(N); while (!ToVisit.empty()) { auto *N = ToVisit.back(); if (!Opened.insert(N).second) { // Close it. remap(N); ToVisit.pop_back(); continue; } for (auto &I : N->operands()) if (auto *MDN = dyn_cast_or_null(I)) if (!Opened.count(MDN) && !Replacements.count(MDN) && !prune(N, MDN) && !isa(MDN)) ToVisit.push_back(MDN); } } bool llvm::stripNonLineTableDebugInfo(Module &M) { bool Changed = false; // First off, delete the debug intrinsics. auto RemoveUses = [&](StringRef Name) { if (auto *DbgVal = M.getFunction(Name)) { while (!DbgVal->use_empty()) cast(DbgVal->user_back())->eraseFromParent(); DbgVal->eraseFromParent(); Changed = true; } }; RemoveUses("llvm.dbg.declare"); RemoveUses("llvm.dbg.value"); // Delete non-CU debug info named metadata nodes. for (auto NMI = M.named_metadata_begin(), NME = M.named_metadata_end(); NMI != NME;) { NamedMDNode *NMD = &*NMI; ++NMI; // Specifically keep dbg.cu around. if (NMD->getName() == "llvm.dbg.cu") continue; } // Drop all dbg attachments from global variables. for (auto &GV : M.globals()) GV.eraseMetadata(LLVMContext::MD_dbg); DebugTypeInfoRemoval Mapper(M.getContext()); auto remap = [&](MDNode *Node) -> MDNode * { if (!Node) return nullptr; Mapper.traverseAndRemap(Node); auto *NewNode = Mapper.mapNode(Node); Changed |= Node != NewNode; Node = NewNode; return NewNode; }; // Rewrite the DebugLocs to be equivalent to what // -gline-tables-only would have created. for (auto &F : M) { if (auto *SP = F.getSubprogram()) { Mapper.traverseAndRemap(SP); auto *NewSP = cast(Mapper.mapNode(SP)); Changed |= SP != NewSP; F.setSubprogram(NewSP); } for (auto &BB : F) { for (auto &I : BB) { auto remapDebugLoc = [&](DebugLoc DL) -> DebugLoc { auto *Scope = DL.getScope(); MDNode *InlinedAt = DL.getInlinedAt(); Scope = remap(Scope); InlinedAt = remap(InlinedAt); return DebugLoc::get(DL.getLine(), DL.getCol(), Scope, InlinedAt); }; if (I.getDebugLoc() != DebugLoc()) I.setDebugLoc(remapDebugLoc(I.getDebugLoc())); // Remap DILocations in untyped MDNodes (e.g., llvm.loop). SmallVector, 2> MDs; I.getAllMetadata(MDs); for (auto Attachment : MDs) if (auto *T = dyn_cast_or_null(Attachment.second)) for (unsigned N = 0; N < T->getNumOperands(); ++N) if (auto *Loc = dyn_cast_or_null(T->getOperand(N))) if (Loc != DebugLoc()) T->replaceOperandWith(N, remapDebugLoc(Loc)); } } } // Create a new llvm.dbg.cu, which is equivalent to the one // -gline-tables-only would have created. for (auto &NMD : M.getNamedMDList()) { SmallVector Ops; for (MDNode *Op : NMD.operands()) Ops.push_back(remap(Op)); if (!Changed) continue; NMD.clearOperands(); for (auto *Op : Ops) if (Op) NMD.addOperand(Op); } return Changed; } unsigned llvm::getDebugMetadataVersionFromModule(const Module &M) { if (auto *Val = mdconst::dyn_extract_or_null( M.getModuleFlag("Debug Info Version"))) return Val->getZExtValue(); return 0; } void Instruction::applyMergedLocation(const DILocation *LocA, const DILocation *LocB) { if (LocA && LocB && (LocA == LocB || !LocA->canDiscriminate(*LocB))) { setDebugLoc(LocA); return; } if (!LocA || !LocB || !isa(this)) { setDebugLoc(nullptr); return; } SmallPtrSet InlinedLocationsA; for (DILocation *L = LocA->getInlinedAt(); L; L = L->getInlinedAt()) InlinedLocationsA.insert(L); const DILocation *Result = LocB; for (DILocation *L = LocB->getInlinedAt(); L; L = L->getInlinedAt()) { Result = L; if (InlinedLocationsA.count(L)) break; } setDebugLoc(DILocation::get( Result->getContext(), 0, 0, Result->getScope(), Result->getInlinedAt())); } + +//===----------------------------------------------------------------------===// +// LLVM C API implementations. +//===----------------------------------------------------------------------===// + +static unsigned map_from_llvmDWARFsourcelanguage(LLVMDWARFSourceLanguage lang) { + switch (lang) { +#define HANDLE_DW_LANG(ID, NAME, VERSION, VENDOR) \ +case LLVMDWARFSourceLanguage##NAME: return ID; +#include "llvm/BinaryFormat/Dwarf.def" +#undef HANDLE_DW_LANG + } + llvm_unreachable("Unhandled Tag"); +} + +unsigned LLVMDebugMetadataVersion() { + return DEBUG_METADATA_VERSION; +} + +LLVMDIBuilderRef LLVMCreateDIBuilderDisallowUnresolved(LLVMModuleRef M) { + return wrap(new DIBuilder(*unwrap(M), false)); +} + +LLVMDIBuilderRef LLVMCreateDIBuilder(LLVMModuleRef M) { + return wrap(new DIBuilder(*unwrap(M))); +} + +unsigned LLVMGetModuleDebugMetadataVersion(LLVMModuleRef M) { + return getDebugMetadataVersionFromModule(*unwrap(M)); +} + +LLVMBool LLVMStripModuleDebugInfo(LLVMModuleRef M) { + return StripDebugInfo(*unwrap(M)); +} + +void LLVMDisposeDIBuilder(LLVMDIBuilderRef Builder) { + delete unwrap(Builder); +} + +void LLVMDIBuilderFinalize(LLVMDIBuilderRef Builder) { + unwrap(Builder)->finalize(); +} + +LLVMMetadataRef LLVMDIBuilderCreateCompileUnit( + LLVMDIBuilderRef Builder, LLVMDWARFSourceLanguage Lang, + LLVMMetadataRef FileRef, const char *Producer, size_t ProducerLen, + LLVMBool isOptimized, const char *Flags, size_t FlagsLen, + unsigned RuntimeVer, const char *SplitName, size_t SplitNameLen, + LLVMDWARFEmissionKind Kind, unsigned DWOId, LLVMBool SplitDebugInlining, + LLVMBool DebugInfoForProfiling) { + auto File = unwrap(FileRef); + + return wrap(unwrap(Builder)->createCompileUnit( + map_from_llvmDWARFsourcelanguage(Lang), File, + StringRef(Producer, ProducerLen), isOptimized, + StringRef(Flags, FlagsLen), RuntimeVer, + StringRef(SplitName, SplitNameLen), + static_cast(Kind), DWOId, + SplitDebugInlining, DebugInfoForProfiling)); +} + +LLVMMetadataRef +LLVMDIBuilderCreateFile(LLVMDIBuilderRef Builder, const char *Filename, + size_t FilenameLen, const char *Directory, + size_t DirectoryLen) { + return wrap(unwrap(Builder)->createFile(StringRef(Filename, FilenameLen), + StringRef(Directory, DirectoryLen))); +} + +LLVMMetadataRef +LLVMDIBuilderCreateDebugLocation(LLVMContextRef Ctx, unsigned Line, + unsigned Column, LLVMMetadataRef Scope, + LLVMMetadataRef InlinedAt) { + return wrap(DILocation::get(*unwrap(Ctx), Line, Column, unwrap(Scope), + unwrap(InlinedAt))); +} diff --git a/llvm/test/Bindings/llvm-c/debug_info.ll b/llvm/test/Bindings/llvm-c/debug_info.ll new file mode 100644 index 000000000000..7c62abfae5ce --- /dev/null +++ b/llvm/test/Bindings/llvm-c/debug_info.ll @@ -0,0 +1,8 @@ +; RUN: llvm-c-test --test-dibuilder | FileCheck %s + +; CHECK: ; ModuleID = 'debuginfo.c' +; CHECK-NEXT: source_filename = "debuginfo.c" + +; CHECK: !llvm.dbg.cu = !{!0} +; CHECK: !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "llvm-c-test", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false) +; CHECK-NEXT: !1 = !DIFile(filename: "debuginfo.c\00", directory: ".") diff --git a/llvm/tools/llvm-c-test/CMakeLists.txt b/llvm/tools/llvm-c-test/CMakeLists.txt index a2bde0d9714f..bce0f4a5a420 100644 --- a/llvm/tools/llvm-c-test/CMakeLists.txt +++ b/llvm/tools/llvm-c-test/CMakeLists.txt @@ -1,55 +1,56 @@ set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} BitReader Core MCDisassembler Object Support Target ) # We should only have llvm-c-test use libLLVM if libLLVM is built with the # default list of components. Using libLLVM with custom components can result in # build failures. set (USE_LLVM_DYLIB FALSE) if (TARGET LLVM) set (USE_LLVM_DYLIB TRUE) if (DEFINED LLVM_DYLIB_COMPONENTS) foreach(c in ${LLVM_LINK_COMPONENTS}) list(FIND LLVM_DYLIB_COMPONENTS ${c} C_IDX) if (C_IDX EQUAL -1) set(USE_LLVM_DYLIB FALSE) break() endif() endforeach() endif() endif() if(USE_LLVM_DYLIB) set(LLVM_LINK_COMPONENTS) endif() if (LLVM_COMPILER_IS_GCC_COMPATIBLE) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wstrict-prototypes") endif () add_llvm_tool(llvm-c-test attributes.c calc.c + debuginfo.c diagnostic.c disassemble.c echo.cpp helpers.c include-all.c main.c module.c metadata.c object.c targets.c ) if(USE_LLVM_DYLIB) target_link_libraries(llvm-c-test LLVM) endif() diff --git a/llvm/tools/llvm-c-test/debuginfo.c b/llvm/tools/llvm-c-test/debuginfo.c new file mode 100644 index 000000000000..2da3887a1721 --- /dev/null +++ b/llvm/tools/llvm-c-test/debuginfo.c @@ -0,0 +1,38 @@ +/*===-- debuginfo.c - tool for testing libLLVM and llvm-c API -------------===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* Tests for the LLVM C DebugInfo API *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#include "llvm-c-test.h" +#include "llvm-c/DebugInfo.h" +#include +#include + +int llvm_test_dibuilder() { + LLVMModuleRef M = LLVMModuleCreateWithName("debuginfo.c"); + LLVMDIBuilderRef DIB = LLVMCreateDIBuilder(M); + + LLVMMetadataRef File = LLVMDIBuilderCreateFile(DIB, "debuginfo.c", 12, + ".", 1); + + LLVMDIBuilderCreateCompileUnit(DIB, + LLVMDWARFSourceLanguageC, File,"llvm-c-test", 11, 0, NULL, 0, 0, + NULL, 0, LLVMDWARFEmissionFull, 0, 0, 0); + + char *MStr = LLVMPrintModuleToString(M); + puts(MStr); + LLVMDisposeMessage(MStr); + + LLVMDisposeDIBuilder(DIB); + LLVMDisposeModule(M); + + return 0; +} diff --git a/llvm/tools/llvm-c-test/llvm-c-test.h b/llvm/tools/llvm-c-test/llvm-c-test.h index 2a7090484b0e..cf9a0f99de64 100644 --- a/llvm/tools/llvm-c-test/llvm-c-test.h +++ b/llvm/tools/llvm-c-test/llvm-c-test.h @@ -1,63 +1,66 @@ /*===-- llvm-c-test.h - tool for testing libLLVM and llvm-c API -----------===*\ |* *| |* The LLVM Compiler Infrastructure *| |* *| |* This file is distributed under the University of Illinois Open Source *| |* License. See LICENSE.TXT for details. *| |* *| |*===----------------------------------------------------------------------===*| |* *| |* Header file for llvm-c-test *| |* *| \*===----------------------------------------------------------------------===*/ #ifndef LLVM_C_TEST_H #define LLVM_C_TEST_H #include #include "llvm-c/Core.h" #ifdef __cplusplus extern "C" { #endif // helpers.c void llvm_tokenize_stdin(void (*cb)(char **tokens, int ntokens)); // module.c LLVMModuleRef llvm_load_module(bool Lazy, bool New); int llvm_module_dump(bool Lazy, bool New); int llvm_module_list_functions(void); int llvm_module_list_globals(void); // calc.c int llvm_calc(void); // disassemble.c int llvm_disassemble(void); +// debuginfo.c +int llvm_test_dibuilder(void); + // metadata.c int llvm_add_named_metadata_operand(void); int llvm_set_metadata(void); // object.c int llvm_object_list_sections(void); int llvm_object_list_symbols(void); // targets.c int llvm_targets_list(void); // echo.c int llvm_echo(void); // diagnostic.c int llvm_test_diagnostic_handler(void); // attributes.c int llvm_test_function_attributes(void); int llvm_test_callsite_attributes(void); #ifdef __cplusplus } #endif /* !defined(__cplusplus) */ #endif diff --git a/llvm/tools/llvm-c-test/main.c b/llvm/tools/llvm-c-test/main.c index 9bc0c96c3d65..5130783d6a69 100644 --- a/llvm/tools/llvm-c-test/main.c +++ b/llvm/tools/llvm-c-test/main.c @@ -1,104 +1,109 @@ /*===-- main.c - tool for testing libLLVM and llvm-c API ------------------===*\ |* *| |* The LLVM Compiler Infrastructure *| |* *| |* This file is distributed under the University of Illinois Open Source *| |* License. See LICENSE.TXT for details. *| |* *| |*===----------------------------------------------------------------------===*| |* *| |* Main file for llvm-c-tests. "Parses" arguments and dispatches. *| |* *| \*===----------------------------------------------------------------------===*/ #include "llvm-c-test.h" #include "llvm-c/BitReader.h" #include #include #include static void print_usage(void) { fprintf(stderr, "llvm-c-test command\n\n"); fprintf(stderr, " Commands:\n"); fprintf(stderr, " * --module-dump\n"); fprintf(stderr, " Read bitcode from stdin - print disassembly\n\n"); fprintf(stderr, " * --lazy-module-dump\n"); fprintf(stderr, " Lazily read bitcode from stdin - print disassembly\n\n"); fprintf(stderr, " * --new-module-dump\n"); fprintf(stderr, " Read bitcode from stdin - print disassembly\n\n"); fprintf(stderr, " * --lazy-new-module-dump\n"); fprintf(stderr, " Lazily read bitcode from stdin - print disassembly\n\n"); fprintf(stderr, " * --module-list-functions\n"); fprintf(stderr, " Read bitcode from stdin - list summary of functions\n\n"); fprintf(stderr, " * --module-list-globals\n"); fprintf(stderr, " Read bitcode from stdin - list summary of globals\n\n"); fprintf(stderr, " * --targets-list\n"); fprintf(stderr, " List available targets\n\n"); fprintf(stderr, " * --object-list-sections\n"); fprintf(stderr, " Read object file form stdin - list sections\n\n"); fprintf(stderr, " * --object-list-symbols\n"); fprintf(stderr, " Read object file form stdin - list symbols (like nm)\n\n"); fprintf(stderr, " * --disassemble\n"); fprintf(stderr, " Read lines of triple, hex ascii machine code from stdin " "- print disassembly\n\n"); fprintf(stderr, " * --calc\n"); fprintf( stderr, " Read lines of name, rpn from stdin - print generated module\n\n"); fprintf(stderr, " * --echo\n"); fprintf(stderr, " Read bitcode file form stdin - print it back out\n\n"); fprintf(stderr, " * --test-diagnostic-handler\n"); fprintf(stderr, " Read bitcode file form stdin with a diagnostic handler set\n\n"); + fprintf(stderr, " * --test-dibuilder\n"); + fprintf(stderr, + " Run tests for the DIBuilder C API - print generated module\n\n"); } int main(int argc, char **argv) { LLVMPassRegistryRef pr = LLVMGetGlobalPassRegistry(); LLVMInitializeCore(pr); if (argc == 2 && !strcmp(argv[1], "--lazy-new-module-dump")) { return llvm_module_dump(true, true); } else if (argc == 2 && !strcmp(argv[1], "--new-module-dump")) { return llvm_module_dump(false, true); } else if (argc == 2 && !strcmp(argv[1], "--lazy-module-dump")) { return llvm_module_dump(true, false); } else if (argc == 2 && !strcmp(argv[1], "--module-dump")) { return llvm_module_dump(false, false); } else if (argc == 2 && !strcmp(argv[1], "--module-list-functions")) { return llvm_module_list_functions(); } else if (argc == 2 && !strcmp(argv[1], "--module-list-globals")) { return llvm_module_list_globals(); } else if (argc == 2 && !strcmp(argv[1], "--targets-list")) { return llvm_targets_list(); } else if (argc == 2 && !strcmp(argv[1], "--object-list-sections")) { return llvm_object_list_sections(); } else if (argc == 2 && !strcmp(argv[1], "--object-list-symbols")) { return llvm_object_list_symbols(); } else if (argc == 2 && !strcmp(argv[1], "--disassemble")) { return llvm_disassemble(); } else if (argc == 2 && !strcmp(argv[1], "--calc")) { return llvm_calc(); } else if (argc == 2 && !strcmp(argv[1], "--add-named-metadata-operand")) { return llvm_add_named_metadata_operand(); } else if (argc == 2 && !strcmp(argv[1], "--set-metadata")) { return llvm_set_metadata(); } else if (argc == 2 && !strcmp(argv[1], "--test-function-attributes")) { return llvm_test_function_attributes(); } else if (argc == 2 && !strcmp(argv[1], "--test-callsite-attributes")) { return llvm_test_callsite_attributes(); } else if (argc == 2 && !strcmp(argv[1], "--echo")) { return llvm_echo(); } else if (argc == 2 && !strcmp(argv[1], "--test-diagnostic-handler")) { return llvm_test_diagnostic_handler(); + } else if (argc == 2 && !strcmp(argv[1], "--test-dibuilder")) { + return llvm_test_dibuilder(); } else { print_usage(); } return 1; }