zequanwu created this revision. zequanwu added reviewers: rnk, labath. Herald added a project: All. zequanwu requested review of this revision. Herald added a project: LLDB. Herald added a subscriber: lldb-commits.
`PdbAstBuilder::GetParentDeclContextForSymbol` finds the public symbol that has same address as the given symbol, then creates parent DeclContext from demangled name. When ICF happens, there are multiple public symbols share the same address. It may creates the wrong parent DeclContext. This fixes it by filtering all public symbols that has the same addrss with base name. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D133243 Files: lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp lldb/test/Shell/SymbolFile/NativePDB/icf.cpp
Index: lldb/test/Shell/SymbolFile/NativePDB/icf.cpp =================================================================== --- /dev/null +++ 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: }; Index: lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp +++ lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp @@ -470,9 +470,9 @@ return result; } -static llvm::Optional<PublicSym32> FindPublicSym(const SegmentOffset &addr, - SymbolStream &syms, - PublicsStream &publics) { +static llvm::SmallVector<PublicSym32> FindPublicSyms(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, @@ -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<PublicSym32>(sym, p)); - if (p.Segment == addr.segment && p.Offset == addr.offset) - return p; - return llvm::None; + llvm::SmallVector<PublicSym32, 1> public_syms; + while (iter != addr_map.end()) { + 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) + 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<PublicSym32> pub = - FindPublicSym(addr, m_index.symrecords(), m_index.publics()); - if (!pub) - return CreateDeclInfoForUndecoratedName(getSymbolName(sym)).first; + llvm::SmallVector<PublicSym32> 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<llvm::ms_demangle::Node *> 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<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()); - 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<TypeIndex> 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) {
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits