blob: 5726955a029ef9e88f86f35b8c929278158f82d0 [file] [edit]
//===-- 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/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"
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->getElement(1);
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 (ExprOp.getOp() == dwarf::DW_OP_LLVM_arg) {
AddLocationOp(Locations.getVariableLocationOp(ExprOp.getArg(0)),
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");
}