[llvm-branch-commits] [llvm] [llvm-debuginfo-analyzer] Add support for LLVM IR format. (PR #135440)
Jeremy Morse via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu May 1 07:59:01 PDT 2025
================
@@ -0,0 +1,2348 @@
+//===-- LVIRReader.cpp ----------------------------------------------------===//
+//
+// 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 implements the LVIRReader class.
+// It supports LLVM text IR and bitcode format.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/LogicalView/Readers/LVIRReader.h"
+#include "llvm/CodeGen/DebugHandlerBase.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVLine.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVType.h"
+#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IRReader/IRReader.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Object/IRObjectFile.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/SourceMgr.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::logicalview;
+
+#define DEBUG_TYPE "IRReader"
+
+// Extra debug traces. Default is false
+#define DEBUG_ALL
+
+// These flavours of DINodes are not handled:
+// DW_TAG_APPLE_property = 19896
+// DW_TAG_atomic_type = 71
+// DW_TAG_common_block = 26
+// DW_TAG_file_type = 41
+// DW_TAG_friend = 42
+// DW_TAG_generic_subrange = 69
+// DW_TAG_immutable_type = 75
+// DW_TAG_module = 30
+
+// Create a logical element and setup the following information:
+// - Name, DWARF tag, line
+// - Collect any file information
+LVElement *LVIRReader::constructElement(const DINode *DN) {
+ dwarf::Tag Tag = DN->getTag();
+ LVElement *Element = createElement(Tag);
+ if (Element) {
+ Element->setTag(Tag);
+ addMD(DN, Element);
+
+ StringRef Name = getMDName(DN);
+ if (!Name.empty())
+ Element->setName(Name);
+
+ // Record any file information.
+ if (const DIFile *File = getMDFile(DN))
+ getOrCreateSourceID(File);
+ }
+
+ return Element;
+}
+
+void LVIRReader::mapFortranLanguage(unsigned DWLang) {
+ switch (DWLang) {
+ case dwarf::DW_LANG_Fortran77:
+ case dwarf::DW_LANG_Fortran90:
+ case dwarf::DW_LANG_Fortran95:
+ case dwarf::DW_LANG_Fortran03:
+ case dwarf::DW_LANG_Fortran08:
+ case dwarf::DW_LANG_Fortran18:
+ LanguageIsFortran = true;
+ break;
+ default:
+ LanguageIsFortran = false;
+ }
+}
+
+// Looking at IR generated with the '-gdwarf -gsplit-dwarf=split' the only
+// difference is setting the 'DICompileUnit::splitDebugFilename' to the
+// name of the split filename: "xxx.dwo".
+bool LVIRReader::includeMinimalInlineScopes() const {
+ return getCUNode()->getEmissionKind() == DICompileUnit::LineTablesOnly;
+}
+
+// For the given 'DIFile' generate an index 1-based to indicate the
+// source file where the logical element is declared.
+// In DWARF v4, the files are 1-indexed.
+// In DWARF v5, the files are 0-indexed.
+// The IR reader expects the indexes as 1-indexed.
+// Each compile unit, keeps track of the last assigned index.
+size_t LVIRReader::getOrCreateSourceID(const DIFile *File) {
+ if (!File)
+ return 0;
+
+#ifdef DEBUG_ALL
+ LLVM_DEBUG({
+ dbgs() << "\n[getOrCreateSourceID] DIFile\n";
+ File->dump();
+ });
+#endif
+
+ addMD(File, CompileUnit);
+
+ LLVM_DEBUG({
+ dbgs() << "Directory: '" << File->getDirectory() << "'\n";
+ dbgs() << "Filename: '" << File->getFilename() << "'\n";
+ });
+ size_t FileIndex = 0;
+ LVCompileUnitFiles::iterator Iter = CompileUnitFiles.find(File);
+ if (Iter == CompileUnitFiles.cend()) {
+ FileIndex = getFileIndex(CompileUnit);
+ std::string Directory(File->getDirectory());
+ if (Directory.empty())
+ Directory = std::string(CompileUnit->getCompilationDirectory());
+
+ std::string FullName;
+ raw_string_ostream Out(FullName);
+ Out << Directory << "/" << llvm::sys::path::filename(File->getFilename());
+ CompileUnit->addFilename(transformPath(FullName));
+ CompileUnitFiles.emplace(File, ++FileIndex);
+ updateFileIndex(CompileUnit, FileIndex);
+ } else {
+ FileIndex = Iter->second;
+ }
+
+ LLVM_DEBUG({ dbgs() << "FileIndex: " << FileIndex << "\n"; });
+ return FileIndex;
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, unsigned Line,
+ const DIFile *File) {
+ if (Line == 0)
+ return;
+
+ // After the scopes are created, the generic reader traverses the 'Children'
+ // and perform additional setting tasks (resolve types names, references,
+ // etc.). One of those tasks is select the correct string pool index based on
+ // the commmand line options: --attribute=filename or --attribute=pathname.
+ // As the 'Children' do not include logical lines, do that selection now,
+ // by calling 'setFilename' if the logical element is a line.
+ size_t FileID = getOrCreateSourceID(File);
+ if (Element->getIsLine())
+ Element->setFilename(CompileUnit->getFilename(FileID));
+ else
+ Element->setFilenameIndex(FileID);
+ Element->setLineNumber(Line);
+
+ LLVM_DEBUG({
+ dbgs() << "\n[addSourceLine]\n";
+ File->dump();
+ dbgs() << "FileIndex: " << Element->getFilenameIndex() << ", ";
+ dbgs() << "ID: " << Element->getID() << ", ";
+ dbgs() << "Kind: " << Element->kind() << ", ";
+ dbgs() << "Line: " << Element->getLineNumber() << ", ";
+ dbgs() << "Name: " << Element->getName() << "\n";
+ });
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, const DIGlobalVariable *G) {
+ assert(G);
+ addSourceLine(Element, G->getLine(), G->getFile());
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, const DIImportedEntity *IE) {
+ assert(IE);
+ addSourceLine(Element, IE->getLine(), IE->getFile());
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, const DILabel *L) {
+ assert(L);
+ addSourceLine(Element, L->getLine(), L->getFile());
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, const DILocalVariable *V) {
+ assert(V);
+ addSourceLine(Element, V->getLine(), V->getFile());
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, const DILocation *DL) {
+ assert(DL);
+ addSourceLine(Element, DL->getLine(), DL->getFile());
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, const DIObjCProperty *Ty) {
+ assert(Ty);
+ addSourceLine(Element, Ty->getLine(), Ty->getFile());
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, const DISubprogram *SP) {
+ assert(SP);
+ addSourceLine(Element, SP->getLine(), SP->getFile());
+}
+
+void LVIRReader::addSourceLine(LVElement *Element, const DIType *Ty) {
+ assert(Ty);
+ addSourceLine(Element, Ty->getLine(), Ty->getFile());
+}
+
+void LVIRReader::addConstantValue(LVElement *Element,
+ const DIExpression *DIExpr) {
+ std::optional<DIExpression::SignedOrUnsignedConstant> Constant =
+ DIExpr->isConstant();
+ std::stringstream Stream;
+ if (DIExpression::SignedOrUnsignedConstant::SignedConstant == Constant) {
+ int64_t Value = DIExpr->getElement(1);
+ if (Value < 0) {
+ Stream << "-";
+ Value = std::abs(Value);
+ }
+ Stream << hexString(Value, 2);
+ Element->setValue(Stream.str());
+ } else if (DIExpression::SignedOrUnsignedConstant::UnsignedConstant ==
+ Constant) {
+ uint64_t Value = DIExpr->getElement(1);
+ Stream << hexString(Value, 2);
+ Element->setValue(Stream.str());
+ }
+}
+
+void LVIRReader::addConstantValue(LVElement *Element, const ConstantInt *CI,
+ const DIType *Ty) {
+ addConstantValue(Element, CI->getValue(), Ty);
+}
+
+void LVIRReader::addConstantValue(LVElement *Element, uint64_t Val,
+ const DIType *Ty) {
+ addConstantValue(Element, DebugHandlerBase::isUnsignedDIType(Ty), Val);
+}
+
+void LVIRReader::addConstantValue(LVElement *Element, bool Unsigned,
+ uint64_t Val) {
+ addConstantValue(Element, llvm::APInt(64, Val, Unsigned), Unsigned);
+}
+
+void LVIRReader::addConstantValue(LVElement *Element, const APInt &Val,
+ const DIType *Ty) {
+ addConstantValue(Element, Val, DebugHandlerBase::isUnsignedDIType(Ty));
+}
+
+void LVIRReader::addConstantValue(LVElement *Element, const APInt &Value,
+ bool Unsigned) {
+ SmallString<128> StringValue;
+ Value.toString(StringValue, /*Radix=*/16, /*Signed=*/!Unsigned,
+ /*formatAsCLiteral=*/true, /*UpperCase=*/false,
+ /*InsertSeparators=*/false);
+ Element->setValue(StringValue.str());
+}
+
+void LVIRReader::addString(LVElement *Element, StringRef String) {
+ Element->setValue(String);
+}
+
+void LVIRReader::processLocationGaps() {
+ if (options().getAttributeAnyLocation())
+ for (LVSymbol *Symbol : SymbolsWithLocations)
+ Symbol->fillLocationGaps();
+}
+
+void LVIRReader::processScopes() {
+ // - Calculate their location ranges.
+ // - Assign unique offset to the logical scopes, symbols and types,
+ // as the code the handles public names, expects them to have one.
+ // Use an arbitrary increment of 4.
+ // - Resolve any line pattern match.
+ LVOffset Offset = 0;
+ auto SetOffset = [&](LVElement *Element) {
+ Element->setOffset(Offset);
+ Offset += OffsetIncrease;
+ };
+
+ std::function<void(LVScope *)> TraverseScope = [&](LVScope *Current) {
+ LVOffset Lower = Offset;
+ SetOffset(Current);
+ constructRange(Current);
+
+ if (const LVScopes *Scopes = Current->getScopes())
+ for (LVScope *Scope : *Scopes)
+ TraverseScope(Scope);
+
+ // Set an arbitrary 'Offset' for symbols and types.
+ if (const LVSymbols *Symbols = Current->getSymbols())
+ for (LVSymbol *Symbol : *Symbols)
+ SetOffset(Symbol);
+ if (const LVTypes *Types = Current->getTypes())
+ for (LVType *Type : *Types)
+ SetOffset(Type);
+
+ // Resolve any given pattern.
+ if (const LVLines *Lines = Current->getLines())
+ for (LVLine *Line : *Lines)
+ patterns().resolvePatternMatch(Line);
+
+ // Calculate contributions to the debug info.
+ LVOffset Upper = Offset;
+ if (options().getPrintSizes())
+ CompileUnit->addSize(Current, Lower, Upper);
+ };
+
+ TraverseScope(CompileUnit);
+}
+
+std::string LVIRReader::getRegisterName(LVSmall Opcode,
+ ArrayRef<uint64_t> Operands) {
+ // At this point we are operating on a logical view item, with no access
+ // to the underlying DWARF data used by LLVM.
+ // We do not support DW_OP_regval_type here.
+ if (Opcode == dwarf::DW_OP_regval_type)
+ return {};
+
+ if (Opcode == dwarf::DW_OP_regx || Opcode == dwarf::DW_OP_bregx) {
+ // If the following trace is enabled, its output will be intermixed
+ // with the logical view output, causing some confusion.
+ // Leaving it here, just for any specific needs.
+ // LLVM_DEBUG({
+ // dbgs() << "Printing Value: " << Operands[0] << " - "
+ // << DbgValueRanges->getVariableName(Operands[0]) << "\n";
+ // });
+ return DbgValueRanges->getVariableName(Operands[0]);
+ }
+
+ llvm_unreachable("We shouldn't actually have any other reg types here!");
+}
+
+LVScope *LVIRReader::getParentScopeImpl(const DIScope *Context) {
+ if (!Context)
+ return CompileUnit;
+
+#ifdef DEBUG_ALL
+ LLVM_DEBUG({
+ dbgs() << "\n[getParentScopeImpl] DIScope\n";
+ Context->dump();
+ });
+#endif
+
+ // Check for an already seen scope parent.
+ if (LVScope *Parent = getScopeForSeenMD(Context))
+ return Parent;
+
+ // Traverse the scope hierarchy and construct the required scopes.
+ return traverseParentScope(Context);
+}
+
+// Get the logical parent for the given metadata node.
+LVScope *LVIRReader::getParentScope(const DILocation *DL) {
+ assert(DL && "Invalid metadata node.");
+#ifdef DEBUG_ALL
+ LLVM_DEBUG({
+ dbgs() << "\n[getParentScope] DILocation\n";
+ DL->dump();
+ });
+#endif
+
+ return getParentScopeImpl(cast<DIScope>(DL->getScope()));
+}
+
+// Get the logical parent for the given metadata node.
+LVScope *LVIRReader::getParentScope(const DINode *DN) {
+ assert(DN && "Invalid metadata node.");
+#ifdef DEBUG_ALL
+ LLVM_DEBUG({
+ dbgs() << "\n[getParentScope] DINode\n";
+ DN->dump();
+ });
+#endif
+
+ return getParentScopeImpl(getMDScope(DN));
+}
+
+// Traverse the scope hierarchy and create each node in the hierarchy.
+LVScope *LVIRReader::traverseParentScope(const DIScope *Context) {
+ if (!Context)
+ return CompileUnit;
+
+#ifdef DEBUG_ALL
+ LLVM_DEBUG({
+ dbgs() << "\n[traverseParentScope] DIScope\n";
+ Context->dump();
+ });
+#endif
+
+ // Check if the metadata is already seen.
+ if (LVScope *Parent = getScopeForSeenMD(Context))
+ return Parent;
+
+ // Create the scope parent.
+ LVElement *Element = constructElement(Context);
+ if (Element) {
+ const DIScope *ParentContext = nullptr;
+ if (const auto *SP = dyn_cast<DISubprogram>(Context)) {
+ // Check for a specific 'Unit'.
+ if (DICompileUnit *CU = SP->getUnit())
+ ParentContext = getMDScope(SP->getDeclaration() ? CU : Context);
+ } else {
+ ParentContext = getMDScope(Context);
+ }
+ LVScope *Parent = traverseParentScope(ParentContext);
+ if (Parent) {
+ Parent->addElement(Element);
+ constructScope(Element, Context);
+ }
+ }
+
+ return static_cast<LVScope *>(Element);
+}
+
+// DW_TAG_base_type
+// DW_AT_name ("__ARRAY_SIZE_TYPE__")
+// DW_AT_byte_size (0x08)
+// DW_AT_encoding (DW_ATE_unsigned)
+LVType *LVIRReader::getIndexType() {
+ if (NodeIndexType)
+ return NodeIndexType;
+
+ // Construct an integer type to use for indexes.
+ NodeIndexType = static_cast<LVType *>(createElement(dwarf::DW_TAG_base_type));
+ if (NodeIndexType) {
+ NodeIndexType->setIsFinalized();
+ NodeIndexType->setName("__ARRAY_SIZE_TYPE__");
+ CompileUnit->addElement(NodeIndexType);
+ }
+
+ return NodeIndexType;
+}
+
+// addGlobalName - Add a new global name to the compile unit.
+void LVIRReader::addGlobalName(StringRef Name, LVElement *Element,
+ const DIScope *Context) {
+ assert(Element && "Invalid logical element.");
+ LLVM_DEBUG({
+ dbgs() << "\n[addGlobalName] DIScope\n";
+ Context->dump();
+ });
+}
+
+// Add accessibility info if available.
+void LVIRReader::addAccess(LVElement *Element, DINode::DIFlags Flags) {
+ assert(Element && "Invalid logical element.");
+ LLVM_DEBUG({ dbgs() << "\n[addAccess] DIFlags " << Flags << "\n"; });
+
+ if ((Flags & DINode::FlagAccessibility) == DINode::FlagZero) {
+ LVScope *Parent = Element->getParentScope();
+ if (Parent->getIsClass())
+ Element->setAccessibilityCode(dwarf::DW_ACCESS_private);
+ else if (Parent->getIsStructure() || Parent->getIsUnion())
+ Element->setAccessibilityCode(dwarf::DW_ACCESS_public);
+ return;
+ }
+
+ if ((Flags & DINode::FlagAccessibility) == DINode::FlagProtected)
+ Element->setAccessibilityCode(dwarf::DW_ACCESS_protected);
+ else if ((Flags & DINode::FlagAccessibility) == DINode::FlagPrivate)
+ Element->setAccessibilityCode(dwarf::DW_ACCESS_private);
+ else if ((Flags & DINode::FlagAccessibility) == DINode::FlagPublic)
+ Element->setAccessibilityCode(dwarf::DW_ACCESS_public);
+};
+
+// getFile()
+// DIScope
+// DILocation
+// DIVariable
+// DICommonBlock
+// DILabel
+// DIObjCProperty
+// DIImportedEntity
+// DIMacroFile
+const DIFile *LVIRReader::getMDFile(const MDNode *MD) const {
+ assert(MD && "Invalid metadata node.");
+#ifdef DEBUG_ALL
+ LLVM_DEBUG({
+ dbgs() << "\n[getMDFile] MDNode\n";
+ MD->dump();
+ });
+#endif
+
+ if (auto *T = dyn_cast<DIScope>(MD))
+ return T->getFile();
+
+ if (auto *T = dyn_cast<DILocation>(MD))
+ return T->getFile();
+
+ if (auto *T = dyn_cast<DIVariable>(MD))
+ return T->getFile();
+
+ if (auto *T = dyn_cast<DICommonBlock>(MD))
+ return T->getFile();
+
+ if (auto *T = dyn_cast<DILabel>(MD))
+ return T->getFile();
+
+ if (auto *T = dyn_cast<DIObjCProperty>(MD))
+ return T->getFile();
+
+ if (auto *T = dyn_cast<DIImportedEntity>(MD))
+ return T->getFile();
+
+ if (auto *T = dyn_cast<DIMacroFile>(MD))
+ return T->getFile();
+
+ return nullptr;
+}
+
+// getName()
+// DIScope
+// DIType
+// DISubprogram
+// DINamespace
+// DIModule
+// DITemplateParameter
+// DIVariable
+// DICommonBlock
+// DILabel
+// DIObjCProperty
+// DIImportedEntity
+// DIMacro
+// DIEnumerator
+StringRef LVIRReader::getMDName(const DINode *DN) const {
+ assert(DN && "Invalid metadata node.");
+#ifdef DEBUG_ALL
+ LLVM_DEBUG({
+ dbgs() << "\n[getMDName] DINode\n";
+ DN->dump();
+ });
+#endif
+
+ if (auto *T = dyn_cast<DIType>(DN))
+ return T->getName();
+
+ if (auto *T = dyn_cast<DISubprogram>(DN))
+ return T->getName();
+
+ if (auto *T = dyn_cast<DINamespace>(DN))
+ return T->getName();
+
+ if (auto *T = dyn_cast<DICommonBlock>(DN))
+ return T->getName();
+
+ if (auto *T = dyn_cast<DIModule>(DN))
+ return T->getName();
+
+ if (auto *T = dyn_cast<DIImportedEntity>(DN))
+ return T->getName();
+
+ if (auto *T = dyn_cast<DICompositeType>(DN))
+ return T->getName();
+
+ if (auto *T = dyn_cast<DIDerivedType>(DN))
+ return T->getName();
+
+ if (auto *T = dyn_cast<DILexicalBlockBase>(DN))
+ return T->getName();
+
+ if (auto *T = dyn_cast<DIEnumerator>(DN))
+ return T->getName();
+
+ if (/*auto *T = */ dyn_cast<DISubrange>(DN))
+ return StringRef();
+
+ if (auto *T = dyn_cast<DIVariable>(DN))
+ return T->getName();
+
+ if (auto *T = dyn_cast<DIScope>(DN))
+ return T->getName();
+
+ if (auto *T = dyn_cast<DITemplateParameter>(DN))
+ return T->getName();
+
+ if (auto *T = dyn_cast<DILabel>(DN))
+ return T->getName();
+
+ if (auto *T = dyn_cast<DIObjCProperty>(DN))
+ return T->getName();
+
+ if (auto *T = dyn_cast<DIMacro>(DN))
+ return T->getName();
+
+ assert((isa<DIFile>(DN) || isa<DICompileUnit>(DN)) && "Unhandled DINode.");
+ return StringRef();
+}
+
+const DIScope *LVIRReader::getMDScope(const DINode *DN) const {
+ assert(DN && "Invalid metadata node.");
+#ifdef DEBUG_ALL
+ LLVM_DEBUG({
+ dbgs() << "\n[getMDScope] DINode\n";
+ DN->dump();
+ });
+#endif
+
+ if (dyn_cast<DIBasicType>(DN))
+ return getCUNode();
+
+ if (auto *T = dyn_cast<DINamespace>(DN)) {
+ // The scope for global namespaces is nullptr.
+ const DIScope *Context = T->getScope();
+ if (!Context)
+ Context = getCUNode();
+ return Context;
+ }
+
+ if (auto *T = dyn_cast<DIImportedEntity>(DN))
+ return T->getScope();
+
+ if (auto *T = dyn_cast<DIVariable>(DN))
+ return T->getScope();
+
+ if (auto *T = dyn_cast<DIScope>(DN))
+ return T->getScope();
+
+ assert((isa<DIFile>(DN) || isa<DICompileUnit>(DN)) && "Unhandled DINode.");
+
+ // Assume the scope to be the compile unit.
+ return getCUNode();
+}
+
+//===----------------------------------------------------------------------===//
+// Logical elements construction using IR metadata.
+//===----------------------------------------------------------------------===//
+void LVIRReader::addTemplateParams(LVElement *Element,
+ const DINodeArray TParams) {
+ assert(Element && "Invalid logical element");
+ // assert(TParams && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[addTemplateParams] DINodeArray\n";
+ // TParams->dump();
+ for (const auto *Entry : TParams)
+ Entry->dump();
+ });
+
+ // Add template parameters.
+ for (const auto *Entry : TParams) {
+ if (const auto *TTP = dyn_cast<DITemplateTypeParameter>(Entry))
+ constructTemplateTypeParameter(Element, TTP);
+ else if (const auto *TVP = dyn_cast<DITemplateValueParameter>(Entry))
+ constructTemplateValueParameter(Element, TVP);
+ }
+}
+
+// DISubprogram
+void LVIRReader::applySubprogramAttributes(LVScope *Function,
+ const DISubprogram *SP,
+ bool SkipSPAttributes) {
+ assert(Function && "Invalid logical element");
+ assert(SP && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[applySubprogramAttributes] DISubprogram\n";
+ SP->dump();
+ });
+
+ // If -fdebug-info-for-profiling is enabled, need to emit the subprogram
+ // and its source location.
+ bool SkipSPSourceLocation =
+ SkipSPAttributes && !getCUNode()->getDebugInfoForProfiling();
+ if (!SkipSPSourceLocation)
+ if (applySubprogramDefinitionAttributes(Function, SP, SkipSPAttributes))
+ return;
+
+ if (!SkipSPSourceLocation)
+ addSourceLine(Function, SP);
+
+ // Skip the rest of the attributes under -gmlt to save space.
+ if (SkipSPAttributes)
+ return;
+
+ DITypeRefArray Args;
+ if (const DISubroutineType *SPTy = SP->getType())
+ Args = SPTy->getTypeArray();
+
+ // Construct subprogram return type.
+ if (Args.size()) {
+ LVElement *ElementType = getOrCreateType(Args[0]);
+ Function->setType(ElementType);
+ }
+
+ // Add virtuality info if available.
+ Function->setVirtualityCode(SP->getVirtuality());
+
+ if (!SP->isDefinition()) {
+ // Add arguments. Do not add arguments for subprogram definition. They will
+ // be handled while processing variables.
+ constructSubprogramArguments(Function, Args);
+ }
+
+ if (SP->isArtificial())
+ Function->setIsArtificial();
+
+ if (!SP->isLocalToUnit())
+ Function->setIsExternal();
+
+ // Add accessibility info if available.
+ addAccess(Function, SP->getFlags());
+}
+
+// DISubprogram
+bool LVIRReader::applySubprogramDefinitionAttributes(LVScope *Function,
+ const DISubprogram *SP,
+ bool Minimal) {
+ assert(Function && "Invalid logical element");
+ assert(SP && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[applySubprogramDefinitionAttributes] DISubprogram\n";
+ SP->dump();
+ });
+
+ LVScope *Reference = nullptr;
+ StringRef DeclLinkageName;
+ if (const DISubprogram *SPDecl = SP->getDeclaration()) {
+ if (!Minimal) {
+ DITypeRefArray DeclArgs, DefinitionArgs;
+ DeclArgs = SPDecl->getType()->getTypeArray();
+ DefinitionArgs = SP->getType()->getTypeArray();
+
+ if (DeclArgs.size() && DefinitionArgs.size())
+ if (DefinitionArgs[0] != nullptr && DeclArgs[0] != DefinitionArgs[0]) {
+ LVElement *ElementType = getOrCreateType(DefinitionArgs[0]);
+ Function->setType(ElementType);
+ }
+
+ Reference = getScopeForSeenMD(SPDecl);
+ assert(Reference && "Scope should've already been constructed.");
+ // Look at the Decl's linkage name only if we emitted it.
+ if (useAllLinkageNames())
+ DeclLinkageName = SPDecl->getLinkageName();
+ unsigned DeclID = getOrCreateSourceID(SPDecl->getFile());
+ unsigned DefID = getOrCreateSourceID(SP->getFile());
+ if (DeclID != DefID)
+ Function->setFilenameIndex(DefID);
+
+ if (SP->getLine() != SPDecl->getLine())
+ Function->setLineNumber(SP->getLine());
+ }
+ }
+
+ // Add function template parameters.
+ addTemplateParams(Function, SP->getTemplateParams());
+
+ // Add the linkage name if we have one and it isn't in the Decl.
+ StringRef LinkageName = SP->getLinkageName();
+ assert(((LinkageName.empty() || DeclLinkageName.empty()) ||
+ LinkageName == DeclLinkageName) &&
+ "decl has a linkage name and it is different");
+ if (DeclLinkageName.empty() && (useAllLinkageNames()))
+ // Always emit it for abstract subprograms.
+ Function->setLinkageName(LinkageName);
+
+ if (!Reference)
+ return false;
+
+ // Refer to the function declaration where all the other attributes will be
+ // found.
+ Function->setReference(Reference);
+ Function->setHasReferenceSpecification();
+
+ return true;
+}
+
+void LVIRReader::applySubprogramAttributesToDefinition(LVScope *Function,
+ const DISubprogram *SP) {
+ assert(Function && "Invalid logical element");
+ assert(SP && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[applySubprogramAttributesToDefinition] DISubprogram\n";
+ SP->dump();
+ });
+
+ applySubprogramAttributes(Function, SP, includeMinimalInlineScopes());
+}
+
+// DICompositeType
+void LVIRReader::constructAggregate(LVScopeAggregate *Aggregate,
+ const DICompositeType *CTy) {
+ assert(Aggregate && "Invalid logical element");
+ assert(CTy && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[constructAggregate] DICompositeType\n";
+ CTy->dump();
+ });
+
+ if (Aggregate->getIsFinalized())
+ return;
+ Aggregate->setIsFinalized();
+
+ dwarf::Tag Tag = Aggregate->getTag();
+ if (Tag == dwarf::DW_TAG_variant_part) {
+ }
+
+ // Add template parameters to a class, structure or union types.
+ if (Tag == dwarf::DW_TAG_class_type || Tag == dwarf::DW_TAG_structure_type ||
+ Tag == dwarf::DW_TAG_union_type)
+ addTemplateParams(Aggregate, CTy->getTemplateParams());
+
+ // Add elements to aggregate type.
+ for (const auto Member : CTy->getElements()) {
+ if (!Member)
+ continue;
+ LLVM_DEBUG({
+ dbgs() << "\nAggregate Element\n";
+ Member->dump();
+ });
+ if (const auto *SP = dyn_cast<DISubprogram>(Member))
+ getOrCreateSubprogram(SP);
+ else if (const DIDerivedType *DT = dyn_cast<DIDerivedType>(Member)) {
+ dwarf::Tag Tag = Member->getTag();
+ if (Tag == dwarf::DW_TAG_member || Tag == dwarf::DW_TAG_variable) {
+ if (DT->isStaticMember())
+ getOrCreateStaticMember(Aggregate, DT);
+ else
+ getOrCreateMember(Aggregate, DT);
+ } else {
+ getOrCreateType(DT, Aggregate);
+ }
+ }
+ }
+}
+
+// DICompositeType
+void LVIRReader::constructArray(LVScopeArray *Array,
+ const DICompositeType *CTy) {
+ assert(Array && "Invalid logical element");
+ assert(CTy && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[constructArray] DICompositeType\n";
+ CTy->dump();
+ });
+
+ if (Array->getIsFinalized())
+ return;
+ Array->setIsFinalized();
+
+ if (LVElement *BaseType = getOrCreateType(CTy->getBaseType()))
+ Array->setType(BaseType);
+
+ // Get an anonymous type for index type.
+ LVType *IndexType = getIndexType();
+
+ // Add subranges to array type.
+ DINodeArray Entries = CTy->getElements();
+ for (DINode *DN : Entries) {
+ if (auto *SR = dyn_cast_or_null<DINode>(DN)) {
+ if (SR->getTag() == dwarf::DW_TAG_subrange_type)
+ constructSubrange(Array, cast<DISubrange>(SR), IndexType);
+ else if (SR->getTag() == dwarf::DW_TAG_generic_subrange)
+ constructGenericSubrange(Array, cast<DIGenericSubrange>(SR), IndexType);
+ }
+ }
+}
+
+// DICompositeType
+void LVIRReader::constructEnum(LVScopeEnumeration *Enumeration,
+ const DICompositeType *CTy) {
+ assert(Enumeration && "Invalid logical element");
+ assert(CTy && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[constructEnum] DICompositeType\n";
+ CTy->dump();
+ });
+
+ if (Enumeration->getIsFinalized())
+ return;
+ Enumeration->setIsFinalized();
+
+ const DIType *Ty = CTy->getBaseType();
+ bool IsUnsigned = Ty && DebugHandlerBase::isUnsignedDIType(Ty);
+
+ if (LVElement *BaseType = getOrCreateType(Ty))
+ Enumeration->setType(BaseType);
+
+ if (CTy->getFlags() & DINode::FlagEnumClass)
+ Enumeration->setIsEnumClass();
+
+ // Add enumerators to enumeration type.
+ DINodeArray Entries = CTy->getElements();
+ for (const DINode *DN : Entries) {
+ if (auto *Enum = dyn_cast_or_null<DIEnumerator>(DN)) {
+ if (LVElement *Enumerator = constructElement(Enum)) {
+ Enumerator->setIsFinalized();
+ Enumeration->addElement(Enumerator);
+ addConstantValue(Enumerator, Enum->getValue(), IsUnsigned);
+ }
+ }
+ }
+}
+
+void LVIRReader::constructGenericSubrange(LVScopeArray *Array,
+ const DIGenericSubrange *GSR,
+ LVType *IndexType) {
+ assert(Array && "Invalid logical element");
+ assert(GSR && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[constructGenericSubrange] DIGenericSubrange\n";
+ GSR->dump();
+ });
+
+ LLVM_DEBUG({ dbgs() << "\nNot implemented\n"; });
+}
+
+// DIImportedEntity
+void LVIRReader::constructImportedEntity(LVElement *Element,
+ const DIImportedEntity *IE) {
+ assert(Element && "Invalid logical element");
+ assert(IE && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[constructImportedEntity] DIImportedEntity\n";
+ IE->dump();
+ });
+
+ if (LVElement *Import = constructElement(IE)) {
+ Import->setIsFinalized();
+ addSourceLine(Import, IE);
+ LVScope *Parent = getParentScope(IE);
+ Parent->addElement(Import);
+
+ const DINode *Entity = IE->getEntity();
+ LVElement *Target = getElementForSeenMD(Entity);
+ if (!Target) {
+ if (const auto *Ty = dyn_cast<DIType>(Entity))
+ Target = getOrCreateType(Ty);
+ else if (const auto *SP = dyn_cast<DISubprogram>(Entity))
+ Target = getOrCreateSubprogram(SP);
+ else if (const auto *NS = dyn_cast<DINamespace>(Entity))
+ Target = getOrCreateNamespace(NS);
+ else if (const auto *M = dyn_cast<DIModule>(Entity))
+ Target = getOrCreateScope(M);
+ }
+ Import->setType(Target);
+ }
+}
+
+LVScope *LVIRReader::getOrCreateAbstractScope(LVScope *OriginScope,
+ const DILocation *DL) {
+ assert(OriginScope && "Invalid logical element");
+ assert(DL && "Invalid metadata node.");
+ LLVM_DEBUG({
+ dbgs() << "\n[getOrCreateAbstractScope] DILocation\n";
+ DL->dump();
+ });
+
+ const DILocation *InlinedAt = DL->getInlinedAt();
+ DILocalScope *Context = DL->getScope();
+ LLVM_DEBUG({
+ dbgs() << "\nParent Scope:\n";
+ OriginScope->getParentScope()->dump();
+ dbgs() << "\nOriginScope:\n";
+ OriginScope->dump();
+ dbgs() << "\nInlinedAt:\n";
+ InlinedAt->dump();
+ dbgs() << "\nContext:\n";
+ Context->dump();
+ });
+
+ dwarf::Tag Tag = OriginScope->getTag();
+ if (OriginScope->getIsFunction() || OriginScope->getIsInlinedFunction()) {
+ Tag = dwarf::DW_TAG_inlined_subroutine;
+ OriginScope->setInlineCode(dwarf::DW_INL_inlined);
+ }
+ LVScope *AbstractScope = static_cast<LVScope *>(createElement(Tag));
+ if (AbstractScope) {
+ addInlinedScope(OriginScope, AbstractScope);
+ AbstractScope->setTag(Tag);
+ AbstractScope->setIsFinalized();
+ AbstractScope->setName(OriginScope->getName());
+ AbstractScope->setType(OriginScope->getType());
+
+ AbstractScope->setCallLineNumber(InlinedAt->getLine());
+ AbstractScope->setCallFilenameIndex(
+ getOrCreateSourceID(InlinedAt->getFile()));
+
+ AbstractScope->setReference(OriginScope);
+ AbstractScope->setHasReferenceAbstract();
----------------
jmorse wrote:
The object name is `AbstractScope`, but you're setting the inlining-site information on it and referring to the "origin" scope from it. This really sounds like the "Abstract" scope is actually the _inlined_ scope. An inlined subroutine in DWARF is what contains that information:
```
0x0000008a: DW_TAG_inlined_subroutine
DW_AT_abstract_origin (0x00000036 "Max")
DW_AT_low_pc (0x000000000000000b)
DW_AT_high_pc (0x0000000000000014)
DW_AT_call_file ("/home/jmorse/test2.c")
DW_AT_call_line (16)
DW_AT_call_column (0x0c)
```
i.e. it has a call line, file index, and reference to another scope.
https://github.com/llvm/llvm-project/pull/135440
More information about the llvm-branch-commits
mailing list