|
|
|
|
@@ -7,6 +7,9 @@
|
|
|
|
|
#include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h"
|
|
|
|
|
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
|
|
|
|
|
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
|
|
|
|
|
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
|
|
|
|
|
#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
|
|
|
|
|
#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
|
|
|
|
|
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
|
|
|
|
|
#include "llvm/Demangle/MicrosoftDemangle.h"
|
|
|
|
|
|
|
|
|
|
@@ -150,8 +153,8 @@ TranslateCallingConvention(llvm::codeview::CallingConvention conv) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static llvm::Optional<CVTagRecord>
|
|
|
|
|
GetNestedTagRecord(const NestedTypeRecord &Record, const CVTagRecord &parent,
|
|
|
|
|
TpiStream &tpi) {
|
|
|
|
|
GetNestedTagDefinition(const NestedTypeRecord &Record,
|
|
|
|
|
const CVTagRecord &parent, TpiStream &tpi) {
|
|
|
|
|
// An LF_NESTTYPE is essentially a nested typedef / using declaration, but it
|
|
|
|
|
// is also used to indicate the primary definition of a nested class. That is
|
|
|
|
|
// to say, if you have:
|
|
|
|
|
@@ -218,7 +221,7 @@ PdbAstBuilder::CreateDeclInfoForType(const TagRecord &record, TypeIndex ti) {
|
|
|
|
|
llvm::ms_demangle::TagTypeNode *ttn = demangler.parseTagUniqueName(sv);
|
|
|
|
|
llvm::ms_demangle::IdentifierNode *idn =
|
|
|
|
|
ttn->QualifiedName->getUnqualifiedIdentifier();
|
|
|
|
|
std::string uname = idn->toString();
|
|
|
|
|
std::string uname = idn->toString(llvm::ms_demangle::OF_NoTagSpecifier);
|
|
|
|
|
|
|
|
|
|
llvm::ms_demangle::NodeArrayNode *name_components =
|
|
|
|
|
ttn->QualifiedName->Components;
|
|
|
|
|
@@ -261,15 +264,55 @@ PdbAstBuilder::CreateDeclInfoForType(const TagRecord &record, TypeIndex ti) {
|
|
|
|
|
return {context, uname};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool IsUniqueNameEnumTag(llvm::StringRef unique_name) {
|
|
|
|
|
if (unique_name.size() < 4)
|
|
|
|
|
return false;
|
|
|
|
|
return unique_name[3] == 'W';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::string GetParentUniqueName(llvm::StringRef unique_name) {
|
|
|
|
|
if (unique_name.size() < 4)
|
|
|
|
|
return unique_name;
|
|
|
|
|
size_t start = IsUniqueNameEnumTag(unique_name) ? 5 : 4;
|
|
|
|
|
size_t end = unique_name.find('@');
|
|
|
|
|
if (end == llvm::StringRef::npos)
|
|
|
|
|
return unique_name;
|
|
|
|
|
std::string result = unique_name.str();
|
|
|
|
|
return result.erase(start, end - start + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbAstBuilder::BuildParentMap() {
|
|
|
|
|
LazyRandomTypeCollection &types = m_index.tpi().typeCollection();
|
|
|
|
|
|
|
|
|
|
llvm::DenseMap<TypeIndex, TypeIndex> forward_to_full;
|
|
|
|
|
llvm::DenseMap<TypeIndex, TypeIndex> full_to_forward;
|
|
|
|
|
|
|
|
|
|
struct RecordIndices {
|
|
|
|
|
TypeIndex forward;
|
|
|
|
|
TypeIndex full;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
llvm::StringMap<RecordIndices> record_indices;
|
|
|
|
|
|
|
|
|
|
for (auto ti = types.getFirst(); ti; ti = types.getNext(*ti)) {
|
|
|
|
|
CVType type = types.getType(*ti);
|
|
|
|
|
if (!IsTagRecord(type))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
CVTagRecord tag = CVTagRecord::create(type);
|
|
|
|
|
|
|
|
|
|
RecordIndices &indices = record_indices[tag.asTag().getUniqueName()];
|
|
|
|
|
if (tag.asTag().isForwardRef())
|
|
|
|
|
indices.forward = *ti;
|
|
|
|
|
else
|
|
|
|
|
indices.full = *ti;
|
|
|
|
|
|
|
|
|
|
if (indices.full != TypeIndex::None() &&
|
|
|
|
|
indices.forward != TypeIndex::None()) {
|
|
|
|
|
forward_to_full[indices.forward] = indices.full;
|
|
|
|
|
full_to_forward[indices.full] = indices.forward;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We're looking for LF_NESTTYPE records in the field list, so ignore
|
|
|
|
|
// forward references (no field list), and anything without a nested class
|
|
|
|
|
// (since there won't be any LF_NESTTYPE records).
|
|
|
|
|
@@ -285,27 +328,26 @@ void PdbAstBuilder::BuildParentMap() {
|
|
|
|
|
|
|
|
|
|
PdbIndex &index;
|
|
|
|
|
llvm::DenseMap<TypeIndex, TypeIndex> &parents;
|
|
|
|
|
|
|
|
|
|
unsigned unnamed_type_index = 1;
|
|
|
|
|
TypeIndex parent;
|
|
|
|
|
const CVTagRecord &parent_cvt;
|
|
|
|
|
|
|
|
|
|
llvm::Error visitKnownMember(CVMemberRecord &CVR,
|
|
|
|
|
NestedTypeRecord &Record) override {
|
|
|
|
|
std::string unnamed_type_name;
|
|
|
|
|
if (Record.Name.empty()) {
|
|
|
|
|
unnamed_type_name =
|
|
|
|
|
llvm::formatv("<unnamed-type-$S{0}>", unnamed_type_index).str();
|
|
|
|
|
Record.Name = unnamed_type_name;
|
|
|
|
|
++unnamed_type_index;
|
|
|
|
|
}
|
|
|
|
|
llvm::Optional<CVTagRecord> tag =
|
|
|
|
|
GetNestedTagRecord(Record, parent_cvt, index.tpi());
|
|
|
|
|
GetNestedTagDefinition(Record, parent_cvt, index.tpi());
|
|
|
|
|
if (!tag)
|
|
|
|
|
return llvm::ErrorSuccess();
|
|
|
|
|
|
|
|
|
|
parents[Record.Type] = parent;
|
|
|
|
|
if (!tag->asTag().isForwardRef())
|
|
|
|
|
return llvm::ErrorSuccess();
|
|
|
|
|
|
|
|
|
|
llvm::Expected<TypeIndex> full_decl =
|
|
|
|
|
index.tpi().findFullDeclForForwardRef(Record.Type);
|
|
|
|
|
if (!full_decl) {
|
|
|
|
|
llvm::consumeError(full_decl.takeError());
|
|
|
|
|
return llvm::ErrorSuccess();
|
|
|
|
|
}
|
|
|
|
|
parents[*full_decl] = parent;
|
|
|
|
|
return llvm::ErrorSuccess();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
@@ -316,11 +358,102 @@ void PdbAstBuilder::BuildParentMap() {
|
|
|
|
|
if (error)
|
|
|
|
|
llvm::consumeError(std::move(error));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Now that we know the forward -> full mapping of all type indices, we can
|
|
|
|
|
// re-write all the indices. At the end of this process, we want a mapping
|
|
|
|
|
// consisting of fwd -> full and full -> full for all child -> parent indices.
|
|
|
|
|
// We can re-write the values in place, but for the keys, we must save them
|
|
|
|
|
// off so that we don't modify the map in place while also iterating it.
|
|
|
|
|
std::vector<TypeIndex> full_keys;
|
|
|
|
|
std::vector<TypeIndex> fwd_keys;
|
|
|
|
|
for (auto &entry : m_parent_types) {
|
|
|
|
|
TypeIndex key, value;
|
|
|
|
|
std::tie(key, value) = entry;
|
|
|
|
|
|
|
|
|
|
auto iter = forward_to_full.find(value);
|
|
|
|
|
if (iter != forward_to_full.end())
|
|
|
|
|
entry.second = iter->second;
|
|
|
|
|
|
|
|
|
|
iter = forward_to_full.find(key);
|
|
|
|
|
if (iter != forward_to_full.end())
|
|
|
|
|
fwd_keys.push_back(key);
|
|
|
|
|
else
|
|
|
|
|
full_keys.push_back(key);
|
|
|
|
|
}
|
|
|
|
|
for (TypeIndex fwd : fwd_keys) {
|
|
|
|
|
TypeIndex full = forward_to_full[fwd];
|
|
|
|
|
m_parent_types[full] = m_parent_types[fwd];
|
|
|
|
|
}
|
|
|
|
|
for (TypeIndex full : full_keys) {
|
|
|
|
|
TypeIndex fwd = full_to_forward[full];
|
|
|
|
|
m_parent_types[fwd] = m_parent_types[full];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Now that
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool isLocalVariableType(SymbolKind K) {
|
|
|
|
|
switch (K) {
|
|
|
|
|
case S_REGISTER:
|
|
|
|
|
case S_REGREL32:
|
|
|
|
|
case S_LOCAL:
|
|
|
|
|
return true;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::string
|
|
|
|
|
RenderScopeList(llvm::ArrayRef<llvm::ms_demangle::Node *> nodes) {
|
|
|
|
|
lldbassert(!nodes.empty());
|
|
|
|
|
|
|
|
|
|
std::string result = nodes.front()->toString();
|
|
|
|
|
nodes = nodes.drop_front();
|
|
|
|
|
while (!nodes.empty()) {
|
|
|
|
|
result += "::";
|
|
|
|
|
result += nodes.front()->toString(llvm::ms_demangle::OF_NoTagSpecifier);
|
|
|
|
|
nodes = nodes.drop_front();
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static llvm::Optional<PublicSym32> FindPublicSym(const SegmentOffset &addr,
|
|
|
|
|
SymbolStream &syms,
|
|
|
|
|
PublicsStream &publics) {
|
|
|
|
|
llvm::FixedStreamArray<ulittle32_t> addr_map = publics.getAddressMap();
|
|
|
|
|
auto iter = std::lower_bound(
|
|
|
|
|
addr_map.begin(), addr_map.end(), addr,
|
|
|
|
|
[&](const ulittle32_t &x, const SegmentOffset &y) {
|
|
|
|
|
CVSymbol s1 = syms.readRecord(x);
|
|
|
|
|
lldbassert(s1.kind() == S_PUB32);
|
|
|
|
|
PublicSym32 p1;
|
|
|
|
|
llvm::cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(s1, p1));
|
|
|
|
|
if (p1.Segment < y.segment)
|
|
|
|
|
return true;
|
|
|
|
|
return p1.Offset < y.offset;
|
|
|
|
|
});
|
|
|
|
|
if (iter == addr_map.end())
|
|
|
|
|
return llvm::None;
|
|
|
|
|
CVSymbol sym = syms.readRecord(*iter);
|
|
|
|
|
lldbassert(sym.kind() == S_PUB32);
|
|
|
|
|
PublicSym32 p;
|
|
|
|
|
llvm::cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(sym, p));
|
|
|
|
|
if (p.Segment == addr.segment && p.Offset == addr.offset)
|
|
|
|
|
return p;
|
|
|
|
|
return llvm::None;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clang::Decl *PdbAstBuilder::GetOrCreateSymbolForId(PdbCompilandSymId id) {
|
|
|
|
|
CVSymbol cvs = m_index.ReadSymbolRecord(id);
|
|
|
|
|
|
|
|
|
|
if (isLocalVariableType(cvs.kind())) {
|
|
|
|
|
clang::DeclContext *scope = GetParentDeclContext(id);
|
|
|
|
|
clang::Decl *scope_decl = clang::Decl::castFromDeclContext(scope);
|
|
|
|
|
PdbCompilandSymId scope_id(id.modi, m_decl_to_status[scope_decl].uid);
|
|
|
|
|
return GetOrCreateVariableDecl(scope_id, id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (cvs.kind()) {
|
|
|
|
|
case S_GPROC32:
|
|
|
|
|
case S_LPROC32:
|
|
|
|
|
@@ -333,14 +466,6 @@ clang::Decl *PdbAstBuilder::GetOrCreateSymbolForId(PdbCompilandSymId id) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
case S_BLOCK32:
|
|
|
|
|
return GetOrCreateBlockDecl(id);
|
|
|
|
|
case S_REGISTER:
|
|
|
|
|
case S_REGREL32:
|
|
|
|
|
case S_LOCAL: {
|
|
|
|
|
clang::DeclContext *scope = GetParentDeclContext(id);
|
|
|
|
|
clang::Decl *scope_decl = clang::Decl::castFromDeclContext(scope);
|
|
|
|
|
PdbCompilandSymId scope_id(id.modi, m_decl_to_status[scope_decl].uid);
|
|
|
|
|
return GetOrCreateLocalVariableDecl(scope_id, id);
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
@@ -371,6 +496,11 @@ clang::Decl *PdbAstBuilder::GetOrCreateDeclForUid(PdbSymUid uid) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clang::DeclContext *PdbAstBuilder::GetOrCreateDeclContextForUid(PdbSymUid uid) {
|
|
|
|
|
if (uid.kind() == PdbSymUidKind::CompilandSym) {
|
|
|
|
|
if (uid.asCompilandSym().offset == 0)
|
|
|
|
|
return &GetTranslationUnitDecl();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clang::Decl *decl = GetOrCreateDeclForUid(uid);
|
|
|
|
|
if (!decl)
|
|
|
|
|
return nullptr;
|
|
|
|
|
@@ -385,14 +515,60 @@ clang::DeclContext *PdbAstBuilder::GetParentDeclContext(PdbSymUid uid) {
|
|
|
|
|
case PdbSymUidKind::CompilandSym: {
|
|
|
|
|
llvm::Optional<PdbCompilandSymId> scope =
|
|
|
|
|
FindSymbolScope(m_index, uid.asCompilandSym());
|
|
|
|
|
if (!scope)
|
|
|
|
|
if (scope)
|
|
|
|
|
return GetOrCreateDeclContextForUid(*scope);
|
|
|
|
|
|
|
|
|
|
CVSymbol sym = m_index.ReadSymbolRecord(uid.asCompilandSym());
|
|
|
|
|
if (!SymbolHasAddress(sym))
|
|
|
|
|
return &GetTranslationUnitDecl();
|
|
|
|
|
return GetOrCreateDeclContextForUid(*scope);
|
|
|
|
|
SegmentOffset addr = GetSegmentAndOffset(sym);
|
|
|
|
|
llvm::Optional<PublicSym32> pub =
|
|
|
|
|
FindPublicSym(addr, m_index.symrecords(), m_index.publics());
|
|
|
|
|
if (!pub)
|
|
|
|
|
return &GetTranslationUnitDecl();
|
|
|
|
|
|
|
|
|
|
llvm::ms_demangle::Demangler demangler;
|
|
|
|
|
StringView name{pub->Name.begin(), pub->Name.size()};
|
|
|
|
|
llvm::ms_demangle::SymbolNode *node = demangler.parse(name);
|
|
|
|
|
if (!node)
|
|
|
|
|
return &GetTranslationUnitDecl();
|
|
|
|
|
llvm::ArrayRef<llvm::ms_demangle::Node *> name_components{
|
|
|
|
|
node->Name->Components->Nodes, node->Name->Components->Count - 1};
|
|
|
|
|
|
|
|
|
|
if (!name_components.empty()) {
|
|
|
|
|
// Render the current list of scope nodes as a fully qualified name, and
|
|
|
|
|
// look it up in the debug info as a type name. If we find something,
|
|
|
|
|
// this is a type (which may itself be prefixed by a namespace). If we
|
|
|
|
|
// don't, this is a list of namespaces.
|
|
|
|
|
std::string qname = RenderScopeList(name_components);
|
|
|
|
|
std::vector<TypeIndex> matches = m_index.tpi().findRecordsByName(qname);
|
|
|
|
|
while (!matches.empty()) {
|
|
|
|
|
clang::QualType qt = GetOrCreateType(matches.back());
|
|
|
|
|
clang::TagDecl *tag = qt->getAsTagDecl();
|
|
|
|
|
if (tag)
|
|
|
|
|
return clang::TagDecl::castToDeclContext(tag);
|
|
|
|
|
matches.pop_back();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// It's not a type. It must be a series of namespaces.
|
|
|
|
|
clang::DeclContext *context = &GetTranslationUnitDecl();
|
|
|
|
|
while (!name_components.empty()) {
|
|
|
|
|
std::string ns = name_components.front()->toString();
|
|
|
|
|
context = m_clang.GetUniqueNamespaceDeclaration(ns.c_str(), context);
|
|
|
|
|
name_components = name_components.drop_front();
|
|
|
|
|
}
|
|
|
|
|
return context;
|
|
|
|
|
}
|
|
|
|
|
case PdbSymUidKind::Type:
|
|
|
|
|
case PdbSymUidKind::Type: {
|
|
|
|
|
// It could be a namespace, class, or global. We don't support nested
|
|
|
|
|
// functions yet. Anyway, we just need to consult the parent type map.
|
|
|
|
|
break;
|
|
|
|
|
PdbTypeSymId type_id = uid.asTypeSym();
|
|
|
|
|
auto iter = m_parent_types.find(type_id.index);
|
|
|
|
|
if (iter == m_parent_types.end())
|
|
|
|
|
return &GetTranslationUnitDecl();
|
|
|
|
|
return GetOrCreateDeclContextForUid(PdbTypeSymId(iter->second));
|
|
|
|
|
}
|
|
|
|
|
case PdbSymUidKind::FieldListMember:
|
|
|
|
|
// In this case the parent DeclContext is the one for the class that this
|
|
|
|
|
// member is inside of.
|
|
|
|
|
@@ -531,10 +707,9 @@ PdbAstBuilder::CreateModifierType(const ModifierRecord &modifier) {
|
|
|
|
|
|
|
|
|
|
clang::QualType PdbAstBuilder::CreateRecordType(PdbTypeSymId id,
|
|
|
|
|
const TagRecord &record) {
|
|
|
|
|
clang::DeclContext *decl_context = nullptr;
|
|
|
|
|
clang::DeclContext *context = nullptr;
|
|
|
|
|
std::string uname;
|
|
|
|
|
std::tie(decl_context, uname) = CreateDeclInfoForType(record, id.index);
|
|
|
|
|
|
|
|
|
|
std::tie(context, uname) = CreateDeclInfoForType(record, id.index);
|
|
|
|
|
clang::TagTypeKind ttk = TranslateUdtKind(record);
|
|
|
|
|
lldb::AccessType access =
|
|
|
|
|
(ttk == clang::TTK_Class) ? lldb::eAccessPrivate : lldb::eAccessPublic;
|
|
|
|
|
@@ -544,7 +719,7 @@ clang::QualType PdbAstBuilder::CreateRecordType(PdbTypeSymId id,
|
|
|
|
|
metadata.SetIsDynamicCXXType(false);
|
|
|
|
|
|
|
|
|
|
CompilerType ct =
|
|
|
|
|
m_clang.CreateRecordType(decl_context, access, uname.c_str(), ttk,
|
|
|
|
|
m_clang.CreateRecordType(context, access, uname.c_str(), ttk,
|
|
|
|
|
lldb::eLanguageTypeC_plus_plus, &metadata);
|
|
|
|
|
|
|
|
|
|
lldbassert(ct.IsValid());
|
|
|
|
|
@@ -583,6 +758,12 @@ PdbAstBuilder::GetOrCreateBlockDecl(PdbCompilandSymId block_id) {
|
|
|
|
|
|
|
|
|
|
clang::BlockDecl *block_decl = m_clang.CreateBlockDeclaration(scope);
|
|
|
|
|
m_uid_to_decl.insert({toOpaqueUid(block_id), block_decl});
|
|
|
|
|
|
|
|
|
|
DeclStatus status;
|
|
|
|
|
status.resolved = true;
|
|
|
|
|
status.uid = toOpaqueUid(block_id);
|
|
|
|
|
m_decl_to_status.insert({block_decl, status});
|
|
|
|
|
|
|
|
|
|
return block_decl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -595,12 +776,16 @@ clang::VarDecl *PdbAstBuilder::CreateVariableDecl(PdbSymUid uid, CVSymbol sym,
|
|
|
|
|
&scope, var_info.name.str().c_str(), qt);
|
|
|
|
|
|
|
|
|
|
m_uid_to_decl[toOpaqueUid(uid)] = var_decl;
|
|
|
|
|
DeclStatus status;
|
|
|
|
|
status.resolved = true;
|
|
|
|
|
status.uid = toOpaqueUid(uid);
|
|
|
|
|
m_decl_to_status.insert({var_decl, status});
|
|
|
|
|
return var_decl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clang::VarDecl *
|
|
|
|
|
PdbAstBuilder::GetOrCreateLocalVariableDecl(PdbCompilandSymId scope_id,
|
|
|
|
|
PdbCompilandSymId var_id) {
|
|
|
|
|
PdbAstBuilder::GetOrCreateVariableDecl(PdbCompilandSymId scope_id,
|
|
|
|
|
PdbCompilandSymId var_id) {
|
|
|
|
|
if (clang::Decl *decl = TryGetDecl(var_id))
|
|
|
|
|
return llvm::dyn_cast<clang::VarDecl>(decl);
|
|
|
|
|
|
|
|
|
|
@@ -610,8 +795,7 @@ PdbAstBuilder::GetOrCreateLocalVariableDecl(PdbCompilandSymId scope_id,
|
|
|
|
|
return CreateVariableDecl(PdbSymUid(var_id), sym, *scope);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clang::VarDecl *
|
|
|
|
|
PdbAstBuilder::GetOrCreateGlobalVariableDecl(PdbGlobalSymId var_id) {
|
|
|
|
|
clang::VarDecl *PdbAstBuilder::GetOrCreateVariableDecl(PdbGlobalSymId var_id) {
|
|
|
|
|
if (clang::Decl *decl = TryGetDecl(var_id))
|
|
|
|
|
return llvm::dyn_cast<clang::VarDecl>(decl);
|
|
|
|
|
|
|
|
|
|
@@ -706,6 +890,12 @@ PdbAstBuilder::GetOrCreateFunctionDecl(PdbCompilandSymId func_id) {
|
|
|
|
|
return llvm::dyn_cast<clang::FunctionDecl>(decl);
|
|
|
|
|
|
|
|
|
|
clang::DeclContext *parent = GetParentDeclContext(PdbSymUid(func_id));
|
|
|
|
|
std::string context_name;
|
|
|
|
|
if (clang::NamespaceDecl *ns = llvm::dyn_cast<clang::NamespaceDecl>(parent)) {
|
|
|
|
|
context_name = ns->getQualifiedNameAsString();
|
|
|
|
|
} else if (clang::TagDecl *tag = llvm::dyn_cast<clang::TagDecl>(parent)) {
|
|
|
|
|
context_name = tag->getQualifiedNameAsString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CVSymbol cvs = m_index.ReadSymbolRecord(func_id);
|
|
|
|
|
ProcSym proc(static_cast<SymbolRecordKind>(cvs.kind()));
|
|
|
|
|
@@ -713,6 +903,8 @@ PdbAstBuilder::GetOrCreateFunctionDecl(PdbCompilandSymId func_id) {
|
|
|
|
|
|
|
|
|
|
PdbTypeSymId type_id(proc.FunctionType);
|
|
|
|
|
clang::QualType qt = GetOrCreateType(type_id);
|
|
|
|
|
if (qt.isNull())
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
|
|
clang::StorageClass storage = clang::SC_None;
|
|
|
|
|
if (proc.Kind == SymbolRecordKind::ProcSym)
|
|
|
|
|
@@ -723,11 +915,19 @@ PdbAstBuilder::GetOrCreateFunctionDecl(PdbCompilandSymId func_id) {
|
|
|
|
|
|
|
|
|
|
CompilerType func_ct = ToCompilerType(qt);
|
|
|
|
|
|
|
|
|
|
llvm::StringRef proc_name = proc.Name;
|
|
|
|
|
proc_name.consume_front(context_name);
|
|
|
|
|
proc_name.consume_front("::");
|
|
|
|
|
|
|
|
|
|
clang::FunctionDecl *function_decl = m_clang.CreateFunctionDeclaration(
|
|
|
|
|
parent, proc.Name.str().c_str(), func_ct, storage, false);
|
|
|
|
|
parent, proc_name.str().c_str(), func_ct, storage, false);
|
|
|
|
|
|
|
|
|
|
lldbassert(m_uid_to_decl.count(toOpaqueUid(func_id)) == 0);
|
|
|
|
|
m_uid_to_decl[toOpaqueUid(func_id)] = function_decl;
|
|
|
|
|
DeclStatus status;
|
|
|
|
|
status.resolved = true;
|
|
|
|
|
status.uid = toOpaqueUid(func_id);
|
|
|
|
|
m_decl_to_status.insert({function_decl, status});
|
|
|
|
|
|
|
|
|
|
CreateFunctionParameters(func_id, *function_decl, func_type->getNumParams());
|
|
|
|
|
|
|
|
|
|
@@ -866,6 +1066,180 @@ PdbAstBuilder::CreateProcedureType(const ProcedureRecord &proc) {
|
|
|
|
|
func_sig_ast_type.GetOpaqueQualType());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool isTagDecl(clang::DeclContext &context) {
|
|
|
|
|
return !!llvm::dyn_cast<clang::TagDecl>(&context);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool isFunctionDecl(clang::DeclContext &context) {
|
|
|
|
|
return !!llvm::dyn_cast<clang::FunctionDecl>(&context);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool isBlockDecl(clang::DeclContext &context) {
|
|
|
|
|
return !!llvm::dyn_cast<clang::BlockDecl>(&context);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbAstBuilder::ParseAllNamespacesPlusChildrenOf(
|
|
|
|
|
llvm::Optional<llvm::StringRef> parent) {
|
|
|
|
|
TypeIndex ti{m_index.tpi().TypeIndexBegin()};
|
|
|
|
|
for (const CVType &cvt : m_index.tpi().typeArray()) {
|
|
|
|
|
PdbTypeSymId tid{ti};
|
|
|
|
|
++ti;
|
|
|
|
|
|
|
|
|
|
if (!IsTagRecord(cvt))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
CVTagRecord tag = CVTagRecord::create(cvt);
|
|
|
|
|
|
|
|
|
|
if (!parent.hasValue()) {
|
|
|
|
|
clang::QualType qt = GetOrCreateType(tid);
|
|
|
|
|
CompleteType(qt);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Call CreateDeclInfoForType unconditionally so that the namespace info
|
|
|
|
|
// gets created. But only call CreateRecordType if the namespace name
|
|
|
|
|
// matches.
|
|
|
|
|
clang::DeclContext *context = nullptr;
|
|
|
|
|
std::string uname;
|
|
|
|
|
std::tie(context, uname) = CreateDeclInfoForType(tag.asTag(), tid.index);
|
|
|
|
|
if (!context->isNamespace())
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
clang::NamespaceDecl *ns = llvm::dyn_cast<clang::NamespaceDecl>(context);
|
|
|
|
|
std::string actual_ns = ns->getQualifiedNameAsString();
|
|
|
|
|
if (llvm::StringRef(actual_ns).startswith(*parent)) {
|
|
|
|
|
clang::QualType qt = GetOrCreateType(tid);
|
|
|
|
|
CompleteType(qt);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t module_count = m_index.dbi().modules().getModuleCount();
|
|
|
|
|
for (uint16_t modi = 0; modi < module_count; ++modi) {
|
|
|
|
|
CompilandIndexItem &cii = m_index.compilands().GetOrCreateCompiland(modi);
|
|
|
|
|
const CVSymbolArray &symbols = cii.m_debug_stream.getSymbolArray();
|
|
|
|
|
auto iter = symbols.begin();
|
|
|
|
|
while (iter != symbols.end()) {
|
|
|
|
|
PdbCompilandSymId sym_id{modi, iter.offset()};
|
|
|
|
|
|
|
|
|
|
switch (iter->kind()) {
|
|
|
|
|
case S_GPROC32:
|
|
|
|
|
case S_LPROC32:
|
|
|
|
|
GetOrCreateFunctionDecl(sym_id);
|
|
|
|
|
iter = symbols.at(getScopeEndOffset(*iter));
|
|
|
|
|
break;
|
|
|
|
|
case S_GDATA32:
|
|
|
|
|
case S_GTHREAD32:
|
|
|
|
|
case S_LDATA32:
|
|
|
|
|
case S_LTHREAD32:
|
|
|
|
|
GetOrCreateVariableDecl(PdbCompilandSymId(modi, 0), sym_id);
|
|
|
|
|
++iter;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
++iter;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static CVSymbolArray skipFunctionParameters(clang::Decl &decl,
|
|
|
|
|
const CVSymbolArray &symbols) {
|
|
|
|
|
clang::FunctionDecl *func_decl = llvm::dyn_cast<clang::FunctionDecl>(&decl);
|
|
|
|
|
if (!func_decl)
|
|
|
|
|
return symbols;
|
|
|
|
|
unsigned int params = func_decl->getNumParams();
|
|
|
|
|
if (params == 0)
|
|
|
|
|
return symbols;
|
|
|
|
|
|
|
|
|
|
CVSymbolArray result = symbols;
|
|
|
|
|
|
|
|
|
|
while (!result.empty()) {
|
|
|
|
|
if (params == 0)
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
CVSymbol sym = *result.begin();
|
|
|
|
|
result.drop_front();
|
|
|
|
|
|
|
|
|
|
if (!isLocalVariableType(sym.kind()))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
--params;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbAstBuilder::ParseBlockChildren(PdbCompilandSymId block_id) {
|
|
|
|
|
CVSymbol sym = m_index.ReadSymbolRecord(block_id);
|
|
|
|
|
lldbassert(sym.kind() == S_GPROC32 || sym.kind() == S_LPROC32 ||
|
|
|
|
|
sym.kind() == S_BLOCK32);
|
|
|
|
|
CompilandIndexItem &cii =
|
|
|
|
|
m_index.compilands().GetOrCreateCompiland(block_id.modi);
|
|
|
|
|
CVSymbolArray symbols =
|
|
|
|
|
cii.m_debug_stream.getSymbolArrayForScope(block_id.offset);
|
|
|
|
|
|
|
|
|
|
// Function parameters should already have been created when the function was
|
|
|
|
|
// parsed.
|
|
|
|
|
if (sym.kind() == S_GPROC32 || sym.kind() == S_LPROC32)
|
|
|
|
|
symbols =
|
|
|
|
|
skipFunctionParameters(*m_uid_to_decl[toOpaqueUid(block_id)], symbols);
|
|
|
|
|
|
|
|
|
|
auto begin = symbols.begin();
|
|
|
|
|
while (begin != symbols.end()) {
|
|
|
|
|
PdbCompilandSymId child_sym_id(block_id.modi, begin.offset());
|
|
|
|
|
GetOrCreateSymbolForId(child_sym_id);
|
|
|
|
|
if (begin->kind() == S_BLOCK32) {
|
|
|
|
|
ParseBlockChildren(child_sym_id);
|
|
|
|
|
begin = symbols.at(getScopeEndOffset(*begin));
|
|
|
|
|
}
|
|
|
|
|
++begin;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbAstBuilder::ParseDeclsForSimpleContext(clang::DeclContext &context) {
|
|
|
|
|
|
|
|
|
|
clang::Decl *decl = clang::Decl::castFromDeclContext(&context);
|
|
|
|
|
lldbassert(decl);
|
|
|
|
|
|
|
|
|
|
auto iter = m_decl_to_status.find(decl);
|
|
|
|
|
lldbassert(iter != m_decl_to_status.end());
|
|
|
|
|
|
|
|
|
|
if (auto *tag = llvm::dyn_cast<clang::TagDecl>(&context)) {
|
|
|
|
|
CompleteTagDecl(*tag);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isFunctionDecl(context) || isBlockDecl(context)) {
|
|
|
|
|
PdbCompilandSymId block_id = PdbSymUid(iter->second.uid).asCompilandSym();
|
|
|
|
|
ParseBlockChildren(block_id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbAstBuilder::ParseDeclsForContext(clang::DeclContext &context) {
|
|
|
|
|
// Namespaces aren't explicitly represented in the debug info, and the only
|
|
|
|
|
// way to parse them is to parse all type info, demangling every single type
|
|
|
|
|
// and trying to reconstruct the DeclContext hierarchy this way. Since this
|
|
|
|
|
// is an expensive operation, we have to special case it so that we do other
|
|
|
|
|
// work (such as parsing the items that appear within the namespaces) at the
|
|
|
|
|
// same time.
|
|
|
|
|
if (context.isTranslationUnit()) {
|
|
|
|
|
ParseAllNamespacesPlusChildrenOf(llvm::None);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (context.isNamespace()) {
|
|
|
|
|
clang::NamespaceDecl &ns = *llvm::dyn_cast<clang::NamespaceDecl>(&context);
|
|
|
|
|
std::string qname = ns.getQualifiedNameAsString();
|
|
|
|
|
ParseAllNamespacesPlusChildrenOf(llvm::StringRef{qname});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isTagDecl(context) || isFunctionDecl(context) || isBlockDecl(context)) {
|
|
|
|
|
ParseDeclsForSimpleContext(context);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CompilerDecl PdbAstBuilder::ToCompilerDecl(clang::Decl &decl) {
|
|
|
|
|
return {&m_clang, &decl};
|
|
|
|
|
}
|
|
|
|
|
@@ -879,4 +1253,9 @@ PdbAstBuilder::ToCompilerDeclContext(clang::DeclContext &context) {
|
|
|
|
|
return {&m_clang, &context};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clang::DeclContext *
|
|
|
|
|
PdbAstBuilder::FromCompilerDeclContext(CompilerDeclContext context) {
|
|
|
|
|
return static_cast<clang::DeclContext *>(context.GetOpaqueDeclContext());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PdbAstBuilder::Dump(Stream &stream) { m_clang.Dump(stream); }
|
|
|
|
|
|