summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/lit/SymbolFile/PDB/variables-locations.test2
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp449
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h12
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp10
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp6
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp12
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h3
7 files changed, 443 insertions, 51 deletions
diff --git a/lldb/lit/SymbolFile/PDB/variables-locations.test b/lldb/lit/SymbolFile/PDB/variables-locations.test
index e3ac63aa9f0..7696dc92cee 100644
--- a/lldb/lit/SymbolFile/PDB/variables-locations.test
+++ b/lldb/lit/SymbolFile/PDB/variables-locations.test
@@ -1,6 +1,6 @@
REQUIRES: system-windows, lld
RUN: %build --compiler=clang-cl --output=%t.exe %S/Inputs/VariablesLocationsTest.cpp
-RUN: %lldb -b -s %S/Inputs/VariablesLocationsTest.script -- %t.exe | FileCheck %s
+RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -b -s %S/Inputs/VariablesLocationsTest.script -- %t.exe | FileCheck %s
CHECK: g_var = 2222
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
index 3f6ce1513f0..8cf332f8a95 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
@@ -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); }
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h
index 8917a445a81..9538d675171 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h
@@ -66,9 +66,10 @@ public:
clang::DeclContext &context);
clang::FunctionDecl *GetOrCreateFunctionDecl(PdbCompilandSymId func_id);
clang::BlockDecl *GetOrCreateBlockDecl(PdbCompilandSymId block_id);
- clang::VarDecl *GetOrCreateLocalVariableDecl(PdbCompilandSymId scope_id,
- PdbCompilandSymId var_id);
- clang::VarDecl *GetOrCreateGlobalVariableDecl(PdbGlobalSymId var_id);
+ clang::VarDecl *GetOrCreateVariableDecl(PdbCompilandSymId scope_id,
+ PdbCompilandSymId var_id);
+ clang::VarDecl *GetOrCreateVariableDecl(PdbGlobalSymId var_id);
+ void ParseDeclsForContext(clang::DeclContext &context);
clang::QualType GetBasicType(lldb::BasicType type);
clang::QualType GetOrCreateType(PdbTypeSymId type);
@@ -79,6 +80,7 @@ public:
CompilerDecl ToCompilerDecl(clang::Decl &decl);
CompilerType ToCompilerType(clang::QualType qt);
CompilerDeclContext ToCompilerDeclContext(clang::DeclContext &context);
+ clang::DeclContext *FromCompilerDeclContext(CompilerDeclContext context);
ClangASTContext &clang() { return m_clang; }
ClangASTImporter &importer() { return m_importer; }
@@ -111,6 +113,10 @@ private:
llvm::codeview::CVSymbol sym,
clang::DeclContext &scope);
+ void ParseAllNamespacesPlusChildrenOf(llvm::Optional<llvm::StringRef> parent);
+ void ParseDeclsForSimpleContext(clang::DeclContext &context);
+ void ParseBlockChildren(PdbCompilandSymId block_id);
+
void BuildParentMap();
std::pair<clang::DeclContext *, std::string>
CreateDeclInfoForType(const llvm::codeview::TagRecord &record, TypeIndex ti);
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
index 40a4b5ccdf4..51a3d106180 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
@@ -136,15 +136,7 @@ void PdbIndex::BuildAddrToSymbolMap(CompilandIndexItem &cci) {
// If the debug info is incorrect, we could have multiple symbols with the
// same address. So use try_emplace instead of insert, and the first one
// will win.
- auto insert_result =
- cci.m_symbols_by_va.insert(std::make_pair(va, PdbSymUid(cu_sym_id)));
- (void)insert_result;
-
- // The odds of an error in some function such as GetSegmentAndOffset or
- // MakeVirtualAddress are much higher than the odds of encountering bad
- // debug info, so assert that this item was inserted in the map as opposed
- // to having already been there.
- lldbassert(insert_result.second);
+ cci.m_symbols_by_va.try_emplace(va, PdbSymUid(cu_sym_id));
}
}
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
index c99ace01517..72ed3a7329e 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
@@ -733,7 +733,11 @@ size_t lldb_private::npdb::GetSizeOfType(PdbTypeSymId id,
return 0;
}
- CVType cvt = tpi.getType(id.index);
+ TypeIndex index = id.index;
+ if (IsForwardRefUdt(index, tpi))
+ index = llvm::cantFail(tpi.findFullDeclForForwardRef(index));
+
+ CVType cvt = tpi.getType(index);
switch (cvt.kind()) {
case LF_MODIFIER:
return GetSizeOfType({LookThroughModifierRecord(cvt)}, tpi);
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index 0208d3cbaa5..9868a3283e0 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -759,7 +759,7 @@ VariableSP SymbolFileNativePDB::CreateGlobalVariable(PdbGlobalSymId var_id) {
std::make_shared<SymbolFileType>(*this, toOpaqueUid(tid));
Variable::RangeList ranges;
- m_ast->GetOrCreateGlobalVariableDecl(var_id);
+ m_ast->GetOrCreateVariableDecl(var_id);
DWARFExpression location = MakeGlobalLocationExpression(
section, offset, GetObjectFile()->GetModule());
@@ -845,6 +845,14 @@ Block &SymbolFileNativePDB::GetOrCreateBlock(PdbCompilandSymId block_id) {
return CreateBlock(block_id);
}
+void SymbolFileNativePDB::ParseDeclsForContext(
+ lldb_private::CompilerDeclContext decl_ctx) {
+ clang::DeclContext *context = m_ast->FromCompilerDeclContext(decl_ctx);
+ if (!context)
+ return;
+ m_ast->ParseDeclsForContext(*context);
+}
+
lldb::CompUnitSP SymbolFileNativePDB::ParseCompileUnitAtIndex(uint32_t index) {
if (index >= GetNumCompileUnits())
return CompUnitSP();
@@ -1262,7 +1270,7 @@ VariableSP SymbolFileNativePDB::CreateLocalVariable(PdbCompilandSymId scope_id,
false, false);
if (!is_param)
- m_ast->GetOrCreateLocalVariableDecl(scope_id, var_id);
+ m_ast->GetOrCreateVariableDecl(scope_id, var_id);
m_local_variables[toOpaqueUid(var_id)] = var_sp;
return var_sp;
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
index dece19dbb71..bb119a06d5d 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -77,6 +77,9 @@ public:
uint32_t GetNumCompileUnits() override;
+ void
+ ParseDeclsForContext(lldb_private::CompilerDeclContext decl_ctx) override;
+
lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override;
lldb::LanguageType ParseCompileUnitLanguage(const SymbolContext &sc) override;
OpenPOWER on IntegriCloud