3565 lines
125 KiB
C++
3565 lines
125 KiB
C++
|
//===-- 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 file’s .debug$T section or a PDB file’s 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();
|
|||
|
}
|