| //===-- 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 textual and bitcode IR format. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/DebugInfo/LogicalView/Readers/LVIRReader.h" | |
| #include "llvm/ADT/ScopeExit.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/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" | |
| namespace { | |
| // Abstract scopes mapped to the associated inlined scopes. | |
| // When creating inlined scopes, there is no direct information to find | |
| // the correct lexical scope. | |
| using LVScopeEntry = std::pair<const DILocalScope *, const DILocation *>; | |
| using LVInlinedScopes = | |
| std::unordered_map<LVScopeEntry, LVScope *, | |
| pair_hash<const DILocalScope *, const DILocation *>>; | |
| LVInlinedScopes InlinedScopes; | |
| void addInlinedScope(const DILocalScope *OriginContext, | |
| const DILocation *InlinedAt, LVScope *InlinedScope) { | |
| auto Entry = LVScopeEntry(OriginContext, InlinedAt); | |
| InlinedScopes.try_emplace(Entry, InlinedScope); | |
| } | |
| LVScope *getInlinedScope(const DILocalScope *OriginContext, | |
| const DILocation *InlinedAt) { | |
| auto Entry = LVScopeEntry(OriginContext, InlinedAt); | |
| LVInlinedScopes::const_iterator Iter = InlinedScopes.find(Entry); | |
| return Iter != InlinedScopes.end() ? Iter->second : nullptr; | |
| } | |
| // Used to find the correct location for the inlined lexical blocks that | |
| // are allocated at their enclosing function level. | |
| // Keep a link between the inlined scope and its associated origin scope. | |
| using LVInlinedToOrigin = std::unordered_map<LVScope *, LVScope *>; | |
| LVInlinedToOrigin InlinedToOrigin; | |
| // Keep a list of inlined scopes created from the same origin scope. | |
| // The original scope can be inlined multiple times. | |
| using LVList = llvm::SmallVector<LVScope *, 2>; | |
| using LVInlinedList = std::unordered_map<LVScope *, LVList>; | |
| LVInlinedList InlinedList; | |
| void addInlinedInfo(LVScope *Origin, LVScope *Inlined) { | |
| // Add the link between the inlined and the origin scopes. | |
| InlinedToOrigin.try_emplace(Inlined, Origin); | |
| // For the given origin scope, add the inlined scope to its inlined list. | |
| auto [It, _] = InlinedList.try_emplace(Origin, LVList{}); | |
| LVList &List = It->second; | |
| List.push_back(Inlined); | |
| } | |
| LVList &getInlinedList(LVScope *Origin) { | |
| static LVList EmptyList; | |
| auto It = InlinedList.find(Origin); | |
| return (It == InlinedList.end()) ? EmptyList : It->second; | |
| } | |
| #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) | |
| void dumpInlinedInfo(const char *Text, bool Full = false) { | |
| // Use 17 as the field length; it corresponds to '{InlinedFunction}' | |
| constexpr unsigned LEN = 17; | |
| auto PrintEntry = [&](auto Text, LVScope *Scope) { | |
| std::stringstream SS; | |
| SS << Text << hexSquareString(Scope->getID()) | |
| << hexSquareString(Scope->getParentScope()->getID()) << " " | |
| << std::setw(LEN) << std::left << formattedKind(Scope->kind()); | |
| dbgs() << SS.str(); | |
| }; | |
| auto PrintExtra = [&](auto Text, LVScope *Scope) { | |
| dbgs() << Text; | |
| Scope->dumpCommon(); | |
| }; | |
| // For each origin scope prints its associated inlined scopes. | |
| dbgs() << "\nOrigin -> Inlined list: " << Text << "\n\n"; | |
| for (auto &Entry : InlinedList) { | |
| LVScope *OriginScope = Entry.first; | |
| LVList &List = Entry.second; | |
| PrintEntry("", OriginScope); | |
| dbgs() << "\n"; | |
| unsigned Count = 0; | |
| for (auto &Scope : List) { | |
| dbgs() << decString(++Count, /*Width=*/2); | |
| PrintEntry(" ", Scope); | |
| dbgs() << "\n"; | |
| } | |
| } | |
| dbgs() << "\nOrigin -> Inlined: " << Text << "\n\n"; | |
| for (auto &Entry : InlinedToOrigin) { | |
| LVScope *InlinedScope = Entry.first; | |
| LVScope *OriginScope = Entry.second; | |
| PrintEntry("", InlinedScope); | |
| dbgs() << " -> "; | |
| PrintEntry("", OriginScope); | |
| dbgs() << "\n"; | |
| } | |
| if (Full) { | |
| dbgs() << "\n"; | |
| for (auto &Entry : InlinedToOrigin) { | |
| LVScope *InlinedScope = Entry.first; | |
| LVScope *OriginScope = Entry.second; | |
| PrintExtra("OriginParent: ", OriginScope->getParentScope()); | |
| PrintExtra("Origin: ", OriginScope); | |
| PrintExtra("InlinedParent: ", InlinedScope->getParentScope()); | |
| PrintExtra("Inlined: ", InlinedScope); | |
| dbgs() << "\n"; | |
| } | |
| } | |
| } | |
| #endif | |
| } // namespace | |
| // These flavours of 'DINode's are not implemented but technically possible: | |
| // DW_TAG_APPLE_property = 0x4200 | |
| // DW_TAG_atomic_type = 0x0047 | |
| // DW_TAG_common_block = 0x001a | |
| // DW_TAG_file_type = 0x0029 | |
| // DW_TAG_friend = 0x002a | |
| // DW_TAG_generic_subrange = 0x0045 | |
| // DW_TAG_immutable_type = 0x004b | |
| // DW_TAG_module = 0x001e | |
| // DW_TAG_variant_part = 0x0033 | |
| // 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); | |
| if (StringRef Name = getMDName(DN); !Name.empty()) | |
| Element->setName(Name); | |
| // Record any file information. | |
| if (const DIFile *File = getMDFile(DN)) | |
| getOrCreateSourceID(File); | |
| } | |
| return Element; | |
| } | |
| void LVIRReader::setDefaultLowerBound(LVSourceLanguage *SL) { | |
| assert(SL && "Invalid language ID."); | |
| StringRef LanguageName = SL->getName(); | |
| // Fortran uses 1 as the default lowerbound; other languages use 0. | |
| DefaultLowerBound = LanguageName.contains("fortran") ? 1 : 0; | |
| LLVM_DEBUG({ dbgs() << "Language Name: " << LanguageName << "\n"; }); | |
| } | |
| bool LVIRReader::includeMinimalInlineScopes() const { | |
| return getCUNode()->getEmissionKind() == DICompileUnit::LineTablesOnly; | |
| } | |
| size_t LVIRReader::getOrCreateSourceID(const DIFile *File) { | |
| if (!File) | |
| return 0; | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[getOrCreateSourceID]\n"; | |
| dbgs() << "File: "; | |
| File->dump(TheModule); | |
| }); | |
| addMD(File, CompileUnit); | |
| LLVM_DEBUG({ | |
| dbgs() << "Directory: '" << File->getDirectory() << "'\n"; | |
| dbgs() << "Filename: '" << File->getFilename() << "'\n"; | |
| }); | |
| size_t FileIndex = getFileIndex(CompileUnit); | |
| auto [Iter, Inserted] = CompileUnitFiles.try_emplace(File, ++FileIndex); | |
| if (Inserted) { | |
| 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)); | |
| 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 performs 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(TheModule); | |
| 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 *OP) { | |
| assert(OP); | |
| addSourceLine(Element, OP->getLine(), OP->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(); | |
| if (Constant == std::nullopt) | |
| return; | |
| std::stringstream Stream; | |
| uint64_t Value = DIExpr->getConstantValue(); | |
| if (DIExpression::SignedOrUnsignedConstant::SignedConstant == Constant) { | |
| if (int64_t SignedValue = static_cast<int64_t>(Value); SignedValue < 0) { | |
| Stream << "-"; | |
| Value = static_cast<uint64_t>(-SignedValue); | |
| } | |
| } | |
| Stream << hexString(Value, 2); | |
| Element->setValue(Stream.str()); | |
| } | |
| void LVIRReader::addConstantValue(LVElement *Element, const ConstantFP *CFP) { | |
| addConstantValue(Element, CFP->getValueAPF().bitcastToAPInt(), true); | |
| } | |
| 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, uint64_t Val, | |
| bool Unsigned) { | |
| 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::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. | |
| // At this stage the compile unit and the root scopes they have the | |
| // same offset, which is incorrect. Update the compile unit offset. | |
| LVOffset Offset = OFFSET_INCREASE; | |
| auto SetOffset = [&](LVElement *Element) { | |
| Element->setOffset(Offset); | |
| Offset += OFFSET_INCREASE; | |
| }; | |
| 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, but strictly-increasing '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] << " - " | |
| // << ValueNameMap.getName(Operands[0]) << "\n"; | |
| // }); | |
| // Add an extra space for a better layout when printing locations. | |
| return " " + ValueNameMap.getName(Operands[0]); | |
| } | |
| llvm_unreachable("We shouldn't actually have any other reg types here!"); | |
| } | |
| LVScope *LVIRReader::getParentScopeImpl(const DIScope *Context) { | |
| if (!Context) | |
| return CompileUnit; | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[getParentScopeImpl]\n"; | |
| dbgs() << "Context: "; | |
| Context->dump(TheModule); | |
| }); | |
| // 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."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[getParentScope]\n"; | |
| dbgs() << "DL: "; | |
| DL->dump(TheModule); | |
| }); | |
| 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."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[getParentScope]\n"; | |
| dbgs() << "DN: "; | |
| DN->dump(TheModule); | |
| }); | |
| return getParentScopeImpl(getMDScope(DN)); | |
| } | |
| LVScope *LVIRReader::traverseParentScope(const DIScope *Context) { | |
| if (!Context) | |
| return CompileUnit; | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[traverseParentScope]\n"; | |
| dbgs() << "Context: \n"; | |
| Context->dump(TheModule); | |
| }); | |
| // 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() { | |
| // This function is not meant to be called from multiple threads. | |
| 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; | |
| } | |
| void LVIRReader::addAccess(LVElement *Element, DINode::DIFlags Flags) { | |
| assert(Element && "Invalid logical element."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[addAccess]\n"; | |
| dbgs() << "Flags: " << Flags << "\n"; | |
| }); | |
| const unsigned Accessibility = (Flags & DINode::FlagAccessibility); | |
| switch (Accessibility) { | |
| case DINode::FlagProtected: | |
| Element->setAccessibilityCode(dwarf::DW_ACCESS_protected); | |
| return; | |
| case DINode::FlagPrivate: | |
| Element->setAccessibilityCode(dwarf::DW_ACCESS_private); | |
| return; | |
| case DINode::FlagPublic: | |
| Element->setAccessibilityCode(dwarf::DW_ACCESS_public); | |
| return; | |
| case DINode::FlagZero: | |
| // If no explicit access control, provide the default for the parent. | |
| LVScope *Parent = Element->getParentScope(); | |
| if (Parent->getIsClass()) { | |
| Element->setAccessibilityCode(dwarf::DW_ACCESS_private); | |
| return; | |
| } | |
| if (Parent->getIsStructure() || Parent->getIsUnion()) { | |
| Element->setAccessibilityCode(dwarf::DW_ACCESS_public); | |
| return; | |
| } | |
| } | |
| } | |
| // getFile() | |
| // DIScope | |
| // DILocation | |
| // DIVariable | |
| // DICommonBlock | |
| // DILabel | |
| // DIObjCProperty | |
| // DIImportedEntity | |
| // DIMacroFile | |
| const DIFile *LVIRReader::getMDFile(const MDNode *MD) const { | |
| assert(MD && "Invalid metadata node."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[getMDFile]\n"; | |
| dbgs() << "MD: "; | |
| MD->dump(TheModule); | |
| }); | |
| 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; | |
| } | |
| // getMDName() | |
| // 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."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[getMDName]\n"; | |
| dbgs() << "DN: "; | |
| DN->dump(TheModule); | |
| }); | |
| 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<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) || isa<DISubrange>(DN)) && | |
| "Unhandled DINode."); | |
| return StringRef(); | |
| } | |
| const DIScope *LVIRReader::getMDScope(const DINode *DN) const { | |
| assert(DN && "Invalid metadata node."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[getMDScope]\n"; | |
| dbgs() << "DN: "; | |
| DN->dump(TheModule); | |
| }); | |
| 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]\n"; | |
| for (const auto *Entry : TParams) { | |
| dbgs() << "Entry: "; | |
| Entry->dump(TheModule); | |
| } | |
| }); | |
| // 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]\n"; | |
| dbgs() << "SP: "; | |
| SP->dump(TheModule); | |
| }); | |
| // 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; | |
| DITypeArray 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]\n"; | |
| dbgs() << "SP: "; | |
| SP->dump(TheModule); | |
| }); | |
| LVScope *Reference = nullptr; | |
| StringRef DeclLinkageName; | |
| if (const DISubprogram *SPDecl = SP->getDeclaration()) { | |
| if (!Minimal) { | |
| DITypeArray DeclArgs, DefinitionArgs; | |
| DeclArgs = SPDecl->getType()->getTypeArray(); | |
| DefinitionArgs = SP->getType()->getTypeArray(); | |
| // The element zero in 'DefinitionArgs' and 'DeclArgs' arrays is | |
| // the subprogram return type. A 'void' return does not have a | |
| // type and it is represented by a 'nullptr' value. | |
| // For the given test case and its IR: | |
| // | |
| // 1 struct Bar { | |
| // 2 bool foo(int a); | |
| // 3 }; | |
| // 4 | |
| // 5 bool Bar::foo(int a) { | |
| // 6 return false; | |
| // 7 } | |
| // | |
| // !10 = !DISubprogram(name: "foo", line: 5, type: !14, | |
| // spFlags: DISPFlagDefinition) | |
| // !13 = !DISubprogram(name: "foo", line: 2, type: !14, spFlags: 0) | |
| // !14 = !DISubroutineType(types: !15) | |
| // !15 = !{!16, !17, !18} | |
| // !16 = !DIBasicType(name: "bool", ...) | |
| // | |
| // '!15' represents both 'DefinitionArgs' and 'DeclArgs' arrays. | |
| // For cases where they have a different metadata node, use the | |
| // type from the 'DefinitionArgs' array as the correct type. | |
| 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(); | |
| // Always emit it for abstract subprograms. | |
| if (DeclLinkageName != LinkageName && (useAllLinkageNames())) | |
| 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; | |
| } | |
| // DICompositeType | |
| void LVIRReader::constructAggregate(LVScopeAggregate *Aggregate, | |
| const DICompositeType *CTy) { | |
| assert(Aggregate && "Invalid logical element"); | |
| assert(CTy && "Invalid metadata node."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[constructAggregate]\n"; | |
| dbgs() << "CTy: "; | |
| CTy->dump(TheModule); | |
| }); | |
| if (Aggregate->getIsFinalized()) | |
| return; | |
| Aggregate->setIsFinalized(); | |
| dwarf::Tag Tag = Aggregate->getTag(); | |
| // 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() << "\nMember: "; | |
| Member->dump(TheModule); | |
| }); | |
| 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(Aggregate, DT); | |
| } | |
| } | |
| } | |
| } | |
| // DICompositeType | |
| void LVIRReader::constructArray(LVScopeArray *Array, | |
| const DICompositeType *CTy) { | |
| assert(Array && "Invalid logical element"); | |
| assert(CTy && "Invalid metadata node."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[constructArray]\n"; | |
| dbgs() << "CTy: "; | |
| CTy->dump(TheModule); | |
| }); | |
| 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]\n"; | |
| dbgs() << "CTy: "; | |
| CTy->dump(TheModule); | |
| }); | |
| 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]\n"; | |
| dbgs() << "GSR: "; | |
| GSR->dump(TheModule); | |
| }); | |
| 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]\n"; | |
| dbgs() << "IE: "; | |
| IE->dump(TheModule); | |
| }); | |
| 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); | |
| } | |
| } | |
| // Traverse the 'inlinedAt' chain and create their associated inlined scopes. | |
| LVScope *LVIRReader::getOrCreateInlinedScope(const DILocation *DL) { | |
| assert(DL && "Invalid metadata node."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[getOrCreateInlinedScope]\n"; | |
| dbgs() << "DL: "; | |
| DL->dump(TheModule); | |
| }); | |
| const DILocalScope *OriginContext = DL->getScope(); | |
| LLVM_DEBUG({ | |
| dbgs() << "OriginContext: "; | |
| OriginContext->dump(TheModule); | |
| }); | |
| auto CreateScope = [&](const DILocalScope *Context) -> LVScope * { | |
| LVScope *Scope = nullptr; | |
| if (const auto *SP = dyn_cast<DISubprogram>(Context)) | |
| Scope = getOrCreateSubprogram(SP); | |
| else | |
| Scope = getOrCreateScope(Context); | |
| LLVM_DEBUG({ | |
| dbgs() << "Scope: "; | |
| Scope->dumpCommon(); | |
| }); | |
| return Scope; | |
| }; | |
| const DILocation *InlinedAt = DL->getInlinedAt(); | |
| if (!InlinedAt) | |
| return CreateScope(OriginContext); | |
| LLVM_DEBUG({ | |
| dbgs() << "InlinedAt: "; | |
| InlinedAt->dump(TheModule); | |
| }); | |
| // Check if the inlined scope is already created. | |
| if (LVScope *InlinedScope = getInlinedScope(OriginContext, InlinedAt)) | |
| return InlinedScope; | |
| // Get or create the original context, which will be the seed for the | |
| // inlined scope that we intend to create. | |
| LVScope *OriginScope = CreateScope(OriginContext); | |
| dwarf::Tag Tag = OriginScope->getTag(); | |
| if (OriginScope->getIsFunction() || OriginScope->getIsInlinedFunction()) { | |
| Tag = dwarf::DW_TAG_inlined_subroutine; | |
| OriginScope->setInlineCode(dwarf::DW_INL_inlined); | |
| } | |
| LVScope *InlinedScope = static_cast<LVScope *>(createElement(Tag)); | |
| if (InlinedScope) { | |
| addInlinedScope(OriginContext, InlinedAt, InlinedScope); | |
| InlinedScope->setTag(Tag); | |
| InlinedScope->setIsFinalized(); | |
| InlinedScope->setName(OriginScope->getName()); | |
| InlinedScope->setType(OriginScope->getType()); | |
| InlinedScope->setCallLineNumber(InlinedAt->getLine()); | |
| InlinedScope->setCallFilenameIndex( | |
| getOrCreateSourceID(InlinedAt->getFile())); | |
| InlinedScope->setReference(OriginScope); | |
| InlinedScope->setHasReferenceAbstract(); | |
| // Record the link between the origin and the inlined scope, to be | |
| // used to get the correct parent scope for logical lexical scopes. | |
| LLVM_DEBUG({ | |
| dbgs() << "Linking\n"; | |
| OriginScope->dumpCommon(); | |
| InlinedScope->dumpCommon(); | |
| }); | |
| addInlinedInfo(OriginScope, InlinedScope); | |
| LLVM_DEBUG({ | |
| DILocalScope *AbstractContext = InlinedAt->getScope(); | |
| dbgs() << "AbstractContext: "; | |
| AbstractContext->dump(TheModule); | |
| }); | |
| LVScope *AbstractScope = getOrCreateInlinedScope(InlinedAt); | |
| assert(AbstractScope && "Logical scope is NULL."); | |
| LLVM_DEBUG({ | |
| dbgs() << "AbstractScope: "; | |
| AbstractScope->dumpCommon(); | |
| }); | |
| // Add the created inlined scope. | |
| AbstractScope->addElement(InlinedScope); | |
| LLVM_DEBUG({ | |
| dbgs() << "InlinedScope: "; | |
| InlinedScope->dumpCommon(); | |
| }); | |
| } | |
| return InlinedScope; | |
| } | |
| LVScope *LVIRReader::getOrCreateAbstractScope(const DILocation *DL) { | |
| assert(DL && "Invalid metadata node."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[getOrCreateAbstractScope]\n"; | |
| dbgs() << "DL: "; | |
| DL->dump(TheModule); | |
| }); | |
| // Create the 'inlined' scope. | |
| LVScope *InlinedScope = getOrCreateInlinedScope(DL); | |
| assert(InlinedScope && "InlinedScope is null."); | |
| return InlinedScope; | |
| } | |
| void LVIRReader::constructLine(LVScope *Scope, const DISubprogram *SP, | |
| Instruction &I, | |
| bool &GenerateLineBeforePrologue) { | |
| assert(Scope && "Invalid logical element"); | |
| assert(SP && "Invalid metadata node."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[constructLine]\n"; | |
| dbgs() << "Instruction: "; | |
| I.dump(); | |
| dbgs() << "Logical Scope: "; | |
| Scope->dumpCommon(); | |
| }); | |
| auto AddDebugLine = [&](LVScope *Parent, unsigned ID) -> LVLine * { | |
| assert(Parent && "Invalid logical element"); | |
| assert(ID == Metadata::DILocationKind && "Invalid Metadata Object"); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[AddDebugLine]\n"; | |
| dbgs() << "Parent: "; | |
| Parent->dumpCommon(); | |
| }); | |
| LVLine *Line = createLineDebug(); | |
| if (Line) { | |
| Parent->addElement(Line); | |
| Line->setIsFinalized(); | |
| Line->setAddress(CurrentOffset); | |
| // FIXME: How to get discrimination flags: | |
| // IsStmt, BasicBlock, EndSequence, EpilogueBegin, PrologueEnd. | |
| // | |
| // Explore the 'Key Instructions' information added to the metadata: | |
| // !DILocation(line: ..., scope: ..., atomGroup: ..., atomRank: ...) | |
| // Add mapping for this debug line. | |
| CompileUnit->addMapping(Line, /*SectionIndex=*/0); | |
| // Replicate the DWARF reader functionality of adding a linkage | |
| // name to a function with ranges (logical lines), regardless if | |
| // the declaration has already one. | |
| if (!Parent->getLinkageNameIndex() && | |
| Parent->getHasReferenceSpecification()) { | |
| Parent->setLinkageName(Parent->getReference()->getLinkageName()); | |
| } | |
| GenerateLineBeforePrologue = false; | |
| } | |
| return Line; | |
| }; | |
| auto AddAssemblerLine = [&](LVScope *Parent) { | |
| assert(Parent && "Invalid logical element"); | |
| static const char *WhiteSpace = " \t\n\r\f\v"; | |
| static std::string Metadata("metadata "); | |
| auto RemoveAll = [](std::string &Input, std::string &Pattern) { | |
| std::string::size_type Len = Pattern.length(); | |
| for (std::string::size_type Index = Input.find(Pattern); | |
| Index != std::string::npos; Index = Input.find(Pattern)) | |
| Input.erase(Index, Len); | |
| }; | |
| std::string InstructionText; | |
| raw_string_ostream Stream(InstructionText); | |
| Stream << I; | |
| // Remove the 'metadata ' pattern from the instruction text. | |
| RemoveAll(InstructionText, Metadata); | |
| std::string_view Text(InstructionText); | |
| const auto pos(Text.find_first_not_of(WhiteSpace)); | |
| Text.remove_prefix(std::min(pos, Text.length())); | |
| // Create an instruction line at the given scope. | |
| if (LVLineAssembler *Line = createLineAssembler()) { | |
| Line->setIsFinalized(); | |
| Line->setAddress(CurrentOffset); | |
| Line->setName(Text); | |
| Parent->addElement(Line); | |
| } | |
| }; | |
| LVScope *Parent = Scope; | |
| if (const DebugLoc DbgLoc = I.getDebugLoc()) { | |
| const DILocation *DL = DbgLoc.get(); | |
| LLVM_DEBUG({ | |
| dbgs() << "DL: "; | |
| DL->dump(TheModule); | |
| }); | |
| Parent = getOrCreateAbstractScope(DL); | |
| assert(Parent && "Invalid logical element"); | |
| LLVM_DEBUG({ | |
| dbgs() << "Parent: "; | |
| Parent->dumpCommon(); | |
| }); | |
| if (options().getPrintLines() && DL->getLine()) { | |
| if (LVLine *Line = AddDebugLine(Parent, DL->getMetadataID())) { | |
| addMD(DL, Line); | |
| addSourceLine(Line, DL); | |
| GenerateLineBeforePrologue = false; | |
| } | |
| } | |
| } | |
| // Generate a logical line before the function prologue. | |
| if (options().getPrintLines() && GenerateLineBeforePrologue) { | |
| if (LVLine *Line = AddDebugLine(Parent, Metadata::DILocationKind)) { | |
| addSourceLine(Line, SP); | |
| GenerateLineBeforePrologue = false; | |
| } | |
| } | |
| // Create assembler line. | |
| if (options().getPrintInstructions()) | |
| AddAssemblerLine(Parent); | |
| } | |
| LVSymbol *LVIRReader::getOrCreateMember(LVScope *Aggregate, | |
| const DIDerivedType *DT) { | |
| assert(Aggregate && "Invalid logical element"); | |
| assert(DT && "Invalid metadata node."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[getOrCreateMember]\n"; | |
| dbgs() << "DT: "; | |
| DT->dump(TheModule); | |
| }); | |
| LVSymbol *Member = getSymbolForSeenMD(DT); | |
| if (Member && Member->getIsFinalized()) | |
| return Member; | |
| if (!options().getPrintSymbols()) { | |
| // Just create the symbol type. | |
| getOrCreateType(DT->getBaseType()); | |
| return nullptr; | |
| } | |
| if (!Member) | |
| Member = static_cast<LVSymbol *>(getOrCreateType(Aggregate, DT)); | |
| if (Member) { | |
| Member->setIsFinalized(); | |
| addSourceLine(Member, DT); | |
| if (DT->getTag() == dwarf::DW_TAG_inheritance && DT->isVirtual()) { | |
| Member->addLocation(dwarf::DW_AT_data_member_location, /*LowPC=*/0, | |
| /*HighPC=*/-1, /*SectionOffset=*/0, | |
| /*OffsetOnEntry=*/0); | |
| } else { | |
| uint64_t OffsetInBytes = 0; | |
| bool IsBitfield = DT->isBitField(); | |
| if (IsBitfield) { | |
| Member->setBitSize(DT->getSizeInBits()); | |
| } else { | |
| // This is not a bitfield. | |
| OffsetInBytes = DT->getOffsetInBits() / 8; | |
| } | |
| if (DwarfVersion <= 2) { | |
| // DW_AT_data_member_location: | |
| // DW_FORM_data1, DW_OP_plus_uconst, DW_FORM_udata, OffsetInBytes | |
| Member->addLocation(dwarf::DW_AT_data_member_location, /*LowPC=*/0, | |
| /*HighPC=*/-1, /*SectionOffset=*/0, | |
| /*OffsetOnEntry=*/0); | |
| Member->addLocationOperands(dwarf::DW_OP_plus_uconst, {OffsetInBytes}); | |
| } else if (!IsBitfield || DwarfVersion < 4) { | |
| // DW_AT_data_member_location: | |
| // DW_FORM_udata, OffsetInBytes | |
| Member->addLocationConstant(dwarf::DW_AT_data_member_location, | |
| OffsetInBytes, | |
| /*OffsetOnEntry=*/0); | |
| } | |
| } | |
| } | |
| // Add accessibility info if available. | |
| if (!DT->isStaticMember()) | |
| addAccess(Member, DT->getFlags()); | |
| if (DT->isVirtual()) | |
| Member->setVirtualityCode(dwarf::DW_VIRTUALITY_virtual); | |
| if (DT->isArtificial()) | |
| Member->setIsArtificial(); | |
| return Member; | |
| } | |
| // DIBasicType | |
| // DICommonBlock | |
| // DICompileUnit | |
| // DICompositeType | |
| // DIDerivedType | |
| // DIFile | |
| // DILexicalBlock | |
| // DILexicalBlockFile | |
| // DIModule | |
| // DINamespace | |
| // DISubprogram | |
| // DISubroutineType | |
| // DIStringType | |
| void LVIRReader::constructScope(LVElement *Element, const DIScope *Context) { | |
| assert(Element && "Invalid logical element"); | |
| assert(Context && "Invalid metadata node."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[constructScope]\n"; | |
| dbgs() << "Context: "; | |
| Context->dump(TheModule); | |
| }); | |
| if (const DICompositeType *CTy = | |
| dyn_cast_if_present<DICompositeType>(Context)) { | |
| constructType(static_cast<LVScope *>(Element), CTy); | |
| } else if (const DIDerivedType *DT = | |
| dyn_cast_if_present<DIDerivedType>(Context)) { | |
| constructType(Element, DT); | |
| } else if (const DISubprogram *SP = | |
| dyn_cast_if_present<DISubprogram>(Context)) { | |
| getOrCreateSubprogram(static_cast<LVScope *>(Element), SP); | |
| } else if (dyn_cast_if_present<DINamespace>(Context)) { | |
| Element->setIsFinalized(); | |
| } else if (dyn_cast_if_present<DILexicalBlock>(Context)) { | |
| Element->setIsFinalized(); | |
| } | |
| } | |
| LVSymbol *LVIRReader::getOrCreateStaticMember(LVScope *Aggregate, | |
| const DIDerivedType *DT) { | |
| assert(Aggregate && "Invalid logical element"); | |
| assert(DT && "Invalid metadata node."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[getOrCreateStaticMember]\n"; | |
| dbgs() << "DT: "; | |
| DT->dump(TheModule); | |
| }); | |
| LVSymbol *Member = getSymbolForSeenMD(DT); | |
| if (Member && Member->getIsFinalized()) | |
| return Member; | |
| if (!options().getPrintSymbols()) { | |
| // Just create the symbol type. | |
| getOrCreateType(DT->getBaseType()); | |
| return nullptr; | |
| } | |
| if (!Member) | |
| Member = static_cast<LVSymbol *>(getOrCreateType(Aggregate, DT)); | |
| if (Member) { | |
| Member->setIsFinalized(); | |
| addSourceLine(Member, DT); | |
| Member->setIsExternal(); | |
| } | |
| return Member; | |
| } | |
| // DISubprogram | |
| LVScope *LVIRReader::getOrCreateSubprogram(const DISubprogram *SP) { | |
| assert(SP && "Invalid metadata node."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[getOrCreateSubprogram]\n"; | |
| dbgs() << "SP: "; | |
| SP->dump(TheModule); | |
| }); | |
| LVScope *Function = getScopeForSeenMD(SP); | |
| if (Function && Function->getIsFinalized()) | |
| return Function; | |
| if (!Function) | |
| Function = static_cast<LVScope *>(constructElement(SP)); | |
| if (Function) { | |
| // For both member functions (declaration and definition) its parent | |
| // is the containing class. The 'definition' points back to its | |
| // 'declaration' via the 'getDeclaration' return value. | |
| LVScope *Parent = SP->getDeclaration() | |
| ? SP->isLocalToUnit() || SP->isDefinition() | |
| ? CompileUnit | |
| : getParentScope(SP)->getParentScope() | |
| : getParentScope(SP); | |
| // The 'getParentScope' traverses the scope hierarchy and it creates | |
| // the scope chain and any associated types. | |
| // Check that the 'Function' is not already in the parent. | |
| if (!Function->getParent()) | |
| Parent->addElement(Function); | |
| getOrCreateSubprogram(Function, SP, includeMinimalInlineScopes()); | |
| } | |
| return Function; | |
| } | |
| // DISubprogram | |
| LVScope *LVIRReader::getOrCreateSubprogram(LVScope *Function, | |
| const DISubprogram *SP, | |
| bool Minimal) { | |
| assert(Function && "Invalid logical element"); | |
| assert(SP && "Invalid metadata node."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[getOrCreateSubprogram]\n"; | |
| dbgs() << "SP: "; | |
| SP->dump(TheModule); | |
| }); | |
| if (Function->getIsFinalized()) | |
| return Function; | |
| Function->setIsFinalized(); | |
| // Get 'declaration' node in order to generate the DW_AT_specification. | |
| if (const DISubprogram *SPDecl = SP->getDeclaration()) { | |
| if (!Minimal) { | |
| // Build the declaration now to ensure it precedes the definition. | |
| getOrCreateSubprogram(SPDecl); | |
| } | |
| } | |
| // Check for additional retained nodes. | |
| for (const MDNode *DN : SP->getRetainedNodes()) { | |
| if (const auto *IE = dyn_cast<DIImportedEntity>(DN)) | |
| constructImportedEntity(Function, IE); | |
| else if (const auto *TTP = dyn_cast<DITemplateTypeParameter>(DN)) | |
| constructTemplateTypeParameter(Function, TTP); | |
| else if (const auto *TVP = dyn_cast<DITemplateValueParameter>(DN)) | |
| constructTemplateValueParameter(Function, TVP); | |
| else if (const auto *GVE = dyn_cast<DIGlobalVariableExpression>(DN)) | |
| getOrCreateVariable(GVE); | |
| } | |
| applySubprogramAttributes(Function, SP); | |
| // Check if we are dealing with the Global Init/Cleanup Function. | |
| if (SP->isArtificial() && SP->isLocalToUnit() && SP->isDefinition() && | |
| SP->getName().empty()) | |
| Function->setName(SP->getLinkageName()); | |
| return Function; | |
| } | |
| void LVIRReader::constructSubprogramArguments(LVScope *Function, | |
| const DITypeArray Args) { | |
| assert(Function && "Invalid logical element"); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[constructSubprogramArguments]\n"; | |
| for (unsigned i = 1, N = Args.size(); i < N; ++i) { | |
| if (const DIType *Ty = Args[i]) { | |
| dbgs() << "Ty: "; | |
| Ty->dump(TheModule); | |
| } | |
| } | |
| }); | |
| for (unsigned I = 1, N = Args.size(); I < N; ++I) { | |
| const DIType *Ty = Args[I]; | |
| LVElement *Parameter = nullptr; | |
| if (Ty) { | |
| // Create a formal parameter. | |
| LVElement *ParameterType = getOrCreateType(Ty); | |
| Parameter = createElement(dwarf::DW_TAG_formal_parameter); | |
| if (Parameter) { | |
| Parameter->setType(ParameterType); | |
| if (Ty->isArtificial()) | |
| Parameter->setIsArtificial(); | |
| } | |
| } else { | |
| // Add an unspecified parameter. | |
| Parameter = createElement(dwarf::DW_TAG_unspecified_parameters); | |
| } | |
| if (Parameter) { | |
| Function->addElement(Parameter); | |
| Parameter->setIsFinalized(); | |
| } | |
| } | |
| } | |
| // DISubrange | |
| void LVIRReader::constructSubrange(LVScopeArray *Array, const DISubrange *SR, | |
| LVType *IndexType) { | |
| assert(Array && "Invalid logical element"); | |
| assert(SR && "Invalid metadata node."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[constructSubrange]\n"; | |
| dbgs() << "SR: "; | |
| SR->dump(TheModule); | |
| }); | |
| // The DISubrange can be shared between different arrays, when they are | |
| // the same. We need to create independent logical elements for each one, | |
| // as they are going to be added to different arrays. | |
| if (LVTypeSubrange *Subrange = | |
| static_cast<LVTypeSubrange *>(constructElement(SR))) { | |
| Subrange->setIsFinalized(); | |
| Array->addElement(Subrange); | |
| Subrange->setType(IndexType); | |
| int64_t Count = 0; | |
| // If Subrange has a Count field, use it. | |
| // Otherwise, if it has an upperboud, use (upperbound - lowerbound + 1), | |
| // where lowerbound is from the LowerBound field of the Subrange, | |
| // or the language default lowerbound if that field is unspecified. | |
| if (auto *CI = dyn_cast_if_present<ConstantInt *>(SR->getCount())) | |
| Count = CI->getSExtValue(); | |
| else if (auto *UI = | |
| dyn_cast_if_present<ConstantInt *>(SR->getUpperBound())) { | |
| // Fortran uses 1 as the default lowerbound; other languages use 0. | |
| int64_t Lowerbound = getDefaultLowerBound(); | |
| auto *LI = dyn_cast_if_present<ConstantInt *>(SR->getLowerBound()); | |
| Lowerbound = (LI) ? LI->getSExtValue() : Lowerbound; | |
| Count = UI->getSExtValue() - Lowerbound + 1; | |
| } | |
| Subrange->setCount(Count); | |
| } | |
| } | |
| // DITemplateTypeParameter | |
| void LVIRReader::constructTemplateTypeParameter( | |
| LVElement *Element, const DITemplateTypeParameter *TTP) { | |
| assert(Element && "Invalid logical element"); | |
| assert(TTP && "Invalid metadata node."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[constructTemplateTypeParameter]\n"; | |
| dbgs() << "TTP: "; | |
| TTP->dump(TheModule); | |
| }); | |
| // The DITemplateTypeParameter can be shared between different subprogram | |
| // in their DITemplateParameterArray describing the template parameters. | |
| // We need to create independent logical elements for each one, as they are | |
| // going to be added to different function. | |
| if (LVElement *Parameter = constructElement(TTP)) { | |
| Parameter->setIsFinalized(); | |
| // Add element to parent (always the given Element). | |
| LVScope *Parent = static_cast<LVScope *>(Element); | |
| Parent->addElement(Parameter); | |
| // Mark the parent as template. | |
| Parent->setIsTemplate(); | |
| // Add the type if it exists, it could be void and therefore no type. | |
| if (const DIType *Ty = TTP->getType()) { | |
| LVElement *Type = getElementForSeenMD(Ty); | |
| if (!Type) | |
| Type = getOrCreateType(Ty); | |
| Parameter->setType(Type); | |
| } | |
| } | |
| } | |
| // DITemplateValueParameter | |
| void LVIRReader::constructTemplateValueParameter( | |
| LVElement *Element, const DITemplateValueParameter *TVP) { | |
| assert(Element && "Invalid logical element"); | |
| assert(TVP && "Invalid metadata node."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[constructTemplateValueParameter]\n"; | |
| dbgs() << "TVP: "; | |
| TVP->dump(TheModule); | |
| }); | |
| // The DITemplateValueParameter can be shared between different subprogram | |
| // in their DITemplateParameterArray describing the template parameters. | |
| // We need to create independent logical elements for each one, as they are | |
| // going to be added to different function. | |
| if (LVElement *Parameter = constructElement(TVP)) { | |
| Parameter->setIsFinalized(); | |
| // Add element to parent (always the given Element). | |
| LVScope *Parent = static_cast<LVScope *>(Element); | |
| Parent->addElement(Parameter); | |
| // Mark the parent as template. | |
| Parent->setIsTemplate(); | |
| // Add the type if there is one, template template and template parameter | |
| // packs will not have a type. | |
| if (TVP->getTag() == dwarf::DW_TAG_template_value_parameter) { | |
| LVElement *Type = getOrCreateType(TVP->getType()); | |
| Parameter->setType(Type); | |
| } | |
| if (Metadata *Value = TVP->getValue()) { | |
| if (ConstantInt *CI = mdconst::dyn_extract<ConstantInt>(Value)) | |
| addConstantValue(Parameter, CI, TVP->getType()); | |
| else if (ConstantFP *CF = mdconst::dyn_extract<ConstantFP>(Value)) | |
| addConstantValue(Parameter, CF); | |
| else if (mdconst::dyn_extract<GlobalValue>(Value)) { | |
| // We cannot describe the location of dllimport'd entities: the | |
| // computation of their address requires loads from the IAT. | |
| Parameter->setValue("Unable to describe global value"); | |
| } else if (TVP->getTag() == dwarf::DW_TAG_GNU_template_template_param) { | |
| assert(isa<MDString>(Value)); | |
| // Add the value for dwarf::DW_AT_GNU_template_name. | |
| Parameter->setValue(cast<MDString>(Value)->getString()); | |
| } else if (TVP->getTag() == dwarf::DW_TAG_GNU_template_parameter_pack) { | |
| addTemplateParams(Parameter, cast<MDTuple>(Value)); | |
| } | |
| } | |
| } | |
| } | |
| // DICompositeType | |
| // DW_TAG_array_type | |
| // DW_TAG_class_type | |
| // DW_TAG_enumeration_type | |
| // DW_TAG_structure_type | |
| // DW_TAG_union_type | |
| void LVIRReader::constructType(LVScope *Scope, const DICompositeType *CTy) { | |
| assert(Scope && "Invalid logical element"); | |
| assert(CTy && "Invalid metadata node."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[constructType]\n"; | |
| dbgs() << "CTy: "; | |
| CTy->dump(TheModule); | |
| }); | |
| dwarf::Tag Tag = Scope->getTag(); | |
| switch (Tag) { | |
| case dwarf::DW_TAG_array_type: | |
| constructArray(static_cast<LVScopeArray *>(Scope), CTy); | |
| break; | |
| case dwarf::DW_TAG_enumeration_type: | |
| constructEnum(static_cast<LVScopeEnumeration *>(Scope), CTy); | |
| break; | |
| // FIXME: Not implemented. | |
| case dwarf::DW_TAG_variant_part: | |
| case dwarf::DW_TAG_namelist: | |
| break; | |
| case dwarf::DW_TAG_structure_type: | |
| case dwarf::DW_TAG_union_type: | |
| case dwarf::DW_TAG_class_type: { | |
| constructAggregate(static_cast<LVScopeAggregate *>(Scope), CTy); | |
| break; | |
| } | |
| default: | |
| break; | |
| } | |
| if (Tag == dwarf::DW_TAG_enumeration_type || | |
| Tag == dwarf::DW_TAG_class_type || Tag == dwarf::DW_TAG_structure_type || | |
| Tag == dwarf::DW_TAG_union_type) { | |
| // Add accessibility info if available. | |
| addAccess(Scope, CTy->getFlags()); | |
| // Add source line info if available. | |
| if (!CTy->isForwardDecl()) | |
| addSourceLine(Scope, CTy); | |
| } | |
| } | |
| // DIDerivedType | |
| // DW_TAG_atomic_type | |
| // DW_TAG_const_type | |
| // DW_TAG_friend | |
| // DW_TAG_inheritance | |
| // DW_TAG_member | |
| // DW_TAG_immutable_type | |
| // DW_TAG_pointer_type | |
| // DW_TAG_ptr_to_member_type | |
| // DW_TAG_reference_type | |
| // DW_TAG_restrict_type | |
| // DW_TAG_typedef | |
| // DW_TAG_volatile_type | |
| void LVIRReader::constructType(LVElement *Element, const DIDerivedType *DT) { | |
| assert(Element && "Invalid logical element"); | |
| assert(DT && "Invalid metadata node."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[constructType]\n"; | |
| dbgs() << "DT: "; | |
| DT->dump(TheModule); | |
| }); | |
| // For DW_TAG_member, the flag is set during the construction of the | |
| // aggregate type (DICompositeType). | |
| if (DT->getTag() != dwarf::DW_TAG_member) | |
| Element->setIsFinalized(); | |
| LVElement *BaseType = getOrCreateType(DT->getBaseType()); | |
| Element->setType(BaseType); | |
| // Add accessibility info if available. | |
| if (!DT->isStaticMember()) | |
| addAccess(Element, DT->getFlags()); | |
| if (DT->isVirtual()) | |
| Element->setVirtualityCode(dwarf::DW_VIRTUALITY_virtual); | |
| if (DT->isArtificial()) | |
| Element->setIsArtificial(); | |
| // Add source line info if available and TyDesc is not a forward declaration. | |
| if (!DT->isForwardDecl()) | |
| addSourceLine(Element, DT); | |
| } | |
| // DISubroutineType | |
| void LVIRReader::constructType(LVScope *Function, | |
| const DISubroutineType *SPTy) { | |
| assert(Function && "Invalid logical element"); | |
| assert(SPTy && "Invalid metadata node."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[constructType]\n"; | |
| dbgs() << "SPTy: "; | |
| SPTy->dump(TheModule); | |
| }); | |
| if (Function->getIsFinalized()) | |
| return; | |
| Function->setIsFinalized(); | |
| // For DISubprogram, the DISubroutineType contains the types for: | |
| // return type, param 1 type, ..., param n type | |
| DITypeArray Args = SPTy->getTypeArray(); | |
| if (Args.size()) { | |
| LVElement *ElementType = getOrCreateType(Args[0]); | |
| Function->setType(ElementType); | |
| } | |
| constructSubprogramArguments(Function, Args); | |
| } | |
| // DINamespace | |
| LVScope *LVIRReader::getOrCreateNamespace(const DINamespace *NS) { | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[getOrCreateNamespace]\n"; | |
| dbgs() << "NS: "; | |
| NS->dump(TheModule); | |
| }); | |
| LVScope *Scope = getOrCreateScope(NS); | |
| if (Scope) { | |
| StringRef Name = NS->getName(); | |
| if (Name.empty()) | |
| Scope->setName("(anonymous namespace)"); | |
| } | |
| return Scope; | |
| } | |
| LVScope *LVIRReader::getOrCreateScope(const DIScope *Context) { | |
| assert(Context && "Invalid metadata node."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[getOrCreateScope]\n"; | |
| dbgs() << "Context: "; | |
| Context->dump(TheModule); | |
| }); | |
| // Check if the scope is already created. | |
| LVScope *Scope = getScopeForSeenMD(Context); | |
| if (Scope) | |
| return Scope; | |
| Scope = static_cast<LVScope *>(constructElement(Context)); | |
| if (Scope) { | |
| // Add element to parent. | |
| LVScope *Parent = getParentScope(Context); | |
| Parent->addElement(Scope); | |
| } | |
| return Scope; | |
| } | |
| // DICompositeType | |
| // DIDerivedType | |
| // DISubroutineType | |
| LVElement *LVIRReader::getOrCreateType(LVScope *Scope, const DIType *Ty) { | |
| if (!Ty) | |
| return nullptr; | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[getOrCreateType]\n"; | |
| dbgs() << "Ty :"; | |
| Ty->dump(TheModule); | |
| }); | |
| // Check if the element is already created. | |
| LVElement *Element = getElementForSeenMD(Ty); | |
| if (Element) | |
| return Element; | |
| Element = constructElement(Ty); | |
| if (Element) { | |
| // Add element to parent. | |
| LVScope *Parent = Scope ? Scope : getParentScope(Ty); | |
| Parent->addElement(Element); | |
| if (isa<DIBasicType>(Ty)) { | |
| Element->setIsFinalized(); | |
| } else if (const DIDerivedType *DT = dyn_cast<DIDerivedType>(Ty)) { | |
| constructType(Element, DT); | |
| } else if (const DICompositeType *CTy = dyn_cast<DICompositeType>(Ty)) { | |
| constructType(static_cast<LVScope *>(Element), CTy); | |
| } else if (const DISubroutineType *SPTy = dyn_cast<DISubroutineType>(Ty)) { | |
| constructType(static_cast<LVScope *>(Element), SPTy); | |
| } | |
| } | |
| return Element; | |
| } | |
| // DIGlobalVariableExpression | |
| LVSymbol * | |
| LVIRReader::getOrCreateVariable(const DIGlobalVariableExpression *GVE) { | |
| assert(GVE && "Invalid metadata node."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[getOrCreateVariable]\n"; | |
| dbgs() << "GVE: "; | |
| GVE->dump(TheModule); | |
| }); | |
| const DIGlobalVariable *DIGV = GVE->getVariable(); | |
| LVSymbol *Symbol = getSymbolForSeenMD(DIGV); | |
| if (!Symbol) | |
| Symbol = getOrCreateVariable(DIGV); | |
| if (Symbol) { | |
| // Add location and operation entries. | |
| Symbol->addLocation(dwarf::DW_AT_location, /*LowPC=*/0, /*HighPC=*/-1, | |
| /*SectionOffset=*/0, /*OffsetOnEntry=*/0); | |
| Symbol->addLocationOperands(dwarf::DW_OP_addrx, PoolAddressIndex++); | |
| if (const DIExpression *DIExpr = GVE->getExpression()) | |
| addConstantValue(Symbol, DIExpr); | |
| } | |
| return Symbol; | |
| } | |
| LVSymbol *LVIRReader::getOrCreateInlinedVariable(LVSymbol *OriginSymbol, | |
| const DILocation *DL) { | |
| assert(OriginSymbol && "Invalid logical element"); | |
| assert(DL && "Invalid metadata node."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[getOrCreateInlinedVariable]\n"; | |
| dbgs() << "DL: "; | |
| DL->dump(TheModule); | |
| }); | |
| const DILocation *InlinedAt = DL->getInlinedAt(); | |
| if (!InlinedAt) { | |
| return nullptr; | |
| } | |
| dwarf::Tag Tag = OriginSymbol->getTag(); | |
| LVSymbol *InlinedSymbol = static_cast<LVSymbol *>(createElement(Tag)); | |
| if (InlinedSymbol) { | |
| InlinedSymbol->setTag(Tag); | |
| InlinedSymbol->setIsFinalized(); | |
| InlinedSymbol->setName(OriginSymbol->getName()); | |
| InlinedSymbol->setType(OriginSymbol->getType()); | |
| InlinedSymbol->setCallLineNumber(InlinedAt->getLine()); | |
| InlinedSymbol->setCallFilenameIndex( | |
| getOrCreateSourceID(InlinedAt->getFile())); | |
| OriginSymbol->setInlineCode(dwarf::DW_INL_inlined); | |
| InlinedSymbol->setReference(OriginSymbol); | |
| InlinedSymbol->setHasReferenceAbstract(); | |
| if (OriginSymbol->getIsParameter()) | |
| InlinedSymbol->setIsParameter(); | |
| // Get or create the local scope associated with the location. | |
| LVScope *InlinedScope = getOrCreateInlinedScope(DL); | |
| assert(InlinedScope && "Invalid logical element"); | |
| // Add the created inlined scope. | |
| InlinedScope->addElement(InlinedSymbol); | |
| } | |
| return InlinedSymbol; | |
| } | |
| // DIGlobalVariable | |
| // DILocalVariable | |
| LVSymbol *LVIRReader::getOrCreateVariable(const DIVariable *Var, | |
| const DILocation *DL) { | |
| assert(Var && "Invalid metadata node."); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[getOrCreateVariable]\n"; | |
| dbgs() << "Var: "; | |
| Var->dump(TheModule); | |
| if (DL) { | |
| dbgs() << "DL: "; | |
| DL->dump(TheModule); | |
| } | |
| }); | |
| // Use the 'InlinedAt' information to identify a symbol that is being | |
| // inlined. Its abstract representation is created just once. | |
| const DILocation *InlinedAt = DL ? DL->getInlinedAt() : nullptr; | |
| LVSymbol *Symbol = getSymbolForSeenMD(Var); | |
| if (Symbol && Symbol->getIsFinalized() && !InlinedAt) | |
| return Symbol; | |
| if (!options().getPrintSymbols()) { | |
| // Just create the symbol type. | |
| getOrCreateType(Var->getType()); | |
| if (const DIGlobalVariable *GV = dyn_cast<DIGlobalVariable>(Var)) { | |
| if (MDTuple *TP = GV->getTemplateParams()) | |
| addTemplateParams(Symbol, DINodeArray(TP)); | |
| } | |
| return nullptr; | |
| } | |
| if (!Symbol) | |
| Symbol = static_cast<LVSymbol *>(constructElement(Var)); | |
| if (Symbol && !Symbol->getIsFinalized()) { | |
| Symbol->setIsFinalized(); | |
| LVScope *Parent = getParentScope(Var); | |
| Parent->addElement(Symbol); | |
| Symbol->setName(Var->getName()); | |
| // Create symbol type. | |
| if (LVElement *SymbolType = getOrCreateType(Var->getType())) | |
| Symbol->setType(SymbolType); | |
| if (const DILocalVariable *LV = dyn_cast<DILocalVariable>(Var)) { | |
| // Add line number info. | |
| addSourceLine(Symbol, LV); | |
| if (LV->isParameter()) { | |
| Symbol->setIsParameter(); | |
| if (LV->isArtificial()) | |
| Symbol->setIsArtificial(); | |
| } | |
| } else { | |
| const DIGlobalVariable *GV = dyn_cast<DIGlobalVariable>(Var); | |
| if (useAllLinkageNames()) | |
| Symbol->setLinkageName(GV->getLinkageName()); | |
| // Get 'declaration' node in order to generate the DW_AT_specification. | |
| if (const DIDerivedType *GVDecl = GV->getStaticDataMemberDeclaration()) { | |
| LVSymbol *Reference = static_cast<LVSymbol *>(getOrCreateType(GVDecl)); | |
| if (Reference) { | |
| Symbol->setReference(Reference); | |
| Symbol->setHasReferenceSpecification(); | |
| } | |
| } else { | |
| if (!GV->isLocalToUnit()) | |
| Symbol->setIsExternal(); | |
| // Add line number info. | |
| addSourceLine(Symbol, GV); | |
| } | |
| if (MDTuple *TP = GV->getTemplateParams()) | |
| addTemplateParams(Symbol, DINodeArray(TP)); | |
| } | |
| } | |
| // Create the 'inlined' symbol. | |
| if (DL) | |
| getOrCreateInlinedVariable(Symbol, DL); | |
| return Symbol; | |
| } | |
| #ifdef LLVM_DEBUG | |
| void LVIRReader::printAllInstructions(BasicBlock *BB) { | |
| const Function *F = BB->getParent(); | |
| if (!F) | |
| return; | |
| LLVM_DEBUG({ | |
| const DISubprogram *SP = cast<DISubprogram>(F->getSubprogram()); | |
| dbgs() << "\nBegin all instructions: '" << SP->getName() << "'\n"; | |
| for (Instruction &I : *BB) { | |
| dbgs() << "I: '" << I << "'\n"; | |
| for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) { | |
| dbgs() << " Var: "; | |
| DVR.getVariable()->dump(TheModule); | |
| } | |
| if (const auto *DL = | |
| cast_or_null<DILocation>(I.getMetadata(LLVMContext::MD_dbg))) { | |
| dbgs() << " DL: "; | |
| DL->dump(TheModule); | |
| } | |
| } | |
| dbgs() << "End all instructions: '" << SP->getName() << "'\n\n"; | |
| }); | |
| } | |
| #endif | |
| void LVIRReader::processBasicBlocks(Function &F) { | |
| const DISubprogram *SP = cast_or_null<DISubprogram>(F.getSubprogram()); | |
| if (!SP) | |
| return; | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[processBasicBlocks]\n"; | |
| dbgs() << "SP: "; | |
| SP->dump(TheModule); | |
| }); | |
| // Check if we need to add a dwarf::DW_TAG_unspecified_parameters. | |
| bool AddUnspecifiedParameters = false; | |
| if (const DISubroutineType *SPTy = SP->getType()) { | |
| DITypeArray Args = SPTy->getTypeArray(); | |
| unsigned N = Args.size(); | |
| if (N > 1) { | |
| const DIType *Ty = Args[N - 1]; | |
| if (!Ty) | |
| AddUnspecifiedParameters = true; | |
| } | |
| } | |
| LVScope *Scope = getOrCreateSubprogram(SP); | |
| SmallVector<DebugVariableAggregate> SeenVars; | |
| // Handle dbg.values and dbg.declare. | |
| auto HandleDbgVariable = [&](auto *DbgVar) { | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[HandleDbgVariable]\n"; | |
| dbgs() << "DbgVar: "; | |
| DbgVar->dump(); | |
| }); | |
| DebugVariableAggregate DVA(DbgVar); | |
| if (!DbgValueRanges->hasVariableEntry(DVA)) { | |
| DbgValueRanges->addVariable(&F, DVA); | |
| SeenVars.push_back(DVA); | |
| } | |
| // Skip undefined values. | |
| if (!DbgVar->isKillLocation()) | |
| getOrCreateVariable(DbgVar->getVariable(), DbgVar->getDebugLoc().get()); | |
| }; | |
| // Generate logical debug line before prologue. | |
| bool GenerateLineBeforePrologue = true; | |
| for (BasicBlock &BB : F) { | |
| printAllInstructions(&BB); | |
| for (Instruction &I : BB) { | |
| LLVM_DEBUG(dbgs() << "\nInstruction: '" << I << "'\n"); | |
| if (const auto *DL = | |
| cast_or_null<DILocation>(I.getMetadata(LLVMContext::MD_dbg))) { | |
| LLVM_DEBUG({ | |
| dbgs() << " Location: "; | |
| DL->dump(TheModule); | |
| }); | |
| getOrCreateAbstractScope(DL); | |
| } | |
| for (DbgVariableRecord &DVR : filterDbgVars(I.getDbgRecordRange())) | |
| HandleDbgVariable(&DVR); | |
| if (options().getPrintAnyLine()) | |
| constructLine(Scope, SP, I, GenerateLineBeforePrologue); | |
| InstrLineAddrMap[I.getIterator().getNodePtr()] = CurrentOffset; | |
| // Update code offset. | |
| updateLineOffset(); | |
| } | |
| InstrLineAddrMap[BB.end().getNodePtr()] = CurrentOffset; | |
| } | |
| GenerateLineBeforePrologue = false; | |
| if (AddUnspecifiedParameters) { | |
| LVElement *Parameter = createElement(dwarf::DW_TAG_unspecified_parameters); | |
| if (Parameter) { | |
| Parameter->setIsFinalized(); | |
| Scope->addElement(Parameter); | |
| } | |
| } | |
| LLVM_DEBUG({ dbgs() << "\nTraverse seen debug variables\n"; }); | |
| for (const DebugVariableAggregate &DVA : SeenVars) { | |
| LLVM_DEBUG({ DbgValueRanges->printValues(DVA, dbgs()); }); | |
| DILocalVariable *LV = const_cast<DILocalVariable *>(DVA.getVariable()); | |
| LVSymbol *Symbol = getSymbolForSeenMD(LV); | |
| // Undefined only value, ignore. | |
| if (!Symbol) | |
| continue; | |
| LLVM_DEBUG({ | |
| DIType *Ty = LV->getType(); | |
| uint64_t Size = Ty ? Ty->getSizeInBits() / CHAR_BIT : 1; | |
| LV->dump(TheModule); | |
| Ty->dump(TheModule); | |
| dbgs() << "Type size: " << Size << "\n"; | |
| }); | |
| auto AddLocationOp = [&](Value *V, bool IsMem) { | |
| uint64_t RegValue = ValueNameMap.addValue(V); | |
| if (IsMem) | |
| Symbol->addLocationOperands(dwarf::DW_OP_bregx, {RegValue, 0}); | |
| else | |
| Symbol->addLocationOperands(dwarf::DW_OP_regx, RegValue); | |
| }; | |
| auto AddLocation = [&](DbgValueDef DV) { | |
| bool IsMem = DV.IsMemory; | |
| DIExpression *CanonicalExpr = const_cast<DIExpression *>( | |
| DIExpression::convertToVariadicExpression(DV.Expression)); | |
| RawLocationWrapper Locations(DV.Locations); | |
| for (DIExpression::ExprOperand ExprOp : CanonicalExpr->expr_ops()) { | |
| if (auto Arg = dyn_cast<DIExpression::ArgOp>(ExprOp)) { | |
| AddLocationOp(Locations.getVariableLocationOp(Arg.getIndex()), IsMem); | |
| } else { | |
| if (ExprOp.getOp() > std::numeric_limits<uint8_t>::max()) | |
| LLVM_DEBUG(dbgs() << "Bad DWARF op: " << ExprOp.getOp() << "\n"); | |
| uint8_t ShortOp = (uint8_t)ExprOp.getOp(); | |
| Symbol->addLocationOperands( | |
| ShortOp, | |
| ArrayRef<uint64_t>(std::next(ExprOp.get()), ExprOp.getNumArgs())); | |
| } | |
| } | |
| }; | |
| if (DbgValueRanges->hasSingleLocEntry(DVA)) { | |
| DbgValueDef DV = DbgValueRanges->getSingleLoc(DVA); | |
| Symbol->addLocation(llvm::dwarf::DW_AT_location, /*LowPC=*/0, | |
| /*HighPC=*/-1, /*SectionOffset=*/0, | |
| /*OffsetOnEntry=*/0); | |
| assert(DV.IsMemory && "Single location should be memory!"); | |
| AddLocation(DV); | |
| } else { | |
| for (const DbgRangeEntry &Entry : | |
| DbgValueRanges->getVariableRanges(DVA)) { | |
| // These line addresses should have already been inserted into the | |
| // InstrLineAddrMap, so we assume they are present here. | |
| LVOffset Start = InstrLineAddrMap.at(Entry.Start.getNodePtr()); | |
| LVOffset End = InstrLineAddrMap.at(Entry.End.getNodePtr()); | |
| Symbol->addLocation(llvm::dwarf::DW_AT_location, Start, End, | |
| /*SectionOffset=*/0, /*OffsetOnEntry=*/0); | |
| DbgValueDef DV = Entry.Value; | |
| AddLocation(DV); | |
| } | |
| } | |
| } | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // IR Reader entry point. | |
| //===----------------------------------------------------------------------===// | |
| Error LVIRReader::createScopes() { | |
| LLVM_DEBUG({ | |
| W.startLine() << "\n"; | |
| W.printString("File", getFilename()); | |
| W.printString("Format", FileFormatName); | |
| }); | |
| // The IR Reader supports only debug records. | |
| // We identify the debug input format and if it is intrinsics, it is | |
| // converted to the debug records. | |
| if (Error Err = LVReader::createScopes()) | |
| return Err; | |
| LLVMContext Context; | |
| SMDiagnostic Err; | |
| std::unique_ptr<Module> M = | |
| parseIR(isa<IRObjectFile *>(InputFile) | |
| ? cast<IRObjectFile *>(InputFile)->getMemoryBufferRef() | |
| : *(cast<MemoryBufferRef *>(InputFile)), | |
| Err, Context); | |
| if (!M) { | |
| // Print explanatory error message. | |
| if (options().getWarningAll()) | |
| Err.print("", outs()); | |
| return createStringError(errc::invalid_argument, | |
| "Could not create IR module for: %s", | |
| getFilename().str().c_str()); | |
| } | |
| TheModule = M.get(); | |
| if (!TheModule->getNamedMetadata("llvm.dbg.cu")) { | |
| LLVM_DEBUG(dbgs() << "Skipping module without debug info\n"); | |
| return Error::success(); | |
| } | |
| DwarfVersion = TheModule->getDwarfVersion(); | |
| LLVM_DEBUG({ dbgs() << "\nProcess CompileUnits\n"; }); | |
| for (const DICompileUnit *CU : TheModule->debug_compile_units()) { | |
| LLVM_DEBUG({ | |
| dbgs() << "\nCU: "; | |
| CU->dump(TheModule); | |
| }); | |
| CompileUnit = static_cast<LVScopeCompileUnit *>(constructElement(CU)); | |
| CUNode = const_cast<DICompileUnit *>(CU); | |
| const DIFile *File = CU->getFile(); | |
| CompileUnit->setName(File->getFilename()); | |
| CompileUnit->setCompilationDirectory(File->getDirectory()); | |
| CompileUnit->setIsFinalized(); | |
| Root->addElement(CompileUnit); | |
| // As the IR format uses the DWARF symbolic constants, the setting | |
| // of the source language must use the DWARF language definitions. | |
| uint16_t LanguageName = CU->getSourceLanguage().getName(); | |
| LVSourceLanguage SL = LVSourceLanguage( | |
| static_cast<llvm::dwarf::SourceLanguage>(LanguageName)); | |
| setDefaultLowerBound(&SL); | |
| if (options().getAttributeLanguage()) | |
| CompileUnit->setSourceLanguage(SL); | |
| if (options().getAttributeProducer()) | |
| CompileUnit->setProducer(CU->getProducer()); | |
| // Global Variables. | |
| LLVM_DEBUG({ dbgs() << "\nGlobal Variables\n"; }); | |
| for (const DIGlobalVariableExpression *GVE : CU->getGlobalVariables()) | |
| getOrCreateVariable(GVE); | |
| // The enumeration types need to be created, regardless if they are | |
| // nested to any other aggregate type, as they are not included in | |
| // their elements. But their scope is correct (aggregate). | |
| LLVM_DEBUG({ dbgs() << "\nEnumeration Types\n"; }); | |
| for (auto *ET : CU->getEnumTypes()) | |
| getOrCreateType(ET); | |
| // Retained types. | |
| LLVM_DEBUG({ dbgs() << "\nRetained Types\n"; }); | |
| for (const auto *RT : CU->getRetainedTypes()) { | |
| if (const auto *Ty = dyn_cast<DIType>(RT)) { | |
| getOrCreateType(Ty); | |
| } else { | |
| getOrCreateSubprogram(cast<DISubprogram>(RT)); | |
| } | |
| } | |
| // Imported entities. | |
| LLVM_DEBUG({ dbgs() << "\nImported Entities\n"; }); | |
| for (const auto *IE : CU->getImportedEntities()) | |
| constructImportedEntity(CompileUnit, IE); | |
| } | |
| // Traverse Functions. | |
| LLVM_DEBUG({ | |
| dbgs() << "\nFunctions\n"; | |
| for (Function &F : M->getFunctionList()) | |
| if (const auto *SP = cast_or_null<DISubprogram>(F.getSubprogram())) | |
| SP->dump(TheModule); | |
| }); | |
| for (Function &F : M->getFunctionList()) | |
| processBasicBlocks(F); | |
| // Perform extra tasks on the created scopes. | |
| resolveInlinedLexicalScopes(); | |
| removeEmptyScopes(); | |
| processLocationGaps(); | |
| processScopes(); | |
| if (options().getInternalIntegrity()) | |
| checkScopes(CompileUnit); | |
| TheModule = nullptr; | |
| return Error::success(); | |
| } | |
| void LVIRReader::constructRange(LVScope *Scope, LVAddress LowPC, | |
| LVAddress HighPC) { | |
| assert(Scope && "Invalid logical element"); | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[constructRange]\n"; | |
| dbgs() << "ID: " << hexString(Scope->getID()) << " "; | |
| dbgs() << "LowPC: " << hexString(LowPC) << " "; | |
| dbgs() << "HighPC: " << hexString(HighPC) << " "; | |
| dbgs() << "Name: " << Scope->getName() << "\n"; | |
| }); | |
| // Process ranges base on logical lines. | |
| Scope->addObject(LowPC, HighPC); | |
| if (!Scope->getIsCompileUnit()) { | |
| // If the scope is a function, add it to the public names. | |
| if ((options().getAttributePublics() || options().getPrintAnyLine()) && | |
| Scope->getIsFunction() && !Scope->getIsInlinedFunction()) | |
| CompileUnit->addPublicName(Scope, LowPC, HighPC); | |
| } | |
| addSectionRange(/*SectionIndex=*/0, Scope, LowPC, HighPC); | |
| // Replicate DWARF reader funtionality of processing DW_AT_ranges for | |
| // the compilation unit. | |
| CompileUnit->addObject(LowPC, HighPC); | |
| addSectionRange(/*SectionIndex=*/0, CompileUnit, LowPC, HighPC); | |
| } | |
| // Create the location ranges for the given scope and in the case of | |
| // functions, generate an entry in the public names set. | |
| void LVIRReader::constructRange(LVScope *Scope) { | |
| LLVM_DEBUG({ | |
| dbgs() << "\n[constructRange]\n"; | |
| dbgs() << "ID: " << hexString(Scope->getID()) << " "; | |
| dbgs() << "Name: " << Scope->getName() << "\n\n"; | |
| }); | |
| auto NextRange = [&](LVAddress Offset) -> LVAddress { | |
| return Offset + OFFSET_INCREASE - 1; | |
| }; | |
| // Get any logical lines. | |
| const LVLines *Lines = Scope->getLines(); | |
| if (!Lines) | |
| return; | |
| // Traverse the logical lines and build the logical ranges. | |
| LVAddress Lower = 0; | |
| LVAddress Upper = 0; | |
| LVAddress Current = 0; | |
| LVAddress Previous = 0; | |
| for (const LVLine *Line : *Lines) { | |
| LLVM_DEBUG({ | |
| dbgs() << "[" << hexString(Line->getAddress()) << "] "; | |
| dbgs() << "LineNo: " << decString(Line->getLineNumber()) << "\n"; | |
| dbgs() << "Lower: " << hexString(Lower) << " "; | |
| dbgs() << "Upper: " << hexString(Upper) << " "; | |
| dbgs() << "Previous: " << hexString(Previous) << " "; | |
| dbgs() << "Current: " << hexString(Current) << "\n"; | |
| }); | |
| if (!Upper) { | |
| // First line in range. | |
| Lower = Line->getAddress(); | |
| Upper = NextRange(Lower); | |
| Current = Lower; | |
| continue; | |
| } | |
| Previous = Current; | |
| Current = Line->getAddress(); | |
| if (Current == Previous) { | |
| // Contiguous lines at the same address (Debug and its assembler). | |
| continue; | |
| } | |
| if (Current == Upper + 1) { | |
| // There is no gap. | |
| Upper = NextRange(Current); | |
| } else { | |
| // There is a gap. | |
| constructRange(Scope, Lower, Upper); | |
| Lower = Current; | |
| Upper = NextRange(Lower); | |
| } | |
| } | |
| constructRange(Scope, Lower, Upper); | |
| } | |
| // At this point, all scopes for the compile unit have been created. | |
| // The following aditional steps need to be performed on them: | |
| // - If the lexical block doesn't have non-scope children, skip its | |
| // emission and put its children directly to the parent scope. | |
| // The '--internal=id' is turned on just for debugging traces. Then | |
| // it is turned to its previous state. | |
| void LVIRReader::removeEmptyScopes() { | |
| LLVM_DEBUG({ dbgs() << "\n[removeEmptyScopes]\n"; }); | |
| SmallVector<LVScope *> EmptyScopes; | |
| // Delete lexically empty scopes. | |
| auto DeleteEmptyScopes = [&]() { | |
| if (EmptyScopes.empty()) | |
| return; | |
| LLVM_DEBUG({ | |
| dbgs() << "\n** Collected empty scopes **\n"; | |
| for (auto Scope : EmptyScopes) | |
| Scope->print(dbgs()); | |
| }); | |
| LVScope *Parent = nullptr; | |
| for (auto Scope : EmptyScopes) { | |
| Parent = Scope->getParentScope(); | |
| LLVM_DEBUG({ | |
| dbgs() << "Scope: " << Scope->getID() << ", "; | |
| dbgs() << "Parent: " << Parent->getID() << "\n"; | |
| }); | |
| // If the target scope has lines, move them to the scope parent. | |
| const LVLines *Lines = Scope->getLines(); | |
| if (Lines) { | |
| LVLines Pack; | |
| std::copy(Lines->begin(), Lines->end(), std::back_inserter(Pack)); | |
| for (LVLine *Line : Pack) { | |
| if (Scope->removeElement(Line)) { | |
| LLVM_DEBUG({ dbgs() << "Line: " << Line->getID() << "\n"; }); | |
| Line->resetParent(); | |
| Parent->addElement(Line); | |
| Line->updateLevel(Parent, /*Moved=*/false); | |
| } | |
| } | |
| } | |
| if (Parent->removeElement(Scope)) { | |
| const LVScopes *Scopes = Scope->getScopes(); | |
| if (Scopes) { | |
| for (LVScope *Child : *Scopes) { | |
| LLVM_DEBUG({ dbgs() << "Child: " << Child->getID() << "\n"; }); | |
| Child->resetParent(); | |
| Parent->addElement(Child); | |
| Child->updateLevel(Parent, /*Moved=*/false); | |
| } | |
| } | |
| } | |
| } | |
| }; | |
| // Traverse the scopes tree and collect those lexical blocks that do not | |
| // have non-scope children. Do not include the lines as they are included | |
| // in the logical view as a way to show their associated logical scope. | |
| std::function<void(LVScope *)> TraverseScope = [&](LVScope *Current) { | |
| auto IsEmpty = [](LVScope *Scope) -> bool { | |
| return !Scope->getSymbols() && !Scope->getTypes() && !Scope->getRanges(); | |
| }; | |
| if (const LVScopes *Scopes = Current->getScopes()) { | |
| for (LVScope *Scope : *Scopes) { | |
| if (Scope->getIsLexicalBlock() && IsEmpty(Scope)) | |
| EmptyScopes.push_back(Scope); | |
| TraverseScope(Scope); | |
| } | |
| } | |
| }; | |
| // Preserve current setting for '--internal=id'. | |
| bool InternalID = options().getInternalID(); | |
| llvm::scope_exit ResetSetting([&] { | |
| // Restore setting for '--internal=id'. | |
| if (!InternalID) | |
| options().resetInternalID(); | |
| }); | |
| options().setInternalID(); | |
| LLVM_DEBUG({ | |
| dbgs() << "\nBefore - RemoveEmptyScopes\n"; | |
| printCollectedElements(Root); | |
| }); | |
| TraverseScope(CompileUnit); | |
| DeleteEmptyScopes(); | |
| LLVM_DEBUG({ | |
| dbgs() << "\nAfter - RemoveEmptyScopes\n"; | |
| printCollectedElements(Root); | |
| }); | |
| } | |
| // The IR generated by Clang, allocates the inlined lexical scopes | |
| // at the enclosing function level. Move them to the correct scope. | |
| void LVIRReader::resolveInlinedLexicalScopes() { | |
| LLVM_DEBUG({ dbgs() << "\n[resolveInlinedLexicalScopes]\n"; }); | |
| LLVM_DEBUG({ dumpInlinedInfo("Before", /*Full=*/false); }); | |
| std::function<void(LVScope * Scope)> TraverseChildren = [&](LVScope *Parent) { | |
| LLVM_DEBUG({ | |
| dbgs() << "\nParent Scope: "; | |
| Parent->dumpCommon(); | |
| }); | |
| // Get associated inlined scopes for the parent scope. | |
| LVList &ParentInlinedList = getInlinedList(Parent); | |
| // Check if the inlined scope parent is in the ParentInlinedList. | |
| auto CheckInlinedScope = [&](LVList &ScopeInlinedList) -> bool { | |
| bool Matched = true; | |
| for (auto &InlinedScope : ScopeInlinedList) { | |
| LLVM_DEBUG({ | |
| dbgs() << "Inlined Scope: "; | |
| InlinedScope->dumpCommon(); | |
| }); | |
| LVScope *ParentScope = InlinedScope->getParentScope(); | |
| for (auto &ParentInlinedScope : ParentInlinedList) { | |
| if (ParentInlinedScope != ParentScope) { | |
| // If the parent for the inlined scope is not the Parent Inlined | |
| // list, it means the lexical scope is incorrect. | |
| // Stop the traversal as the other inlined scopes will have the | |
| // same problem as they were created from the same original scope. | |
| LLVM_DEBUG({ | |
| dbgs() << "\nIncorrect parent scope\n"; | |
| dbgs() << "ParentInlinedScope: "; | |
| ParentInlinedScope->dumpCommon(); | |
| dbgs() << "ParentScope: "; | |
| ParentScope->dumpCommon(); | |
| dbgs() << "\n"; | |
| }); | |
| Matched = false; | |
| break; | |
| } | |
| } | |
| if (!Matched) | |
| break; | |
| } | |
| return Matched; | |
| }; | |
| // Adjust the inlined scopes based on the ParentInlinedList. | |
| auto AdjustInlinedScope = [&](LVList &ScopeInlinedList) { | |
| assert(ScopeInlinedList.size() == ParentInlinedList.size() && | |
| "Scope list do not have same number of items."); | |
| LLVM_DEBUG({ dbgs() << "Begin scope adjustment\n"; }); | |
| LVScope *CurrentParent = nullptr; | |
| LVScope *TargetParent = nullptr; | |
| LVScope *InlinedScope = nullptr; | |
| auto ItInlined = ScopeInlinedList.begin(); | |
| auto ItParent = ParentInlinedList.begin(); | |
| while (ItInlined != ScopeInlinedList.end()) { | |
| TargetParent = *ItParent; | |
| InlinedScope = *ItInlined; | |
| CurrentParent = InlinedScope->getParentScope(); | |
| LLVM_DEBUG({ | |
| dbgs() << "Target Parent: "; | |
| TargetParent->dumpCommon(); | |
| dbgs() << "Current Parent: "; | |
| CurrentParent->dumpCommon(); | |
| dbgs() << "Inlined: "; | |
| InlinedScope->dumpCommon(); | |
| }); | |
| // Correct lexical scope. | |
| if (CurrentParent->removeElement(InlinedScope)) { | |
| TargetParent->addElement(InlinedScope); | |
| InlinedScope->updateLevel(TargetParent, /*Moved=*/false); | |
| } | |
| ++ItInlined; | |
| ++ItParent; | |
| } | |
| LLVM_DEBUG({ dbgs() << "End scope adjustment\n"; }); | |
| }; | |
| // Traverse the scope children. | |
| if (const LVScopes *Children = Parent->getScopes()) | |
| for (LVScope *Scope : *Children) { | |
| LLVM_DEBUG({ | |
| dbgs() << "\nOrigin Scope: "; | |
| Scope->dumpCommon(); | |
| }); | |
| // Get associated inlined scopes for the scope. | |
| LVList &ScopeInlinedList = getInlinedList(Scope); | |
| if (!CheckInlinedScope(ScopeInlinedList)) { | |
| // AdjustInlinedScope to the correct lexical scope. | |
| AdjustInlinedScope(ScopeInlinedList); | |
| } | |
| TraverseChildren(Scope); | |
| } | |
| }; | |
| // Traverse the origin scopes and for each function scope, analyze their | |
| // associated inlined scopes to see if they have to be move to their | |
| // correct lexical scope. | |
| for (auto &Entry : InlinedList) { | |
| LVScope *OriginScope = Entry.first; | |
| if (OriginScope->getIsFunction()) | |
| TraverseChildren(OriginScope); | |
| } | |
| LLVM_DEBUG({ dumpInlinedInfo("After", /*Full=*/false); }); | |
| } | |
| // During the IR-to-logical-view construction, traverse all the logical | |
| // elements to check if they have been properly constructed (finalized). | |
| void LVIRReader::checkScopes(LVScope *Scope) { | |
| LLVM_DEBUG({ dbgs() << "\n[checkScopes]\n"; }); | |
| auto PrintElement = [](LVElement *Element) { | |
| LLVM_DEBUG({ | |
| dwarf::Tag Tag = Element->getTag(); | |
| size_t ID = Element->getID(); | |
| const char *Kind = Element->kind(); | |
| StringRef Name = Element->getName(); | |
| uint32_t LineNumber = Element->getLineNumber(); | |
| dbgs() << "Tag: " | |
| << formatv("{0} ", fmt_align(Tag, AlignStyle::Left, 35)); | |
| dbgs() << "ID: " << formatv("{0} ", fmt_align(ID, AlignStyle::Left, 5)); | |
| dbgs() << "Kind: " | |
| << formatv("{0} ", fmt_align(Kind, AlignStyle::Left, 15)); | |
| dbgs() << "Line: " | |
| << formatv("{0} ", fmt_align(LineNumber, AlignStyle::Left, 5)); | |
| dbgs() << "Name: '" << std::string(Name) << "' "; | |
| dbgs() << "\n"; | |
| }); | |
| }; | |
| std::function<void(LVScope * Parent)> Traverse = [&](LVScope *Current) { | |
| auto Check = [&](auto *Entry) { | |
| if (Entry) | |
| if (!Entry->getIsFinalized()) | |
| PrintElement(Entry); | |
| }; | |
| for (LVElement *Element : Current->getChildren()) | |
| Check(Element); | |
| if (Current->getScopes()) | |
| for (LVScope *Scope : *Current->getScopes()) | |
| Traverse(Scope); | |
| }; | |
| // Start traversing the scopes root and check its integrity. | |
| Traverse(Scope); | |
| } | |
| void LVIRReader::sortScopes() { Root->sort(); } | |
| void LVIRReader::print(raw_ostream &OS) const { | |
| OS << "LVIRReader\n"; | |
| LLVM_DEBUG(dbgs() << "CreateReaders\n"); | |
| } |