bolt/deps/llvm-18.1.8/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp
2025-02-14 19:21:04 +01:00

3564 lines
125 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//===-- LVCodeViewVisitor.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 LVCodeViewVisitor class.
//
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h"
#include "llvm/BinaryFormat/Magic.h"
#include "llvm/DebugInfo/CodeView/EnumTables.h"
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
#include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h"
#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
#include "llvm/DebugInfo/LogicalView/Core/LVType.h"
#include "llvm/DebugInfo/LogicalView/Readers/LVCodeViewReader.h"
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
#include "llvm/DebugInfo/PDB/Native/InputFile.h"
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
#include "llvm/DebugInfo/PDB/Native/RawError.h"
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
#include "llvm/DebugInfo/PDB/PDB.h"
#include "llvm/Demangle/Demangle.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormatAdapters.h"
#include "llvm/Support/FormatVariadic.h"
using namespace llvm;
using namespace llvm::codeview;
using namespace llvm::object;
using namespace llvm::pdb;
using namespace llvm::logicalview;
#define DEBUG_TYPE "CodeViewUtilities"
namespace llvm {
namespace logicalview {
static TypeIndex getTrueType(TypeIndex &TI) {
// Dealing with a MSVC generated PDB, we encountered a type index with the
// value of: 0x0280xxxx where xxxx=0000.
//
// There is some documentation about type indices:
// https://llvm.org/docs/PDB/TpiStream.html
//
// A type index is a 32-bit integer that uniquely identifies a type inside
// of an object files .debug$T section or a PDB files TPI or IPI stream.
// The value of the type index for the first type record from the TPI stream
// is given by the TypeIndexBegin member of the TPI Stream Header although
// in practice this value is always equal to 0x1000 (4096).
//
// Any type index with a high bit set is considered to come from the IPI
// stream, although this appears to be more of a hack, and LLVM does not
// generate type indices of this nature. They can, however, be observed in
// Microsoft PDBs occasionally, so one should be prepared to handle them.
// Note that having the high bit set is not a necessary condition to
// determine whether a type index comes from the IPI stream, it is only
// sufficient.
LLVM_DEBUG(
{ dbgs() << "Index before: " << HexNumber(TI.getIndex()) << "\n"; });
TI.setIndex(TI.getIndex() & 0x0000ffff);
LLVM_DEBUG(
{ dbgs() << "Index after: " << HexNumber(TI.getIndex()) << "\n"; });
return TI;
}
static const EnumEntry<TypeLeafKind> LeafTypeNames[] = {
#define CV_TYPE(enum, val) {#enum, enum},
#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
};
// Return the type name pointed by the type index. It uses the kind to query
// the associated name for the record type.
static StringRef getRecordName(LazyRandomTypeCollection &Types, TypeIndex TI) {
if (TI.isSimple())
return {};
StringRef RecordName;
CVType CVReference = Types.getType(TI);
auto GetName = [&](auto Record) {
if (Error Err = TypeDeserializer::deserializeAs(
const_cast<CVType &>(CVReference), Record))
consumeError(std::move(Err));
else
RecordName = Record.getName();
};
TypeRecordKind RK = static_cast<TypeRecordKind>(CVReference.kind());
if (RK == TypeRecordKind::Class || RK == TypeRecordKind::Struct)
GetName(ClassRecord(RK));
else if (RK == TypeRecordKind::Union)
GetName(UnionRecord(RK));
else if (RK == TypeRecordKind::Enum)
GetName(EnumRecord(RK));
return RecordName;
}
} // namespace logicalview
} // namespace llvm
#undef DEBUG_TYPE
#define DEBUG_TYPE "CodeViewDataVisitor"
namespace llvm {
namespace logicalview {
// Keeps the type indexes with line information.
using LVLineRecords = std::vector<TypeIndex>;
namespace {
class LVTypeRecords {
LVShared *Shared = nullptr;
// Logical elements associated to their CodeView Type Index.
using RecordEntry = std::pair<TypeLeafKind, LVElement *>;
using RecordTable = std::map<TypeIndex, RecordEntry>;
RecordTable RecordFromTypes;
RecordTable RecordFromIds;
using NameTable = std::map<StringRef, TypeIndex>;
NameTable NameFromTypes;
NameTable NameFromIds;
public:
LVTypeRecords(LVShared *Shared) : Shared(Shared) {}
void add(uint32_t StreamIdx, TypeIndex TI, TypeLeafKind Kind,
LVElement *Element = nullptr);
void add(uint32_t StreamIdx, TypeIndex TI, StringRef Name);
LVElement *find(uint32_t StreamIdx, TypeIndex TI, bool Create = true);
TypeIndex find(uint32_t StreamIdx, StringRef Name);
};
class LVForwardReferences {
// Forward reference and its definitions (Name as key).
using ForwardEntry = std::pair<TypeIndex, TypeIndex>;
using ForwardTypeNames = std::map<StringRef, ForwardEntry>;
ForwardTypeNames ForwardTypesNames;
// Forward reference and its definition (TypeIndex as key).
using ForwardType = std::map<TypeIndex, TypeIndex>;
ForwardType ForwardTypes;
// Forward types and its references.
void add(TypeIndex TIForward, TypeIndex TIReference) {
ForwardTypes.emplace(TIForward, TIReference);
}
void add(StringRef Name, TypeIndex TIForward) {
if (ForwardTypesNames.find(Name) == ForwardTypesNames.end()) {
ForwardTypesNames.emplace(
std::piecewise_construct, std::forward_as_tuple(Name),
std::forward_as_tuple(TIForward, TypeIndex::None()));
} else {
// Update a recorded definition with its reference.
ForwardTypesNames[Name].first = TIForward;
add(TIForward, ForwardTypesNames[Name].second);
}
}
// Update a previously recorded forward reference with its definition.
void update(StringRef Name, TypeIndex TIReference) {
if (ForwardTypesNames.find(Name) != ForwardTypesNames.end()) {
// Update the recorded forward reference with its definition.
ForwardTypesNames[Name].second = TIReference;
add(ForwardTypesNames[Name].first, TIReference);
} else {
// We have not seen the forward reference. Insert the definition.
ForwardTypesNames.emplace(
std::piecewise_construct, std::forward_as_tuple(Name),
std::forward_as_tuple(TypeIndex::None(), TIReference));
}
}
public:
LVForwardReferences() = default;
void record(bool IsForwardRef, StringRef Name, TypeIndex TI) {
// We are expecting for the forward references to be first. But that
// is not always the case. A name must be recorded regardless of the
// order in which the forward reference appears.
(IsForwardRef) ? add(Name, TI) : update(Name, TI);
}
TypeIndex find(TypeIndex TIForward) {
return (ForwardTypes.find(TIForward) != ForwardTypes.end())
? ForwardTypes[TIForward]
: TypeIndex::None();
}
TypeIndex find(StringRef Name) {
return (ForwardTypesNames.find(Name) != ForwardTypesNames.end())
? ForwardTypesNames[Name].second
: TypeIndex::None();
}
// If the given TI corresponds to a reference, return the reference.
// Otherwise return the given TI.
TypeIndex remap(TypeIndex TI) {
TypeIndex Forward = find(TI);
return Forward.isNoneType() ? TI : Forward;
}
};
// Namespace deduction.
class LVNamespaceDeduction {
LVShared *Shared = nullptr;
using Names = std::map<StringRef, LVScope *>;
Names NamespaceNames;
using LookupSet = std::set<StringRef>;
LookupSet DeducedScopes;
LookupSet UnresolvedScopes;
LookupSet IdentifiedNamespaces;
void add(StringRef Name, LVScope *Namespace) {
if (NamespaceNames.find(Name) == NamespaceNames.end())
NamespaceNames.emplace(Name, Namespace);
}
public:
LVNamespaceDeduction(LVShared *Shared) : Shared(Shared) {}
void init();
void add(StringRef String);
LVScope *get(LVStringRefs Components);
LVScope *get(StringRef Name, bool CheckScope = true);
// Find the logical namespace for the 'Name' component.
LVScope *find(StringRef Name) {
LVScope *Namespace = (NamespaceNames.find(Name) != NamespaceNames.end())
? NamespaceNames[Name]
: nullptr;
return Namespace;
}
// For the given lexical components, return a tuple with the first entry
// being the outermost namespace and the second entry being the first
// non-namespace.
LVLexicalIndex find(LVStringRefs Components) {
if (Components.empty())
return {};
LVStringRefs::size_type FirstNamespace = 0;
LVStringRefs::size_type FirstNonNamespace;
for (LVStringRefs::size_type Index = 0; Index < Components.size();
++Index) {
FirstNonNamespace = Index;
LookupSet::iterator Iter = IdentifiedNamespaces.find(Components[Index]);
if (Iter == IdentifiedNamespaces.end())
// The component is not a namespace name.
break;
}
return std::make_tuple(FirstNamespace, FirstNonNamespace);
}
};
// Strings.
class LVStringRecords {
using StringEntry = std::tuple<uint32_t, std::string, LVScopeCompileUnit *>;
using StringIds = std::map<TypeIndex, StringEntry>;
StringIds Strings;
public:
LVStringRecords() = default;
void add(TypeIndex TI, StringRef String) {
static uint32_t Index = 0;
if (Strings.find(TI) == Strings.end())
Strings.emplace(
std::piecewise_construct, std::forward_as_tuple(TI),
std::forward_as_tuple(++Index, std::string(String), nullptr));
}
StringRef find(TypeIndex TI) {
StringIds::iterator Iter = Strings.find(TI);
return Iter != Strings.end() ? std::get<1>(Iter->second) : StringRef{};
}
uint32_t findIndex(TypeIndex TI) {
StringIds::iterator Iter = Strings.find(TI);
return Iter != Strings.end() ? std::get<0>(Iter->second) : 0;
}
// Move strings representing the filenames to the compile unit.
void addFilenames();
void addFilenames(LVScopeCompileUnit *Scope);
};
} // namespace
using LVTypeKinds = std::set<TypeLeafKind>;
using LVSymbolKinds = std::set<SymbolKind>;
// The following data keeps forward information, type records, names for
// namespace deduction, strings records, line records.
// It is shared by the type visitor, symbol visitor and logical visitor and
// it is independent from the CodeViewReader.
struct LVShared {
LVCodeViewReader *Reader;
LVLogicalVisitor *Visitor;
LVForwardReferences ForwardReferences;
LVLineRecords LineRecords;
LVNamespaceDeduction NamespaceDeduction;
LVStringRecords StringRecords;
LVTypeRecords TypeRecords;
// In order to determine which types and/or symbols records should be handled
// by the reader, we record record kinds seen by the type and symbol visitors.
// At the end of the scopes creation, the '--internal=tag' option will allow
// to print the unique record ids collected.
LVTypeKinds TypeKinds;
LVSymbolKinds SymbolKinds;
LVShared(LVCodeViewReader *Reader, LVLogicalVisitor *Visitor)
: Reader(Reader), Visitor(Visitor), NamespaceDeduction(this),
TypeRecords(this) {}
~LVShared() = default;
};
} // namespace logicalview
} // namespace llvm
void LVTypeRecords::add(uint32_t StreamIdx, TypeIndex TI, TypeLeafKind Kind,
LVElement *Element) {
RecordTable &Target =
(StreamIdx == StreamTPI) ? RecordFromTypes : RecordFromIds;
Target.emplace(std::piecewise_construct, std::forward_as_tuple(TI),
std::forward_as_tuple(Kind, Element));
}
void LVTypeRecords::add(uint32_t StreamIdx, TypeIndex TI, StringRef Name) {
NameTable &Target = (StreamIdx == StreamTPI) ? NameFromTypes : NameFromIds;
Target.emplace(Name, TI);
}
LVElement *LVTypeRecords::find(uint32_t StreamIdx, TypeIndex TI, bool Create) {
RecordTable &Target =
(StreamIdx == StreamTPI) ? RecordFromTypes : RecordFromIds;
LVElement *Element = nullptr;
RecordTable::iterator Iter = Target.find(TI);
if (Iter != Target.end()) {
Element = Iter->second.second;
if (Element || !Create)
return Element;
// Create the logical element if not found.
Element = Shared->Visitor->createElement(Iter->second.first);
if (Element) {
Element->setOffset(TI.getIndex());
Element->setOffsetFromTypeIndex();
Target[TI].second = Element;
}
}
return Element;
}
TypeIndex LVTypeRecords::find(uint32_t StreamIdx, StringRef Name) {
NameTable &Target = (StreamIdx == StreamTPI) ? NameFromTypes : NameFromIds;
NameTable::iterator Iter = Target.find(Name);
return Iter != Target.end() ? Iter->second : TypeIndex::None();
}
void LVStringRecords::addFilenames() {
for (StringIds::const_reference Entry : Strings) {
StringRef Name = std::get<1>(Entry.second);
LVScopeCompileUnit *Scope = std::get<2>(Entry.second);
Scope->addFilename(transformPath(Name));
}
Strings.clear();
}
void LVStringRecords::addFilenames(LVScopeCompileUnit *Scope) {
for (StringIds::reference Entry : Strings)
if (!std::get<2>(Entry.second))
std::get<2>(Entry.second) = Scope;
}
void LVNamespaceDeduction::add(StringRef String) {
StringRef InnerComponent;
StringRef OuterComponent;
std::tie(OuterComponent, InnerComponent) = getInnerComponent(String);
DeducedScopes.insert(InnerComponent);
if (OuterComponent.size())
UnresolvedScopes.insert(OuterComponent);
}
void LVNamespaceDeduction::init() {
// We have 2 sets of names:
// - deduced scopes (class, structure, union and enum) and
// - unresolved scopes, that can represent namespaces or any deduced.
// Before creating the namespaces, we have to traverse the unresolved
// and remove any references to already deduced scopes.
LVStringRefs Components;
for (const StringRef &Unresolved : UnresolvedScopes) {
Components = getAllLexicalComponents(Unresolved);
for (const StringRef &Component : Components) {
LookupSet::iterator Iter = DeducedScopes.find(Component);
if (Iter == DeducedScopes.end())
IdentifiedNamespaces.insert(Component);
}
}
LLVM_DEBUG({
auto Print = [&](LookupSet &Container, const char *Title) {
auto Header = [&]() {
dbgs() << formatv("\n{0}\n", fmt_repeat('=', 72));
dbgs() << formatv("{0}\n", Title);
dbgs() << formatv("{0}\n", fmt_repeat('=', 72));
};
Header();
for (const StringRef &Item : Container)
dbgs() << formatv("'{0}'\n", Item.str().c_str());
};
Print(DeducedScopes, "Deducted Scopes");
Print(UnresolvedScopes, "Unresolved Scopes");
Print(IdentifiedNamespaces, "Namespaces");
});
}
LVScope *LVNamespaceDeduction::get(LVStringRefs Components) {
LLVM_DEBUG({
for (const StringRef &Component : Components)
dbgs() << formatv("'{0}'\n", Component.str().c_str());
});
if (Components.empty())
return nullptr;
// Update the namespaces relationship.
LVScope *Namespace = nullptr;
LVScope *Parent = Shared->Reader->getCompileUnit();
for (const StringRef &Component : Components) {
// Check if we have seen the namespace.
Namespace = find(Component);
if (!Namespace) {
// We have identified namespaces that are generated by MSVC. Mark them
// as 'system' so they will be excluded from the logical view.
Namespace = Shared->Reader->createScopeNamespace();
Namespace->setTag(dwarf::DW_TAG_namespace);
Namespace->setName(Component);
Parent->addElement(Namespace);
getReader().isSystemEntry(Namespace);
add(Component, Namespace);
}
Parent = Namespace;
}
return Parent;
}
LVScope *LVNamespaceDeduction::get(StringRef ScopedName, bool CheckScope) {
LVStringRefs Components = getAllLexicalComponents(ScopedName);
if (CheckScope)
llvm::erase_if(Components, [&](StringRef Component) {
LookupSet::iterator Iter = IdentifiedNamespaces.find(Component);
return Iter == IdentifiedNamespaces.end();
});
LLVM_DEBUG(
{ dbgs() << formatv("ScopedName: '{0}'\n", ScopedName.str().c_str()); });
return get(Components);
}
#undef DEBUG_TYPE
#define DEBUG_TYPE "CodeViewTypeVisitor"
//===----------------------------------------------------------------------===//
// TypeRecord traversal.
//===----------------------------------------------------------------------===//
void LVTypeVisitor::printTypeIndex(StringRef FieldName, TypeIndex TI,
uint32_t StreamIdx) const {
codeview::printTypeIndex(W, FieldName, TI,
StreamIdx == StreamTPI ? Types : Ids);
}
Error LVTypeVisitor::visitTypeBegin(CVType &Record) {
return visitTypeBegin(Record, TypeIndex::fromArrayIndex(Types.size()));
}
Error LVTypeVisitor::visitTypeBegin(CVType &Record, TypeIndex TI) {
LLVM_DEBUG({
W.getOStream() << formatTypeLeafKind(Record.kind());
W.getOStream() << " (" << HexNumber(TI.getIndex()) << ")\n";
});
if (options().getInternalTag())
Shared->TypeKinds.insert(Record.kind());
// The collected type records, will be use to create the logical elements
// during the symbols traversal when a type is referenced.
CurrentTypeIndex = TI;
Shared->TypeRecords.add(StreamIdx, TI, Record.kind());
return Error::success();
}
Error LVTypeVisitor::visitUnknownType(CVType &Record) {
LLVM_DEBUG({ W.printNumber("Length", uint32_t(Record.content().size())); });
return Error::success();
}
Error LVTypeVisitor::visitMemberBegin(CVMemberRecord &Record) {
LLVM_DEBUG({
W.startLine() << formatTypeLeafKind(Record.Kind);
W.getOStream() << " {\n";
W.indent();
});
return Error::success();
}
Error LVTypeVisitor::visitMemberEnd(CVMemberRecord &Record) {
LLVM_DEBUG({
W.unindent();
W.startLine() << "}\n";
});
return Error::success();
}
Error LVTypeVisitor::visitUnknownMember(CVMemberRecord &Record) {
LLVM_DEBUG({ W.printHex("UnknownMember", unsigned(Record.Kind)); });
return Error::success();
}
// LF_BUILDINFO (TPI)/(IPI)
Error LVTypeVisitor::visitKnownRecord(CVType &Record, BuildInfoRecord &Args) {
// All the args are references into the TPI/IPI stream.
LLVM_DEBUG({
W.printNumber("NumArgs", static_cast<uint32_t>(Args.getArgs().size()));
ListScope Arguments(W, "Arguments");
for (TypeIndex Arg : Args.getArgs())
printTypeIndex("ArgType", Arg, StreamIPI);
});
// Only add the strings that hold information about filenames. They will be
// used to complete the line/file information for the logical elements.
// There are other strings holding information about namespaces.
TypeIndex TI;
StringRef String;
// Absolute CWD path
TI = Args.getArgs()[BuildInfoRecord::BuildInfoArg::CurrentDirectory];
String = Ids.getTypeName(TI);
if (!String.empty())
Shared->StringRecords.add(TI, String);
// Get the compile unit name.
TI = Args.getArgs()[BuildInfoRecord::BuildInfoArg::SourceFile];
String = Ids.getTypeName(TI);
if (!String.empty())
Shared->StringRecords.add(TI, String);
LogicalVisitor->setCompileUnitName(std::string(String));
return Error::success();
}
// LF_CLASS, LF_STRUCTURE, LF_INTERFACE (TPI)
Error LVTypeVisitor::visitKnownRecord(CVType &Record, ClassRecord &Class) {
LLVM_DEBUG({
printTypeIndex("TypeIndex", CurrentTypeIndex, StreamTPI);
printTypeIndex("FieldListType", Class.getFieldList(), StreamTPI);
W.printString("Name", Class.getName());
});
// Collect class name for scope deduction.
Shared->NamespaceDeduction.add(Class.getName());
Shared->ForwardReferences.record(Class.isForwardRef(), Class.getName(),
CurrentTypeIndex);
// Collect class name for contained scopes deduction.
Shared->TypeRecords.add(StreamIdx, CurrentTypeIndex, Class.getName());
return Error::success();
}
// LF_ENUM (TPI)
Error LVTypeVisitor::visitKnownRecord(CVType &Record, EnumRecord &Enum) {
LLVM_DEBUG({
printTypeIndex("TypeIndex", CurrentTypeIndex, StreamTPI);
printTypeIndex("FieldListType", Enum.getFieldList(), StreamTPI);
W.printString("Name", Enum.getName());
});
// Collect enum name for scope deduction.
Shared->NamespaceDeduction.add(Enum.getName());
return Error::success();
}
// LF_FUNC_ID (TPI)/(IPI)
Error LVTypeVisitor::visitKnownRecord(CVType &Record, FuncIdRecord &Func) {
LLVM_DEBUG({
printTypeIndex("TypeIndex", CurrentTypeIndex, StreamTPI);
printTypeIndex("Type", Func.getFunctionType(), StreamTPI);
printTypeIndex("Parent", Func.getParentScope(), StreamTPI);
W.printString("Name", Func.getName());
});
// Collect function name for scope deduction.
Shared->NamespaceDeduction.add(Func.getName());
return Error::success();
}
// LF_PROCEDURE (TPI)
Error LVTypeVisitor::visitKnownRecord(CVType &Record, ProcedureRecord &Proc) {
LLVM_DEBUG({
printTypeIndex("TypeIndex", CurrentTypeIndex, StreamTPI);
printTypeIndex("ReturnType", Proc.getReturnType(), StreamTPI);
W.printNumber("NumParameters", Proc.getParameterCount());
printTypeIndex("ArgListType", Proc.getArgumentList(), StreamTPI);
});
// Collect procedure information as they can be referenced by typedefs.
Shared->TypeRecords.add(StreamTPI, CurrentTypeIndex, {});
return Error::success();
}
// LF_STRING_ID (TPI)/(IPI)
Error LVTypeVisitor::visitKnownRecord(CVType &Record, StringIdRecord &String) {
// No additional references are needed.
LLVM_DEBUG({
printTypeIndex("Id", String.getId(), StreamIPI);
W.printString("StringData", String.getString());
});
return Error::success();
}
// LF_UDT_SRC_LINE (TPI)/(IPI)
Error LVTypeVisitor::visitKnownRecord(CVType &Record,
UdtSourceLineRecord &Line) {
// UDT and SourceFile are references into the TPI/IPI stream.
LLVM_DEBUG({
printTypeIndex("UDT", Line.getUDT(), StreamIPI);
printTypeIndex("SourceFile", Line.getSourceFile(), StreamIPI);
W.printNumber("LineNumber", Line.getLineNumber());
});
Shared->LineRecords.push_back(CurrentTypeIndex);
return Error::success();
}
// LF_UNION (TPI)
Error LVTypeVisitor::visitKnownRecord(CVType &Record, UnionRecord &Union) {
LLVM_DEBUG({
W.printNumber("MemberCount", Union.getMemberCount());
printTypeIndex("FieldList", Union.getFieldList(), StreamTPI);
W.printNumber("SizeOf", Union.getSize());
W.printString("Name", Union.getName());
if (Union.hasUniqueName())
W.printString("UniqueName", Union.getUniqueName());
});
// Collect union name for scope deduction.
Shared->NamespaceDeduction.add(Union.getName());
Shared->ForwardReferences.record(Union.isForwardRef(), Union.getName(),
CurrentTypeIndex);
// Collect class name for contained scopes deduction.
Shared->TypeRecords.add(StreamIdx, CurrentTypeIndex, Union.getName());
return Error::success();
}
#undef DEBUG_TYPE
#define DEBUG_TYPE "CodeViewSymbolVisitor"
//===----------------------------------------------------------------------===//
// SymbolRecord traversal.
//===----------------------------------------------------------------------===//
void LVSymbolVisitorDelegate::printRelocatedField(StringRef Label,
uint32_t RelocOffset,
uint32_t Offset,
StringRef *RelocSym) {
Reader->printRelocatedField(Label, CoffSection, RelocOffset, Offset,
RelocSym);
}
void LVSymbolVisitorDelegate::getLinkageName(uint32_t RelocOffset,
uint32_t Offset,
StringRef *RelocSym) {
Reader->getLinkageName(CoffSection, RelocOffset, Offset, RelocSym);
}
StringRef
LVSymbolVisitorDelegate::getFileNameForFileOffset(uint32_t FileOffset) {
Expected<StringRef> Name = Reader->getFileNameForFileOffset(FileOffset);
if (!Name) {
consumeError(Name.takeError());
return {};
}
return *Name;
}
DebugStringTableSubsectionRef LVSymbolVisitorDelegate::getStringTable() {
return Reader->CVStringTable;
}
void LVSymbolVisitor::printLocalVariableAddrRange(
const LocalVariableAddrRange &Range, uint32_t RelocationOffset) {
DictScope S(W, "LocalVariableAddrRange");
if (ObjDelegate)
ObjDelegate->printRelocatedField("OffsetStart", RelocationOffset,
Range.OffsetStart);
W.printHex("ISectStart", Range.ISectStart);
W.printHex("Range", Range.Range);
}
void LVSymbolVisitor::printLocalVariableAddrGap(
ArrayRef<LocalVariableAddrGap> Gaps) {
for (const LocalVariableAddrGap &Gap : Gaps) {
ListScope S(W, "LocalVariableAddrGap");
W.printHex("GapStartOffset", Gap.GapStartOffset);
W.printHex("Range", Gap.Range);
}
}
void LVSymbolVisitor::printTypeIndex(StringRef FieldName, TypeIndex TI) const {
codeview::printTypeIndex(W, FieldName, TI, Types);
}
Error LVSymbolVisitor::visitSymbolBegin(CVSymbol &Record) {
return visitSymbolBegin(Record, 0);
}
Error LVSymbolVisitor::visitSymbolBegin(CVSymbol &Record, uint32_t Offset) {
SymbolKind Kind = Record.kind();
LLVM_DEBUG({
W.printNumber("Offset", Offset);
W.printEnum("Begin Kind", unsigned(Kind), getSymbolTypeNames());
});
if (options().getInternalTag())
Shared->SymbolKinds.insert(Kind);
LogicalVisitor->CurrentElement = LogicalVisitor->createElement(Kind);
if (!LogicalVisitor->CurrentElement) {
LLVM_DEBUG({
// We have an unsupported Symbol or Type Record.
// W.printEnum("Kind ignored", unsigned(Kind), getSymbolTypeNames());
});
return Error::success();
}
// Offset carried by the traversal routines when dealing with streams.
CurrentOffset = Offset;
IsCompileUnit = false;
if (!LogicalVisitor->CurrentElement->getOffsetFromTypeIndex())
LogicalVisitor->CurrentElement->setOffset(Offset);
if (symbolOpensScope(Kind) || (IsCompileUnit = symbolIsCompileUnit(Kind))) {
assert(LogicalVisitor->CurrentScope && "Invalid scope!");
LogicalVisitor->addElement(LogicalVisitor->CurrentScope, IsCompileUnit);
} else {
if (LogicalVisitor->CurrentSymbol)
LogicalVisitor->addElement(LogicalVisitor->CurrentSymbol);
if (LogicalVisitor->CurrentType)
LogicalVisitor->addElement(LogicalVisitor->CurrentType);
}
return Error::success();
}
Error LVSymbolVisitor::visitSymbolEnd(CVSymbol &Record) {
SymbolKind Kind = Record.kind();
LLVM_DEBUG(
{ W.printEnum("End Kind", unsigned(Kind), getSymbolTypeNames()); });
if (symbolEndsScope(Kind)) {
LogicalVisitor->popScope();
}
return Error::success();
}
Error LVSymbolVisitor::visitUnknownSymbol(CVSymbol &Record) {
LLVM_DEBUG({ W.printNumber("Length", Record.length()); });
return Error::success();
}
// S_BLOCK32
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, BlockSym &Block) {
LLVM_DEBUG({
W.printHex("CodeSize", Block.CodeSize);
W.printHex("Segment", Block.Segment);
W.printString("BlockName", Block.Name);
});
if (LVScope *Scope = LogicalVisitor->CurrentScope) {
StringRef LinkageName;
if (ObjDelegate)
ObjDelegate->getLinkageName(Block.getRelocationOffset(), Block.CodeOffset,
&LinkageName);
Scope->setLinkageName(LinkageName);
if (options().getGeneralCollectRanges()) {
// Record converted segment::offset addressing for this scope.
LVAddress Addendum = Reader->getSymbolTableAddress(LinkageName);
LVAddress LowPC =
Reader->linearAddress(Block.Segment, Block.CodeOffset, Addendum);
LVAddress HighPC = LowPC + Block.CodeSize - 1;
Scope->addObject(LowPC, HighPC);
}
}
return Error::success();
}
// S_BPREL32
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record,
BPRelativeSym &Local) {
LLVM_DEBUG({
printTypeIndex("Type", Local.Type);
W.printNumber("Offset", Local.Offset);
W.printString("VarName", Local.Name);
});
if (LVSymbol *Symbol = LogicalVisitor->CurrentSymbol) {
Symbol->setName(Local.Name);
// From the MS_Symbol_Type.pdf documentation (S_BPREL32):
// This symbol specifies symbols that are allocated on the stack for a
// procedure. For C and C++, these include the actual function parameters
// and the local non-static variables of functions.
// However, the offset for 'this' comes as a negative value.
// Symbol was created as 'variable'; determine its real kind.
Symbol->resetIsVariable();
if (Local.Name.equals("this")) {
Symbol->setIsParameter();
Symbol->setIsArtificial();
} else {
// Determine symbol kind.
bool(Local.Offset > 0) ? Symbol->setIsParameter()
: Symbol->setIsVariable();
}
// Update correct debug information tag.
if (Symbol->getIsParameter())
Symbol->setTag(dwarf::DW_TAG_formal_parameter);
LVElement *Element = LogicalVisitor->getElement(StreamTPI, Local.Type);
if (Element && Element->getIsScoped()) {
// We have a local type. Find its parent function.
LVScope *Parent = Symbol->getFunctionParent();
// The element representing the type has been already finalized. If
// the type is an aggregate type, its members have been already added.
// As the type is local, its level will be changed.
// FIXME: Currently the algorithm used to scope lambda functions is
// incorrect. Before we allocate the type at this scope, check if is
// already allocated in other scope.
if (!Element->getParentScope()) {
Parent->addElement(Element);
Element->updateLevel(Parent);
}
}
Symbol->setType(Element);
}
return Error::success();
}
// S_REGREL32
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record,
RegRelativeSym &Local) {
LLVM_DEBUG({
printTypeIndex("Type", Local.Type);
W.printNumber("Offset", Local.Offset);
W.printString("VarName", Local.Name);
});
if (LVSymbol *Symbol = LogicalVisitor->CurrentSymbol) {
Symbol->setName(Local.Name);
// Symbol was created as 'variable'; determine its real kind.
Symbol->resetIsVariable();
// Check for the 'this' symbol.
if (Local.Name.equals("this")) {
Symbol->setIsArtificial();
Symbol->setIsParameter();
} else {
// Determine symbol kind.
determineSymbolKind(Symbol, Local.Register);
}
// Update correct debug information tag.
if (Symbol->getIsParameter())
Symbol->setTag(dwarf::DW_TAG_formal_parameter);
LVElement *Element = LogicalVisitor->getElement(StreamTPI, Local.Type);
if (Element && Element->getIsScoped()) {
// We have a local type. Find its parent function.
LVScope *Parent = Symbol->getFunctionParent();
// The element representing the type has been already finalized. If
// the type is an aggregate type, its members have been already added.
// As the type is local, its level will be changed.
// FIXME: Currently the algorithm used to scope lambda functions is
// incorrect. Before we allocate the type at this scope, check if is
// already allocated in other scope.
if (!Element->getParentScope()) {
Parent->addElement(Element);
Element->updateLevel(Parent);
}
}
Symbol->setType(Element);
}
return Error::success();
}
// S_BUILDINFO
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &CVR,
BuildInfoSym &BuildInfo) {
LLVM_DEBUG({ printTypeIndex("BuildId", BuildInfo.BuildId); });
CVType CVBuildType = Ids.getType(BuildInfo.BuildId);
if (Error Err = LogicalVisitor->finishVisitation(
CVBuildType, BuildInfo.BuildId, Reader->getCompileUnit()))
return Err;
return Error::success();
}
// S_COMPILE2
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record,
Compile2Sym &Compile2) {
LLVM_DEBUG({
W.printEnum("Language", uint8_t(Compile2.getLanguage()),
getSourceLanguageNames());
W.printFlags("Flags", uint32_t(Compile2.getFlags()),
getCompileSym3FlagNames());
W.printEnum("Machine", unsigned(Compile2.Machine), getCPUTypeNames());
W.printString("VersionName", Compile2.Version);
});
// MSVC generates the following sequence for a CodeView module:
// S_OBJNAME --> Set 'CurrentObjectName'.
// S_COMPILE2 --> Set the compile unit name using 'CurrentObjectName'.
// ...
// S_BUILDINFO --> Extract the source name.
//
// Clang generates the following sequence for a CodeView module:
// S_COMPILE2 --> Set the compile unit name to empty string.
// ...
// S_BUILDINFO --> Extract the source name.
//
// For both toolchains, update the compile unit name from S_BUILDINFO.
if (LVScope *Scope = LogicalVisitor->CurrentScope) {
// The name of the CU, was extracted from the 'BuildInfo' subsection.
Reader->setCompileUnitCPUType(Compile2.Machine);
Scope->setName(CurrentObjectName);
if (options().getAttributeProducer())
Scope->setProducer(Compile2.Version);
getReader().isSystemEntry(Scope, CurrentObjectName);
// The line records in CodeView are recorded per Module ID. Update
// the relationship between the current CU and the Module ID.
Reader->addModule(Scope);
// Updated the collected strings with their associated compile unit.
Shared->StringRecords.addFilenames(Reader->getCompileUnit());
}
// Clear any previous ObjectName.
CurrentObjectName = "";
return Error::success();
}
// S_COMPILE3
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record,
Compile3Sym &Compile3) {
LLVM_DEBUG({
W.printEnum("Language", uint8_t(Compile3.getLanguage()),
getSourceLanguageNames());
W.printFlags("Flags", uint32_t(Compile3.getFlags()),
getCompileSym3FlagNames());
W.printEnum("Machine", unsigned(Compile3.Machine), getCPUTypeNames());
W.printString("VersionName", Compile3.Version);
});
// MSVC generates the following sequence for a CodeView module:
// S_OBJNAME --> Set 'CurrentObjectName'.
// S_COMPILE3 --> Set the compile unit name using 'CurrentObjectName'.
// ...
// S_BUILDINFO --> Extract the source name.
//
// Clang generates the following sequence for a CodeView module:
// S_COMPILE3 --> Set the compile unit name to empty string.
// ...
// S_BUILDINFO --> Extract the source name.
//
// For both toolchains, update the compile unit name from S_BUILDINFO.
if (LVScope *Scope = LogicalVisitor->CurrentScope) {
// The name of the CU, was extracted from the 'BuildInfo' subsection.
Reader->setCompileUnitCPUType(Compile3.Machine);
Scope->setName(CurrentObjectName);
if (options().getAttributeProducer())
Scope->setProducer(Compile3.Version);
getReader().isSystemEntry(Scope, CurrentObjectName);
// The line records in CodeView are recorded per Module ID. Update
// the relationship between the current CU and the Module ID.
Reader->addModule(Scope);
// Updated the collected strings with their associated compile unit.
Shared->StringRecords.addFilenames(Reader->getCompileUnit());
}
// Clear any previous ObjectName.
CurrentObjectName = "";
return Error::success();
}
// S_CONSTANT, S_MANCONSTANT
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record,
ConstantSym &Constant) {
LLVM_DEBUG({
printTypeIndex("Type", Constant.Type);
W.printNumber("Value", Constant.Value);
W.printString("Name", Constant.Name);
});
if (LVSymbol *Symbol = LogicalVisitor->CurrentSymbol) {
Symbol->setName(Constant.Name);
Symbol->setType(LogicalVisitor->getElement(StreamTPI, Constant.Type));
Symbol->resetIncludeInPrint();
}
return Error::success();
}
// S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE
Error LVSymbolVisitor::visitKnownRecord(
CVSymbol &Record,
DefRangeFramePointerRelFullScopeSym &DefRangeFramePointerRelFullScope) {
// DefRanges don't have types, just registers and code offsets.
LLVM_DEBUG({
if (LocalSymbol)
W.getOStream() << formatv("Symbol: {0}, ", LocalSymbol->getName());
W.printNumber("Offset", DefRangeFramePointerRelFullScope.Offset);
});
if (LVSymbol *Symbol = LocalSymbol) {
Symbol->setHasCodeViewLocation();
LocalSymbol = nullptr;
// Add location debug location. Operands: [Offset, 0].
dwarf::Attribute Attr =
dwarf::Attribute(SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE);
uint64_t Operand1 = DefRangeFramePointerRelFullScope.Offset;
Symbol->addLocation(Attr, 0, 0, 0, 0);
Symbol->addLocationOperands(LVSmall(Attr), {Operand1});
}
return Error::success();
}
// S_DEFRANGE_FRAMEPOINTER_REL
Error LVSymbolVisitor::visitKnownRecord(
CVSymbol &Record, DefRangeFramePointerRelSym &DefRangeFramePointerRel) {
// DefRanges don't have types, just registers and code offsets.
LLVM_DEBUG({
if (LocalSymbol)
W.getOStream() << formatv("Symbol: {0}, ", LocalSymbol->getName());
W.printNumber("Offset", DefRangeFramePointerRel.Hdr.Offset);
printLocalVariableAddrRange(DefRangeFramePointerRel.Range,
DefRangeFramePointerRel.getRelocationOffset());
printLocalVariableAddrGap(DefRangeFramePointerRel.Gaps);
});
// We are expecting the following sequence:
// 128 | S_LOCAL [size = 20] `ParamBar`
// ...
// 148 | S_DEFRANGE_FRAMEPOINTER_REL [size = 16]
if (LVSymbol *Symbol = LocalSymbol) {
Symbol->setHasCodeViewLocation();
LocalSymbol = nullptr;
// Add location debug location. Operands: [Offset, 0].
dwarf::Attribute Attr =
dwarf::Attribute(SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL);
uint64_t Operand1 = DefRangeFramePointerRel.Hdr.Offset;
LocalVariableAddrRange Range = DefRangeFramePointerRel.Range;
LVAddress Address =
Reader->linearAddress(Range.ISectStart, Range.OffsetStart);
Symbol->addLocation(Attr, Address, Address + Range.Range, 0, 0);
Symbol->addLocationOperands(LVSmall(Attr), {Operand1});
}
return Error::success();
}
// S_DEFRANGE_REGISTER_REL
Error LVSymbolVisitor::visitKnownRecord(
CVSymbol &Record, DefRangeRegisterRelSym &DefRangeRegisterRel) {
// DefRanges don't have types, just registers and code offsets.
LLVM_DEBUG({
if (LocalSymbol)
W.getOStream() << formatv("Symbol: {0}, ", LocalSymbol->getName());
W.printBoolean("HasSpilledUDTMember",
DefRangeRegisterRel.hasSpilledUDTMember());
W.printNumber("OffsetInParent", DefRangeRegisterRel.offsetInParent());
W.printNumber("BasePointerOffset",
DefRangeRegisterRel.Hdr.BasePointerOffset);
printLocalVariableAddrRange(DefRangeRegisterRel.Range,
DefRangeRegisterRel.getRelocationOffset());
printLocalVariableAddrGap(DefRangeRegisterRel.Gaps);
});
if (LVSymbol *Symbol = LocalSymbol) {
Symbol->setHasCodeViewLocation();
LocalSymbol = nullptr;
// Add location debug location. Operands: [Register, Offset].
dwarf::Attribute Attr =
dwarf::Attribute(SymbolKind::S_DEFRANGE_REGISTER_REL);
uint64_t Operand1 = DefRangeRegisterRel.Hdr.Register;
uint64_t Operand2 = DefRangeRegisterRel.Hdr.BasePointerOffset;
LocalVariableAddrRange Range = DefRangeRegisterRel.Range;
LVAddress Address =
Reader->linearAddress(Range.ISectStart, Range.OffsetStart);
Symbol->addLocation(Attr, Address, Address + Range.Range, 0, 0);
Symbol->addLocationOperands(LVSmall(Attr), {Operand1, Operand2});
}
return Error::success();
}
// S_DEFRANGE_REGISTER
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record,
DefRangeRegisterSym &DefRangeRegister) {
// DefRanges don't have types, just registers and code offsets.
LLVM_DEBUG({
if (LocalSymbol)
W.getOStream() << formatv("Symbol: {0}, ", LocalSymbol->getName());
W.printEnum("Register", uint16_t(DefRangeRegister.Hdr.Register),
getRegisterNames(Reader->getCompileUnitCPUType()));
W.printNumber("MayHaveNoName", DefRangeRegister.Hdr.MayHaveNoName);
printLocalVariableAddrRange(DefRangeRegister.Range,
DefRangeRegister.getRelocationOffset());
printLocalVariableAddrGap(DefRangeRegister.Gaps);
});
if (LVSymbol *Symbol = LocalSymbol) {
Symbol->setHasCodeViewLocation();
LocalSymbol = nullptr;
// Add location debug location. Operands: [Register, 0].
dwarf::Attribute Attr = dwarf::Attribute(SymbolKind::S_DEFRANGE_REGISTER);
uint64_t Operand1 = DefRangeRegister.Hdr.Register;
LocalVariableAddrRange Range = DefRangeRegister.Range;
LVAddress Address =
Reader->linearAddress(Range.ISectStart, Range.OffsetStart);
Symbol->addLocation(Attr, Address, Address + Range.Range, 0, 0);
Symbol->addLocationOperands(LVSmall(Attr), {Operand1});
}
return Error::success();
}
// S_DEFRANGE_SUBFIELD_REGISTER
Error LVSymbolVisitor::visitKnownRecord(
CVSymbol &Record, DefRangeSubfieldRegisterSym &DefRangeSubfieldRegister) {
// DefRanges don't have types, just registers and code offsets.
LLVM_DEBUG({
if (LocalSymbol)
W.getOStream() << formatv("Symbol: {0}, ", LocalSymbol->getName());
W.printEnum("Register", uint16_t(DefRangeSubfieldRegister.Hdr.Register),
getRegisterNames(Reader->getCompileUnitCPUType()));
W.printNumber("MayHaveNoName", DefRangeSubfieldRegister.Hdr.MayHaveNoName);
W.printNumber("OffsetInParent",
DefRangeSubfieldRegister.Hdr.OffsetInParent);
printLocalVariableAddrRange(DefRangeSubfieldRegister.Range,
DefRangeSubfieldRegister.getRelocationOffset());
printLocalVariableAddrGap(DefRangeSubfieldRegister.Gaps);
});
if (LVSymbol *Symbol = LocalSymbol) {
Symbol->setHasCodeViewLocation();
LocalSymbol = nullptr;
// Add location debug location. Operands: [Register, 0].
dwarf::Attribute Attr =
dwarf::Attribute(SymbolKind::S_DEFRANGE_SUBFIELD_REGISTER);
uint64_t Operand1 = DefRangeSubfieldRegister.Hdr.Register;
LocalVariableAddrRange Range = DefRangeSubfieldRegister.Range;
LVAddress Address =
Reader->linearAddress(Range.ISectStart, Range.OffsetStart);
Symbol->addLocation(Attr, Address, Address + Range.Range, 0, 0);
Symbol->addLocationOperands(LVSmall(Attr), {Operand1});
}
return Error::success();
}
// S_DEFRANGE_SUBFIELD
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record,
DefRangeSubfieldSym &DefRangeSubfield) {
// DefRanges don't have types, just registers and code offsets.
LLVM_DEBUG({
if (LocalSymbol)
W.getOStream() << formatv("Symbol: {0}, ", LocalSymbol->getName());
if (ObjDelegate) {
DebugStringTableSubsectionRef Strings = ObjDelegate->getStringTable();
auto ExpectedProgram = Strings.getString(DefRangeSubfield.Program);
if (!ExpectedProgram) {
consumeError(ExpectedProgram.takeError());
return llvm::make_error<CodeViewError>(
"String table offset outside of bounds of String Table!");
}
W.printString("Program", *ExpectedProgram);
}
W.printNumber("OffsetInParent", DefRangeSubfield.OffsetInParent);
printLocalVariableAddrRange(DefRangeSubfield.Range,
DefRangeSubfield.getRelocationOffset());
printLocalVariableAddrGap(DefRangeSubfield.Gaps);
});
if (LVSymbol *Symbol = LocalSymbol) {
Symbol->setHasCodeViewLocation();
LocalSymbol = nullptr;
// Add location debug location. Operands: [Program, 0].
dwarf::Attribute Attr = dwarf::Attribute(SymbolKind::S_DEFRANGE_SUBFIELD);
uint64_t Operand1 = DefRangeSubfield.Program;
LocalVariableAddrRange Range = DefRangeSubfield.Range;
LVAddress Address =
Reader->linearAddress(Range.ISectStart, Range.OffsetStart);
Symbol->addLocation(Attr, Address, Address + Range.Range, 0, 0);
Symbol->addLocationOperands(LVSmall(Attr), {Operand1, /*Operand2=*/0});
}
return Error::success();
}
// S_DEFRANGE
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record,
DefRangeSym &DefRange) {
// DefRanges don't have types, just registers and code offsets.
LLVM_DEBUG({
if (LocalSymbol)
W.getOStream() << formatv("Symbol: {0}, ", LocalSymbol->getName());
if (ObjDelegate) {
DebugStringTableSubsectionRef Strings = ObjDelegate->getStringTable();
auto ExpectedProgram = Strings.getString(DefRange.Program);
if (!ExpectedProgram) {
consumeError(ExpectedProgram.takeError());
return llvm::make_error<CodeViewError>(
"String table offset outside of bounds of String Table!");
}
W.printString("Program", *ExpectedProgram);
}
printLocalVariableAddrRange(DefRange.Range, DefRange.getRelocationOffset());
printLocalVariableAddrGap(DefRange.Gaps);
});
if (LVSymbol *Symbol = LocalSymbol) {
Symbol->setHasCodeViewLocation();
LocalSymbol = nullptr;
// Add location debug location. Operands: [Program, 0].
dwarf::Attribute Attr = dwarf::Attribute(SymbolKind::S_DEFRANGE);
uint64_t Operand1 = DefRange.Program;
LocalVariableAddrRange Range = DefRange.Range;
LVAddress Address =
Reader->linearAddress(Range.ISectStart, Range.OffsetStart);
Symbol->addLocation(Attr, Address, Address + Range.Range, 0, 0);
Symbol->addLocationOperands(LVSmall(Attr), {Operand1, /*Operand2=*/0});
}
return Error::success();
}
// S_FRAMEPROC
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record,
FrameProcSym &FrameProc) {
if (LVScope *Function = LogicalVisitor->getReaderScope()) {
// S_FRAMEPROC contains extra information for the function described
// by any of the previous generated records:
// S_GPROC32, S_LPROC32, S_LPROC32_ID, S_GPROC32_ID.
// The generated sequence is:
// S_GPROC32_ID ...
// S_FRAMEPROC ...
// Collect additional inline flags for the current scope function.
FrameProcedureOptions Flags = FrameProc.Flags;
if (FrameProcedureOptions::MarkedInline ==
(Flags & FrameProcedureOptions::MarkedInline))
Function->setInlineCode(dwarf::DW_INL_declared_inlined);
if (FrameProcedureOptions::Inlined ==
(Flags & FrameProcedureOptions::Inlined))
Function->setInlineCode(dwarf::DW_INL_inlined);
// To determine the symbol kind for any symbol declared in that function,
// we can access the S_FRAMEPROC for the parent scope function. It contains
// information about the local fp and param fp registers and compare with
// the register in the S_REGREL32 to get a match.
codeview::CPUType CPU = Reader->getCompileUnitCPUType();
LocalFrameRegister = FrameProc.getLocalFramePtrReg(CPU);
ParamFrameRegister = FrameProc.getParamFramePtrReg(CPU);
}
return Error::success();
}
// S_GDATA32, S_LDATA32, S_LMANDATA, S_GMANDATA
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, DataSym &Data) {
LLVM_DEBUG({
printTypeIndex("Type", Data.Type);
W.printString("DisplayName", Data.Name);
});
if (LVSymbol *Symbol = LogicalVisitor->CurrentSymbol) {
StringRef LinkageName;
if (ObjDelegate)
ObjDelegate->getLinkageName(Data.getRelocationOffset(), Data.DataOffset,
&LinkageName);
Symbol->setName(Data.Name);
Symbol->setLinkageName(LinkageName);
// The MSVC generates local data as initialization for aggregates. It
// contains the address for an initialization function.
// The symbols contains the '$initializer$' pattern. Allow them only if
// the '--internal=system' option is given.
// 0 | S_LDATA32 `Struct$initializer$`
// type = 0x1040 (void ()*)
if (getReader().isSystemEntry(Symbol) && !options().getAttributeSystem()) {
Symbol->resetIncludeInPrint();
return Error::success();
}
if (LVScope *Namespace = Shared->NamespaceDeduction.get(Data.Name)) {
// The variable is already at different scope. In order to reflect
// the correct parent, move it to the namespace.
if (Symbol->getParentScope()->removeElement(Symbol))
Namespace->addElement(Symbol);
}
Symbol->setType(LogicalVisitor->getElement(StreamTPI, Data.Type));
if (Record.kind() == SymbolKind::S_GDATA32)
Symbol->setIsExternal();
}
return Error::success();
}
// S_INLINESITE
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record,
InlineSiteSym &InlineSite) {
LLVM_DEBUG({ printTypeIndex("Inlinee", InlineSite.Inlinee); });
if (LVScope *InlinedFunction = LogicalVisitor->CurrentScope) {
LVScope *AbstractFunction = Reader->createScopeFunction();
AbstractFunction->setIsSubprogram();
AbstractFunction->setTag(dwarf::DW_TAG_subprogram);
AbstractFunction->setInlineCode(dwarf::DW_INL_inlined);
AbstractFunction->setIsInlinedAbstract();
InlinedFunction->setReference(AbstractFunction);
LogicalVisitor->startProcessArgumentList();
// 'Inlinee' is a Type ID.
CVType CVFunctionType = Ids.getType(InlineSite.Inlinee);
if (Error Err = LogicalVisitor->finishVisitation(
CVFunctionType, InlineSite.Inlinee, AbstractFunction))
return Err;
LogicalVisitor->stopProcessArgumentList();
// For inlined functions set the linkage name to be the same as
// the name. It used to find their lines and ranges.
StringRef Name = AbstractFunction->getName();
InlinedFunction->setName(Name);
InlinedFunction->setLinkageName(Name);
// Process annotation bytes to calculate code and line offsets.
if (Error Err = LogicalVisitor->inlineSiteAnnotation(
AbstractFunction, InlinedFunction, InlineSite))
return Err;
}
return Error::success();
}
// S_LOCAL
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, LocalSym &Local) {
LLVM_DEBUG({
printTypeIndex("Type", Local.Type);
W.printFlags("Flags", uint16_t(Local.Flags), getLocalFlagNames());
W.printString("VarName", Local.Name);
});
if (LVSymbol *Symbol = LogicalVisitor->CurrentSymbol) {
Symbol->setName(Local.Name);
// Symbol was created as 'variable'; determine its real kind.
Symbol->resetIsVariable();
// Be sure the 'this' symbol is marked as 'compiler generated'.
if (bool(Local.Flags & LocalSymFlags::IsCompilerGenerated) ||
Local.Name.equals("this")) {
Symbol->setIsArtificial();
Symbol->setIsParameter();
} else {
bool(Local.Flags & LocalSymFlags::IsParameter) ? Symbol->setIsParameter()
: Symbol->setIsVariable();
}
// Update correct debug information tag.
if (Symbol->getIsParameter())
Symbol->setTag(dwarf::DW_TAG_formal_parameter);
LVElement *Element = LogicalVisitor->getElement(StreamTPI, Local.Type);
if (Element && Element->getIsScoped()) {
// We have a local type. Find its parent function.
LVScope *Parent = Symbol->getFunctionParent();
// The element representing the type has been already finalized. If
// the type is an aggregate type, its members have been already added.
// As the type is local, its level will be changed.
Parent->addElement(Element);
Element->updateLevel(Parent);
}
Symbol->setType(Element);
// The CodeView records (S_DEFFRAME_*) describing debug location for
// this symbol, do not have any direct reference to it. Those records
// are emitted after this symbol. Record the current symbol.
LocalSymbol = Symbol;
}
return Error::success();
}
// S_OBJNAME
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, ObjNameSym &ObjName) {
LLVM_DEBUG({
W.printHex("Signature", ObjName.Signature);
W.printString("ObjectName", ObjName.Name);
});
CurrentObjectName = ObjName.Name;
return Error::success();
}
// S_GPROC32, S_LPROC32, S_LPROC32_ID, S_GPROC32_ID
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, ProcSym &Proc) {
if (InFunctionScope)
return llvm::make_error<CodeViewError>("Visiting a ProcSym while inside "
"function scope!");
InFunctionScope = true;
LLVM_DEBUG({
printTypeIndex("FunctionType", Proc.FunctionType);
W.printHex("Segment", Proc.Segment);
W.printFlags("Flags", static_cast<uint8_t>(Proc.Flags),
getProcSymFlagNames());
W.printString("DisplayName", Proc.Name);
});
// Clang and Microsoft generated different debug information records:
// For functions definitions:
// Clang: S_GPROC32 -> LF_FUNC_ID -> LF_PROCEDURE
// Microsoft: S_GPROC32 -> LF_PROCEDURE
// For member function definition:
// Clang: S_GPROC32 -> LF_MFUNC_ID -> LF_MFUNCTION
// Microsoft: S_GPROC32 -> LF_MFUNCTION
// In order to support both sequences, if we found LF_FUNCTION_ID, just
// get the TypeIndex for LF_PROCEDURE.
// For the given test case, we have the sequence:
// namespace NSP_local {
// void foo_local() {
// }
// }
//
// 0x1000 | LF_STRING_ID String: NSP_local
// 0x1002 | LF_PROCEDURE
// return type = 0x0003 (void), # args = 0, param list = 0x1001
// calling conv = cdecl, options = None
// 0x1003 | LF_FUNC_ID
// name = foo_local, type = 0x1002, parent scope = 0x1000
// 0 | S_GPROC32_ID `NSP_local::foo_local`
// type = `0x1003 (foo_local)`
// 0x1004 | LF_STRING_ID String: suite
// 0x1005 | LF_STRING_ID String: suite_local.cpp
//
// The LF_STRING_ID can hold different information:
// 0x1000 - The enclosing namespace.
// 0x1004 - The compile unit directory name.
// 0x1005 - The compile unit name.
//
// Before deducting its scope, we need to evaluate its type and create any
// associated namespaces.
if (LVScope *Function = LogicalVisitor->CurrentScope) {
StringRef LinkageName;
if (ObjDelegate)
ObjDelegate->getLinkageName(Proc.getRelocationOffset(), Proc.CodeOffset,
&LinkageName);
// The line table can be accessed using the linkage name.
Reader->addToSymbolTable(LinkageName, Function);
Function->setName(Proc.Name);
Function->setLinkageName(LinkageName);
if (options().getGeneralCollectRanges()) {
// Record converted segment::offset addressing for this scope.
LVAddress Addendum = Reader->getSymbolTableAddress(LinkageName);
LVAddress LowPC =
Reader->linearAddress(Proc.Segment, Proc.CodeOffset, Addendum);
LVAddress HighPC = LowPC + Proc.CodeSize - 1;
Function->addObject(LowPC, HighPC);
// If the scope is a function, add it to the public names.
if ((options().getAttributePublics() || options().getPrintAnyLine()) &&
!Function->getIsInlinedFunction())
Reader->getCompileUnit()->addPublicName(Function, LowPC, HighPC);
}
if (Function->getIsSystem() && !options().getAttributeSystem()) {
Function->resetIncludeInPrint();
return Error::success();
}
TypeIndex TIFunctionType = Proc.FunctionType;
if (TIFunctionType.isSimple())
Function->setType(LogicalVisitor->getElement(StreamTPI, TIFunctionType));
else {
// We have to detect the correct stream, using the lexical parent
// name, as there is not other obvious way to get the stream.
// Normal function: LF_FUNC_ID (TPI)/(IPI)
// LF_PROCEDURE (TPI)
// Lambda function: LF_MFUNCTION (TPI)
// Member function: LF_MFUNC_ID (TPI)/(IPI)
StringRef OuterComponent;
std::tie(OuterComponent, std::ignore) = getInnerComponent(Proc.Name);
TypeIndex TI = Shared->ForwardReferences.find(OuterComponent);
std::optional<CVType> CVFunctionType;
auto GetRecordType = [&]() -> bool {
CVFunctionType = Ids.tryGetType(TIFunctionType);
if (!CVFunctionType)
return false;
if (TI.isNoneType())
// Normal function.
if (CVFunctionType->kind() == LF_FUNC_ID)
return true;
// Member function.
return (CVFunctionType->kind() == LF_MFUNC_ID);
};
// We can have a LF_FUNC_ID, LF_PROCEDURE or LF_MFUNCTION.
if (!GetRecordType()) {
CVFunctionType = Types.tryGetType(TIFunctionType);
if (!CVFunctionType)
return llvm::make_error<CodeViewError>("Invalid type index");
}
if (Error Err = LogicalVisitor->finishVisitation(
*CVFunctionType, TIFunctionType, Function))
return Err;
}
if (Record.kind() == SymbolKind::S_GPROC32 ||
Record.kind() == SymbolKind::S_GPROC32_ID)
Function->setIsExternal();
// We don't have a way to see if the symbol is compiler generated. Use
// the linkage name, to detect `scalar deleting destructor' functions.
std::string DemangledSymbol = demangle(LinkageName);
if (DemangledSymbol.find("scalar deleting dtor") != std::string::npos) {
Function->setIsArtificial();
} else {
// Clang generates global ctor and dtor names containing the substrings:
// 'dynamic initializer for' and 'dynamic atexit destructor for'.
if (DemangledSymbol.find("dynamic atexit destructor for") !=
std::string::npos)
Function->setIsArtificial();
}
}
return Error::success();
}
// S_END
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record,
ScopeEndSym &ScopeEnd) {
InFunctionScope = false;
return Error::success();
}
// S_THUNK32
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, Thunk32Sym &Thunk) {
if (InFunctionScope)
return llvm::make_error<CodeViewError>("Visiting a Thunk32Sym while inside "
"function scope!");
InFunctionScope = true;
LLVM_DEBUG({
W.printHex("Segment", Thunk.Segment);
W.printString("Name", Thunk.Name);
});
if (LVScope *Function = LogicalVisitor->CurrentScope)
Function->setName(Thunk.Name);
return Error::success();
}
// S_UDT, S_COBOLUDT
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, UDTSym &UDT) {
LLVM_DEBUG({
printTypeIndex("Type", UDT.Type);
W.printString("UDTName", UDT.Name);
});
if (LVType *Type = LogicalVisitor->CurrentType) {
if (LVScope *Namespace = Shared->NamespaceDeduction.get(UDT.Name)) {
if (Type->getParentScope()->removeElement(Type))
Namespace->addElement(Type);
}
Type->setName(UDT.Name);
// We have to determine if the typedef is a real C/C++ definition or is
// the S_UDT record that describe all the user defined types.
// 0 | S_UDT `Name` original type = 0x1009
// 0x1009 | LF_STRUCTURE `Name`
// Ignore type definitions for RTTI types:
// _s__RTTIBaseClassArray, _s__RTTIBaseClassDescriptor,
// _s__RTTICompleteObjectLocator, _s__RTTIClassHierarchyDescriptor.
if (getReader().isSystemEntry(Type))
Type->resetIncludeInPrint();
else {
StringRef RecordName = getRecordName(Types, UDT.Type);
if (UDT.Name.equals(RecordName))
Type->resetIncludeInPrint();
Type->setType(LogicalVisitor->getElement(StreamTPI, UDT.Type));
}
}
return Error::success();
}
// S_UNAMESPACE
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record,
UsingNamespaceSym &UN) {
LLVM_DEBUG({ W.printString("Namespace", UN.Name); });
return Error::success();
}
// S_ARMSWITCHTABLE
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &CVR,
JumpTableSym &JumpTable) {
LLVM_DEBUG({
W.printHex("BaseOffset", JumpTable.BaseOffset);
W.printNumber("BaseSegment", JumpTable.BaseSegment);
W.printFlags("SwitchType", static_cast<uint16_t>(JumpTable.SwitchType),
getJumpTableEntrySizeNames());
W.printHex("BranchOffset", JumpTable.BranchOffset);
W.printHex("TableOffset", JumpTable.TableOffset);
W.printNumber("BranchSegment", JumpTable.BranchSegment);
W.printNumber("TableSegment", JumpTable.TableSegment);
W.printNumber("EntriesCount", JumpTable.EntriesCount);
});
return Error::success();
}
// S_CALLERS, S_CALLEES, S_INLINEES
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, CallerSym &Caller) {
LLVM_DEBUG({
llvm::StringRef FieldName;
switch (Caller.getKind()) {
case SymbolRecordKind::CallerSym:
FieldName = "Callee";
break;
case SymbolRecordKind::CalleeSym:
FieldName = "Caller";
break;
case SymbolRecordKind::InlineesSym:
FieldName = "Inlinee";
break;
default:
return llvm::make_error<CodeViewError>(
"Unknown CV Record type for a CallerSym object!");
}
for (auto FuncID : Caller.Indices) {
printTypeIndex(FieldName, FuncID);
}
});
return Error::success();
}
#undef DEBUG_TYPE
#define DEBUG_TYPE "CodeViewLogicalVisitor"
//===----------------------------------------------------------------------===//
// Logical visitor.
//===----------------------------------------------------------------------===//
LVLogicalVisitor::LVLogicalVisitor(LVCodeViewReader *Reader, ScopedPrinter &W,
InputFile &Input)
: Reader(Reader), W(W), Input(Input) {
// The LogicalVisitor connects the CodeViewReader with the visitors that
// traverse the types, symbols, etc. Do any initialization that is needed.
Shared = std::make_shared<LVShared>(Reader, this);
}
void LVLogicalVisitor::printTypeIndex(StringRef FieldName, TypeIndex TI,
uint32_t StreamIdx) {
codeview::printTypeIndex(W, FieldName, TI,
StreamIdx == StreamTPI ? types() : ids());
}
void LVLogicalVisitor::printTypeBegin(CVType &Record, TypeIndex TI,
LVElement *Element, uint32_t StreamIdx) {
W.getOStream() << "\n";
W.startLine() << formatTypeLeafKind(Record.kind());
W.getOStream() << " (" << HexNumber(TI.getIndex()) << ")";
W.getOStream() << " {\n";
W.indent();
W.printEnum("TypeLeafKind", unsigned(Record.kind()), ArrayRef(LeafTypeNames));
printTypeIndex("TI", TI, StreamIdx);
W.startLine() << "Element: " << HexNumber(Element->getOffset()) << " "
<< Element->getName() << "\n";
}
void LVLogicalVisitor::printTypeEnd(CVType &Record) {
W.unindent();
W.startLine() << "}\n";
}
void LVLogicalVisitor::printMemberBegin(CVMemberRecord &Record, TypeIndex TI,
LVElement *Element,
uint32_t StreamIdx) {
W.getOStream() << "\n";
W.startLine() << formatTypeLeafKind(Record.Kind);
W.getOStream() << " (" << HexNumber(TI.getIndex()) << ")";
W.getOStream() << " {\n";
W.indent();
W.printEnum("TypeLeafKind", unsigned(Record.Kind), ArrayRef(LeafTypeNames));
printTypeIndex("TI", TI, StreamIdx);
W.startLine() << "Element: " << HexNumber(Element->getOffset()) << " "
<< Element->getName() << "\n";
}
void LVLogicalVisitor::printMemberEnd(CVMemberRecord &Record) {
W.unindent();
W.startLine() << "}\n";
}
Error LVLogicalVisitor::visitUnknownType(CVType &Record, TypeIndex TI) {
LLVM_DEBUG({
printTypeIndex("\nTI", TI, StreamTPI);
W.printNumber("Length", uint32_t(Record.content().size()));
});
return Error::success();
}
// LF_ARGLIST (TPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record, ArgListRecord &Args,
TypeIndex TI, LVElement *Element) {
ArrayRef<TypeIndex> Indices = Args.getIndices();
uint32_t Size = Indices.size();
LLVM_DEBUG({
printTypeBegin(Record, TI, Element, StreamTPI);
W.printNumber("NumArgs", Size);
ListScope Arguments(W, "Arguments");
for (uint32_t I = 0; I < Size; ++I)
printTypeIndex("ArgType", Indices[I], StreamTPI);
printTypeEnd(Record);
});
LVScope *Function = static_cast<LVScope *>(Element);
for (uint32_t Index = 0; Index < Size; ++Index) {
TypeIndex ParameterType = Indices[Index];
createParameter(ParameterType, StringRef(), Function);
}
return Error::success();
}
// LF_ARRAY (TPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record, ArrayRecord &AT,
TypeIndex TI, LVElement *Element) {
LLVM_DEBUG({
printTypeBegin(Record, TI, Element, StreamTPI);
printTypeIndex("ElementType", AT.getElementType(), StreamTPI);
printTypeIndex("IndexType", AT.getIndexType(), StreamTPI);
W.printNumber("SizeOf", AT.getSize());
W.printString("Name", AT.getName());
printTypeEnd(Record);
});
if (Element->getIsFinalized())
return Error::success();
Element->setIsFinalized();
LVScopeArray *Array = static_cast<LVScopeArray *>(Element);
if (!Array)
return Error::success();
Reader->getCompileUnit()->addElement(Array);
TypeIndex TIElementType = AT.getElementType();
LVType *PrevSubrange = nullptr;
LazyRandomTypeCollection &Types = types();
// As the logical view is modeled on DWARF, for each dimension we have to
// create a DW_TAG_subrange_type, with dimension size.
// The subrange type can be: unsigned __int32 or unsigned __int64.
auto AddSubrangeType = [&](ArrayRecord &AR) {
LVType *Subrange = Reader->createTypeSubrange();
Subrange->setTag(dwarf::DW_TAG_subrange_type);
Subrange->setType(getElement(StreamTPI, AR.getIndexType()));
Subrange->setCount(AR.getSize());
Subrange->setOffset(
TIElementType.isSimple()
? (uint32_t)(TypeLeafKind)TIElementType.getSimpleKind()
: TIElementType.getIndex());
Array->addElement(Subrange);
if (PrevSubrange)
if (int64_t Count = Subrange->getCount())
PrevSubrange->setCount(PrevSubrange->getCount() / Count);
PrevSubrange = Subrange;
};
// Preserve the original TypeIndex; it would be updated in the case of:
// - The array type contains qualifiers.
// - In multidimensional arrays, the last LF_ARRAY entry contains the type.
TypeIndex TIArrayType;
// For each dimension in the array, there is a LF_ARRAY entry. The last
// entry contains the array type, which can be a LF_MODIFIER in the case
// of the type being modified by a qualifier (const, etc).
ArrayRecord AR(AT);
CVType CVEntry = Record;
while (CVEntry.kind() == LF_ARRAY) {
// Create the subrange information, required by the logical view. Once
// the array has been processed, the dimension sizes will updated, as
// the sizes are a progression. For instance:
// sizeof(int) = 4
// int Array[2]; Sizes: 8 Dim: 8 / 4 -> [2]
// int Array[2][3]; Sizes: 24, 12 Dim: 24 / 12 -> [2]
// Dim: 12 / 4 -> [3]
// int Array[2][3][4]; sizes: 96, 48, 16 Dim: 96 / 48 -> [2]
// Dim: 48 / 16 -> [3]
// Dim: 16 / 4 -> [4]
AddSubrangeType(AR);
TIArrayType = TIElementType;
// The current ElementType can be a modifier, in which case we need to
// get the type being modified.
// If TypeIndex is not a simple type, check if we have a qualified type.
if (!TIElementType.isSimple()) {
CVType CVElementType = Types.getType(TIElementType);
if (CVElementType.kind() == LF_MODIFIER) {
LVElement *QualifiedType =
Shared->TypeRecords.find(StreamTPI, TIElementType);
if (Error Err =
finishVisitation(CVElementType, TIElementType, QualifiedType))
return Err;
// Get the TypeIndex of the type that the LF_MODIFIER modifies.
TIElementType = getModifiedType(CVElementType);
}
}
// Ends the traversal, as we have reached a simple type (int, char, etc).
if (TIElementType.isSimple())
break;
// Read next dimension linked entry, if any.
CVEntry = Types.getType(TIElementType);
if (Error Err = TypeDeserializer::deserializeAs(
const_cast<CVType &>(CVEntry), AR)) {
consumeError(std::move(Err));
break;
}
TIElementType = AR.getElementType();
// NOTE: The typeindex has a value of: 0x0280.0000
getTrueType(TIElementType);
}
Array->setName(AT.getName());
TIArrayType = Shared->ForwardReferences.remap(TIArrayType);
Array->setType(getElement(StreamTPI, TIArrayType));
if (PrevSubrange)
// In the case of an aggregate type (class, struct, union, interface),
// get the aggregate size. As the original record is pointing to its
// reference, we have to update it.
if (uint64_t Size =
isAggregate(CVEntry)
? getSizeInBytesForTypeRecord(Types.getType(TIArrayType))
: getSizeInBytesForTypeIndex(TIElementType))
PrevSubrange->setCount(PrevSubrange->getCount() / Size);
return Error::success();
}
// LF_BITFIELD (TPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record, BitFieldRecord &BF,
TypeIndex TI, LVElement *Element) {
LLVM_DEBUG({
printTypeBegin(Record, TI, Element, StreamTPI);
printTypeIndex("Type", TI, StreamTPI);
W.printNumber("BitSize", BF.getBitSize());
W.printNumber("BitOffset", BF.getBitOffset());
printTypeEnd(Record);
});
Element->setType(getElement(StreamTPI, BF.getType()));
Element->setBitSize(BF.getBitSize());
return Error::success();
}
// LF_BUILDINFO (TPI)/(IPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record, BuildInfoRecord &BI,
TypeIndex TI, LVElement *Element) {
LLVM_DEBUG({
printTypeBegin(Record, TI, Element, StreamIPI);
W.printNumber("NumArgs", static_cast<uint32_t>(BI.getArgs().size()));
ListScope Arguments(W, "Arguments");
for (TypeIndex Arg : BI.getArgs())
printTypeIndex("ArgType", Arg, StreamIPI);
printTypeEnd(Record);
});
// The given 'Element' refers to the current compilation unit.
// All the args are references into the TPI/IPI stream.
TypeIndex TIName = BI.getArgs()[BuildInfoRecord::BuildInfoArg::SourceFile];
std::string Name = std::string(ids().getTypeName(TIName));
// There are cases where LF_BUILDINFO fields are empty.
if (!Name.empty())
Element->setName(Name);
return Error::success();
}
// LF_CLASS, LF_STRUCTURE, LF_INTERFACE (TPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record, ClassRecord &Class,
TypeIndex TI, LVElement *Element) {
LLVM_DEBUG({
printTypeBegin(Record, TI, Element, StreamTPI);
W.printNumber("MemberCount", Class.getMemberCount());
printTypeIndex("FieldList", Class.getFieldList(), StreamTPI);
printTypeIndex("DerivedFrom", Class.getDerivationList(), StreamTPI);
printTypeIndex("VShape", Class.getVTableShape(), StreamTPI);
W.printNumber("SizeOf", Class.getSize());
W.printString("Name", Class.getName());
if (Class.hasUniqueName())
W.printString("UniqueName", Class.getUniqueName());
printTypeEnd(Record);
});
if (Element->getIsFinalized())
return Error::success();
Element->setIsFinalized();
LVScopeAggregate *Scope = static_cast<LVScopeAggregate *>(Element);
if (!Scope)
return Error::success();
Scope->setName(Class.getName());
if (Class.hasUniqueName())
Scope->setLinkageName(Class.getUniqueName());
if (Class.isNested()) {
Scope->setIsNested();
createParents(Class.getName(), Scope);
}
if (Class.isScoped())
Scope->setIsScoped();
// Nested types will be added to their parents at creation. The forward
// references are only processed to finish the referenced element creation.
if (!(Class.isNested() || Class.isScoped())) {
if (LVScope *Namespace = Shared->NamespaceDeduction.get(Class.getName()))
Namespace->addElement(Scope);
else
Reader->getCompileUnit()->addElement(Scope);
}
LazyRandomTypeCollection &Types = types();
TypeIndex TIFieldList = Class.getFieldList();
if (TIFieldList.isNoneType()) {
TypeIndex ForwardType = Shared->ForwardReferences.find(Class.getName());
if (!ForwardType.isNoneType()) {
CVType CVReference = Types.getType(ForwardType);
TypeRecordKind RK = static_cast<TypeRecordKind>(CVReference.kind());
ClassRecord ReferenceRecord(RK);
if (Error Err = TypeDeserializer::deserializeAs(
const_cast<CVType &>(CVReference), ReferenceRecord))
return Err;
TIFieldList = ReferenceRecord.getFieldList();
}
}
if (!TIFieldList.isNoneType()) {
// Pass down the TypeIndex 'TI' for the aggregate containing the field list.
CVType CVFieldList = Types.getType(TIFieldList);
if (Error Err = finishVisitation(CVFieldList, TI, Scope))
return Err;
}
return Error::success();
}
// LF_ENUM (TPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record, EnumRecord &Enum,
TypeIndex TI, LVElement *Element) {
LLVM_DEBUG({
printTypeBegin(Record, TI, Element, StreamTPI);
W.printNumber("NumEnumerators", Enum.getMemberCount());
printTypeIndex("UnderlyingType", Enum.getUnderlyingType(), StreamTPI);
printTypeIndex("FieldListType", Enum.getFieldList(), StreamTPI);
W.printString("Name", Enum.getName());
printTypeEnd(Record);
});
LVScopeEnumeration *Scope = static_cast<LVScopeEnumeration *>(Element);
if (!Scope)
return Error::success();
if (Scope->getIsFinalized())
return Error::success();
Scope->setIsFinalized();
// Set the name, as in the case of nested, it would determine the relation
// to any potential parent, via the LF_NESTTYPE record.
Scope->setName(Enum.getName());
if (Enum.hasUniqueName())
Scope->setLinkageName(Enum.getUniqueName());
Scope->setType(getElement(StreamTPI, Enum.getUnderlyingType()));
if (Enum.isNested()) {
Scope->setIsNested();
createParents(Enum.getName(), Scope);
}
if (Enum.isScoped()) {
Scope->setIsScoped();
Scope->setIsEnumClass();
}
// Nested types will be added to their parents at creation.
if (!(Enum.isNested() || Enum.isScoped())) {
if (LVScope *Namespace = Shared->NamespaceDeduction.get(Enum.getName()))
Namespace->addElement(Scope);
else
Reader->getCompileUnit()->addElement(Scope);
}
TypeIndex TIFieldList = Enum.getFieldList();
if (!TIFieldList.isNoneType()) {
LazyRandomTypeCollection &Types = types();
CVType CVFieldList = Types.getType(TIFieldList);
if (Error Err = finishVisitation(CVFieldList, TIFieldList, Scope))
return Err;
}
return Error::success();
}
// LF_FIELDLIST (TPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record,
FieldListRecord &FieldList,
TypeIndex TI, LVElement *Element) {
LLVM_DEBUG({
printTypeBegin(Record, TI, Element, StreamTPI);
printTypeEnd(Record);
});
if (Error Err = visitFieldListMemberStream(TI, Element, FieldList.Data))
return Err;
return Error::success();
}
// LF_FUNC_ID (TPI)/(IPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record, FuncIdRecord &Func,
TypeIndex TI, LVElement *Element) {
// ParentScope and FunctionType are references into the TPI stream.
LLVM_DEBUG({
printTypeBegin(Record, TI, Element, StreamIPI);
printTypeIndex("ParentScope", Func.getParentScope(), StreamTPI);
printTypeIndex("FunctionType", Func.getFunctionType(), StreamTPI);
W.printString("Name", Func.getName());
printTypeEnd(Record);
});
// The TypeIndex (LF_PROCEDURE) returned by 'getFunctionType' is the
// function propotype, we need to use the function definition.
if (LVScope *FunctionDcl = static_cast<LVScope *>(Element)) {
// For inlined functions, the inlined instance has been already processed
// (all its information is contained in the Symbols section).
// 'Element' points to the created 'abstract' (out-of-line) function.
// Use the parent scope information to allocate it to the correct scope.
LazyRandomTypeCollection &Types = types();
TypeIndex TIParent = Func.getParentScope();
if (FunctionDcl->getIsInlinedAbstract()) {
FunctionDcl->setName(Func.getName());
if (TIParent.isNoneType())
Reader->getCompileUnit()->addElement(FunctionDcl);
}
if (!TIParent.isNoneType()) {
CVType CVParentScope = ids().getType(TIParent);
if (Error Err = finishVisitation(CVParentScope, TIParent, FunctionDcl))
return Err;
}
TypeIndex TIFunctionType = Func.getFunctionType();
CVType CVFunctionType = Types.getType(TIFunctionType);
if (Error Err =
finishVisitation(CVFunctionType, TIFunctionType, FunctionDcl))
return Err;
FunctionDcl->setIsFinalized();
}
return Error::success();
}
// LF_LABEL (TPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record, LabelRecord &LR,
TypeIndex TI, LVElement *Element) {
LLVM_DEBUG({
printTypeBegin(Record, TI, Element, StreamTPI);
printTypeEnd(Record);
});
return Error::success();
}
// LF_MFUNC_ID (TPI)/(IPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record, MemberFuncIdRecord &Id,
TypeIndex TI, LVElement *Element) {
// ClassType and FunctionType are references into the TPI stream.
LLVM_DEBUG({
printTypeBegin(Record, TI, Element, StreamIPI);
printTypeIndex("ClassType", Id.getClassType(), StreamTPI);
printTypeIndex("FunctionType", Id.getFunctionType(), StreamTPI);
W.printString("Name", Id.getName());
printTypeEnd(Record);
});
LVScope *FunctionDcl = static_cast<LVScope *>(Element);
if (FunctionDcl->getIsInlinedAbstract()) {
// For inlined functions, the inlined instance has been already processed
// (all its information is contained in the Symbols section).
// 'Element' points to the created 'abstract' (out-of-line) function.
// Use the parent scope information to allocate it to the correct scope.
if (LVScope *Class = static_cast<LVScope *>(
Shared->TypeRecords.find(StreamTPI, Id.getClassType())))
Class->addElement(FunctionDcl);
}
TypeIndex TIFunctionType = Id.getFunctionType();
CVType CVFunction = types().getType(TIFunctionType);
if (Error Err = finishVisitation(CVFunction, TIFunctionType, Element))
return Err;
return Error::success();
}
// LF_MFUNCTION (TPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record,
MemberFunctionRecord &MF, TypeIndex TI,
LVElement *Element) {
LLVM_DEBUG({
printTypeBegin(Record, TI, Element, StreamTPI);
printTypeIndex("ReturnType", MF.getReturnType(), StreamTPI);
printTypeIndex("ClassType", MF.getClassType(), StreamTPI);
printTypeIndex("ThisType", MF.getThisType(), StreamTPI);
W.printNumber("NumParameters", MF.getParameterCount());
printTypeIndex("ArgListType", MF.getArgumentList(), StreamTPI);
W.printNumber("ThisAdjustment", MF.getThisPointerAdjustment());
printTypeEnd(Record);
});
if (LVScope *MemberFunction = static_cast<LVScope *>(Element)) {
LVElement *Class = getElement(StreamTPI, MF.getClassType());
MemberFunction->setIsFinalized();
MemberFunction->setType(getElement(StreamTPI, MF.getReturnType()));
MemberFunction->setOffset(TI.getIndex());
MemberFunction->setOffsetFromTypeIndex();
if (ProcessArgumentList) {
ProcessArgumentList = false;
if (!MemberFunction->getIsStatic()) {
LVElement *ThisPointer = getElement(StreamTPI, MF.getThisType());
// When creating the 'this' pointer, check if it points to a reference.
ThisPointer->setType(Class);
LVSymbol *This =
createParameter(ThisPointer, StringRef(), MemberFunction);
This->setIsArtificial();
}
// Create formal parameters.
LazyRandomTypeCollection &Types = types();
CVType CVArguments = Types.getType(MF.getArgumentList());
if (Error Err = finishVisitation(CVArguments, MF.getArgumentList(),
MemberFunction))
return Err;
}
}
return Error::success();
}
// LF_METHODLIST (TPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record,
MethodOverloadListRecord &Overloads,
TypeIndex TI, LVElement *Element) {
LLVM_DEBUG({
printTypeBegin(Record, TI, Element, StreamTPI);
printTypeEnd(Record);
});
for (OneMethodRecord &Method : Overloads.Methods) {
CVMemberRecord Record;
Record.Kind = LF_METHOD;
Method.Name = OverloadedMethodName;
if (Error Err = visitKnownMember(Record, Method, TI, Element))
return Err;
}
return Error::success();
}
// LF_MODIFIER (TPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record, ModifierRecord &Mod,
TypeIndex TI, LVElement *Element) {
LLVM_DEBUG({
printTypeBegin(Record, TI, Element, StreamTPI);
printTypeIndex("ModifiedType", Mod.getModifiedType(), StreamTPI);
printTypeEnd(Record);
});
// Create the modified type, which will be attached to the type(s) that
// contains the modifiers.
LVElement *ModifiedType = getElement(StreamTPI, Mod.getModifiedType());
// At this point the types recording the qualifiers do not have a
// scope parent. They must be assigned to the current compile unit.
LVScopeCompileUnit *CompileUnit = Reader->getCompileUnit();
// The incoming element does not have a defined kind. Use the given
// modifiers to complete its type. A type can have more than one modifier;
// in that case, we have to create an extra type to have the other modifier.
LVType *LastLink = static_cast<LVType *>(Element);
if (!LastLink->getParentScope())
CompileUnit->addElement(LastLink);
bool SeenModifier = false;
uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers());
if (Mods & uint16_t(ModifierOptions::Const)) {
SeenModifier = true;
LastLink->setTag(dwarf::DW_TAG_const_type);
LastLink->setIsConst();
LastLink->setName("const");
}
if (Mods & uint16_t(ModifierOptions::Volatile)) {
if (SeenModifier) {
LVType *Volatile = Reader->createType();
Volatile->setIsModifier();
LastLink->setType(Volatile);
LastLink = Volatile;
CompileUnit->addElement(LastLink);
}
LastLink->setTag(dwarf::DW_TAG_volatile_type);
LastLink->setIsVolatile();
LastLink->setName("volatile");
}
if (Mods & uint16_t(ModifierOptions::Unaligned)) {
if (SeenModifier) {
LVType *Unaligned = Reader->createType();
Unaligned->setIsModifier();
LastLink->setType(Unaligned);
LastLink = Unaligned;
CompileUnit->addElement(LastLink);
}
LastLink->setTag(dwarf::DW_TAG_unaligned);
LastLink->setIsUnaligned();
LastLink->setName("unaligned");
}
LastLink->setType(ModifiedType);
return Error::success();
}
// LF_POINTER (TPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record, PointerRecord &Ptr,
TypeIndex TI, LVElement *Element) {
LLVM_DEBUG({
printTypeBegin(Record, TI, Element, StreamTPI);
printTypeIndex("PointeeType", Ptr.getReferentType(), StreamTPI);
W.printNumber("IsFlat", Ptr.isFlat());
W.printNumber("IsConst", Ptr.isConst());
W.printNumber("IsVolatile", Ptr.isVolatile());
W.printNumber("IsUnaligned", Ptr.isUnaligned());
W.printNumber("IsRestrict", Ptr.isRestrict());
W.printNumber("IsThisPtr&", Ptr.isLValueReferenceThisPtr());
W.printNumber("IsThisPtr&&", Ptr.isRValueReferenceThisPtr());
W.printNumber("SizeOf", Ptr.getSize());
if (Ptr.isPointerToMember()) {
const MemberPointerInfo &MI = Ptr.getMemberInfo();
printTypeIndex("ClassType", MI.getContainingType(), StreamTPI);
}
printTypeEnd(Record);
});
// Find the pointed-to type.
LVType *Pointer = static_cast<LVType *>(Element);
LVElement *Pointee = nullptr;
PointerMode Mode = Ptr.getMode();
Pointee = Ptr.isPointerToMember()
? Shared->TypeRecords.find(StreamTPI, Ptr.getReferentType())
: getElement(StreamTPI, Ptr.getReferentType());
// At this point the types recording the qualifiers do not have a
// scope parent. They must be assigned to the current compile unit.
LVScopeCompileUnit *CompileUnit = Reader->getCompileUnit();
// Order for the different modifiers:
// <restrict> <pointer, Reference, ValueReference> <const, volatile>
// Const and volatile already processed.
bool SeenModifier = false;
LVType *LastLink = Pointer;
if (!LastLink->getParentScope())
CompileUnit->addElement(LastLink);
if (Ptr.isRestrict()) {
SeenModifier = true;
LVType *Restrict = Reader->createType();
Restrict->setTag(dwarf::DW_TAG_restrict_type);
Restrict->setIsRestrict();
Restrict->setName("restrict");
LastLink->setType(Restrict);
LastLink = Restrict;
CompileUnit->addElement(LastLink);
}
if (Mode == PointerMode::LValueReference) {
if (SeenModifier) {
LVType *LReference = Reader->createType();
LReference->setIsModifier();
LastLink->setType(LReference);
LastLink = LReference;
CompileUnit->addElement(LastLink);
}
LastLink->setTag(dwarf::DW_TAG_reference_type);
LastLink->setIsReference();
LastLink->setName("&");
}
if (Mode == PointerMode::RValueReference) {
if (SeenModifier) {
LVType *RReference = Reader->createType();
RReference->setIsModifier();
LastLink->setType(RReference);
LastLink = RReference;
CompileUnit->addElement(LastLink);
}
LastLink->setTag(dwarf::DW_TAG_rvalue_reference_type);
LastLink->setIsRvalueReference();
LastLink->setName("&&");
}
// When creating the pointer, check if it points to a reference.
LastLink->setType(Pointee);
return Error::success();
}
// LF_PROCEDURE (TPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record, ProcedureRecord &Proc,
TypeIndex TI, LVElement *Element) {
LLVM_DEBUG({
printTypeBegin(Record, TI, Element, StreamTPI);
printTypeIndex("ReturnType", Proc.getReturnType(), StreamTPI);
W.printNumber("NumParameters", Proc.getParameterCount());
printTypeIndex("ArgListType", Proc.getArgumentList(), StreamTPI);
printTypeEnd(Record);
});
// There is no need to traverse the argument list, as the CodeView format
// declares the parameters as a 'S_LOCAL' symbol tagged as parameter.
// Only process parameters when dealing with inline functions.
if (LVScope *FunctionDcl = static_cast<LVScope *>(Element)) {
FunctionDcl->setType(getElement(StreamTPI, Proc.getReturnType()));
if (ProcessArgumentList) {
ProcessArgumentList = false;
// Create formal parameters.
LazyRandomTypeCollection &Types = types();
CVType CVArguments = Types.getType(Proc.getArgumentList());
if (Error Err = finishVisitation(CVArguments, Proc.getArgumentList(),
FunctionDcl))
return Err;
}
}
return Error::success();
}
// LF_UNION (TPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record, UnionRecord &Union,
TypeIndex TI, LVElement *Element) {
LLVM_DEBUG({
printTypeBegin(Record, TI, Element, StreamTPI);
W.printNumber("MemberCount", Union.getMemberCount());
printTypeIndex("FieldList", Union.getFieldList(), StreamTPI);
W.printNumber("SizeOf", Union.getSize());
W.printString("Name", Union.getName());
if (Union.hasUniqueName())
W.printString("UniqueName", Union.getUniqueName());
printTypeEnd(Record);
});
LVScopeAggregate *Scope = static_cast<LVScopeAggregate *>(Element);
if (!Scope)
return Error::success();
if (Scope->getIsFinalized())
return Error::success();
Scope->setIsFinalized();
Scope->setName(Union.getName());
if (Union.hasUniqueName())
Scope->setLinkageName(Union.getUniqueName());
if (Union.isNested()) {
Scope->setIsNested();
createParents(Union.getName(), Scope);
} else {
if (LVScope *Namespace = Shared->NamespaceDeduction.get(Union.getName()))
Namespace->addElement(Scope);
else
Reader->getCompileUnit()->addElement(Scope);
}
if (!Union.getFieldList().isNoneType()) {
LazyRandomTypeCollection &Types = types();
// Pass down the TypeIndex 'TI' for the aggregate containing the field list.
CVType CVFieldList = Types.getType(Union.getFieldList());
if (Error Err = finishVisitation(CVFieldList, TI, Scope))
return Err;
}
return Error::success();
}
// LF_TYPESERVER2 (TPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record, TypeServer2Record &TS,
TypeIndex TI, LVElement *Element) {
LLVM_DEBUG({
printTypeBegin(Record, TI, Element, StreamTPI);
W.printString("Guid", formatv("{0}", TS.getGuid()).str());
W.printNumber("Age", TS.getAge());
W.printString("Name", TS.getName());
printTypeEnd(Record);
});
return Error::success();
}
// LF_VFTABLE (TPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record, VFTableRecord &VFT,
TypeIndex TI, LVElement *Element) {
LLVM_DEBUG({
printTypeBegin(Record, TI, Element, StreamTPI);
printTypeIndex("CompleteClass", VFT.getCompleteClass(), StreamTPI);
printTypeIndex("OverriddenVFTable", VFT.getOverriddenVTable(), StreamTPI);
W.printHex("VFPtrOffset", VFT.getVFPtrOffset());
W.printString("VFTableName", VFT.getName());
for (const StringRef &N : VFT.getMethodNames())
W.printString("MethodName", N);
printTypeEnd(Record);
});
return Error::success();
}
// LF_VTSHAPE (TPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record,
VFTableShapeRecord &Shape,
TypeIndex TI, LVElement *Element) {
LLVM_DEBUG({
printTypeBegin(Record, TI, Element, StreamTPI);
W.printNumber("VFEntryCount", Shape.getEntryCount());
printTypeEnd(Record);
});
return Error::success();
}
// LF_SUBSTR_LIST (TPI)/(IPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record,
StringListRecord &Strings,
TypeIndex TI, LVElement *Element) {
// All the indices are references into the TPI/IPI stream.
LLVM_DEBUG({
printTypeBegin(Record, TI, Element, StreamIPI);
ArrayRef<TypeIndex> Indices = Strings.getIndices();
uint32_t Size = Indices.size();
W.printNumber("NumStrings", Size);
ListScope Arguments(W, "Strings");
for (uint32_t I = 0; I < Size; ++I)
printTypeIndex("String", Indices[I], StreamIPI);
printTypeEnd(Record);
});
return Error::success();
}
// LF_STRING_ID (TPI)/(IPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record, StringIdRecord &String,
TypeIndex TI, LVElement *Element) {
// All args are references into the TPI/IPI stream.
LLVM_DEBUG({
printTypeIndex("\nTI", TI, StreamIPI);
printTypeIndex("Id", String.getId(), StreamIPI);
W.printString("StringData", String.getString());
});
if (LVScope *Namespace = Shared->NamespaceDeduction.get(
String.getString(), /*CheckScope=*/false)) {
// The function is already at different scope. In order to reflect
// the correct parent, move it to the namespace.
if (LVScope *Scope = Element->getParentScope())
Scope->removeElement(Element);
Namespace->addElement(Element);
}
return Error::success();
}
// LF_UDT_SRC_LINE (TPI)/(IPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record,
UdtSourceLineRecord &SourceLine,
TypeIndex TI, LVElement *Element) {
// All args are references into the TPI/IPI stream.
LLVM_DEBUG({
printTypeIndex("\nTI", TI, StreamIPI);
printTypeIndex("UDT", SourceLine.getUDT(), StreamIPI);
printTypeIndex("SourceFile", SourceLine.getSourceFile(), StreamIPI);
W.printNumber("LineNumber", SourceLine.getLineNumber());
});
return Error::success();
}
// LF_UDT_MOD_SRC_LINE (TPI)/(IPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record,
UdtModSourceLineRecord &ModSourceLine,
TypeIndex TI, LVElement *Element) {
// All args are references into the TPI/IPI stream.
LLVM_DEBUG({
printTypeBegin(Record, TI, Element, StreamIPI);
printTypeIndex("\nTI", TI, StreamIPI);
printTypeIndex("UDT", ModSourceLine.getUDT(), StreamIPI);
printTypeIndex("SourceFile", ModSourceLine.getSourceFile(), StreamIPI);
W.printNumber("LineNumber", ModSourceLine.getLineNumber());
W.printNumber("Module", ModSourceLine.getModule());
printTypeEnd(Record);
});
return Error::success();
}
// LF_PRECOMP (TPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record, PrecompRecord &Precomp,
TypeIndex TI, LVElement *Element) {
LLVM_DEBUG({
printTypeBegin(Record, TI, Element, StreamTPI);
W.printHex("StartIndex", Precomp.getStartTypeIndex());
W.printHex("Count", Precomp.getTypesCount());
W.printHex("Signature", Precomp.getSignature());
W.printString("PrecompFile", Precomp.getPrecompFilePath());
printTypeEnd(Record);
});
return Error::success();
}
// LF_ENDPRECOMP (TPI)
Error LVLogicalVisitor::visitKnownRecord(CVType &Record,
EndPrecompRecord &EndPrecomp,
TypeIndex TI, LVElement *Element) {
LLVM_DEBUG({
printTypeBegin(Record, TI, Element, StreamTPI);
W.printHex("Signature", EndPrecomp.getSignature());
printTypeEnd(Record);
});
return Error::success();
}
Error LVLogicalVisitor::visitUnknownMember(CVMemberRecord &Record,
TypeIndex TI) {
LLVM_DEBUG({ W.printHex("UnknownMember", unsigned(Record.Kind)); });
return Error::success();
}
// LF_BCLASS, LF_BINTERFACE
Error LVLogicalVisitor::visitKnownMember(CVMemberRecord &Record,
BaseClassRecord &Base, TypeIndex TI,
LVElement *Element) {
LLVM_DEBUG({
printMemberBegin(Record, TI, Element, StreamTPI);
printTypeIndex("BaseType", Base.getBaseType(), StreamTPI);
W.printHex("BaseOffset", Base.getBaseOffset());
printMemberEnd(Record);
});
createElement(Record.Kind);
if (LVSymbol *Symbol = CurrentSymbol) {
LVElement *BaseClass = getElement(StreamTPI, Base.getBaseType());
Symbol->setName(BaseClass->getName());
Symbol->setType(BaseClass);
Symbol->setAccessibilityCode(Base.getAccess());
static_cast<LVScope *>(Element)->addElement(Symbol);
}
return Error::success();
}
// LF_MEMBER
Error LVLogicalVisitor::visitKnownMember(CVMemberRecord &Record,
DataMemberRecord &Field, TypeIndex TI,
LVElement *Element) {
LLVM_DEBUG({
printMemberBegin(Record, TI, Element, StreamTPI);
printTypeIndex("Type", Field.getType(), StreamTPI);
W.printHex("FieldOffset", Field.getFieldOffset());
W.printString("Name", Field.getName());
printMemberEnd(Record);
});
// Create the data member.
createDataMember(Record, static_cast<LVScope *>(Element), Field.getName(),
Field.getType(), Field.getAccess());
return Error::success();
}
// LF_ENUMERATE
Error LVLogicalVisitor::visitKnownMember(CVMemberRecord &Record,
EnumeratorRecord &Enum, TypeIndex TI,
LVElement *Element) {
LLVM_DEBUG({
printMemberBegin(Record, TI, Element, StreamTPI);
W.printNumber("EnumValue", Enum.getValue());
W.printString("Name", Enum.getName());
printMemberEnd(Record);
});
createElement(Record.Kind);
if (LVType *Type = CurrentType) {
Type->setName(Enum.getName());
SmallString<16> Value;
Enum.getValue().toString(Value, 16, true, true);
Type->setValue(Value);
static_cast<LVScope *>(Element)->addElement(CurrentType);
}
return Error::success();
}
// LF_INDEX
Error LVLogicalVisitor::visitKnownMember(CVMemberRecord &Record,
ListContinuationRecord &Cont,
TypeIndex TI, LVElement *Element) {
LLVM_DEBUG({
printMemberBegin(Record, TI, Element, StreamTPI);
printTypeIndex("ContinuationIndex", Cont.getContinuationIndex(), StreamTPI);
printMemberEnd(Record);
});
return Error::success();
}
// LF_NESTTYPE
Error LVLogicalVisitor::visitKnownMember(CVMemberRecord &Record,
NestedTypeRecord &Nested, TypeIndex TI,
LVElement *Element) {
LLVM_DEBUG({
printMemberBegin(Record, TI, Element, StreamTPI);
printTypeIndex("Type", Nested.getNestedType(), StreamTPI);
W.printString("Name", Nested.getName());
printMemberEnd(Record);
});
if (LVElement *Typedef = createElement(SymbolKind::S_UDT)) {
Typedef->setName(Nested.getName());
LVElement *NestedType = getElement(StreamTPI, Nested.getNestedType());
Typedef->setType(NestedType);
LVScope *Scope = static_cast<LVScope *>(Element);
Scope->addElement(Typedef);
if (NestedType && NestedType->getIsNested()) {
// 'Element' is an aggregate type that may contains this nested type
// definition. Used their scoped names, to decide on their relationship.
StringRef RecordName = getRecordName(types(), TI);
StringRef NestedTypeName = NestedType->getName();
if (NestedTypeName.size() && RecordName.size()) {
StringRef OuterComponent;
std::tie(OuterComponent, std::ignore) =
getInnerComponent(NestedTypeName);
// We have an already created nested type. Add it to the current scope
// and update all its children if any.
if (OuterComponent.size() && OuterComponent.equals(RecordName)) {
if (!NestedType->getIsScopedAlready()) {
Scope->addElement(NestedType);
NestedType->setIsScopedAlready();
NestedType->updateLevel(Scope);
}
Typedef->resetIncludeInPrint();
}
}
}
}
return Error::success();
}
// LF_ONEMETHOD
Error LVLogicalVisitor::visitKnownMember(CVMemberRecord &Record,
OneMethodRecord &Method, TypeIndex TI,
LVElement *Element) {
LLVM_DEBUG({
printMemberBegin(Record, TI, Element, StreamTPI);
printTypeIndex("Type", Method.getType(), StreamTPI);
// If virtual, then read the vftable offset.
if (Method.isIntroducingVirtual())
W.printHex("VFTableOffset", Method.getVFTableOffset());
W.printString("Name", Method.getName());
printMemberEnd(Record);
});
// All the LF_ONEMETHOD objects share the same type description.
// We have to create a scope object for each one and get the required
// information from the LF_MFUNCTION object.
ProcessArgumentList = true;
if (LVElement *MemberFunction = createElement(TypeLeafKind::LF_ONEMETHOD)) {
MemberFunction->setIsFinalized();
static_cast<LVScope *>(Element)->addElement(MemberFunction);
MemberFunction->setName(Method.getName());
MemberFunction->setAccessibilityCode(Method.getAccess());
MethodKind Kind = Method.getMethodKind();
if (Kind == MethodKind::Static)
MemberFunction->setIsStatic();
MemberFunction->setVirtualityCode(Kind);
MethodOptions Flags = Method.Attrs.getFlags();
if (MethodOptions::CompilerGenerated ==
(Flags & MethodOptions::CompilerGenerated))
MemberFunction->setIsArtificial();
LazyRandomTypeCollection &Types = types();
CVType CVMethodType = Types.getType(Method.getType());
if (Error Err =
finishVisitation(CVMethodType, Method.getType(), MemberFunction))
return Err;
}
ProcessArgumentList = false;
return Error::success();
}
// LF_METHOD
Error LVLogicalVisitor::visitKnownMember(CVMemberRecord &Record,
OverloadedMethodRecord &Method,
TypeIndex TI, LVElement *Element) {
LLVM_DEBUG({
printMemberBegin(Record, TI, Element, StreamTPI);
W.printHex("MethodCount", Method.getNumOverloads());
printTypeIndex("MethodListIndex", Method.getMethodList(), StreamTPI);
W.printString("Name", Method.getName());
printMemberEnd(Record);
});
// Record the overloaded method name, which will be used during the
// traversal of the method list.
LazyRandomTypeCollection &Types = types();
OverloadedMethodName = Method.getName();
CVType CVMethods = Types.getType(Method.getMethodList());
if (Error Err = finishVisitation(CVMethods, Method.getMethodList(), Element))
return Err;
return Error::success();
}
// LF_STMEMBER
Error LVLogicalVisitor::visitKnownMember(CVMemberRecord &Record,
StaticDataMemberRecord &Field,
TypeIndex TI, LVElement *Element) {
LLVM_DEBUG({
printMemberBegin(Record, TI, Element, StreamTPI);
printTypeIndex("Type", Field.getType(), StreamTPI);
W.printString("Name", Field.getName());
printMemberEnd(Record);
});
// Create the data member.
createDataMember(Record, static_cast<LVScope *>(Element), Field.getName(),
Field.getType(), Field.getAccess());
return Error::success();
}
// LF_VFUNCTAB
Error LVLogicalVisitor::visitKnownMember(CVMemberRecord &Record,
VFPtrRecord &VFTable, TypeIndex TI,
LVElement *Element) {
LLVM_DEBUG({
printMemberBegin(Record, TI, Element, StreamTPI);
printTypeIndex("Type", VFTable.getType(), StreamTPI);
printMemberEnd(Record);
});
return Error::success();
}
// LF_VBCLASS, LF_IVBCLASS
Error LVLogicalVisitor::visitKnownMember(CVMemberRecord &Record,
VirtualBaseClassRecord &Base,
TypeIndex TI, LVElement *Element) {
LLVM_DEBUG({
printMemberBegin(Record, TI, Element, StreamTPI);
printTypeIndex("BaseType", Base.getBaseType(), StreamTPI);
printTypeIndex("VBPtrType", Base.getVBPtrType(), StreamTPI);
W.printHex("VBPtrOffset", Base.getVBPtrOffset());
W.printHex("VBTableIndex", Base.getVTableIndex());
printMemberEnd(Record);
});
createElement(Record.Kind);
if (LVSymbol *Symbol = CurrentSymbol) {
LVElement *BaseClass = getElement(StreamTPI, Base.getBaseType());
Symbol->setName(BaseClass->getName());
Symbol->setType(BaseClass);
Symbol->setAccessibilityCode(Base.getAccess());
Symbol->setVirtualityCode(MethodKind::Virtual);
static_cast<LVScope *>(Element)->addElement(Symbol);
}
return Error::success();
}
Error LVLogicalVisitor::visitMemberRecord(CVMemberRecord &Record,
TypeVisitorCallbacks &Callbacks,
TypeIndex TI, LVElement *Element) {
if (Error Err = Callbacks.visitMemberBegin(Record))
return Err;
switch (Record.Kind) {
default:
if (Error Err = Callbacks.visitUnknownMember(Record))
return Err;
break;
#define MEMBER_RECORD(EnumName, EnumVal, Name) \
case EnumName: { \
if (Error Err = \
visitKnownMember<Name##Record>(Record, Callbacks, TI, Element)) \
return Err; \
break; \
}
#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
MEMBER_RECORD(EnumVal, EnumVal, AliasName)
#define TYPE_RECORD(EnumName, EnumVal, Name)
#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
}
if (Error Err = Callbacks.visitMemberEnd(Record))
return Err;
return Error::success();
}
Error LVLogicalVisitor::finishVisitation(CVType &Record, TypeIndex TI,
LVElement *Element) {
switch (Record.kind()) {
default:
if (Error Err = visitUnknownType(Record, TI))
return Err;
break;
#define TYPE_RECORD(EnumName, EnumVal, Name) \
case EnumName: { \
if (Error Err = visitKnownRecord<Name##Record>(Record, TI, Element)) \
return Err; \
break; \
}
#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
TYPE_RECORD(EnumVal, EnumVal, AliasName)
#define MEMBER_RECORD(EnumName, EnumVal, Name)
#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
}
return Error::success();
}
// Customized version of 'FieldListVisitHelper'.
Error LVLogicalVisitor::visitFieldListMemberStream(
TypeIndex TI, LVElement *Element, ArrayRef<uint8_t> FieldList) {
BinaryByteStream Stream(FieldList, llvm::endianness::little);
BinaryStreamReader Reader(Stream);
FieldListDeserializer Deserializer(Reader);
TypeVisitorCallbackPipeline Pipeline;
Pipeline.addCallbackToPipeline(Deserializer);
TypeLeafKind Leaf;
while (!Reader.empty()) {
if (Error Err = Reader.readEnum(Leaf))
return Err;
CVMemberRecord Record;
Record.Kind = Leaf;
if (Error Err = visitMemberRecord(Record, Pipeline, TI, Element))
return Err;
}
return Error::success();
}
void LVLogicalVisitor::addElement(LVScope *Scope, bool IsCompileUnit) {
// The CodeView specifications does not treat S_COMPILE2 and S_COMPILE3
// as symbols that open a scope. The CodeView reader, treat them in a
// similar way as DWARF. As there is no a symbole S_END to close the
// compile unit, we need to check for the next compile unit.
if (IsCompileUnit) {
if (!ScopeStack.empty())
popScope();
InCompileUnitScope = true;
}
pushScope(Scope);
ReaderParent->addElement(Scope);
}
void LVLogicalVisitor::addElement(LVSymbol *Symbol) {
ReaderScope->addElement(Symbol);
}
void LVLogicalVisitor::addElement(LVType *Type) {
ReaderScope->addElement(Type);
}
LVElement *LVLogicalVisitor::createElement(TypeLeafKind Kind) {
CurrentScope = nullptr;
CurrentSymbol = nullptr;
CurrentType = nullptr;
if (Kind < TypeIndex::FirstNonSimpleIndex) {
CurrentType = Reader->createType();
CurrentType->setIsBase();
CurrentType->setTag(dwarf::DW_TAG_base_type);
if (options().getAttributeBase())
CurrentType->setIncludeInPrint();
return CurrentType;
}
switch (Kind) {
// Types.
case TypeLeafKind::LF_ENUMERATE:
CurrentType = Reader->createTypeEnumerator();
CurrentType->setTag(dwarf::DW_TAG_enumerator);
return CurrentType;
case TypeLeafKind::LF_MODIFIER:
CurrentType = Reader->createType();
CurrentType->setIsModifier();
return CurrentType;
case TypeLeafKind::LF_POINTER:
CurrentType = Reader->createType();
CurrentType->setIsPointer();
CurrentType->setName("*");
CurrentType->setTag(dwarf::DW_TAG_pointer_type);
return CurrentType;
// Symbols.
case TypeLeafKind::LF_BCLASS:
case TypeLeafKind::LF_IVBCLASS:
case TypeLeafKind::LF_VBCLASS:
CurrentSymbol = Reader->createSymbol();
CurrentSymbol->setTag(dwarf::DW_TAG_inheritance);
CurrentSymbol->setIsInheritance();
return CurrentSymbol;
case TypeLeafKind::LF_MEMBER:
case TypeLeafKind::LF_STMEMBER:
CurrentSymbol = Reader->createSymbol();
CurrentSymbol->setIsMember();
CurrentSymbol->setTag(dwarf::DW_TAG_member);
return CurrentSymbol;
// Scopes.
case TypeLeafKind::LF_ARRAY:
CurrentScope = Reader->createScopeArray();
CurrentScope->setTag(dwarf::DW_TAG_array_type);
return CurrentScope;
case TypeLeafKind::LF_CLASS:
CurrentScope = Reader->createScopeAggregate();
CurrentScope->setTag(dwarf::DW_TAG_class_type);
CurrentScope->setIsClass();
return CurrentScope;
case TypeLeafKind::LF_ENUM:
CurrentScope = Reader->createScopeEnumeration();
CurrentScope->setTag(dwarf::DW_TAG_enumeration_type);
return CurrentScope;
case TypeLeafKind::LF_METHOD:
case TypeLeafKind::LF_ONEMETHOD:
case TypeLeafKind::LF_PROCEDURE:
CurrentScope = Reader->createScopeFunction();
CurrentScope->setIsSubprogram();
CurrentScope->setTag(dwarf::DW_TAG_subprogram);
return CurrentScope;
case TypeLeafKind::LF_STRUCTURE:
CurrentScope = Reader->createScopeAggregate();
CurrentScope->setIsStructure();
CurrentScope->setTag(dwarf::DW_TAG_structure_type);
return CurrentScope;
case TypeLeafKind::LF_UNION:
CurrentScope = Reader->createScopeAggregate();
CurrentScope->setIsUnion();
CurrentScope->setTag(dwarf::DW_TAG_union_type);
return CurrentScope;
default:
// If '--internal=tag' and '--print=warning' are specified in the command
// line, we record and print each seen 'TypeLeafKind'.
break;
}
return nullptr;
}
LVElement *LVLogicalVisitor::createElement(SymbolKind Kind) {
CurrentScope = nullptr;
CurrentSymbol = nullptr;
CurrentType = nullptr;
switch (Kind) {
// Types.
case SymbolKind::S_UDT:
CurrentType = Reader->createTypeDefinition();
CurrentType->setTag(dwarf::DW_TAG_typedef);
return CurrentType;
// Symbols.
case SymbolKind::S_CONSTANT:
CurrentSymbol = Reader->createSymbol();
CurrentSymbol->setIsConstant();
CurrentSymbol->setTag(dwarf::DW_TAG_constant);
return CurrentSymbol;
case SymbolKind::S_BPREL32:
case SymbolKind::S_REGREL32:
case SymbolKind::S_GDATA32:
case SymbolKind::S_LDATA32:
case SymbolKind::S_LOCAL:
// During the symbol traversal more information is available to
// determine if the symbol is a parameter or a variable. At this
// stage mark it as variable.
CurrentSymbol = Reader->createSymbol();
CurrentSymbol->setIsVariable();
CurrentSymbol->setTag(dwarf::DW_TAG_variable);
return CurrentSymbol;
// Scopes.
case SymbolKind::S_BLOCK32:
CurrentScope = Reader->createScope();
CurrentScope->setIsLexicalBlock();
CurrentScope->setTag(dwarf::DW_TAG_lexical_block);
return CurrentScope;
case SymbolKind::S_COMPILE2:
case SymbolKind::S_COMPILE3:
CurrentScope = Reader->createScopeCompileUnit();
CurrentScope->setTag(dwarf::DW_TAG_compile_unit);
Reader->setCompileUnit(static_cast<LVScopeCompileUnit *>(CurrentScope));
return CurrentScope;
case SymbolKind::S_INLINESITE:
case SymbolKind::S_INLINESITE2:
CurrentScope = Reader->createScopeFunctionInlined();
CurrentScope->setIsInlinedFunction();
CurrentScope->setTag(dwarf::DW_TAG_inlined_subroutine);
return CurrentScope;
case SymbolKind::S_LPROC32:
case SymbolKind::S_GPROC32:
case SymbolKind::S_LPROC32_ID:
case SymbolKind::S_GPROC32_ID:
case SymbolKind::S_SEPCODE:
case SymbolKind::S_THUNK32:
CurrentScope = Reader->createScopeFunction();
CurrentScope->setIsSubprogram();
CurrentScope->setTag(dwarf::DW_TAG_subprogram);
return CurrentScope;
default:
// If '--internal=tag' and '--print=warning' are specified in the command
// line, we record and print each seen 'SymbolKind'.
break;
}
return nullptr;
}
LVElement *LVLogicalVisitor::createElement(TypeIndex TI, TypeLeafKind Kind) {
LVElement *Element = Shared->TypeRecords.find(StreamTPI, TI);
if (!Element) {
// We are dealing with a base type or pointer to a base type, which are
// not included explicitly in the CodeView format.
if (Kind < TypeIndex::FirstNonSimpleIndex) {
Element = createElement(Kind);
Element->setIsFinalized();
Shared->TypeRecords.add(StreamTPI, (TypeIndex)Kind, Kind, Element);
Element->setOffset(Kind);
return Element;
}
// We are dealing with a pointer to a base type.
if (TI.getIndex() < TypeIndex::FirstNonSimpleIndex) {
Element = createElement(Kind);
Shared->TypeRecords.add(StreamTPI, TI, Kind, Element);
Element->setOffset(TI.getIndex());
Element->setOffsetFromTypeIndex();
return Element;
}
W.printString("** Not implemented. **");
printTypeIndex("TypeIndex", TI, StreamTPI);
W.printString("TypeLeafKind", formatTypeLeafKind(Kind));
return nullptr;
}
Element->setOffset(TI.getIndex());
Element->setOffsetFromTypeIndex();
return Element;
}
void LVLogicalVisitor::createDataMember(CVMemberRecord &Record, LVScope *Parent,
StringRef Name, TypeIndex TI,
MemberAccess Access) {
LLVM_DEBUG({
printTypeIndex("TypeIndex", TI, StreamTPI);
W.printString("TypeName", Name);
});
createElement(Record.Kind);
if (LVSymbol *Symbol = CurrentSymbol) {
Symbol->setName(Name);
if (TI.isNoneType() || TI.isSimple())
Symbol->setType(getElement(StreamTPI, TI));
else {
LazyRandomTypeCollection &Types = types();
CVType CVMemberType = Types.getType(TI);
if (CVMemberType.kind() == LF_BITFIELD) {
if (Error Err = finishVisitation(CVMemberType, TI, Symbol)) {
consumeError(std::move(Err));
return;
}
} else
Symbol->setType(getElement(StreamTPI, TI));
}
Symbol->setAccessibilityCode(Access);
Parent->addElement(Symbol);
}
}
LVSymbol *LVLogicalVisitor::createParameter(LVElement *Element, StringRef Name,
LVScope *Parent) {
LVSymbol *Parameter = Reader->createSymbol();
Parent->addElement(Parameter);
Parameter->setIsParameter();
Parameter->setTag(dwarf::DW_TAG_formal_parameter);
Parameter->setName(Name);
Parameter->setType(Element);
return Parameter;
}
LVSymbol *LVLogicalVisitor::createParameter(TypeIndex TI, StringRef Name,
LVScope *Parent) {
return createParameter(getElement(StreamTPI, TI), Name, Parent);
}
LVType *LVLogicalVisitor::createBaseType(TypeIndex TI, StringRef TypeName) {
TypeLeafKind SimpleKind = (TypeLeafKind)TI.getSimpleKind();
TypeIndex TIR = (TypeIndex)SimpleKind;
LLVM_DEBUG({
printTypeIndex("TypeIndex", TIR, StreamTPI);
W.printString("TypeName", TypeName);
});
if (LVElement *Element = Shared->TypeRecords.find(StreamTPI, TIR))
return static_cast<LVType *>(Element);
if (createElement(TIR, SimpleKind)) {
CurrentType->setName(TypeName);
Reader->getCompileUnit()->addElement(CurrentType);
}
return CurrentType;
}
LVType *LVLogicalVisitor::createPointerType(TypeIndex TI, StringRef TypeName) {
LLVM_DEBUG({
printTypeIndex("TypeIndex", TI, StreamTPI);
W.printString("TypeName", TypeName);
});
if (LVElement *Element = Shared->TypeRecords.find(StreamTPI, TI))
return static_cast<LVType *>(Element);
LVType *Pointee = createBaseType(TI, TypeName.drop_back(1));
if (createElement(TI, TypeLeafKind::LF_POINTER)) {
CurrentType->setIsFinalized();
CurrentType->setType(Pointee);
Reader->getCompileUnit()->addElement(CurrentType);
}
return CurrentType;
}
void LVLogicalVisitor::createParents(StringRef ScopedName, LVElement *Element) {
// For the given test case:
//
// struct S { enum E { ... }; };
// S::E V;
//
// 0 | S_LOCAL `V`
// type=0x1004 (S::E), flags = none
// 0x1004 | LF_ENUM `S::E`
// options: has unique name | is nested
// 0x1009 | LF_STRUCTURE `S`
// options: contains nested class
//
// When the local 'V' is processed, its type 'E' is created. But There is
// no direct reference to its parent 'S'. We use the scoped name for 'E',
// to create its parents.
// The input scoped name must have at least parent and nested names.
// Drop the last element name, as it corresponds to the nested type.
LVStringRefs Components = getAllLexicalComponents(ScopedName);
if (Components.size() < 2)
return;
Components.pop_back();
LVStringRefs::size_type FirstNamespace;
LVStringRefs::size_type FirstAggregate;
std::tie(FirstNamespace, FirstAggregate) =
Shared->NamespaceDeduction.find(Components);
LLVM_DEBUG({
W.printString("First Namespace", Components[FirstNamespace]);
W.printString("First NonNamespace", Components[FirstAggregate]);
});
// Create any referenced namespaces.
if (FirstNamespace < FirstAggregate) {
Shared->NamespaceDeduction.get(
LVStringRefs(Components.begin() + FirstNamespace,
Components.begin() + FirstAggregate));
}
// Traverse the enclosing scopes (aggregates) and create them. In the
// case of nested empty aggregates, MSVC does not emit a full record
// description. It emits only the reference record.
LVScope *Aggregate = nullptr;
TypeIndex TIAggregate;
std::string AggregateName = getScopedName(
LVStringRefs(Components.begin(), Components.begin() + FirstAggregate));
// This traversal is executed at least once.
for (LVStringRefs::size_type Index = FirstAggregate;
Index < Components.size(); ++Index) {
AggregateName = getScopedName(LVStringRefs(Components.begin() + Index,
Components.begin() + Index + 1),
AggregateName);
TIAggregate = Shared->ForwardReferences.remap(
Shared->TypeRecords.find(StreamTPI, AggregateName));
Aggregate =
TIAggregate.isNoneType()
? nullptr
: static_cast<LVScope *>(getElement(StreamTPI, TIAggregate));
}
// Workaround for cases where LF_NESTTYPE is missing for nested templates.
// If we manage to get parent information from the scoped name, we can add
// the nested type without relying on the LF_NESTTYPE.
if (Aggregate && !Element->getIsScopedAlready()) {
Aggregate->addElement(Element);
Element->setIsScopedAlready();
}
}
LVElement *LVLogicalVisitor::getElement(uint32_t StreamIdx, TypeIndex TI,
LVScope *Parent) {
LLVM_DEBUG({ printTypeIndex("TypeIndex", TI, StreamTPI); });
TI = Shared->ForwardReferences.remap(TI);
LLVM_DEBUG({ printTypeIndex("TypeIndex Remap", TI, StreamTPI); });
LVElement *Element = Shared->TypeRecords.find(StreamIdx, TI);
if (!Element) {
if (TI.isNoneType() || TI.isSimple()) {
StringRef TypeName = TypeIndex::simpleTypeName(TI);
// If the name ends with "*", create 2 logical types: a pointer and a
// pointee type. TypeIndex is composed of a SympleTypeMode byte followed
// by a SimpleTypeKind byte. The logical pointer will be identified by
// the full TypeIndex value and the pointee by the SimpleTypeKind.
return (TypeName.back() == '*') ? createPointerType(TI, TypeName)
: createBaseType(TI, TypeName);
}
LLVM_DEBUG({ W.printHex("TypeIndex not implemented: ", TI.getIndex()); });
return nullptr;
}
// The element has been finalized.
if (Element->getIsFinalized())
return Element;
// Add the element in case of a given parent.
if (Parent)
Parent->addElement(Element);
// Check for a composite type.
LazyRandomTypeCollection &Types = types();
CVType CVRecord = Types.getType(TI);
if (Error Err = finishVisitation(CVRecord, TI, Element)) {
consumeError(std::move(Err));
return nullptr;
}
Element->setIsFinalized();
return Element;
}
void LVLogicalVisitor::processLines() {
// Traverse the collected LF_UDT_SRC_LINE records and add the source line
// information to the logical elements.
for (const TypeIndex &Entry : Shared->LineRecords) {
CVType CVRecord = ids().getType(Entry);
UdtSourceLineRecord Line;
if (Error Err = TypeDeserializer::deserializeAs(
const_cast<CVType &>(CVRecord), Line))
consumeError(std::move(Err));
else {
LLVM_DEBUG({
printTypeIndex("UDT", Line.getUDT(), StreamIPI);
printTypeIndex("SourceFile", Line.getSourceFile(), StreamIPI);
W.printNumber("LineNumber", Line.getLineNumber());
});
// The TypeIndex returned by 'getUDT()' must point to an already
// created logical element. If no logical element is found, it means
// the LF_UDT_SRC_LINE is associated with a system TypeIndex.
if (LVElement *Element = Shared->TypeRecords.find(
StreamTPI, Line.getUDT(), /*Create=*/false)) {
Element->setLineNumber(Line.getLineNumber());
Element->setFilenameIndex(
Shared->StringRecords.findIndex(Line.getSourceFile()));
}
}
}
}
void LVLogicalVisitor::processNamespaces() {
// Create namespaces.
Shared->NamespaceDeduction.init();
}
void LVLogicalVisitor::processFiles() { Shared->StringRecords.addFilenames(); }
void LVLogicalVisitor::printRecords(raw_ostream &OS) const {
if (!options().getInternalTag())
return;
unsigned Count = 0;
auto PrintItem = [&](StringRef Name) {
auto NewLine = [&]() {
if (++Count == 4) {
Count = 0;
OS << "\n";
}
};
OS << format("%20s", Name.str().c_str());
NewLine();
};
OS << "\nTypes:\n";
for (const TypeLeafKind &Kind : Shared->TypeKinds)
PrintItem(formatTypeLeafKind(Kind));
Shared->TypeKinds.clear();
Count = 0;
OS << "\nSymbols:\n";
for (const SymbolKind &Kind : Shared->SymbolKinds)
PrintItem(LVCodeViewReader::getSymbolKindName(Kind));
Shared->SymbolKinds.clear();
OS << "\n";
}
Error LVLogicalVisitor::inlineSiteAnnotation(LVScope *AbstractFunction,
LVScope *InlinedFunction,
InlineSiteSym &InlineSite) {
// Get the parent scope to update the address ranges of the nested
// scope representing the inlined function.
LVAddress ParentLowPC = 0;
LVScope *Parent = InlinedFunction->getParentScope();
if (const LVLocations *Locations = Parent->getRanges()) {
if (!Locations->empty())
ParentLowPC = (*Locations->begin())->getLowerAddress();
}
// For the given inlinesite, get the initial line number and its
// source filename. Update the logical scope representing it.
uint32_t LineNumber = 0;
StringRef Filename;
LVInlineeInfo::iterator Iter = InlineeInfo.find(InlineSite.Inlinee);
if (Iter != InlineeInfo.end()) {
LineNumber = Iter->second.first;
Filename = Iter->second.second;
AbstractFunction->setLineNumber(LineNumber);
// TODO: This part needs additional work in order to set properly the
// correct filename in order to detect changes between filenames.
// AbstractFunction->setFilename(Filename);
}
LLVM_DEBUG({
dbgs() << "inlineSiteAnnotation\n"
<< "Abstract: " << AbstractFunction->getName() << "\n"
<< "Inlined: " << InlinedFunction->getName() << "\n"
<< "Parent: " << Parent->getName() << "\n"
<< "Low PC: " << hexValue(ParentLowPC) << "\n";
});
// Get the source lines if requested by command line option.
if (!options().getPrintLines())
return Error::success();
// Limitation: Currently we don't track changes in the FileOffset. The
// side effects are the caller that it is unable to differentiate the
// source filename for the inlined code.
uint64_t CodeOffset = ParentLowPC;
int32_t LineOffset = LineNumber;
uint32_t FileOffset = 0;
auto UpdateClose = [&]() { LLVM_DEBUG({ dbgs() << ("\n"); }); };
auto UpdateCodeOffset = [&](uint32_t Delta) {
CodeOffset += Delta;
LLVM_DEBUG({
dbgs() << formatv(" code 0x{0} (+0x{1})", utohexstr(CodeOffset),
utohexstr(Delta));
});
};
auto UpdateLineOffset = [&](int32_t Delta) {
LineOffset += Delta;
LLVM_DEBUG({
char Sign = Delta > 0 ? '+' : '-';
dbgs() << formatv(" line {0} ({1}{2})", LineOffset, Sign,
std::abs(Delta));
});
};
auto UpdateFileOffset = [&](int32_t Offset) {
FileOffset = Offset;
LLVM_DEBUG({ dbgs() << formatv(" file {0}", FileOffset); });
};
LVLines InlineeLines;
auto CreateLine = [&]() {
// Create the logical line record.
LVLineDebug *Line = Reader->createLineDebug();
Line->setAddress(CodeOffset);
Line->setLineNumber(LineOffset);
// TODO: This part needs additional work in order to set properly the
// correct filename in order to detect changes between filenames.
// Line->setFilename(Filename);
InlineeLines.push_back(Line);
};
bool SeenLowAddress = false;
bool SeenHighAddress = false;
uint64_t LowPC = 0;
uint64_t HighPC = 0;
for (auto &Annot : InlineSite.annotations()) {
LLVM_DEBUG({
dbgs() << formatv(" {0}",
fmt_align(toHex(Annot.Bytes), AlignStyle::Left, 9));
});
// Use the opcode to interpret the integer values.
switch (Annot.OpCode) {
case BinaryAnnotationsOpCode::ChangeCodeOffset:
case BinaryAnnotationsOpCode::CodeOffset:
case BinaryAnnotationsOpCode::ChangeCodeLength:
UpdateCodeOffset(Annot.U1);
UpdateClose();
if (Annot.OpCode == BinaryAnnotationsOpCode::ChangeCodeOffset) {
CreateLine();
LowPC = CodeOffset;
SeenLowAddress = true;
break;
}
if (Annot.OpCode == BinaryAnnotationsOpCode::ChangeCodeLength) {
HighPC = CodeOffset - 1;
SeenHighAddress = true;
}
break;
case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset:
UpdateCodeOffset(Annot.U2);
UpdateClose();
break;
case BinaryAnnotationsOpCode::ChangeLineOffset:
case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset:
UpdateCodeOffset(Annot.U1);
UpdateLineOffset(Annot.S1);
UpdateClose();
if (Annot.OpCode ==
BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset)
CreateLine();
break;
case BinaryAnnotationsOpCode::ChangeFile:
UpdateFileOffset(Annot.U1);
UpdateClose();
break;
default:
break;
}
if (SeenLowAddress && SeenHighAddress) {
SeenLowAddress = false;
SeenHighAddress = false;
InlinedFunction->addObject(LowPC, HighPC);
}
}
Reader->addInlineeLines(InlinedFunction, InlineeLines);
UpdateClose();
return Error::success();
}