================ @@ -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 _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits