diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp @@ -470,9 +470,9 @@ return result; } -static llvm::Optional FindPublicSym(const SegmentOffset &addr, - SymbolStream &syms, - PublicsStream &publics) { +static llvm::SmallVector FindPublicSyms(const SegmentOffset &addr, + SymbolStream &syms, + PublicsStream &publics) { llvm::FixedStreamArray addr_map = publics.getAddressMap(); auto iter = std::lower_bound( addr_map.begin(), addr_map.end(), addr, @@ -485,15 +485,17 @@ 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(sym, p)); - if (p.Segment == addr.segment && p.Offset == addr.offset) - return p; - return llvm::None; + llvm::SmallVector public_syms; + while (iter != addr_map.end()) { + CVSymbol sym = syms.readRecord(*iter); + lldbassert(sym.kind() == S_PUB32); + PublicSym32 p; + llvm::cantFail(SymbolDeserializer::deserializeAs(sym, p)); + if (p.Segment == addr.segment && p.Offset == addr.offset) + public_syms.push_back(p); + ++iter; + } + return public_syms; } clang::Decl *PdbAstBuilder::GetOrCreateSymbolForId(PdbCompilandSymId id) { @@ -608,48 +610,56 @@ clang::DeclContext * PdbAstBuilder::GetParentDeclContextForSymbol(const CVSymbol &sym) { - if (!SymbolHasAddress(sym)) - return CreateDeclInfoForUndecoratedName(getSymbolName(sym)).first; + llvm::StringRef full_name = getSymbolName(sym); + llvm::StringRef base_name = full_name.rsplit("::").second; + if (!SymbolHasAddress(sym) || base_name.empty()) + return CreateDeclInfoForUndecoratedName(full_name).first; SegmentOffset addr = GetSegmentAndOffset(sym); - llvm::Optional pub = - FindPublicSym(addr, m_index.symrecords(), m_index.publics()); - if (!pub) - return CreateDeclInfoForUndecoratedName(getSymbolName(sym)).first; + llvm::SmallVector public_syms = + FindPublicSyms(addr, m_index.symrecords(), m_index.publics()); + + for (const PublicSym32 &pub : public_syms) { + llvm::ms_demangle::Demangler demangler; + StringView name{pub.Name.begin(), pub.Name.size()}; + llvm::ms_demangle::SymbolNode *node = demangler.parse(name); + if (!node) + continue; + llvm::ArrayRef name_components{ + node->Name->Components->Nodes, node->Name->Components->Count}; + // Because ICF, we need to filter out the public symbols by base name. + if (name_components.empty() || + base_name != name_components.back()->toString()) + continue; - llvm::ms_demangle::Demangler demangler; - StringView name{pub->Name.begin(), pub->Name.size()}; - llvm::ms_demangle::SymbolNode *node = demangler.parse(name); - if (!node) - return FromCompilerDeclContext(GetTranslationUnitDecl()); - llvm::ArrayRef 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 matches = m_index.tpi().findRecordsByName(qname); - while (!matches.empty()) { - clang::QualType qt = GetOrCreateType(matches.back()); - if (qt.isNull()) - continue; - clang::TagDecl *tag = qt->getAsTagDecl(); - if (tag) - return clang::TagDecl::castToDeclContext(tag); - matches.pop_back(); + name_components = name_components.drop_back(); + 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 matches = m_index.tpi().findRecordsByName(qname); + while (!matches.empty()) { + clang::QualType qt = GetOrCreateType(matches.back()); + if (qt.isNull()) + continue; + 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. - auto context = FromCompilerDeclContext(GetTranslationUnitDecl()); - while (!name_components.empty()) { - std::string ns = name_components.front()->toString(); - context = GetOrCreateNamespaceDecl(ns.c_str(), *context); - name_components = name_components.drop_front(); + // It's not a type. It must be a series of namespaces. + auto *context = FromCompilerDeclContext(GetTranslationUnitDecl()); + while (!name_components.empty()) { + std::string ns = name_components.front()->toString(); + context = GetOrCreateNamespaceDecl(ns.c_str(), *context); + name_components = name_components.drop_front(); + } + return context; } - return context; + return CreateDeclInfoForUndecoratedName(full_name).first; } clang::DeclContext *PdbAstBuilder::GetParentDeclContext(PdbSymUid uid) { diff --git a/lldb/test/Shell/SymbolFile/NativePDB/icf.cpp b/lldb/test/Shell/SymbolFile/NativePDB/icf.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/Shell/SymbolFile/NativePDB/icf.cpp @@ -0,0 +1,55 @@ +// clang-format off +// REQUIRES: lld, x86 + +// Test lldb is not treating function as class method or other way around when icf applies to a +// function and a class method. +// RUN: %clang_cl --target=x86_64-windows-msvc -Od -Z7 -GS- -fno-addrsig -c /Fo%t.obj -- %s +// RUN: lld-link -opt:icf -debug:full -nodefaultlib -entry:main %t.obj -out:%t.exe -pdb:%t.pdb +// RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb-test symbols --dump-ast %t.exe | FileCheck %s + +struct A { + int f1(int x) { + return x * 2; + } +}; +struct B { + int f2(int x) { + return x * 2; + } +}; +namespace N1 { +int f3(void*, int x) { + return x * 2; +} +} // namespace N1 + +namespace N2 { +namespace N3 { + int f4(void*, int x) { + return x * 2; + } +} // namespace N3 +} // namespace N2 + +int main() { + A a; + B b; + return a.f1(1) + b.f2(1) + N1::f3(nullptr, 1) + N2::N3::f4(nullptr, 1); +} + + +// CHECK: namespace N1 { +// CHECK-NEXT: int f3(void *, int x); +// CHECK-NEXT: } +// CHECK-NEXT: namespace N2 { +// CHECK-NEXT: namespace N3 { +// CHECK-NEXT: int f4(void *, int x); +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: int main(); +// CHECK-NEXT: struct A { +// CHECK-NEXT: int f1(int); +// CHECK-NEXT: }; +// CHECK-NEXT: struct B { +// CHECK-NEXT: int f2(int); +// CHECK-NEXT: };