| //===--- CGDebugInfo.cpp - Emit Debug Information for a Module ------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This coordinates the debug information generation while generating code. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "CGDebugInfo.h" |
| #include "CGBlocks.h" |
| #include "CGCXXABI.h" |
| #include "CGObjCRuntime.h" |
| #include "CGRecordLayout.h" |
| #include "CodeGenFunction.h" |
| #include "CodeGenModule.h" |
| #include "ConstantEmitter.h" |
| #include "clang/AST/ASTContext.h" |
| #include "clang/AST/Attr.h" |
| #include "clang/AST/DeclFriend.h" |
| #include "clang/AST/DeclObjC.h" |
| #include "clang/AST/DeclTemplate.h" |
| #include "clang/AST/Expr.h" |
| #include "clang/AST/RecordLayout.h" |
| #include "clang/AST/RecursiveASTVisitor.h" |
| #include "clang/Basic/CodeGenOptions.h" |
| #include "clang/Basic/FileManager.h" |
| #include "clang/Basic/SourceManager.h" |
| #include "clang/Basic/Version.h" |
| #include "clang/Frontend/FrontendOptions.h" |
| #include "clang/Lex/HeaderSearchOptions.h" |
| #include "clang/Lex/ModuleMap.h" |
| #include "clang/Lex/PreprocessorOptions.h" |
| #include "llvm/ADT/DenseSet.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/ADT/StringExtras.h" |
| #include "llvm/IR/Constants.h" |
| #include "llvm/IR/DataLayout.h" |
| #include "llvm/IR/DerivedTypes.h" |
| #include "llvm/IR/Instructions.h" |
| #include "llvm/IR/Intrinsics.h" |
| #include "llvm/IR/Metadata.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/Support/FileSystem.h" |
| #include "llvm/Support/MD5.h" |
| #include "llvm/Support/Path.h" |
| #include "llvm/Support/TimeProfiler.h" |
| using namespace clang; |
| using namespace clang::CodeGen; |
| |
| static uint32_t getTypeAlignIfRequired(const Type *Ty, const ASTContext &Ctx) { |
| auto TI = Ctx.getTypeInfo(Ty); |
| return TI.isAlignRequired() ? TI.Align : 0; |
| } |
| |
| static uint32_t getTypeAlignIfRequired(QualType Ty, const ASTContext &Ctx) { |
| return getTypeAlignIfRequired(Ty.getTypePtr(), Ctx); |
| } |
| |
| static uint32_t getDeclAlignIfRequired(const Decl *D, const ASTContext &Ctx) { |
| return D->hasAttr<AlignedAttr>() ? D->getMaxAlignment() : 0; |
| } |
| |
| CGDebugInfo::CGDebugInfo(CodeGenModule &CGM) |
| : CGM(CGM), DebugKind(CGM.getCodeGenOpts().getDebugInfo()), |
| DebugTypeExtRefs(CGM.getCodeGenOpts().DebugTypeExtRefs), |
| DBuilder(CGM.getModule()) { |
| for (const auto &KV : CGM.getCodeGenOpts().DebugPrefixMap) |
| DebugPrefixMap[KV.first] = KV.second; |
| CreateCompileUnit(); |
| } |
| |
| CGDebugInfo::~CGDebugInfo() { |
| assert(LexicalBlockStack.empty() && |
| "Region stack mismatch, stack not empty!"); |
| } |
| |
| ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, |
| SourceLocation TemporaryLocation) |
| : CGF(&CGF) { |
| init(TemporaryLocation); |
| } |
| |
| ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, |
| bool DefaultToEmpty, |
| SourceLocation TemporaryLocation) |
| : CGF(&CGF) { |
| init(TemporaryLocation, DefaultToEmpty); |
| } |
| |
| void ApplyDebugLocation::init(SourceLocation TemporaryLocation, |
| bool DefaultToEmpty) { |
| auto *DI = CGF->getDebugInfo(); |
| if (!DI) { |
| CGF = nullptr; |
| return; |
| } |
| |
| OriginalLocation = CGF->Builder.getCurrentDebugLocation(); |
| |
| if (OriginalLocation && !DI->CGM.getExpressionLocationsEnabled()) |
| return; |
| |
| if (TemporaryLocation.isValid()) { |
| DI->EmitLocation(CGF->Builder, TemporaryLocation); |
| return; |
| } |
| |
| if (DefaultToEmpty) { |
| CGF->Builder.SetCurrentDebugLocation(llvm::DebugLoc()); |
| return; |
| } |
| |
| // Construct a location that has a valid scope, but no line info. |
| assert(!DI->LexicalBlockStack.empty()); |
| CGF->Builder.SetCurrentDebugLocation( |
| llvm::DILocation::get(DI->LexicalBlockStack.back()->getContext(), 0, 0, |
| DI->LexicalBlockStack.back(), DI->getInlinedAt())); |
| } |
| |
| ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, const Expr *E) |
| : CGF(&CGF) { |
| init(E->getExprLoc()); |
| } |
| |
| ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, llvm::DebugLoc Loc) |
| : CGF(&CGF) { |
| if (!CGF.getDebugInfo()) { |
| this->CGF = nullptr; |
| return; |
| } |
| OriginalLocation = CGF.Builder.getCurrentDebugLocation(); |
| if (Loc) |
| CGF.Builder.SetCurrentDebugLocation(std::move(Loc)); |
| } |
| |
| ApplyDebugLocation::~ApplyDebugLocation() { |
| // Query CGF so the location isn't overwritten when location updates are |
| // temporarily disabled (for C++ default function arguments) |
| if (CGF) |
| CGF->Builder.SetCurrentDebugLocation(std::move(OriginalLocation)); |
| } |
| |
| ApplyInlineDebugLocation::ApplyInlineDebugLocation(CodeGenFunction &CGF, |
| GlobalDecl InlinedFn) |
| : CGF(&CGF) { |
| if (!CGF.getDebugInfo()) { |
| this->CGF = nullptr; |
| return; |
| } |
| auto &DI = *CGF.getDebugInfo(); |
| SavedLocation = DI.getLocation(); |
| assert((DI.getInlinedAt() == |
| CGF.Builder.getCurrentDebugLocation()->getInlinedAt()) && |
| "CGDebugInfo and IRBuilder are out of sync"); |
| |
| DI.EmitInlineFunctionStart(CGF.Builder, InlinedFn); |
| } |
| |
| ApplyInlineDebugLocation::~ApplyInlineDebugLocation() { |
| if (!CGF) |
| return; |
| auto &DI = *CGF->getDebugInfo(); |
| DI.EmitInlineFunctionEnd(CGF->Builder); |
| DI.EmitLocation(CGF->Builder, SavedLocation); |
| } |
| |
| void CGDebugInfo::setLocation(SourceLocation Loc) { |
| // If the new location isn't valid return. |
| if (Loc.isInvalid()) |
| return; |
| |
| CurLoc = CGM.getContext().getSourceManager().getExpansionLoc(Loc); |
| |
| // If we've changed files in the middle of a lexical scope go ahead |
| // and create a new lexical scope with file node if it's different |
| // from the one in the scope. |
| if (LexicalBlockStack.empty()) |
| return; |
| |
| SourceManager &SM = CGM.getContext().getSourceManager(); |
| auto *Scope = cast<llvm::DIScope>(LexicalBlockStack.back()); |
| PresumedLoc PCLoc = SM.getPresumedLoc(CurLoc); |
| if (PCLoc.isInvalid() || Scope->getFile() == getOrCreateFile(CurLoc)) |
| return; |
| |
| if (auto *LBF = dyn_cast<llvm::DILexicalBlockFile>(Scope)) { |
| LexicalBlockStack.pop_back(); |
| LexicalBlockStack.emplace_back(DBuilder.createLexicalBlockFile( |
| LBF->getScope(), getOrCreateFile(CurLoc))); |
| } else if (isa<llvm::DILexicalBlock>(Scope) || |
| isa<llvm::DISubprogram>(Scope)) { |
| LexicalBlockStack.pop_back(); |
| LexicalBlockStack.emplace_back( |
| DBuilder.createLexicalBlockFile(Scope, getOrCreateFile(CurLoc))); |
| } |
| } |
| |
| llvm::DIScope *CGDebugInfo::getDeclContextDescriptor(const Decl *D) { |
| llvm::DIScope *Mod = getParentModuleOrNull(D); |
| return getContextDescriptor(cast<Decl>(D->getDeclContext()), |
| Mod ? Mod : TheCU); |
| } |
| |
| llvm::DIScope *CGDebugInfo::getContextDescriptor(const Decl *Context, |
| llvm::DIScope *Default) { |
| if (!Context) |
| return Default; |
| |
| auto I = RegionMap.find(Context); |
| if (I != RegionMap.end()) { |
| llvm::Metadata *V = I->second; |
| return dyn_cast_or_null<llvm::DIScope>(V); |
| } |
| |
| // Check namespace. |
| if (const auto *NSDecl = dyn_cast<NamespaceDecl>(Context)) |
| return getOrCreateNamespace(NSDecl); |
| |
| if (const auto *RDecl = dyn_cast<RecordDecl>(Context)) |
| if (!RDecl->isDependentType()) |
| return getOrCreateType(CGM.getContext().getTypeDeclType(RDecl), |
| TheCU->getFile()); |
| return Default; |
| } |
| |
| PrintingPolicy CGDebugInfo::getPrintingPolicy() const { |
| PrintingPolicy PP = CGM.getContext().getPrintingPolicy(); |
| |
| // If we're emitting codeview, it's important to try to match MSVC's naming so |
| // that visualizers written for MSVC will trigger for our class names. In |
| // particular, we can't have spaces between arguments of standard templates |
| // like basic_string and vector, but we must have spaces between consecutive |
| // angle brackets that close nested template argument lists. |
| if (CGM.getCodeGenOpts().EmitCodeView) { |
| PP.MSVCFormatting = true; |
| PP.SplitTemplateClosers = true; |
| } else { |
| // For DWARF, printing rules are underspecified. |
| // SplitTemplateClosers yields better interop with GCC and GDB (PR46052). |
| PP.SplitTemplateClosers = true; |
| } |
| |
| PP.SuppressInlineNamespace = false; |
| PP.PrintCanonicalTypes = true; |
| PP.UsePreferredNames = false; |
| PP.AlwaysIncludeTypeForTemplateArgument = true; |
| |
| // Apply -fdebug-prefix-map. |
| PP.Callbacks = &PrintCB; |
| return PP; |
| } |
| |
| StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) { |
| return internString(GetName(FD)); |
| } |
| |
| StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) { |
| SmallString<256> MethodName; |
| llvm::raw_svector_ostream OS(MethodName); |
| OS << (OMD->isInstanceMethod() ? '-' : '+') << '['; |
| const DeclContext *DC = OMD->getDeclContext(); |
| if (const auto *OID = dyn_cast<ObjCImplementationDecl>(DC)) { |
| OS << OID->getName(); |
| } else if (const auto *OID = dyn_cast<ObjCInterfaceDecl>(DC)) { |
| OS << OID->getName(); |
| } else if (const auto *OC = dyn_cast<ObjCCategoryDecl>(DC)) { |
| if (OC->IsClassExtension()) { |
| OS << OC->getClassInterface()->getName(); |
| } else { |
| OS << OC->getIdentifier()->getNameStart() << '(' |
| << OC->getIdentifier()->getNameStart() << ')'; |
| } |
| } else if (const auto *OCD = dyn_cast<ObjCCategoryImplDecl>(DC)) { |
| OS << OCD->getClassInterface()->getName() << '(' << OCD->getName() << ')'; |
| } |
| OS << ' ' << OMD->getSelector().getAsString() << ']'; |
| |
| return internString(OS.str()); |
| } |
| |
| StringRef CGDebugInfo::getSelectorName(Selector S) { |
| return internString(S.getAsString()); |
| } |
| |
| StringRef CGDebugInfo::getClassName(const RecordDecl *RD) { |
| if (isa<ClassTemplateSpecializationDecl>(RD)) { |
| // Copy this name on the side and use its reference. |
| return internString(GetName(RD)); |
| } |
| |
| // quick optimization to avoid having to intern strings that are already |
| // stored reliably elsewhere |
| if (const IdentifierInfo *II = RD->getIdentifier()) |
| return II->getName(); |
| |
| // The CodeView printer in LLVM wants to see the names of unnamed types |
| // because they need to have a unique identifier. |
| // These names are used to reconstruct the fully qualified type names. |
| if (CGM.getCodeGenOpts().EmitCodeView) { |
| if (const TypedefNameDecl *D = RD->getTypedefNameForAnonDecl()) { |
| assert(RD->getDeclContext() == D->getDeclContext() && |
| "Typedef should not be in another decl context!"); |
| assert(D->getDeclName().getAsIdentifierInfo() && |
| "Typedef was not named!"); |
| return D->getDeclName().getAsIdentifierInfo()->getName(); |
| } |
| |
| if (CGM.getLangOpts().CPlusPlus) { |
| StringRef Name; |
| |
| ASTContext &Context = CGM.getContext(); |
| if (const DeclaratorDecl *DD = Context.getDeclaratorForUnnamedTagDecl(RD)) |
| // Anonymous types without a name for linkage purposes have their |
| // declarator mangled in if they have one. |
| Name = DD->getName(); |
| else if (const TypedefNameDecl *TND = |
| Context.getTypedefNameForUnnamedTagDecl(RD)) |
| // Anonymous types without a name for linkage purposes have their |
| // associate typedef mangled in if they have one. |
| Name = TND->getName(); |
| |
| // Give lambdas a display name based on their name mangling. |
| if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) |
| if (CXXRD->isLambda()) |
| return internString( |
| CGM.getCXXABI().getMangleContext().getLambdaString(CXXRD)); |
| |
| if (!Name.empty()) { |
| SmallString<256> UnnamedType("<unnamed-type-"); |
| UnnamedType += Name; |
| UnnamedType += '>'; |
| return internString(UnnamedType); |
| } |
| } |
| } |
| |
| return StringRef(); |
| } |
| |
| Optional<llvm::DIFile::ChecksumKind> |
| CGDebugInfo::computeChecksum(FileID FID, SmallString<32> &Checksum) const { |
| Checksum.clear(); |
| |
| if (!CGM.getCodeGenOpts().EmitCodeView && |
| CGM.getCodeGenOpts().DwarfVersion < 5) |
| return None; |
| |
| SourceManager &SM = CGM.getContext().getSourceManager(); |
| Optional<llvm::MemoryBufferRef> MemBuffer = SM.getBufferOrNone(FID); |
| if (!MemBuffer) |
| return None; |
| |
| llvm::MD5 Hash; |
| llvm::MD5::MD5Result Result; |
| |
| Hash.update(MemBuffer->getBuffer()); |
| Hash.final(Result); |
| |
| Hash.stringifyResult(Result, Checksum); |
| return llvm::DIFile::CSK_MD5; |
| } |
| |
| Optional<StringRef> CGDebugInfo::getSource(const SourceManager &SM, |
| FileID FID) { |
| if (!CGM.getCodeGenOpts().EmbedSource) |
| return None; |
| |
| bool SourceInvalid = false; |
| StringRef Source = SM.getBufferData(FID, &SourceInvalid); |
| |
| if (SourceInvalid) |
| return None; |
| |
| return Source; |
| } |
| |
| llvm::DIFile *CGDebugInfo::getOrCreateFile(SourceLocation Loc) { |
| SourceManager &SM = CGM.getContext().getSourceManager(); |
| StringRef FileName; |
| FileID FID; |
| |
| if (Loc.isInvalid()) { |
| // The DIFile used by the CU is distinct from the main source file. Call |
| // createFile() below for canonicalization if the source file was specified |
| // with an absolute path. |
| FileName = TheCU->getFile()->getFilename(); |
| } else { |
| PresumedLoc PLoc = SM.getPresumedLoc(Loc); |
| FileName = PLoc.getFilename(); |
| |
| if (FileName.empty()) { |
| FileName = TheCU->getFile()->getFilename(); |
| } else { |
| FileName = PLoc.getFilename(); |
| } |
| FID = PLoc.getFileID(); |
| } |
| |
| // Cache the results. |
| auto It = DIFileCache.find(FileName.data()); |
| if (It != DIFileCache.end()) { |
| // Verify that the information still exists. |
| if (llvm::Metadata *V = It->second) |
| return cast<llvm::DIFile>(V); |
| } |
| |
| SmallString<32> Checksum; |
| |
| Optional<llvm::DIFile::ChecksumKind> CSKind = computeChecksum(FID, Checksum); |
| Optional<llvm::DIFile::ChecksumInfo<StringRef>> CSInfo; |
| if (CSKind) |
| CSInfo.emplace(*CSKind, Checksum); |
| return createFile(FileName, CSInfo, getSource(SM, SM.getFileID(Loc))); |
| } |
| |
| llvm::DIFile * |
| CGDebugInfo::createFile(StringRef FileName, |
| Optional<llvm::DIFile::ChecksumInfo<StringRef>> CSInfo, |
| Optional<StringRef> Source) { |
| StringRef Dir; |
| StringRef File; |
| std::string RemappedFile = remapDIPath(FileName); |
| std::string CurDir = remapDIPath(getCurrentDirname()); |
| SmallString<128> DirBuf; |
| SmallString<128> FileBuf; |
| if (llvm::sys::path::is_absolute(RemappedFile)) { |
| // Strip the common prefix (if it is more than just "/") from current |
| // directory and FileName for a more space-efficient encoding. |
| auto FileIt = llvm::sys::path::begin(RemappedFile); |
| auto FileE = llvm::sys::path::end(RemappedFile); |
| auto CurDirIt = llvm::sys::path::begin(CurDir); |
| auto CurDirE = llvm::sys::path::end(CurDir); |
| for (; CurDirIt != CurDirE && *CurDirIt == *FileIt; ++CurDirIt, ++FileIt) |
| llvm::sys::path::append(DirBuf, *CurDirIt); |
| if (std::distance(llvm::sys::path::begin(CurDir), CurDirIt) == 1) { |
| // Don't strip the common prefix if it is only the root "/" |
| // since that would make LLVM diagnostic locations confusing. |
| Dir = {}; |
| File = RemappedFile; |
| } else { |
| for (; FileIt != FileE; ++FileIt) |
| llvm::sys::path::append(FileBuf, *FileIt); |
| Dir = DirBuf; |
| File = FileBuf; |
| } |
| } else { |
| Dir = CurDir; |
| File = RemappedFile; |
| } |
| llvm::DIFile *F = DBuilder.createFile(File, Dir, CSInfo, Source); |
| DIFileCache[FileName.data()].reset(F); |
| return F; |
| } |
| |
| std::string CGDebugInfo::remapDIPath(StringRef Path) const { |
| if (DebugPrefixMap.empty()) |
| return Path.str(); |
| |
| SmallString<256> P = Path; |
| for (const auto &Entry : DebugPrefixMap) |
| if (llvm::sys::path::replace_path_prefix(P, Entry.first, Entry.second)) |
| break; |
| return P.str().str(); |
| } |
| |
| unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) { |
| if (Loc.isInvalid()) |
| return 0; |
| SourceManager &SM = CGM.getContext().getSourceManager(); |
| return SM.getPresumedLoc(Loc).getLine(); |
| } |
| |
| unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc, bool Force) { |
| // We may not want column information at all. |
| if (!Force && !CGM.getCodeGenOpts().DebugColumnInfo) |
| return 0; |
| |
| // If the location is invalid then use the current column. |
| if (Loc.isInvalid() && CurLoc.isInvalid()) |
| return 0; |
| SourceManager &SM = CGM.getContext().getSourceManager(); |
| PresumedLoc PLoc = SM.getPresumedLoc(Loc.isValid() ? Loc : CurLoc); |
| return PLoc.isValid() ? PLoc.getColumn() : 0; |
| } |
| |
| StringRef CGDebugInfo::getCurrentDirname() { |
| if (!CGM.getCodeGenOpts().DebugCompilationDir.empty()) |
| return CGM.getCodeGenOpts().DebugCompilationDir; |
| |
| if (!CWDName.empty()) |
| return CWDName; |
| SmallString<256> CWD; |
| llvm::sys::fs::current_path(CWD); |
| return CWDName = internString(CWD); |
| } |
| |
| void CGDebugInfo::CreateCompileUnit() { |
| SmallString<32> Checksum; |
| Optional<llvm::DIFile::ChecksumKind> CSKind; |
| Optional<llvm::DIFile::ChecksumInfo<StringRef>> CSInfo; |
| |
| // Should we be asking the SourceManager for the main file name, instead of |
| // accepting it as an argument? This just causes the main file name to |
| // mismatch with source locations and create extra lexical scopes or |
| // mismatched debug info (a CU with a DW_AT_file of "-", because that's what |
| // the driver passed, but functions/other things have DW_AT_file of "<stdin>" |
| // because that's what the SourceManager says) |
| |
| // Get absolute path name. |
| SourceManager &SM = CGM.getContext().getSourceManager(); |
| std::string MainFileName = CGM.getCodeGenOpts().MainFileName; |
| if (MainFileName.empty()) |
| MainFileName = "<stdin>"; |
| |
| // The main file name provided via the "-main-file-name" option contains just |
| // the file name itself with no path information. This file name may have had |
| // a relative path, so we look into the actual file entry for the main |
| // file to determine the real absolute path for the file. |
| std::string MainFileDir; |
| if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) { |
| MainFileDir = std::string(MainFile->getDir()->getName()); |
| if (!llvm::sys::path::is_absolute(MainFileName)) { |
| llvm::SmallString<1024> MainFileDirSS(MainFileDir); |
| llvm::sys::path::append(MainFileDirSS, MainFileName); |
| MainFileName = |
| std::string(llvm::sys::path::remove_leading_dotslash(MainFileDirSS)); |
| } |
| // If the main file name provided is identical to the input file name, and |
| // if the input file is a preprocessed source, use the module name for |
| // debug info. The module name comes from the name specified in the first |
| // linemarker if the input is a preprocessed source. |
| if (MainFile->getName() == MainFileName && |
| FrontendOptions::getInputKindForExtension( |
| MainFile->getName().rsplit('.').second) |
| .isPreprocessed()) |
| MainFileName = CGM.getModule().getName().str(); |
| |
| CSKind = computeChecksum(SM.getMainFileID(), Checksum); |
| } |
| |
| llvm::dwarf::SourceLanguage LangTag; |
| const LangOptions &LO = CGM.getLangOpts(); |
| if (LO.CPlusPlus) { |
| if (LO.ObjC) |
| LangTag = llvm::dwarf::DW_LANG_ObjC_plus_plus; |
| else if (LO.CPlusPlus14 && (!CGM.getCodeGenOpts().DebugStrictDwarf || |
| CGM.getCodeGenOpts().DwarfVersion >= 5)) |
| LangTag = llvm::dwarf::DW_LANG_C_plus_plus_14; |
| else if (LO.CPlusPlus11 && (!CGM.getCodeGenOpts().DebugStrictDwarf || |
| CGM.getCodeGenOpts().DwarfVersion >= 5)) |
| LangTag = llvm::dwarf::DW_LANG_C_plus_plus_11; |
| else |
| LangTag = llvm::dwarf::DW_LANG_C_plus_plus; |
| } else if (LO.ObjC) { |
| LangTag = llvm::dwarf::DW_LANG_ObjC; |
| } else if (LO.OpenCL && (!CGM.getCodeGenOpts().DebugStrictDwarf || |
| CGM.getCodeGenOpts().DwarfVersion >= 5)) { |
| LangTag = llvm::dwarf::DW_LANG_OpenCL; |
| } else if (LO.RenderScript) { |
| LangTag = llvm::dwarf::DW_LANG_GOOGLE_RenderScript; |
| } else if (LO.C99) { |
| LangTag = llvm::dwarf::DW_LANG_C99; |
| } else { |
| LangTag = llvm::dwarf::DW_LANG_C89; |
| } |
| |
| std::string Producer = getClangFullVersion(); |
| |
| // Figure out which version of the ObjC runtime we have. |
| unsigned RuntimeVers = 0; |
| if (LO.ObjC) |
| RuntimeVers = LO.ObjCRuntime.isNonFragile() ? 2 : 1; |
| |
| llvm::DICompileUnit::DebugEmissionKind EmissionKind; |
| switch (DebugKind) { |
| case codegenoptions::NoDebugInfo: |
| case codegenoptions::LocTrackingOnly: |
| EmissionKind = llvm::DICompileUnit::NoDebug; |
| break; |
| case codegenoptions::DebugLineTablesOnly: |
| EmissionKind = llvm::DICompileUnit::LineTablesOnly; |
| break; |
| case codegenoptions::DebugDirectivesOnly: |
| EmissionKind = llvm::DICompileUnit::DebugDirectivesOnly; |
| break; |
| case codegenoptions::DebugInfoConstructor: |
| case codegenoptions::LimitedDebugInfo: |
| case codegenoptions::FullDebugInfo: |
| case codegenoptions::UnusedTypeInfo: |
| EmissionKind = llvm::DICompileUnit::FullDebug; |
| break; |
| } |
| |
| uint64_t DwoId = 0; |
| auto &CGOpts = CGM.getCodeGenOpts(); |
| // The DIFile used by the CU is distinct from the main source |
| // file. Its directory part specifies what becomes the |
| // DW_AT_comp_dir (the compilation directory), even if the source |
| // file was specified with an absolute path. |
| if (CSKind) |
| CSInfo.emplace(*CSKind, Checksum); |
| llvm::DIFile *CUFile = DBuilder.createFile( |
| remapDIPath(MainFileName), remapDIPath(getCurrentDirname()), CSInfo, |
| getSource(SM, SM.getMainFileID())); |
| |
| StringRef Sysroot, SDK; |
| if (CGM.getCodeGenOpts().getDebuggerTuning() == llvm::DebuggerKind::LLDB) { |
| Sysroot = CGM.getHeaderSearchOpts().Sysroot; |
| auto B = llvm::sys::path::rbegin(Sysroot); |
| auto E = llvm::sys::path::rend(Sysroot); |
| auto It = std::find_if(B, E, [](auto SDK) { return SDK.endswith(".sdk"); }); |
| if (It != E) |
| SDK = *It; |
| } |
| |
| // Create new compile unit. |
| TheCU = DBuilder.createCompileUnit( |
| LangTag, CUFile, CGOpts.EmitVersionIdentMetadata ? Producer : "", |
| LO.Optimize || CGOpts.PrepareForLTO || CGOpts.PrepareForThinLTO, |
| CGOpts.DwarfDebugFlags, RuntimeVers, CGOpts.SplitDwarfFile, EmissionKind, |
| DwoId, CGOpts.SplitDwarfInlining, CGOpts.DebugInfoForProfiling, |
| CGM.getTarget().getTriple().isNVPTX() |
| ? llvm::DICompileUnit::DebugNameTableKind::None |
| : static_cast<llvm::DICompileUnit::DebugNameTableKind>( |
| CGOpts.DebugNameTable), |
| CGOpts.DebugRangesBaseAddress, remapDIPath(Sysroot), SDK); |
| } |
| |
| llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { |
| llvm::dwarf::TypeKind Encoding; |
| StringRef BTName; |
| switch (BT->getKind()) { |
| #define BUILTIN_TYPE(Id, SingletonId) |
| #define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id: |
| #include "clang/AST/BuiltinTypes.def" |
| case BuiltinType::Dependent: |
| llvm_unreachable("Unexpected builtin type"); |
| case BuiltinType::NullPtr: |
| return DBuilder.createNullPtrType(); |
| case BuiltinType::Void: |
| return nullptr; |
| case BuiltinType::ObjCClass: |
| if (!ClassTy) |
| ClassTy = |
| DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, |
| "objc_class", TheCU, TheCU->getFile(), 0); |
| return ClassTy; |
| case BuiltinType::ObjCId: { |
| // typedef struct objc_class *Class; |
| // typedef struct objc_object { |
| // Class isa; |
| // } *id; |
| |
| if (ObjTy) |
| return ObjTy; |
| |
| if (!ClassTy) |
| ClassTy = |
| DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, |
| "objc_class", TheCU, TheCU->getFile(), 0); |
| |
| unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy); |
| |
| auto *ISATy = DBuilder.createPointerType(ClassTy, Size); |
| |
| ObjTy = DBuilder.createStructType(TheCU, "objc_object", TheCU->getFile(), 0, |
| 0, 0, llvm::DINode::FlagZero, nullptr, |
| llvm::DINodeArray()); |
| |
| DBuilder.replaceArrays( |
| ObjTy, DBuilder.getOrCreateArray(&*DBuilder.createMemberType( |
| ObjTy, "isa", TheCU->getFile(), 0, Size, 0, 0, |
| llvm::DINode::FlagZero, ISATy))); |
| return ObjTy; |
| } |
| case BuiltinType::ObjCSel: { |
| if (!SelTy) |
| SelTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, |
| "objc_selector", TheCU, |
| TheCU->getFile(), 0); |
| return SelTy; |
| } |
| |
| #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ |
| case BuiltinType::Id: \ |
| return getOrCreateStructPtrType("opencl_" #ImgType "_" #Suffix "_t", \ |
| SingletonId); |
| #include "clang/Basic/OpenCLImageTypes.def" |
| case BuiltinType::OCLSampler: |
| return getOrCreateStructPtrType("opencl_sampler_t", OCLSamplerDITy); |
| case BuiltinType::OCLEvent: |
| return getOrCreateStructPtrType("opencl_event_t", OCLEventDITy); |
| case BuiltinType::OCLClkEvent: |
| return getOrCreateStructPtrType("opencl_clk_event_t", OCLClkEventDITy); |
| case BuiltinType::OCLQueue: |
| return getOrCreateStructPtrType("opencl_queue_t", OCLQueueDITy); |
| case BuiltinType::OCLReserveID: |
| return getOrCreateStructPtrType("opencl_reserve_id_t", OCLReserveIDDITy); |
| #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ |
| case BuiltinType::Id: \ |
| return getOrCreateStructPtrType("opencl_" #ExtType, Id##Ty); |
| #include "clang/Basic/OpenCLExtensionTypes.def" |
| |
| #define SVE_TYPE(Name, Id, SingletonId) case BuiltinType::Id: |
| #include "clang/Basic/AArch64SVEACLETypes.def" |
| { |
| ASTContext::BuiltinVectorTypeInfo Info = |
| CGM.getContext().getBuiltinVectorTypeInfo(BT); |
| unsigned NumElemsPerVG = (Info.EC.getKnownMinValue() * Info.NumVectors) / 2; |
| |
| // Debuggers can't extract 1bit from a vector, so will display a |
| // bitpattern for svbool_t instead. |
| if (Info.ElementType == CGM.getContext().BoolTy) { |
| NumElemsPerVG /= 8; |
| Info.ElementType = CGM.getContext().UnsignedCharTy; |
| } |
| |
| auto *LowerBound = |
| llvm::ConstantAsMetadata::get(llvm::ConstantInt::getSigned( |
| llvm::Type::getInt64Ty(CGM.getLLVMContext()), 0)); |
| SmallVector<int64_t, 9> Expr( |
| {llvm::dwarf::DW_OP_constu, NumElemsPerVG, llvm::dwarf::DW_OP_bregx, |
| /* AArch64::VG */ 46, 0, llvm::dwarf::DW_OP_mul, |
| llvm::dwarf::DW_OP_constu, 1, llvm::dwarf::DW_OP_minus}); |
| auto *UpperBound = DBuilder.createExpression(Expr); |
| |
| llvm::Metadata *Subscript = DBuilder.getOrCreateSubrange( |
| /*count*/ nullptr, LowerBound, UpperBound, /*stride*/ nullptr); |
| llvm::DINodeArray SubscriptArray = DBuilder.getOrCreateArray(Subscript); |
| llvm::DIType *ElemTy = |
| getOrCreateType(Info.ElementType, TheCU->getFile()); |
| auto Align = getTypeAlignIfRequired(BT, CGM.getContext()); |
| return DBuilder.createVectorType(/*Size*/ 0, Align, ElemTy, |
| SubscriptArray); |
| } |
| // It doesn't make sense to generate debug info for PowerPC MMA vector types. |
| // So we return a safe type here to avoid generating an error. |
| #define PPC_VECTOR_TYPE(Name, Id, size) \ |
| case BuiltinType::Id: |
| #include "clang/Basic/PPCTypes.def" |
| return CreateType(cast<const BuiltinType>(CGM.getContext().IntTy)); |
| |
| #define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id: |
| #include "clang/Basic/RISCVVTypes.def" |
| { |
| ASTContext::BuiltinVectorTypeInfo Info = |
| CGM.getContext().getBuiltinVectorTypeInfo(BT); |
| |
| unsigned ElementCount = Info.EC.getKnownMinValue(); |
| unsigned SEW = CGM.getContext().getTypeSize(Info.ElementType); |
| |
| bool Fractional = false; |
| unsigned LMUL; |
| unsigned FixedSize = ElementCount * SEW; |
| if (Info.ElementType == CGM.getContext().BoolTy) { |
| // Mask type only occupies one vector register. |
| LMUL = 1; |
| } else if (FixedSize < 64) { |
| // In RVV scalable vector types, we encode 64 bits in the fixed part. |
| Fractional = true; |
| LMUL = 64 / FixedSize; |
| } else { |
| LMUL = FixedSize / 64; |
| } |
| |
| // Element count = (VLENB / SEW) x LMUL |
| SmallVector<int64_t, 9> Expr( |
| // The DW_OP_bregx operation has two operands: a register which is |
| // specified by an unsigned LEB128 number, followed by a signed LEB128 |
| // offset. |
| {llvm::dwarf::DW_OP_bregx, // Read the contents of a register. |
| 4096 + 0xC22, // RISC-V VLENB CSR register. |
| 0, // Offset for DW_OP_bregx. It is dummy here. |
| llvm::dwarf::DW_OP_constu, |
| SEW / 8, // SEW is in bits. |
| llvm::dwarf::DW_OP_div, llvm::dwarf::DW_OP_constu, LMUL}); |
| if (Fractional) |
| Expr.push_back(llvm::dwarf::DW_OP_div); |
| else |
| Expr.push_back(llvm::dwarf::DW_OP_mul); |
| |
| auto *LowerBound = |
| llvm::ConstantAsMetadata::get(llvm::ConstantInt::getSigned( |
| llvm::Type::getInt64Ty(CGM.getLLVMContext()), 0)); |
| auto *UpperBound = DBuilder.createExpression(Expr); |
| llvm::Metadata *Subscript = DBuilder.getOrCreateSubrange( |
| /*count*/ nullptr, LowerBound, UpperBound, /*stride*/ nullptr); |
| llvm::DINodeArray SubscriptArray = DBuilder.getOrCreateArray(Subscript); |
| llvm::DIType *ElemTy = |
| getOrCreateType(Info.ElementType, TheCU->getFile()); |
| |
| auto Align = getTypeAlignIfRequired(BT, CGM.getContext()); |
| return DBuilder.createVectorType(/*Size=*/0, Align, ElemTy, |
| SubscriptArray); |
| } |
| case BuiltinType::UChar: |
| case BuiltinType::Char_U: |
| Encoding = llvm::dwarf::DW_ATE_unsigned_char; |
| break; |
| case BuiltinType::Char_S: |
| case BuiltinType::SChar: |
| Encoding = llvm::dwarf::DW_ATE_signed_char; |
| break; |
| case BuiltinType::Char8: |
| case BuiltinType::Char16: |
| case BuiltinType::Char32: |
| Encoding = llvm::dwarf::DW_ATE_UTF; |
| break; |
| case BuiltinType::UShort: |
| case BuiltinType::UInt: |
| case BuiltinType::UInt128: |
| case BuiltinType::ULong: |
| case BuiltinType::WChar_U: |
| case BuiltinType::ULongLong: |
| Encoding = llvm::dwarf::DW_ATE_unsigned; |
| break; |
| case BuiltinType::Short: |
| case BuiltinType::Int: |
| case BuiltinType::Int128: |
| case BuiltinType::Long: |
| case BuiltinType::WChar_S: |
| case BuiltinType::LongLong: |
| Encoding = llvm::dwarf::DW_ATE_signed; |
| break; |
| case BuiltinType::Bool: |
| Encoding = llvm::dwarf::DW_ATE_boolean; |
| break; |
| case BuiltinType::Half: |
| case BuiltinType::Float: |
| case BuiltinType::LongDouble: |
| case BuiltinType::Float16: |
| case BuiltinType::BFloat16: |
| case BuiltinType::Float128: |
| case BuiltinType::Double: |
| case BuiltinType::Ibm128: |
| // FIXME: For targets where long double, __ibm128 and __float128 have the |
| // same size, they are currently indistinguishable in the debugger without |
| // some special treatment. However, there is currently no consensus on |
| // encoding and this should be updated once a DWARF encoding exists for |
| // distinct floating point types of the same size. |
| Encoding = llvm::dwarf::DW_ATE_float; |
| break; |
| case BuiltinType::ShortAccum: |
| case BuiltinType::Accum: |
| case BuiltinType::LongAccum: |
| case BuiltinType::ShortFract: |
| case BuiltinType::Fract: |
| case BuiltinType::LongFract: |
| case BuiltinType::SatShortFract: |
| case BuiltinType::SatFract: |
| case BuiltinType::SatLongFract: |
| case BuiltinType::SatShortAccum: |
| case BuiltinType::SatAccum: |
| case BuiltinType::SatLongAccum: |
| Encoding = llvm::dwarf::DW_ATE_signed_fixed; |
| break; |
| case BuiltinType::UShortAccum: |
| case BuiltinType::UAccum: |
| case BuiltinType::ULongAccum: |
| case BuiltinType::UShortFract: |
| case BuiltinType::UFract: |
| case BuiltinType::ULongFract: |
| case BuiltinType::SatUShortAccum: |
| case BuiltinType::SatUAccum: |
| case BuiltinType::SatULongAccum: |
| case BuiltinType::SatUShortFract: |
| case BuiltinType::SatUFract: |
| case BuiltinType::SatULongFract: |
| Encoding = llvm::dwarf::DW_ATE_unsigned_fixed; |
| break; |
| } |
| |
| BTName = BT->getName(CGM.getLangOpts()); |
| // Bit size and offset of the type. |
| uint64_t Size = CGM.getContext().getTypeSize(BT); |
| return DBuilder.createBasicType(BTName, Size, Encoding); |
| } |
| |
| llvm::DIType *CGDebugInfo::CreateType(const AutoType *Ty) { |
| return DBuilder.createUnspecifiedType("auto"); |
| } |
| |
| llvm::DIType *CGDebugInfo::CreateType(const ExtIntType *Ty) { |
| |
| StringRef Name = Ty->isUnsigned() ? "unsigned _ExtInt" : "_ExtInt"; |
| llvm::dwarf::TypeKind Encoding = Ty->isUnsigned() |
| ? llvm::dwarf::DW_ATE_unsigned |
| : llvm::dwarf::DW_ATE_signed; |
| |
| return DBuilder.createBasicType(Name, CGM.getContext().getTypeSize(Ty), |
| Encoding); |
| } |
| |
| llvm::DIType *CGDebugInfo::CreateType(const ComplexType *Ty) { |
| // Bit size and offset of the type. |
| llvm::dwarf::TypeKind Encoding = llvm::dwarf::DW_ATE_complex_float; |
| if (Ty->isComplexIntegerType()) |
| Encoding = llvm::dwarf::DW_ATE_lo_user; |
| |
| uint64_t Size = CGM.getContext().getTypeSize(Ty); |
| return DBuilder.createBasicType("complex", Size, Encoding); |
| } |
| |
| static void stripUnusedQualifiers(Qualifiers &Q) { |
| // Ignore these qualifiers for now. |
| Q.removeObjCGCAttr(); |
| Q.removeAddressSpace(); |
| Q.removeObjCLifetime(); |
| Q.removeUnaligned(); |
| } |
| |
| static llvm::dwarf::Tag getNextQualifier(Qualifiers &Q) { |
| if (Q.hasConst()) { |
| Q.removeConst(); |
| return llvm::dwarf::DW_TAG_const_type; |
| } |
| if (Q.hasVolatile()) { |
| Q.removeVolatile(); |
| return llvm::dwarf::DW_TAG_volatile_type; |
| } |
| if (Q.hasRestrict()) { |
| Q.removeRestrict(); |
| return llvm::dwarf::DW_TAG_restrict_type; |
| } |
| return (llvm::dwarf::Tag)0; |
| } |
| |
| // Strip MacroQualifiedTypeLoc and AttributedTypeLoc |
| // as their corresponding types will be ignored |
| // during code generation. Stripping them allows |
| // to maintain proper TypeLoc for a given type |
| // during code generation. |
| static TypeLoc StripMacroAttributed(TypeLoc TL) { |
| if (!TL) |
| return TL; |
| |
| while (true) { |
| if (auto MTL = TL.getAs<MacroQualifiedTypeLoc>()) |
| TL = MTL.getInnerLoc(); |
| else if (auto ATL = TL.getAs<AttributedTypeLoc>()) |
| TL = ATL.getModifiedLoc(); |
| else |
| break; |
| } |
| return TL; |
| } |
| |
| llvm::DIType *CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DIFile *Unit, |
| TypeLoc TL) { |
| QualifierCollector Qc; |
| const Type *T = Qc.strip(Ty); |
| |
| stripUnusedQualifiers(Qc); |
| |
| // We will create one Derived type for one qualifier and recurse to handle any |
| // additional ones. |
| llvm::dwarf::Tag Tag = getNextQualifier(Qc); |
| if (!Tag) { |
| assert(Qc.empty() && "Unknown type qualifier for debug info"); |
| return getOrCreateType(QualType(T, 0), Unit); |
| } |
| |
| QualType NextTy = Qc.apply(CGM.getContext(), T); |
| TypeLoc NextTL; |
| if (NextTy.hasQualifiers()) |
| NextTL = TL; |
| else if (TL) { |
| if (auto QTL = TL.getAs<QualifiedTypeLoc>()) |
| NextTL = StripMacroAttributed(QTL.getNextTypeLoc()); |
| } |
| auto *FromTy = getOrCreateType(NextTy, Unit, NextTL); |
| |
| // No need to fill in the Name, Line, Size, Alignment, Offset in case of |
| // CVR derived types. |
| return DBuilder.createQualifiedType(Tag, FromTy); |
| } |
| |
| llvm::DIType *CGDebugInfo::CreateQualifiedType(const FunctionProtoType *F, |
| llvm::DIFile *Unit) { |
| FunctionProtoType::ExtProtoInfo EPI = F->getExtProtoInfo(); |
| Qualifiers &Q = EPI.TypeQuals; |
| stripUnusedQualifiers(Q); |
| |
| // We will create one Derived type for one qualifier and recurse to handle any |
| // additional ones. |
| llvm::dwarf::Tag Tag = getNextQualifier(Q); |
| if (!Tag) { |
| assert(Q.empty() && "Unknown type qualifier for debug info"); |
| return nullptr; |
| } |
| |
| auto *FromTy = |
| getOrCreateType(CGM.getContext().getFunctionType(F->getReturnType(), |
| F->getParamTypes(), EPI), |
| Unit); |
| |
| // No need to fill in the Name, Line, Size, Alignment, Offset in case of |
| // CVR derived types. |
| return DBuilder.createQualifiedType(Tag, FromTy); |
| } |
| |
| llvm::DIType *CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty, |
| llvm::DIFile *Unit) { |
| |
| // The frontend treats 'id' as a typedef to an ObjCObjectType, |
| // whereas 'id<protocol>' is treated as an ObjCPointerType. For the |
| // debug info, we want to emit 'id' in both cases. |
| if (Ty->isObjCQualifiedIdType()) |
| return getOrCreateType(CGM.getContext().getObjCIdType(), Unit); |
| |
| return CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty, |
| Ty->getPointeeType(), Unit); |
| } |
| |
| llvm::DIType *CGDebugInfo::CreateType(const PointerType *Ty, llvm::DIFile *Unit, |
| TypeLoc TL) { |
| return CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty, |
| Ty->getPointeeType(), Unit, TL); |
| } |
| |
| /// \return whether a C++ mangling exists for the type defined by TD. |
| static bool hasCXXMangling(const TagDecl *TD, llvm::DICompileUnit *TheCU) { |
| switch (TheCU->getSourceLanguage()) { |
| case llvm::dwarf::DW_LANG_C_plus_plus: |
| case llvm::dwarf::DW_LANG_C_plus_plus_11: |
| case llvm::dwarf::DW_LANG_C_plus_plus_14: |
| return true; |
| case llvm::dwarf::DW_LANG_ObjC_plus_plus: |
| return isa<CXXRecordDecl>(TD) || isa<EnumDecl>(TD); |
| default: |
| return false; |
| } |
| } |
| |
| // Determines if the debug info for this tag declaration needs a type |
| // identifier. The purpose of the unique identifier is to deduplicate type |
| // information for identical types across TUs. Because of the C++ one definition |
| // rule (ODR), it is valid to assume that the type is defined the same way in |
| // every TU and its debug info is equivalent. |
| // |
| // C does not have the ODR, and it is common for codebases to contain multiple |
| // different definitions of a struct with the same name in different TUs. |
| // Therefore, if the type doesn't have a C++ mangling, don't give it an |
| // identifer. Type information in C is smaller and simpler than C++ type |
| // information, so the increase in debug info size is negligible. |
| // |
| // If the type is not externally visible, it should be unique to the current TU, |
| // and should not need an identifier to participate in type deduplication. |
| // However, when emitting CodeView, the format internally uses these |
| // unique type name identifers for references between debug info. For example, |
| // the method of a class in an anonymous namespace uses the identifer to refer |
| // to its parent class. The Microsoft C++ ABI attempts to provide unique names |
| // for such types, so when emitting CodeView, always use identifiers for C++ |
| // types. This may create problems when attempting to emit CodeView when the MS |
| // C++ ABI is not in use. |
| static bool needsTypeIdentifier(const TagDecl *TD, CodeGenModule &CGM, |
| llvm::DICompileUnit *TheCU) { |
| // We only add a type identifier for types with C++ name mangling. |
| if (!hasCXXMangling(TD, TheCU)) |
| return false; |
| |
| // Externally visible types with C++ mangling need a type identifier. |
| if (TD->isExternallyVisible()) |
| return true; |
| |
| // CodeView types with C++ mangling need a type identifier. |
| if (CGM.getCodeGenOpts().EmitCodeView) |
| return true; |
| |
| return false; |
| } |
| |
| // Returns a unique type identifier string if one exists, or an empty string. |
| static SmallString<256> getTypeIdentifier(const TagType *Ty, CodeGenModule &CGM, |
| llvm::DICompileUnit *TheCU) { |
| SmallString<256> Identifier; |
| const TagDecl *TD = Ty->getDecl(); |
| |
| if (!needsTypeIdentifier(TD, CGM, TheCU)) |
| return Identifier; |
| if (const auto *RD = dyn_cast<CXXRecordDecl>(TD)) |
| if (RD->getDefinition()) |
| if (RD->isDynamicClass() && |
| CGM.getVTableLinkage(RD) == llvm::GlobalValue::ExternalLinkage) |
| return Identifier; |
| |
| // TODO: This is using the RTTI name. Is there a better way to get |
| // a unique string for a type? |
| llvm::raw_svector_ostream Out(Identifier); |
| CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(QualType(Ty, 0), Out); |
| return Identifier; |
| } |
| |
| /// \return the appropriate DWARF tag for a composite type. |
| static llvm::dwarf::Tag getTagForRecord(const RecordDecl *RD) { |
| llvm::dwarf::Tag Tag; |
| if (RD->isStruct() || RD->isInterface()) |
| Tag = llvm::dwarf::DW_TAG_structure_type; |
| else if (RD->isUnion()) |
| Tag = llvm::dwarf::DW_TAG_union_type; |
| else { |
| // FIXME: This could be a struct type giving a default visibility different |
| // than C++ class type, but needs llvm metadata changes first. |
| assert(RD->isClass()); |
| Tag = llvm::dwarf::DW_TAG_class_type; |
| } |
| return Tag; |
| } |
| |
| llvm::DICompositeType * |
| CGDebugInfo::getOrCreateRecordFwdDecl(const RecordType *Ty, |
| llvm::DIScope *Ctx) { |
| const RecordDecl *RD = Ty->getDecl(); |
| if (llvm::DIType *T = getTypeOrNull(CGM.getContext().getRecordType(RD))) |
| return cast<llvm::DICompositeType>(T); |
| llvm::DIFile *DefUnit = getOrCreateFile(RD->getLocation()); |
| const unsigned Line = |
| getLineNumber(RD->getLocation().isValid() ? RD->getLocation() : CurLoc); |
| StringRef RDName = getClassName(RD); |
| |
| uint64_t Size = 0; |
| uint32_t Align = 0; |
| |
| const RecordDecl *D = RD->getDefinition(); |
| if (D && D->isCompleteDefinition()) |
| Size = CGM.getContext().getTypeSize(Ty); |
| |
| llvm::DINode::DIFlags Flags = llvm::DINode::FlagFwdDecl; |
| |
| // Add flag to nontrivial forward declarations. To be consistent with MSVC, |
| // add the flag if a record has no definition because we don't know whether |
| // it will be trivial or not. |
| if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) |
| if (!CXXRD->hasDefinition() || |
| (CXXRD->hasDefinition() && !CXXRD->isTrivial())) |
| Flags |= llvm::DINode::FlagNonTrivial; |
| |
| // Create the type. |
| SmallString<256> Identifier; |
| // Don't include a linkage name in line tables only. |
| if (CGM.getCodeGenOpts().hasReducedDebugInfo()) |
| Identifier = getTypeIdentifier(Ty, CGM, TheCU); |
| llvm::DICompositeType *RetTy = DBuilder.createReplaceableCompositeType( |
| getTagForRecord(RD), RDName, Ctx, DefUnit, Line, 0, Size, Align, Flags, |
| Identifier); |
| if (CGM.getCodeGenOpts().DebugFwdTemplateParams) |
| if (auto *TSpecial = dyn_cast<ClassTemplateSpecializationDecl>(RD)) |
| DBuilder.replaceArrays(RetTy, llvm::DINodeArray(), |
| CollectCXXTemplateParams(TSpecial, DefUnit)); |
| ReplaceMap.emplace_back( |
| std::piecewise_construct, std::make_tuple(Ty), |
| std::make_tuple(static_cast<llvm::Metadata *>(RetTy))); |
| return RetTy; |
| } |
| |
| llvm::DIType *CGDebugInfo::CreatePointerLikeType(llvm::dwarf::Tag Tag, |
| const Type *Ty, |
| QualType PointeeTy, |
| llvm::DIFile *Unit, |
| TypeLoc TL) { |
| // Bit size, align and offset of the type. |
| // Size is always the size of a pointer. We can't use getTypeSize here |
| // because that does not return the correct value for references. |
| unsigned AddressSpace = CGM.getContext().getTargetAddressSpace(PointeeTy); |
| uint64_t Size = CGM.getTarget().getPointerWidth(AddressSpace); |
| auto Align = getTypeAlignIfRequired(Ty, CGM.getContext()); |
| Optional<unsigned> DWARFAddressSpace = |
| CGM.getTarget().getDWARFAddressSpace(AddressSpace); |
| |
| llvm::DINodeArray Annotations = nullptr; |
| TypeLoc NextTL; |
| if (TL) { |
| SmallVector<llvm::Metadata *, 4> Annots; |
| NextTL = TL.getNextTypeLoc(); |
| if (NextTL) { |
| // Traverse all MacroQualifiedTypeLoc, QualifiedTypeLoc and |
| // AttributedTypeLoc type locations so we can collect |
| // BTFTypeTag attributes for this pointer. |
| while (true) { |
| if (auto MTL = NextTL.getAs<MacroQualifiedTypeLoc>()) { |
| NextTL = MTL.getInnerLoc(); |
| } else if (auto QTL = NextTL.getAs<QualifiedTypeLoc>()) { |
| NextTL = QTL.getNextTypeLoc(); |
| } else if (auto ATL = NextTL.getAs<AttributedTypeLoc>()) { |
| if (const auto *A = ATL.getAttrAs<BTFTypeTagAttr>()) { |
| StringRef BTFTypeTag = A->getBTFTypeTag(); |
| if (!BTFTypeTag.empty()) { |
| llvm::Metadata *Ops[2] = { |
| llvm::MDString::get(CGM.getLLVMContext(), |
| StringRef("btf_type_tag")), |
| llvm::MDString::get(CGM.getLLVMContext(), BTFTypeTag)}; |
| Annots.insert(Annots.begin(), |
| llvm::MDNode::get(CGM.getLLVMContext(), Ops)); |
| } |
| } |
| NextTL = ATL.getModifiedLoc(); |
| } else { |
| break; |
| } |
| } |
| } |
| |
| NextTL = StripMacroAttributed(TL.getNextTypeLoc()); |
| if (Annots.size() > 0) |
| Annotations = DBuilder.getOrCreateArray(Annots); |
| } |
| |
| if (Tag == llvm::dwarf::DW_TAG_reference_type || |
| Tag == llvm::dwarf::DW_TAG_rvalue_reference_type) |
| return DBuilder.createReferenceType(Tag, getOrCreateType(PointeeTy, Unit), |
| Size, Align, DWARFAddressSpace); |
| else |
| return DBuilder.createPointerType(getOrCreateType(PointeeTy, Unit, NextTL), |
| Size, Align, DWARFAddressSpace, |
| StringRef(), Annotations); |
| } |
| |
| llvm::DIType *CGDebugInfo::getOrCreateStructPtrType(StringRef Name, |
| llvm::DIType *&Cache) { |
| if (Cache) |
| return Cache; |
| Cache = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, Name, |
| TheCU, TheCU->getFile(), 0); |
| unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy); |
| Cache = DBuilder.createPointerType(Cache, Size); |
| return Cache; |
| } |
| |
| uint64_t CGDebugInfo::collectDefaultElementTypesForBlockPointer( |
| const BlockPointerType *Ty, llvm::DIFile *Unit, llvm::DIDerivedType *DescTy, |
| unsigned LineNo, SmallVectorImpl<llvm::Metadata *> &EltTys) { |
| QualType FType; |
| |
| // Advanced by calls to CreateMemberType in increments of FType, then |
| // returned as the overall size of the default elements. |
| uint64_t FieldOffset = 0; |
| |
| // Blocks in OpenCL have unique constraints which make the standard fields |
| // redundant while requiring size and align fields for enqueue_kernel. See |
| // initializeForBlockHeader in CGBlocks.cpp |
| if (CGM.getLangOpts().OpenCL) { |
| FType = CGM.getContext().IntTy; |
| EltTys.push_back(CreateMemberType(Unit, FType, "__size", &FieldOffset)); |
| EltTys.push_back(CreateMemberType(Unit, FType, "__align", &FieldOffset)); |
| } else { |
| FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); |
| EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset)); |
| FType = CGM.getContext().IntTy; |
| EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset)); |
| EltTys.push_back(CreateMemberType(Unit, FType, "__reserved", &FieldOffset)); |
| FType = CGM.getContext().getPointerType(Ty->getPointeeType()); |
| EltTys.push_back(CreateMemberType(Unit, FType, "__FuncPtr", &FieldOffset)); |
| FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); |
| uint64_t FieldSize = CGM.getContext().getTypeSize(Ty); |
| uint32_t FieldAlign = CGM.getContext().getTypeAlign(Ty); |
| EltTys.push_back(DBuilder.createMemberType( |
| Unit, "__descriptor", nullptr, LineNo, FieldSize, FieldAlign, |
| FieldOffset, llvm::DINode::FlagZero, DescTy)); |
| FieldOffset += FieldSize; |
| } |
| |
| return FieldOffset; |
| } |
| |
| llvm::DIType *CGDebugInfo::CreateType(const BlockPointerType *Ty, |
| llvm::DIFile *Unit) { |
| SmallVector<llvm::Metadata *, 8> EltTys; |
| QualType FType; |
| uint64_t FieldOffset; |
| llvm::DINodeArray Elements; |
| |
| FieldOffset = 0; |
| FType = CGM.getContext().UnsignedLongTy; |
| EltTys.push_back(CreateMemberType(Unit, FType, "reserved", &FieldOffset)); |
| EltTys.push_back(CreateMemberType(Unit, FType, "Size", &FieldOffset)); |
| |
| Elements = DBuilder.getOrCreateArray(EltTys); |
| EltTys.clear(); |
| |
| llvm::DINode::DIFlags Flags = llvm::DINode::FlagAppleBlock; |
| |
| auto *EltTy = |
| DBuilder.createStructType(Unit, "__block_descriptor", nullptr, 0, |
| FieldOffset, 0, Flags, nullptr, Elements); |
| |
| // Bit size, align and offset of the type. |
| uint64_t Size = CGM.getContext().getTypeSize(Ty); |
| |
| auto *DescTy = DBuilder.createPointerType(EltTy, Size); |
| |
| FieldOffset = collectDefaultElementTypesForBlockPointer(Ty, Unit, DescTy, |
| 0, EltTys); |
| |
| Elements = DBuilder.getOrCreateArray(EltTys); |
| |
| // The __block_literal_generic structs are marked with a special |
| // DW_AT_APPLE_BLOCK attribute and are an implementation detail only |
| // the debugger needs to know about. To allow type uniquing, emit |
| // them without a name or a location. |
| EltTy = DBuilder.createStructType(Unit, "", nullptr, 0, FieldOffset, 0, |
| Flags, nullptr, Elements); |
| |
| return DBuilder.createPointerType(EltTy, Size); |
| } |
| |
| llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty, |
| llvm::DIFile *Unit) { |
| assert(Ty->isTypeAlias()); |
| llvm::DIType *Src = getOrCreateType(Ty->getAliasedType(), Unit); |
| |
| auto *AliasDecl = |
| cast<TypeAliasTemplateDecl>(Ty->getTemplateName().getAsTemplateDecl()) |
| ->getTemplatedDecl(); |
| |
| if (AliasDecl->hasAttr<NoDebugAttr>()) |
| return Src; |
| |
| SmallString<128> NS; |
| llvm::raw_svector_ostream OS(NS); |
| Ty->getTemplateName().print(OS, getPrintingPolicy(), |
| TemplateName::Qualified::None); |
| printTemplateArgumentList(OS, Ty->template_arguments(), getPrintingPolicy()); |
| |
| SourceLocation Loc = AliasDecl->getLocation(); |
| return DBuilder.createTypedef(Src, OS.str(), getOrCreateFile(Loc), |
| getLineNumber(Loc), |
| getDeclContextDescriptor(AliasDecl)); |
| } |
| |
| llvm::DIType *CGDebugInfo::CreateType(const TypedefType *Ty, |
| llvm::DIFile *Unit) { |
| TypeLoc TL; |
| if (const TypeSourceInfo *TSI = Ty->getDecl()->getTypeSourceInfo()) |
| TL = TSI->getTypeLoc(); |
| llvm::DIType *Underlying = |
| getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit, TL); |
| |
| if (Ty->getDecl()->hasAttr<NoDebugAttr>()) |
| return Underlying; |
| |
| // We don't set size information, but do specify where the typedef was |
| // declared. |
| SourceLocation Loc = Ty->getDecl()->getLocation(); |
| |
| uint32_t Align = getDeclAlignIfRequired(Ty->getDecl(), CGM.getContext()); |
| // Typedefs are derived from some other type. |
| llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(Ty->getDecl()); |
| return DBuilder.createTypedef(Underlying, Ty->getDecl()->getName(), |
| getOrCreateFile(Loc), getLineNumber(Loc), |
| getDeclContextDescriptor(Ty->getDecl()), Align, |
| Annotations); |
| } |
| |
| static unsigned getDwarfCC(CallingConv CC) { |
| switch (CC) { |
| case CC_C: |
| // Avoid emitting DW_AT_calling_convention if the C convention was used. |
| return 0; |
| |
| case CC_X86StdCall: |
| return llvm::dwarf::DW_CC_BORLAND_stdcall; |
| case CC_X86FastCall: |
| return llvm::dwarf::DW_CC_BORLAND_msfastcall; |
| case CC_X86ThisCall: |
| return llvm::dwarf::DW_CC_BORLAND_thiscall; |
| case CC_X86VectorCall: |
| return llvm::dwarf::DW_CC_LLVM_vectorcall; |
| case CC_X86Pascal: |
| return llvm::dwarf::DW_CC_BORLAND_pascal; |
| case CC_Win64: |
| return llvm::dwarf::DW_CC_LLVM_Win64; |
| case CC_X86_64SysV: |
| return llvm::dwarf::DW_CC_LLVM_X86_64SysV; |
| case CC_AAPCS: |
| case CC_AArch64VectorCall: |
| return llvm::dwarf::DW_CC_LLVM_AAPCS; |
| case CC_AAPCS_VFP: |
| return llvm::dwarf::DW_CC_LLVM_AAPCS_VFP; |
| case CC_IntelOclBicc: |
| return llvm::dwarf::DW_CC_LLVM_IntelOclBicc; |
| case CC_SpirFunction: |
| return llvm::dwarf::DW_CC_LLVM_SpirFunction; |
| case CC_OpenCLKernel: |
| return llvm::dwarf::DW_CC_LLVM_OpenCLKernel; |
| case CC_Swift: |
| return llvm::dwarf::DW_CC_LLVM_Swift; |
| case CC_SwiftAsync: |
| // [FIXME: swiftasynccc] Update to SwiftAsync once LLVM support lands. |
| return llvm::dwarf::DW_CC_LLVM_Swift; |
| case CC_PreserveMost: |
| return llvm::dwarf::DW_CC_LLVM_PreserveMost; |
| case CC_PreserveAll: |
| return llvm::dwarf::DW_CC_LLVM_PreserveAll; |
| case CC_X86RegCall: |
| return llvm::dwarf::DW_CC_LLVM_X86RegCall; |
| } |
| return 0; |
| } |
| |
| static llvm::DINode::DIFlags getRefFlags(const FunctionProtoType *Func) { |
| llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; |
| if (Func->getExtProtoInfo().RefQualifier == RQ_LValue) |
| Flags |= llvm::DINode::FlagLValueReference; |
| if (Func->getExtProtoInfo().RefQualifier == RQ_RValue) |
| Flags |= llvm::DINode::FlagRValueReference; |
| return Flags; |
| } |
| |
| llvm::DIType *CGDebugInfo::CreateType(const FunctionType *Ty, |
| llvm::DIFile *Unit, TypeLoc TL) { |
| const auto *FPT = dyn_cast<FunctionProtoType>(Ty); |
| if (FPT) { |
| if (llvm::DIType *QTy = CreateQualifiedType(FPT, Unit)) |
| return QTy; |
| } |
| |
| // Create the type without any qualifiers |
| |
| SmallVector<llvm::Metadata *, 16> EltTys; |
| |
| // Add the result type at least. |
| TypeLoc RetTL; |
| if (TL) { |
| if (auto FTL = TL.getAs<FunctionTypeLoc>()) |
| RetTL = FTL.getReturnLoc(); |
| } |
| EltTys.push_back(getOrCreateType(Ty->getReturnType(), Unit, RetTL)); |
| |
| llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; |
| // Set up remainder of arguments if there is a prototype. |
| // otherwise emit it as a variadic function. |
| if (!FPT) { |
| EltTys.push_back(DBuilder.createUnspecifiedParameter()); |
| } else { |
| Flags = getRefFlags(FPT); |
| bool DoneWithTL = false; |
| if (TL) { |
| if (auto FTL = TL.getAs<FunctionTypeLoc>()) { |
| DoneWithTL = true; |
| unsigned Idx = 0; |
| unsigned FTL_NumParams = FTL.getNumParams(); |
| for (const QualType &ParamType : FPT->param_types()) { |
| TypeLoc ParamTL; |
| if (Idx < FTL_NumParams) { |
| if (ParmVarDecl *Param = FTL.getParam(Idx)) { |
| if (const TypeSourceInfo *TSI = Param->getTypeSourceInfo()) |
| ParamTL = TSI->getTypeLoc(); |
| } |
| } |
| EltTys.push_back(getOrCreateType(ParamType, Unit, ParamTL)); |
| Idx++; |
| } |
| } |
| } |
| |
| if (!DoneWithTL) { |
| for (const QualType &ParamType : FPT->param_types()) |
| EltTys.push_back(getOrCreateType(ParamType, Unit)); |
| } |
| if (FPT->isVariadic()) |
| EltTys.push_back(DBuilder.createUnspecifiedParameter()); |
| } |
| |
| llvm::DITypeRefArray EltTypeArray = DBuilder.getOrCreateTypeArray(EltTys); |
| llvm::DIType *F = DBuilder.createSubroutineType( |
| EltTypeArray, Flags, getDwarfCC(Ty->getCallConv())); |
| return F; |
| } |
| |
| /// Convert an AccessSpecifier into the corresponding DINode flag. |
| /// As an optimization, return 0 if the access specifier equals the |
| /// default for the containing type. |
| static llvm::DINode::DIFlags getAccessFlag(AccessSpecifier Access, |
| const RecordDecl *RD) { |
| AccessSpecifier Default = clang::AS_none; |
| if (RD && RD->isClass()) |
| Default = clang::AS_private; |
| else if (RD && (RD->isStruct() || RD->isUnion())) |
| Default = clang::AS_public; |
| |
| if (Access == Default) |
| return llvm::DINode::FlagZero; |
| |
| switch (Access) { |
| case clang::AS_private: |
| return llvm::DINode::FlagPrivate; |
| case clang::AS_protected: |
| return llvm::DINode::FlagProtected; |
| case clang::AS_public: |
| return llvm::DINode::FlagPublic; |
| case clang::AS_none: |
| return llvm::DINode::FlagZero; |
| } |
| llvm_unreachable("unexpected access enumerator"); |
| } |
| |
| llvm::DIType *CGDebugInfo::createBitFieldType(const FieldDecl *BitFieldDecl, |
| llvm::DIScope *RecordTy, |
| const RecordDecl *RD) { |
| StringRef Name = BitFieldDecl->getName(); |
| QualType Ty = BitFieldDecl->getType(); |
| SourceLocation Loc = BitFieldDecl->getLocation(); |
| llvm::DIFile *VUnit = getOrCreateFile(Loc); |
| llvm::DIType *DebugType = getOrCreateType(Ty, VUnit); |
| |
| // Get the location for the field. |
| llvm::DIFile *File = getOrCreateFile(Loc); |
| unsigned Line = getLineNumber(Loc); |
| |
| const CGBitFieldInfo &BitFieldInfo = |
| CGM.getTypes().getCGRecordLayout(RD).getBitFieldInfo(BitFieldDecl); |
| uint64_t SizeInBits = BitFieldInfo.Size; |
| assert(SizeInBits > 0 && "found named 0-width bitfield"); |
| uint64_t StorageOffsetInBits = |
| CGM.getContext().toBits(BitFieldInfo.StorageOffset); |
| uint64_t Offset = BitFieldInfo.Offset; |
| // The bit offsets for big endian machines are reversed for big |
| // endian target, compensate for that as the DIDerivedType requires |
| // un-reversed offsets. |
| if (CGM.getDataLayout().isBigEndian()) |
| Offset = BitFieldInfo.StorageSize - BitFieldInfo.Size - Offset; |
| uint64_t OffsetInBits = StorageOffsetInBits + Offset; |
| llvm::DINode::DIFlags Flags = getAccessFlag(BitFieldDecl->getAccess(), RD); |
| llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(BitFieldDecl); |
| return DBuilder.createBitFieldMemberType( |
| RecordTy, Name, File, Line, SizeInBits, OffsetInBits, StorageOffsetInBits, |
| Flags, DebugType, Annotations); |
| } |
| |
| llvm::DIType * |
| CGDebugInfo::createFieldType(StringRef name, QualType type, SourceLocation loc, |
| AccessSpecifier AS, uint64_t offsetInBits, |
| uint32_t AlignInBits, llvm::DIFile *tunit, |
| llvm::DIScope *scope, const RecordDecl *RD, |
| llvm::DINodeArray Annotations, TypeLoc TL) { |
| llvm::DIType *debugType = getOrCreateType(type, tunit, TL); |
| |
| // Get the location for the field. |
| llvm::DIFile *file = getOrCreateFile(loc); |
| const unsigned line = getLineNumber(loc.isValid() ? loc : CurLoc); |
| |
| uint64_t SizeInBits = 0; |
| auto Align = AlignInBits; |
| if (!type->isIncompleteArrayType()) { |
| TypeInfo TI = CGM.getContext().getTypeInfo(type); |
| SizeInBits = TI.Width; |
| if (!Align) |
| Align = getTypeAlignIfRequired(type, CGM.getContext()); |
| } |
| |
| llvm::DINode::DIFlags flags = getAccessFlag(AS, RD); |
| return DBuilder.createMemberType(scope, name, file, line, SizeInBits, Align, |
| offsetInBits, flags, debugType, Annotations); |
| } |
| |
| void CGDebugInfo::CollectRecordLambdaFields( |
| const CXXRecordDecl *CXXDecl, SmallVectorImpl<llvm::Metadata *> &elements, |
| llvm::DIType *RecordTy) { |
| // For C++11 Lambdas a Field will be the same as a Capture, but the Capture |
| // has the name and the location of the variable so we should iterate over |
| // both concurrently. |
| const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(CXXDecl); |
| RecordDecl::field_iterator Field = CXXDecl->field_begin(); |
| unsigned fieldno = 0; |
| for (CXXRecordDecl::capture_const_iterator I = CXXDecl->captures_begin(), |
| E = CXXDecl->captures_end(); |
| I != E; ++I, ++Field, ++fieldno) { |
| const LambdaCapture &C = *I; |
| if (C.capturesVariable()) { |
| SourceLocation Loc = C.getLocation(); |
| assert(!Field->isBitField() && "lambdas don't have bitfield members!"); |
| VarDecl *V = C.getCapturedVar(); |
| StringRef VName = V->getName(); |
| llvm::DIFile *VUnit = getOrCreateFile(Loc); |
| auto Align = getDeclAlignIfRequired(V, CGM.getContext()); |
| llvm::DIType *FieldType = createFieldType( |
| VName, Field->getType(), Loc, Field->getAccess(), |
| layout.getFieldOffset(fieldno), Align, VUnit, RecordTy, CXXDecl); |
| elements.push_back(FieldType); |
| } else if (C.capturesThis()) { |
| // TODO: Need to handle 'this' in some way by probably renaming the |
| // this of the lambda class and having a field member of 'this' or |
| // by using AT_object_pointer for the function and having that be |
| // used as 'this' for semantic references. |
| FieldDecl *f = *Field; |
| llvm::DIFile *VUnit = getOrCreateFile(f->getLocation()); |
| QualType type = f->getType(); |
| llvm::DIType *fieldType = createFieldType( |
| "this", type, f->getLocation(), f->getAccess(), |
| layout.getFieldOffset(fieldno), VUnit, RecordTy, CXXDecl); |
| |
| elements.push_back(fieldType); |
| } |
| } |
| } |
| |
| llvm::DIDerivedType * |
| CGDebugInfo::CreateRecordStaticField(const VarDecl *Var, llvm::DIType *RecordTy, |
| const RecordDecl *RD) { |
| // Create the descriptor for the static variable, with or without |
| // constant initializers. |
| Var = Var->getCanonicalDecl(); |
| llvm::DIFile *VUnit = getOrCreateFile(Var->getLocation()); |
| llvm::DIType *VTy = getOrCreateType(Var->getType(), VUnit); |
| |
| unsigned LineNumber = getLineNumber(Var->getLocation()); |
| StringRef VName = Var->getName(); |
| llvm::Constant *C = nullptr; |
| if (Var->getInit()) { |
| const APValue *Value = Var->evaluateValue(); |
| if (Value) { |
| if (Value->isInt()) |
| C = llvm::ConstantInt::get(CGM.getLLVMContext(), Value->getInt()); |
| if (Value->isFloat()) |
| C = llvm::ConstantFP::get(CGM.getLLVMContext(), Value->getFloat()); |
| } |
| } |
| |
| llvm::DINode::DIFlags Flags = getAccessFlag(Var->getAccess(), RD); |
| auto Align = getDeclAlignIfRequired(Var, CGM.getContext()); |
| llvm::DIDerivedType *GV = DBuilder.createStaticMemberType( |
| RecordTy, VName, VUnit, LineNumber, VTy, Flags, C, Align); |
| StaticDataMemberCache[Var->getCanonicalDecl()].reset(GV); |
| return GV; |
| } |
| |
| void CGDebugInfo::CollectRecordNormalField( |
| const FieldDecl *field, uint64_t OffsetInBits, llvm::DIFile *tunit, |
| SmallVectorImpl<llvm::Metadata *> &elements, llvm::DIType *RecordTy, |
| const RecordDecl *RD) { |
| StringRef name = field->getName(); |
| QualType type = field->getType(); |
| |
| // Ignore unnamed fields unless they're anonymous structs/unions. |
| if (name.empty() && !type->isRecordType()) |
| return; |
| |
| llvm::DIType *FieldType; |
| if (field->isBitField()) { |
| FieldType = createBitFieldType(field, RecordTy, RD); |
| } else { |
| auto Align = getDeclAlignIfRequired(field, CGM.getContext()); |
| llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(field); |
| TypeLoc TL; |
| if (const TypeSourceInfo *TSI = field->getTypeSourceInfo()) |
| TL = TSI->getTypeLoc(); |
| FieldType = createFieldType(name, type, field->getLocation(), |
| field->getAccess(), OffsetInBits, Align, tunit, |
| RecordTy, RD, Annotations, TL); |
| } |
| |
| elements.push_back(FieldType); |
| } |
| |
| void CGDebugInfo::CollectRecordNestedType( |
| const TypeDecl *TD, SmallVectorImpl<llvm::Metadata *> &elements) { |
| QualType Ty = CGM.getContext().getTypeDeclType(TD); |
| // Injected class names are not considered nested records. |
| if (isa<InjectedClassNameType>(Ty)) |
| return; |
| SourceLocation Loc = TD->getLocation(); |
| llvm::DIType *nestedType = getOrCreateType(Ty, getOrCreateFile(Loc)); |
| elements.push_back(nestedType); |
| } |
| |
| void CGDebugInfo::CollectRecordFields( |
| const RecordDecl *record, llvm::DIFile *tunit, |
| SmallVectorImpl<llvm::Metadata *> &elements, |
| llvm::DICompositeType *RecordTy) { |
| const auto *CXXDecl = dyn_cast<CXXRecordDecl>(record); |
| |
| if (CXXDecl && CXXDecl->isLambda()) |
| CollectRecordLambdaFields(CXXDecl, elements, RecordTy); |
| else { |
| const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(record); |
| |
| // Field number for non-static fields. |
| unsigned fieldNo = 0; |
| |
| // Static and non-static members should appear in the same order as |
| // the corresponding declarations in the source program. |
| for (const auto *I : record->decls()) |
| if (const auto *V = dyn_cast<VarDecl>(I)) { |
| if (V->hasAttr<NoDebugAttr>()) |
| continue; |
| |
| // Skip variable template specializations when emitting CodeView. MSVC |
| // doesn't emit them. |
| if (CGM.getCodeGenOpts().EmitCodeView && |
| isa<VarTemplateSpecializationDecl>(V)) |
| continue; |
| |
| if (isa<VarTemplatePartialSpecializationDecl>(V)) |
| continue; |
| |
| // Reuse the existing static member declaration if one exists |
| auto MI = StaticDataMemberCache.find(V->getCanonicalDecl()); |
| if (MI != StaticDataMemberCache.end()) { |
| assert(MI->second && |
| "Static data member declaration should still exist"); |
| elements.push_back(MI->second); |
| } else { |
| auto Field = CreateRecordStaticField(V, RecordTy, record); |
| elements.push_back(Field); |
| } |
| } else if (const auto *field = dyn_cast<FieldDecl>(I)) { |
| CollectRecordNormalField(field, layout.getFieldOffset(fieldNo), tunit, |
| elements, RecordTy, record); |
| |
| // Bump field number for next field. |
| ++fieldNo; |
| } else if (CGM.getCodeGenOpts().EmitCodeView) { |
| // Debug info for nested types is included in the member list only for |
| // CodeView. |
| if (const auto *nestedType = dyn_cast<TypeDecl>(I)) |
| if (!nestedType->isImplicit() && |
| nestedType->getDeclContext() == record) |
| CollectRecordNestedType(nestedType, elements); |
| } |
| } |
| } |
| |
| llvm::DISubroutineType * |
| CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method, |
| llvm::DIFile *Unit, bool decl) { |
| const FunctionProtoType *Func = Method->getType()->getAs<FunctionProtoType>(); |
| if (Method->isStatic()) |
| return cast_or_null<llvm::DISubroutineType>( |
| getOrCreateType(QualType(Func, 0), Unit)); |
| return getOrCreateInstanceMethodType(Method->getThisType(), Func, Unit, decl); |
| } |
| |
| llvm::DISubroutineType * |
| CGDebugInfo::getOrCreateInstanceMethodType(QualType ThisPtr, |
| const FunctionProtoType *Func, |
| llvm::DIFile *Unit, bool decl) { |
| FunctionProtoType::ExtProtoInfo EPI = Func->getExtProtoInfo(); |
| Qualifiers &Qc = EPI.TypeQuals; |
| Qc.removeConst(); |
| Qc.removeVolatile(); |
| Qc.removeRestrict(); |
| Qc.removeUnaligned(); |
| // Keep the removed qualifiers in sync with |
| // CreateQualifiedType(const FunctionPrototype*, DIFile *Unit) |
| // On a 'real' member function type, these qualifiers are carried on the type |
| // of the first parameter, not as separate DW_TAG_const_type (etc) decorator |
| // tags around them. (But, in the raw function types with qualifiers, they have |
| // to use wrapper types.) |
| |
| // Add "this" pointer. |
| const auto *OriginalFunc = cast<llvm::DISubroutineType>( |
| getOrCreateType(CGM.getContext().getFunctionType( |
| Func->getReturnType(), Func->getParamTypes(), EPI), |
| Unit)); |
| llvm::DITypeRefArray Args = OriginalFunc->getTypeArray(); |
| assert(Args.size() && "Invalid number of arguments!"); |
| |
| SmallVector<llvm::Metadata *, 16> Elts; |
| // First element is always return type. For 'void' functions it is NULL. |
| QualType temp = Func->getReturnType(); |
| if (temp->getTypeClass() == Type::Auto && decl) |
| Elts.push_back(CreateType(cast<AutoType>(temp))); |
| else |
| Elts.push_back(Args[0]); |
| |
| // "this" pointer is always first argument. |
| const CXXRecordDecl *RD = ThisPtr->getPointeeCXXRecordDecl(); |
| if (isa<ClassTemplateSpecializationDecl>(RD)) { |
| // Create pointer type directly in this case. |
| const PointerType *ThisPtrTy = cast<PointerType>(ThisPtr); |
| QualType PointeeTy = ThisPtrTy->getPointeeType(); |
| unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy); |
| uint64_t Size = CGM.getTarget().getPointerWidth(AS); |
| auto Align = getTypeAlignIfRequired(ThisPtrTy, CGM.getContext()); |
| llvm::DIType *PointeeType = getOrCreateType(PointeeTy, Unit); |
| llvm::DIType *ThisPtrType = |
| DBuilder.createPointerType(PointeeType, Size, Align); |
| TypeCache[ThisPtr.getAsOpaquePtr()].reset(ThisPtrType); |
| // TODO: This and the artificial type below are misleading, the |
| // types aren't artificial the argument is, but the current |
| // metadata doesn't represent that. |
| ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType); |
| Elts.push_back(ThisPtrType); |
| } else { |
| llvm::DIType *ThisPtrType = getOrCreateType(ThisPtr, Unit); |
| TypeCache[ThisPtr.getAsOpaquePtr()].reset(ThisPtrType); |
| ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType); |
| Elts.push_back(ThisPtrType); |
| } |
| |
| // Copy rest of the arguments. |
| for (unsigned i = 1, e = Args.size(); i != e; ++i) |
| Elts.push_back(Args[i]); |
| |
| llvm::DITypeRefArray EltTypeArray = DBuilder.getOrCreateTypeArray(Elts); |
| |
| return DBuilder.createSubroutineType(EltTypeArray, OriginalFunc->getFlags(), |
| getDwarfCC(Func->getCallConv())); |
| } |
| |
| /// isFunctionLocalClass - Return true if CXXRecordDecl is defined |
| /// inside a function. |
| static bool isFunctionLocalClass(const CXXRecordDecl *RD) { |
| if (const auto *NRD = dyn_cast<CXXRecordDecl>(RD->getDeclContext())) |
| return isFunctionLocalClass(NRD); |
| if (isa<FunctionDecl>(RD->getDeclContext())) |
| return true; |
| return false; |
| } |
| |
| llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction( |
| const CXXMethodDecl *Method, llvm::DIFile *Unit, llvm::DIType *RecordTy) { |
| bool IsCtorOrDtor = |
| isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method); |
| |
| StringRef MethodName = getFunctionName(Method); |
| llvm::DISubroutineType *MethodTy = getOrCreateMethodType(Method, Unit, true); |
| |
| // Since a single ctor/dtor corresponds to multiple functions, it doesn't |
| // make sense to give a single ctor/dtor a linkage name. |
| StringRef MethodLinkageName; |
| // FIXME: 'isFunctionLocalClass' seems like an arbitrary/unintentional |
| // property to use here. It may've been intended to model "is non-external |
| // type" but misses cases of non-function-local but non-external classes such |
| // as those in anonymous namespaces as well as the reverse - external types |
| // that are function local, such as those in (non-local) inline functions. |
| if (!IsCtorOrDtor && !isFunctionLocalClass(Method->getParent())) |
| MethodLinkageName = CGM.getMangledName(Method); |
| |
| // Get the location for the method. |
| llvm::DIFile *MethodDefUnit = nullptr; |
| unsigned MethodLine = 0; |
| if (!Method->isImplicit()) { |
| MethodDefUnit = getOrCreateFile(Method->getLocation()); |
| MethodLine = getLineNumber(Method->getLocation()); |
| } |
| |
| // Collect virtual method info. |
| llvm::DIType *ContainingType = nullptr; |
| unsigned VIndex = 0; |
| llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; |
| llvm::DISubprogram::DISPFlags SPFlags = llvm::DISubprogram::SPFlagZero; |
| int ThisAdjustment = 0; |
| |
| if (Method->isVirtual()) { |
| if (Method->isPure()) |
| SPFlags |= llvm::DISubprogram::SPFlagPureVirtual; |
| else |
| SPFlags |= llvm::DISubprogram::SPFlagVirtual; |
| |
| if (CGM.getTarget().getCXXABI().isItaniumFamily()) { |
| // It doesn't make sense to give a virtual destructor a vtable index, |
| // since a single destructor has two entries in the vtable. |
| if (!isa<CXXDestructorDecl>(Method)) |
| VIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(Method); |
| } else { |
| // Emit MS ABI vftable information. There is only one entry for the |
| // deleting dtor. |
| const auto *DD = dyn_cast<CXXDestructorDecl>(Method); |
| GlobalDecl GD = DD ? GlobalDecl(DD, Dtor_Deleting) : GlobalDecl(Method); |
| MethodVFTableLocation ML = |
| CGM.getMicrosoftVTableContext().getMethodVFTableLocation(GD); |
| VIndex = ML.Index; |
| |
| // CodeView only records the vftable offset in the class that introduces |
| // the virtual method. This is possible because, unlike Itanium, the MS |
| // C++ ABI does not include all virtual methods from non-primary bases in |
| // the vtable for the most derived class. For example, if C inherits from |
| // A and B, C's primary vftable will not include B's virtual methods. |
| if (Method->size_overridden_methods() == 0) |
| Flags |= llvm::DINode::FlagIntroducedVirtual; |
| |
| // The 'this' adjustment accounts for both the virtual and non-virtual |
| // portions of the adjustment. Presumably the debugger only uses it when |
| // it knows the dynamic type of an object. |
| ThisAdjustment = CGM.getCXXABI() |
| .getVirtualFunctionPrologueThisAdjustment(GD) |
| .getQuantity(); |
| } |
| ContainingType = RecordTy; |
| } |
| |
| // We're checking for deleted C++ special member functions |
| // [Ctors,Dtors, Copy/Move] |
| auto checkAttrDeleted = [&](const auto *Method) { |
| if (Method->getCanonicalDecl()->isDeleted()) |
| SPFlags |= llvm::DISubprogram::SPFlagDeleted; |
| }; |
| |
| switch (Method->getKind()) { |
| |
| case Decl::CXXConstructor: |
| case Decl::CXXDestructor: |
| checkAttrDeleted(Method); |
| break; |
| case Decl::CXXMethod: |
| if (Method->isCopyAssignmentOperator() || |
| Method->isMoveAssignmentOperator()) |
| checkAttrDeleted(Method); |
| break; |
| default: |
| break; |
| } |
| |
| if (Method->isNoReturn()) |
| Flags |= llvm::DINode::FlagNoReturn; |
| |
| if (Method->isStatic()) |
| Flags |= llvm::DINode::FlagStaticMember; |
| if (Method->isImplicit()) |
| Flags |= llvm::DINode::FlagArtificial; |
| Flags |= getAccessFlag(Method->getAccess(), Method->getParent()); |
| if (const auto *CXXC = dyn_cast<CXXConstructorDecl>(Method)) { |
| if (CXXC->isExplicit()) |
| Flags |= llvm::DINode::FlagExplicit; |
| } else if (const auto *CXXC = dyn_cast<CXXConversionDecl>(Method)) { |
| if (CXXC->isExplicit()) |
| Flags |= llvm::DINode::FlagExplicit; |
| } |
| if (Method->hasPrototype()) |
| Flags |= llvm::DINode::FlagPrototyped; |
| if (Method->getRefQualifier() == RQ_LValue) |
| Flags |= llvm::DINode::FlagLValueReference; |
| if (Method->getRefQualifier() == RQ_RValue) |
| Flags |= llvm::DINode::FlagRValueReference; |
| if (!Method->isExternallyVisible()) |
| SPFlags |= llvm::DISubprogram::SPFlagLocalToUnit; |
| if (CGM.getLangOpts().Optimize) |
| SPFlags |= llvm::DISubprogram::SPFlagOptimized; |
| |
| // In this debug mode, emit type info for a class when its constructor type |
| // info is emitted. |
| if (DebugKind == codegenoptions::DebugInfoConstructor) |
| if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(Method)) |
| completeUnusedClass(*CD->getParent()); |
| |
| llvm::DINodeArray TParamsArray = CollectFunctionTemplateParams(Method, Unit); |
| llvm::DISubprogram *SP = DBuilder.createMethod( |
| RecordTy, MethodName, MethodLinkageName, MethodDefUnit, MethodLine, |
| MethodTy, VIndex, ThisAdjustment, ContainingType, Flags, SPFlags, |
| TParamsArray.get()); |
| |
| SPCache[Method->getCanonicalDecl()].reset(SP); |
| |
| return SP; |
| } |
| |
| void CGDebugInfo::CollectCXXMemberFunctions( |
| const CXXRecordDecl *RD, llvm::DIFile *Unit, |
| SmallVectorImpl<llvm::Metadata *> &EltTys, llvm::DIType *RecordTy) { |
| |
| // Since we want more than just the individual member decls if we |
| // have templated functions iterate over every declaration to gather |
| // the functions. |
| for (const auto *I : RD->decls()) { |
| const auto *Method = dyn_cast<CXXMethodDecl>(I); |
| // If the member is implicit, don't add it to the member list. This avoids |
| // the member being added to type units by LLVM, while still allowing it |
| // to be emitted into the type declaration/reference inside the compile |
| // unit. |
| // Ditto 'nodebug' methods, for consistency with CodeGenFunction.cpp. |
| // FIXME: Handle Using(Shadow?)Decls here to create |
| // DW_TAG_imported_declarations inside the class for base decls brought into |
| // derived classes. GDB doesn't seem to notice/leverage these when I tried |
| // it, so I'm not rushing to fix this. (GCC seems to produce them, if |
| // referenced) |
| if (!Method || Method->isImplicit() || Method->hasAttr<NoDebugAttr>()) |
| continue; |
| |
| if (Method->getType()->castAs<FunctionProtoType>()->getContainedAutoType()) |
| continue; |
| |
| // Reuse the existing member function declaration if it exists. |
| // It may be associated with the declaration of the type & should be |
| // reused as we're building the definition. |
| // |
| // This situation can arise in the vtable-based debug info reduction where |
| // implicit members are emitted in a non-vtable TU. |
| auto MI = SPCache.find(Method->getCanonicalDecl()); |
| EltTys.push_back(MI == SPCache.end() |
| ? CreateCXXMemberFunction(Method, Unit, RecordTy) |
| : static_cast<llvm::Metadata *>(MI->second)); |
| } |
| } |
| |
| void CGDebugInfo::CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile *Unit, |
| SmallVectorImpl<llvm::Metadata *> &EltTys, |
| llvm::DIType *RecordTy) { |
| llvm::DenseSet<CanonicalDeclPtr<const CXXRecordDecl>> SeenTypes; |
| CollectCXXBasesAux(RD, Unit, EltTys, RecordTy, RD->bases(), SeenTypes, |
| llvm::DINode::FlagZero); |
| |
| // If we are generating CodeView debug info, we also need to emit records for |
| // indirect virtual base classes. |
| if (CGM.getCodeGenOpts().EmitCodeView) { |
| CollectCXXBasesAux(RD, Unit, EltTys, RecordTy, RD->vbases(), SeenTypes, |
| llvm::DINode::FlagIndirectVirtualBase); |
| } |
| } |
| |
| void CGDebugInfo::CollectCXXBasesAux( |
| const CXXRecordDecl *RD, llvm::DIFile *Unit, |
| SmallVectorImpl<llvm::Metadata *> &EltTys, llvm::DIType *RecordTy, |
| const CXXRecordDecl::base_class_const_range &Bases, |
| llvm::DenseSet<CanonicalDeclPtr<const CXXRecordDecl>> &SeenTypes, |
| llvm::DINode::DIFlags StartingFlags) { |
| const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); |
| for (const auto &BI : Bases) { |
| const auto *Base = |
| cast<CXXRecordDecl>(BI.getType()->castAs<RecordType>()->getDecl()); |
| if (!SeenTypes.insert(Base).second) |
| continue; |
| auto *BaseTy = getOrCreateType(BI.getType(), Unit); |
| llvm::DINode::DIFlags BFlags = StartingFlags; |
| uint64_t BaseOffset; |
| uint32_t VBPtrOffset = 0; |
| |
| if (BI.isVirtual()) { |
| if (CGM.getTarget().getCXXABI().isItaniumFamily()) { |
| // virtual base offset offset is -ve. The code generator emits dwarf |
| // expression where it expects +ve number. |
| BaseOffset = 0 - CGM.getItaniumVTableContext() |
| .getVirtualBaseOffsetOffset(RD, Base) |
| .getQuantity(); |
| } else { |
| // In the MS ABI, store the vbtable offset, which is analogous to the |
| // vbase offset offset in Itanium. |
| BaseOffset = |
| 4 * CGM.getMicrosoftVTableContext().getVBTableIndex(RD, Base); |
| VBPtrOffset = CGM.getContext() |
| .getASTRecordLayout(RD) |
| .getVBPtrOffset() |
| .getQuantity(); |
| } |
| BFlags |= llvm::DINode::FlagVirtual; |
| } else |
| BaseOffset = CGM.getContext().toBits(RL.getBaseClassOffset(Base)); |
| // FIXME: Inconsistent units for BaseOffset. It is in bytes when |
| // BI->isVirtual() and bits when not. |
| |
| BFlags |= getAccessFlag(BI.getAccessSpecifier(), RD); |
| llvm::DIType *DTy = DBuilder.createInheritance(RecordTy, BaseTy, BaseOffset, |
| VBPtrOffset, BFlags); |
| EltTys.push_back(DTy); |
| } |
| } |
| |
| llvm::DINodeArray |
| CGDebugInfo::CollectTemplateParams(Optional<TemplateArgs> OArgs, |
| llvm::DIFile *Unit) { |
| if (!OArgs) |
| return llvm::DINodeArray(); |
| TemplateArgs &Args = *OArgs; |
| SmallVector<llvm::Metadata *, 16> TemplateParams; |
| for (unsigned i = 0, e = Args.Args.size(); i != e; ++i) { |
| const TemplateArgument &TA = Args.Args[i]; |
| StringRef Name; |
| bool defaultParameter = false; |
| if (Args.TList) |
| Name = Args.TList->getParam(i)->getName(); |
| switch (TA.getKind()) { |
| case TemplateArgument::Type: { |
| llvm::DIType *TTy = getOrCreateType(TA.getAsType(), Unit); |
| |
| if (Args.TList) |
| if (auto *templateType = |
| dyn_cast_or_null<TemplateTypeParmDecl>(Args.TList->getParam(i))) |
| if (templateType->hasDefaultArgument()) |
| defaultParameter = |
| templateType->getDefaultArgument() == TA.getAsType(); |
| |
| TemplateParams.push_back(DBuilder.createTemplateTypeParameter( |
| TheCU, Name, TTy, defaultParameter)); |
| |
| } break; |
| case TemplateArgument::Integral: { |
| llvm::DIType *TTy = getOrCreateType(TA.getIntegralType(), Unit); |
| if (Args.TList && CGM.getCodeGenOpts().DwarfVersion >= 5) |
| if (auto *templateType = dyn_cast_or_null<NonTypeTemplateParmDecl>( |
| Args.TList->getParam(i))) |
| if (templateType->hasDefaultArgument() && |
| !templateType->getDefaultArgument()->isValueDependent()) |
| defaultParameter = llvm::APSInt::isSameValue( |
| templateType->getDefaultArgument()->EvaluateKnownConstInt( |
| CGM.getContext()), |
| TA.getAsIntegral()); |
| |
| TemplateParams.push_back(DBuilder.createTemplateValueParameter( |
| TheCU, Name, TTy, defaultParameter, |
| llvm::ConstantInt::get(CGM.getLLVMContext(), TA.getAsIntegral()))); |
| } break; |
| case TemplateArgument::Declaration: { |
| const ValueDecl *D = TA.getAsDecl(); |
| QualType T = TA.getParamTypeForDecl().getDesugaredType(CGM.getContext()); |
| llvm::DIType *TTy = getOrCreateType(T, Unit); |
| llvm::Constant *V = nullptr; |
| // Skip retrieve the value if that template parameter has cuda device |
| // attribute, i.e. that value is not available at the host side. |
| if (!CGM.getLangOpts().CUDA || CGM.getLangOpts().CUDAIsDevice || |
| !D->hasAttr<CUDADeviceAttr>()) { |
| const CXXMethodDecl *MD; |
| // Variable pointer template parameters have a value that is the address |
| // of the variable. |
| if (const auto *VD = dyn_cast<VarDecl>(D)) |
| V = CGM.GetAddrOfGlobalVar(VD); |
| // Member function pointers have special support for building them, |
| // though this is currently unsupported in LLVM CodeGen. |
| else if ((MD = dyn_cast<CXXMethodDecl>(D)) && MD->isInstance()) |
| V = CGM.getCXXABI().EmitMemberFunctionPointer(MD); |
| else if (const auto *FD = dyn_cast<FunctionDecl>(D)) |
| V = CGM.GetAddrOfFunction(FD); |
| // Member data pointers have special handling too to compute the fixed |
| // offset within the object. |
| else if (const auto *MPT = |
| dyn_cast<MemberPointerType>(T.getTypePtr())) { |
| // These five lines (& possibly the above member function pointer |
| // handling) might be able to be refactored to use similar code in |
| // CodeGenModule::getMemberPointerConstant |
| uint64_t fieldOffset = CGM.getContext().getFieldOffset(D); |
| CharUnits chars = |
| CGM.getContext().toCharUnitsFromBits((int64_t)fieldOffset); |
| V = CGM.getCXXABI().EmitMemberDataPointer(MPT, chars); |
| } else if (const auto *GD = dyn_cast<MSGuidDecl>(D)) { |
| V = CGM.GetAddrOfMSGuidDecl(GD).getPointer(); |
| } else if (const auto *TPO = dyn_cast<TemplateParamObjectDecl>(D)) { |
| if (T->isRecordType()) |
| V = ConstantEmitter(CGM).emitAbstract( |
| SourceLocation(), TPO->getValue(), TPO->getType()); |
| else |
| V = CGM.GetAddrOfTemplateParamObject(TPO).getPointer(); |
| } |
| assert(V && "Failed to find template parameter pointer"); |
| V = V->stripPointerCasts(); |
| } |
| TemplateParams.push_back(DBuilder.createTemplateValueParameter( |
| TheCU, Name, TTy, defaultParameter, cast_or_null<llvm::Constant>(V))); |
| } break; |
| case TemplateArgument::NullPtr: { |
| QualType T = TA.getNullPtrType(); |
| llvm::DIType *TTy = getOrCreateType(T, Unit); |
| llvm::Constant *V = nullptr; |
| // Special case member data pointer null values since they're actually -1 |
| // instead of zero. |
| if (const auto *MPT = dyn_cast<MemberPointerType>(T.getTypePtr())) |
| // But treat member function pointers as simple zero integers because |
| // it's easier than having a special case in LLVM's CodeGen. If LLVM |
| // CodeGen grows handling for values of non-null member function |
| // pointers then perhaps we could remove this special case and rely on |
| // EmitNullMemberPointer for member function pointers. |
| if (MPT->isMemberDataPointer()) |
| V = CGM.getCXXABI().EmitNullMemberPointer(MPT); |
| if (!V) |
| V = llvm::ConstantInt::get(CGM.Int8Ty, 0); |
| TemplateParams.push_back(DBuilder.createTemplateValueParameter( |
| TheCU, Name, TTy, defaultParameter, V)); |
| } break; |
| case TemplateArgument::Template: { |
| std::string QualName; |
| llvm::raw_string_ostream OS(QualName); |
| TA.getAsTemplate().getAsTemplateDecl()->printQualifiedName( |
| OS, getPrintingPolicy()); |
| TemplateParams.push_back(DBuilder.createTemplateTemplateParameter( |
| TheCU, Name, nullptr, OS.str())); |
| break; |
| } |
| case TemplateArgument::Pack: |
| TemplateParams.push_back(DBuilder.createTemplateParameterPack( |
| TheCU, Name, nullptr, |
| CollectTemplateParams({{nullptr, TA.getPackAsArray()}}, Unit))); |
| break; |
| case TemplateArgument::Expression: { |
| const Expr *E = TA.getAsExpr(); |
| QualType T = E->getType(); |
| if (E->isGLValue()) |
| T = CGM.getContext().getLValueReferenceType(T); |
| llvm::Constant *V = ConstantEmitter(CGM).emitAbstract(E, T); |
| assert(V && "Expression in template argument isn't constant"); |
| llvm::DIType *TTy = getOrCreateType(T, Unit); |
| TemplateParams.push_back(DBuilder.createTemplateValueParameter( |
| TheCU, Name, TTy, defaultParameter, V->stripPointerCasts())); |
| } break; |
| // And the following should never occur: |
| case TemplateArgument::TemplateExpansion: |
| case TemplateArgument::Null: |
| llvm_unreachable( |
| "These argument types shouldn't exist in concrete types"); |
| } |
| } |
| return DBuilder.getOrCreateArray(TemplateParams); |
| } |
| |
| Optional<CGDebugInfo::TemplateArgs> |
| CGDebugInfo::GetTemplateArgs(const FunctionDecl *FD) const { |
| if (FD->getTemplatedKind() == |
| FunctionDecl::TK_FunctionTemplateSpecialization) { |
| const TemplateParameterList *TList = FD->getTemplateSpecializationInfo() |
| ->getTemplate() |
| ->getTemplateParameters(); |
| return {{TList, FD->getTemplateSpecializationArgs()->asArray()}}; |
| } |
| return None; |
| } |
| Optional<CGDebugInfo::TemplateArgs> |
| CGDebugInfo::GetTemplateArgs(const VarDecl *VD) const { |
| // Always get the full list of parameters, not just the ones from the |
| // specialization. A partial specialization may have fewer parameters than |
| // there are arguments. |
| auto *TS = dyn_cast<VarTemplateSpecializationDecl>(VD); |
| if (!TS) |
| return None; |
| VarTemplateDecl *T = TS->getSpecializedTemplate(); |
| const TemplateParameterList *TList = T->getTemplateParameters(); |
| auto TA = TS->getTemplateArgs().asArray(); |
| return {{TList, TA}}; |
| } |
| Optional<CGDebugInfo::TemplateArgs> |
| CGDebugInfo::GetTemplateArgs(const RecordDecl *RD) const { |
| if (auto *TSpecial = dyn_cast<ClassTemplateSpecializationDecl>(RD)) { |
| // Always get the full list of parameters, not just the ones from the |
| // specialization. A partial specialization may have fewer parameters than |
| // there are arguments. |
| TemplateParameterList *TPList = |
| TSpecial->getSpecializedTemplate()->getTemplateParameters(); |
| const TemplateArgumentList &TAList = TSpecial->getTemplateArgs(); |
| return {{TPList, TAList.asArray()}}; |
| } |
| return None; |
| } |
| |
| llvm::DINodeArray |
| CGDebugInfo::CollectFunctionTemplateParams(const FunctionDecl *FD, |
| llvm::DIFile *Unit) { |
| return CollectTemplateParams(GetTemplateArgs(FD), Unit); |
| } |
| |
| llvm::DINodeArray CGDebugInfo::CollectVarTemplateParams(const VarDecl *VL, |
| llvm::DIFile *Unit) { |
| return CollectTemplateParams(GetTemplateArgs(VL), Unit); |
| } |
| |
| llvm::DINodeArray CGDebugInfo::CollectCXXTemplateParams(const RecordDecl *RD, |
| llvm::DIFile *Unit) { |
| return CollectTemplateParams(GetTemplateArgs(RD), Unit); |
| } |
| |
| llvm::DINodeArray CGDebugInfo::CollectBTFDeclTagAnnotations(const Decl *D) { |
| if (!D->hasAttr<BTFDeclTagAttr>()) |
| return nullptr; |
| |
| SmallVector<llvm::Metadata *, 4> Annotations; |
| for (const auto *I : D->specific_attrs<BTFDeclTagAttr>()) { |
| llvm::Metadata *Ops[2] = { |
| llvm::MDString::get(CGM.getLLVMContext(), StringRef("btf_decl_tag")), |
| llvm::MDString::get(CGM.getLLVMContext(), I->getBTFDeclTag())}; |
| Annotations.push_back(llvm::MDNode::get(CGM.getLLVMContext(), Ops)); |
| } |
| return DBuilder.getOrCreateArray(Annotations); |
| } |
| |
| llvm::DIType *CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile *Unit) { |
| if (VTablePtrType) |
| return VTablePtrType; |
| |
| ASTContext &Context = CGM.getContext(); |
| |
| /* Function type */ |
| llvm::Metadata *STy = getOrCreateType(Context.IntTy, Unit); |
| llvm::DITypeRefArray SElements = DBuilder.getOrCreateTypeArray(STy); |
| llvm::DIType *SubTy = DBuilder.createSubroutineType(SElements); |
| unsigned Size = Context.getTypeSize(Context.VoidPtrTy); |
| unsigned VtblPtrAddressSpace = CGM.getTarget().getVtblPtrAddressSpace(); |
| Optional<unsigned> DWARFAddressSpace = |
| CGM.getTarget().getDWARFAddressSpace(VtblPtrAddressSpace); |
| |
| llvm::DIType *vtbl_ptr_type = DBuilder.createPointerType( |
| SubTy, Size, 0, DWARFAddressSpace, "__vtbl_ptr_type"); |
| VTablePtrType = DBuilder.createPointerType(vtbl_ptr_type, Size); |
| return VTablePtrType; |
| } |
| |
| StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) { |
| // Copy the gdb compatible name on the side and use its reference. |
| return internString("_vptr$", RD->getNameAsString()); |
| } |
| |
| StringRef CGDebugInfo::getDynamicInitializerName(const VarDecl *VD, |
| DynamicInitKind StubKind, |
| llvm::Function *InitFn) { |
| // If we're not emitting codeview, use the mangled name. For Itanium, this is |
| // arbitrary. |
| if (!CGM.getCodeGenOpts().EmitCodeView || |
| StubKind == DynamicInitKind::GlobalArrayDestructor) |
| return InitFn->getName(); |
| |
| // Print the normal qualified name for the variable, then break off the last |
| // NNS, and add the appropriate other text. Clang always prints the global |
| // variable name without template arguments, so we can use rsplit("::") and |
| // then recombine the pieces. |
| SmallString<128> QualifiedGV; |
| StringRef Quals; |
| StringRef GVName; |
| { |
| llvm::raw_svector_ostream OS(QualifiedGV); |
| VD->printQualifiedName(OS, getPrintingPolicy()); |
| std::tie(Quals, GVName) = OS.str().rsplit("::"); |
| if (GVName.empty()) |
| std::swap(Quals, GVName); |
| } |
| |
| SmallString<128> InitName; |
| llvm::raw_svector_ostream OS(InitName); |
| if (!Quals.empty()) |
| OS << Quals << "::"; |
| |
| switch (StubKind) { |
| case DynamicInitKind::NoStub: |
| case DynamicInitKind::GlobalArrayDestructor: |
| llvm_unreachable("not an initializer"); |
| case DynamicInitKind::Initializer: |
| OS << "`dynamic initializer for '"; |
| break; |
| case DynamicInitKind::AtExit: |
| OS << "`dynamic atexit destructor for '"; |
| break; |
| } |
| |
| OS << GVName; |
| |
| // Add any template specialization args. |
| if (const auto *VTpl = dyn_cast<VarTemplateSpecializationDecl>(VD)) { |
| printTemplateArgumentList(OS, VTpl->getTemplateArgs().asArray(), |
| getPrintingPolicy()); |
| } |
| |
| OS << '\''; |
| |
| return internString(OS.str()); |
| } |
| |
| void CGDebugInfo::CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile *Unit, |
| SmallVectorImpl<llvm::Metadata *> &EltTys) { |
| // If this class is not dynamic then there is not any vtable info to collect. |
| if (!RD->isDynamicClass()) |
| return; |
| |
| // Don't emit any vtable shape or vptr info if this class doesn't have an |
| // extendable vfptr. This can happen if the class doesn't have virtual |
| // methods, or in the MS ABI if those virtual methods only come from virtually |
| // inherited bases. |
| const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); |
| if (!RL.hasExtendableVFPtr()) |
| return; |
| |
| // CodeView needs to know how large the vtable of every dynamic class is, so |
| // emit a special named pointer type into the element list. The vptr type |
| // points to this type as well. |
| llvm::DIType *VPtrTy = nullptr; |
| bool NeedVTableShape = CGM.getCodeGenOpts().EmitCodeView && |
| CGM.getTarget().getCXXABI().isMicrosoft(); |
| if (NeedVTableShape) { |
| uint64_t PtrWidth = |
| CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy); |
| const VTableLayout &VFTLayout = |
| CGM.getMicrosoftVTableContext().getVFTableLayout(RD, CharUnits::Zero()); |
| unsigned VSlotCount = |
| VFTLayout.vtable_components().size() - CGM.getLangOpts().RTTIData; |
| unsigned VTableWidth = PtrWidth * VSlotCount; |
| unsigned VtblPtrAddressSpace = CGM.getTarget().getVtblPtrAddressSpace(); |
| Optional<unsigned> DWARFAddressSpace = |
| CGM.getTarget().getDWARFAddressSpace(VtblPtrAddressSpace); |
| |
| // Create a very wide void* type and insert it directly in the element list. |
| llvm::DIType *VTableType = DBuilder.createPointerType( |
| nullptr, VTableWidth, 0, DWARFAddressSpace, "__vtbl_ptr_type"); |
| EltTys.push_back(VTableType); |
| |
| // The vptr is a pointer to this special vtable type. |
| VPtrTy = DBuilder.createPointerType(VTableType, PtrWidth); |
| } |
| |
| // If there is a primary base then the artificial vptr member lives there. |
| if (RL.getPrimaryBase()) |
| return; |
| |
| if (!VPtrTy) |
| VPtrTy = getOrCreateVTablePtrType(Unit); |
| |
| unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy); |
| llvm::DIType *VPtrMember = |
| DBuilder.createMemberType(Unit, getVTableName(RD), Unit, 0, Size, 0, 0, |
| llvm::DINode::FlagArtificial, VPtrTy); |
| EltTys.push_back(VPtrMember); |
| } |
| |
| llvm::DIType *CGDebugInfo::getOrCreateRecordType(QualType RTy, |
| SourceLocation Loc) { |
| assert(CGM.getCodeGenOpts().hasReducedDebugInfo()); |
| llvm::DIType *T = getOrCreateType(RTy, getOrCreateFile(Loc)); |
| return T; |
| } |
| |
| llvm::DIType *CGDebugInfo::getOrCreateInterfaceType(QualType D, |
| SourceLocation Loc) { |
| return getOrCreateStandaloneType(D, Loc); |
| } |
| |
| llvm::DIType *CGDebugInfo::getOrCreateStandaloneType(QualType D, |
| SourceLocation Loc) { |
| assert(CGM.getCodeGenOpts().hasReducedDebugInfo()); |
| assert(!D.isNull() && "null type"); |
| llvm::DIType *T = getOrCreateType(D, getOrCreateFile(Loc)); |
| assert(T && "could not create debug info for type"); |
| |
| RetainedTypes.push_back(D.getAsOpaquePtr()); |
| return T; |
| } |
| |
| void CGDebugInfo::addHeapAllocSiteMetadata(llvm::CallBase *CI, |
| QualType AllocatedTy, |
| SourceLocation Loc) { |
| if (CGM.getCodeGenOpts().getDebugInfo() <= |
| codegenoptions::DebugLineTablesOnly) |
| return; |
| llvm::MDNode *node; |
| if (AllocatedTy->isVoidType()) |
| node = llvm::MDNode::get(CGM.getLLVMContext(), None); |
| else |
| node = getOrCreateType(AllocatedTy, getOrCreateFile(Loc)); |
| |
| CI->setMetadata("heapallocsite", node); |
| } |
| |
| void CGDebugInfo::completeType(const EnumDecl *ED) { |
| if (DebugKind <= codegenoptions::DebugLineTablesOnly) |
| return; |
| QualType Ty = CGM.getContext().getEnumType(ED); |
| void *TyPtr = Ty.getAsOpaquePtr(); |
| auto I = TypeCache.find(TyPtr); |
| if (I == TypeCache.end() || !cast<llvm::DIType>(I->second)->isForwardDecl()) |
| return; |
| llvm::DIType *Res = CreateTypeDefinition(Ty->castAs<EnumType>()); |
| assert(!Res->isForwardDecl()); |
| TypeCache[TyPtr].reset(Res); |
| } |
| |
| void CGDebugInfo::completeType(const RecordDecl *RD) { |
| if (DebugKind > codegenoptions::LimitedDebugInfo || |
| !CGM.getLangOpts().CPlusPlus) |
| completeRequiredType(RD); |
| } |
| |
| /// Return true if the class or any of its methods are marked dllimport. |
| static bool isClassOrMethodDLLImport(const CXXRecordDecl *RD) { |
| if (RD->hasAttr<DLLImportAttr>()) |
| return true; |
| for (const CXXMethodDecl *MD : RD->methods()) |
| if (MD->hasAttr<DLLImportAttr>()) |
| return true; |
| return false; |
| } |
| |
| /// Does a type definition exist in an imported clang module? |
| static bool isDefinedInClangModule(const RecordDecl *RD) { |
| // Only definitions that where imported from an AST file come from a module. |
| if (!RD || !RD->isFromASTFile()) |
| return false; |
| // Anonymous entities cannot be addressed. Treat them as not from module. |
| if (!RD->isExternallyVisible() && RD->getName().empty()) |
| return false; |
| if (auto *CXXDecl = dyn_cast<CXXRecordDecl>(RD)) { |
| if (!CXXDecl->isCompleteDefinition()) |
| return false; |
| // Check wether RD is a template. |
| auto TemplateKind = CXXDecl->getTemplateSpecializationKind(); |
| if (TemplateKind != TSK_Undeclared) { |
| // Unfortunately getOwningModule() isn't accurate enough to find the |
| // owning module of a ClassTemplateSpecializationDecl that is inside a |
| // namespace spanning multiple modules. |
| bool Explicit = false; |
| if (auto *TD = dyn_cast<ClassTemplateSpecializationDecl>(CXXDecl)) |
| Explicit = TD->isExplicitInstantiationOrSpecialization(); |
| if (!Explicit && CXXDecl->getEnclosingNamespaceContext()) |
| return false; |
| // This is a template, check the origin of the first member. |
| if (CXXDecl->field_begin() == CXXDecl->field_end()) |
| return TemplateKind == TSK_ExplicitInstantiationDeclaration; |
| if (!CXXDecl->field_begin()->isFromASTFile()) |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| void CGDebugInfo::completeClassData(const RecordDecl *RD) { |
| if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) |
| if (CXXRD->isDynamicClass() && |
| CGM.getVTableLinkage(CXXRD) == |
| llvm::GlobalValue::AvailableExternallyLinkage && |
| !isClassOrMethodDLLImport(CXXRD)) |
| return; |
| |
| if (DebugTypeExtRefs && isDefinedInClangModule(RD->getDefinition())) |
| return; |
| |
| completeClass(RD); |
| } |
| |
| void CGDebugInfo::completeClass(const RecordDecl *RD) { |
| if (DebugKind <= codegenoptions::DebugLineTablesOnly) |
| return; |
| QualType Ty = CGM.getContext().getRecordType(RD); |
| void *TyPtr = Ty.getAsOpaquePtr(); |
| auto I = TypeCache.find(TyPtr); |
| if (I != TypeCache.end() && !cast<llvm::DIType>(I->second)->isForwardDecl()) |
| return; |
| llvm::DIType *Res = CreateTypeDefinition(Ty->castAs<RecordType>()); |
| assert(!Res->isForwardDecl()); |
| TypeCache[TyPtr].reset(Res); |
| } |
| |
| static bool hasExplicitMemberDefinition(CXXRecordDecl::method_iterator I, |
| CXXRecordDecl::method_iterator End) { |
| for (CXXMethodDecl *MD : llvm::make_range(I, End)) |
| if (FunctionDecl *Tmpl = MD->getInstantiatedFromMemberFunction()) |
| if (!Tmpl->isImplicit() && Tmpl->isThisDeclarationADefinition() && |
| !MD->getMemberSpecializationInfo()->isExplicitSpecialization()) |
| return true; |
| return false; |
| } |
| |
| static bool canUseCtorHoming(const CXXRecordDecl *RD) { |
| // Constructor homing can be used for classes that cannnot be constructed |
| // without emitting code for one of their constructors. This is classes that |
| // don't have trivial or constexpr constructors, or can be created from |
| // aggregate initialization. Also skip lambda objects because they don't call |
| // constructors. |
| |
| // Skip this optimization if the class or any of its methods are marked |
| // dllimport. |
| if (isClassOrMethodDLLImport(RD)) |
| return false; |
| |
| return !RD->isLambda() && !RD->isAggregate() && |
| !RD->hasTrivialDefaultConstructor() && |
| !RD->hasConstexprNonCopyMoveConstructor(); |
| } |
| |
| static bool shouldOmitDefinition(codegenoptions::DebugInfoKind DebugKind, |
| bool DebugTypeExtRefs, const RecordDecl *RD, |
| const LangOptions &LangOpts) { |
| if (DebugTypeExtRefs && isDefinedInClangModule(RD->getDefinition())) |
| return true; |
| |
| if (auto *ES = RD->getASTContext().getExternalSource()) |
| if (ES->hasExternalDefinitions(RD) == ExternalASTSource::EK_Always) |
| return true; |
| |
| // Only emit forward declarations in line tables only to keep debug info size |
| // small. This only applies to CodeView, since we don't emit types in DWARF |
| // line tables only. |
| if (DebugKind == codegenoptions::DebugLineTablesOnly) |
| return true; |
| |
| if (DebugKind > codegenoptions::LimitedDebugInfo || |
| RD->hasAttr<StandaloneDebugAttr>()) |
| return false; |
| |
| if (!LangOpts.CPlusPlus) |
| return false; |
| |
| if (!RD->isCompleteDefinitionRequired()) |
| return true; |
| |
|