Index: lldb/lit/SymbolFile/NativePDB/Inputs/ast-reconstruction.lldbinit =================================================================== --- /dev/null +++ lldb/lit/SymbolFile/NativePDB/Inputs/ast-reconstruction.lldbinit @@ -0,0 +1,23 @@ +target variable ABR +target variable ATR +target variable BAR +target variable BT +target variable GlobalC +target variable GlobalU +target variable GlobalS +target variable GlobalE + +target modules dump ast + +target variable ABR +target variable ATR +target variable BAR +target variable BT +target variable GlobalC +target variable GlobalU +target variable GlobalS +target variable GlobalE + +target modules dump ast + +quit \ No newline at end of file Index: lldb/lit/SymbolFile/NativePDB/ast-reconstruction.cpp =================================================================== --- /dev/null +++ lldb/lit/SymbolFile/NativePDB/ast-reconstruction.cpp @@ -0,0 +1,124 @@ +// clang-format off +// REQUIRES: lld + +// RUN: clang-cl /Z7 /GS- /GR- /c -Xclang -fkeep-static-consts /Fo%t.obj -- %s +// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj +// RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb -f %t.exe -s \ +// RUN: %p/Inputs/ast-reconstruction.lldbinit 2>&1 | FileCheck %s +// RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb -f %t.exe -s \ +// RUN: %p/Inputs/ast-reconstruction.lldbinit 2>&1 | FileCheck \ +// RUN: --check-prefix=NODUPE-NS1 %s +// RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb -f %t.exe -s \ +// RUN: %p/Inputs/ast-reconstruction.lldbinit 2>&1 | FileCheck \ +// RUN: --check-prefix=NODUPE-NS2 %s +// RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb -f %t.exe -s \ +// RUN: %p/Inputs/ast-reconstruction.lldbinit 2>&1 | FileCheck \ +// RUN: --check-prefix=NODUPE-TAGRECORD %s +// RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb -f %t.exe -s \ +// RUN: %p/Inputs/ast-reconstruction.lldbinit 2>&1 | FileCheck \ +// RUN: --check-prefix=NODUPE-C %s +// RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb -f %t.exe -s \ +// RUN: %p/Inputs/ast-reconstruction.lldbinit 2>&1 | FileCheck \ +// RUN: --check-prefix=NODUPE-U %s +// RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb -f %t.exe -s \ +// RUN: %p/Inputs/ast-reconstruction.lldbinit 2>&1 | FileCheck \ +// RUN: --check-prefix=NODUPE-S %s +// RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb -f %t.exe -s \ +// RUN: %p/Inputs/ast-reconstruction.lldbinit 2>&1 | FileCheck \ +// RUN: --check-prefix=NODUPE-E %s + + +struct S {}; +class C {}; +union U {}; +enum class E { + A = 1 +}; + +namespace NS1 { + namespace NS2 { + struct TagRecord { }; + } + + struct Tag2 { + class TagRecord {}; + }; +} + +struct NS2 { + struct NS1 { + union TagRecord {}; + }; + enum TagRecord {}; +}; + +S GlobalS; +C GlobalC; +U GlobalU; +E GlobalE = E::A; + +NS1::NS2::TagRecord ABR; +NS1::Tag2::TagRecord ATR; +NS2::NS1::TagRecord BAR; +NS2::TagRecord BT; + +// CHECK: TranslationUnitDecl +// CHECK: |-NamespaceDecl {{.*}} NS1 +// CHECK: | |-NamespaceDecl {{.*}} NS2 +// CHECK: | | `-CXXRecordDecl {{.*}} struct TagRecord definition +// CHECK: | | `-MSInheritanceAttr {{.*}} Implicit __single_inheritance +// CHECK: | `-NamespaceDecl {{.*}} Tag2 +// CHECK: | `-CXXRecordDecl {{.*}} class TagRecord definition +// CHECK: | `-MSInheritanceAttr {{.*}} Implicit __single_inheritance +// CHECK: |-NamespaceDecl {{.*}} NS2 +// CHECK: | `-NamespaceDecl {{.*}} NS1 +// CHECK: | `-CXXRecordDecl {{.*}} union TagRecord definition +// CHECK: | `-MSInheritanceAttr {{.*}} Implicit __single_inheritance +// CHECK: |-EnumDecl {{.*}} TagRecord +// CHECK: |-CXXRecordDecl {{.*}} class C definition +// CHECK: | `-MSInheritanceAttr {{.*}} Implicit __single_inheritance +// CHECK: |-CXXRecordDecl {{.*}} union U definition +// CHECK: | `-MSInheritanceAttr {{.*}} Implicit __single_inheritance +// CHECK: |-CXXRecordDecl {{.*}} struct S definition +// CHECK: | `-MSInheritanceAttr {{.*}} Implicit __single_inheritance +// CHECK: |-EnumDecl {{.*}} E +// CHECK: `- + +// NODUPE-NS1: TranslationUnitDecl +// NODUPE-NS1: |-NamespaceDecl {{.*}} NS1 +// NODUPE-NS1-NOT: |-NamespaceDecl {{.*}} NS1 +// NODUPE-NS1: `- + +// NODUPE-NS2: TranslationUnitDecl +// NODUPE-NS2: |-NamespaceDecl {{.*}} NS1 +// NODUPE-NS2-NOT: |-NamespaceDecl {{.*}} NS1 +// NODUPE-NS2: `- + +// NODUPE-TAGRECORD: TranslationUnitDecl +// NODUPE-TAGRECORD: | | `-CXXRecordDecl {{.*}} struct TagRecord definition +// NODUPE-TAGRECORD-NOT: | | `-CXXRecordDecl {{.*}} struct TagRecord definition +// NODUPE-TAGRECORD: `- + +// NODUPE-C: TranslationUnitDecl +// NODUPE-C: |-CXXRecordDecl {{.*}} class C definition +// NODUPE-C-NOT: |-CXXRecordDecl {{.*}} class C definition +// NODUPE-C: `- + +// NODUPE-U: TranslationUnitDecl +// NODUPE-U: |-CXXRecordDecl {{.*}} union U definition +// NODUPE-U-NOT: |-CXXRecordDecl {{.*}} union U definition +// NODUPE-U: `- + +// NODUPE-S: TranslationUnitDecl +// NODUPE-S: |-CXXRecordDecl {{.*}} struct S definition +// NODUPE-S-NOT: |-CXXRecordDecl {{.*}} struct S definition +// NODUPE-S: `- + +// NODUPE-E: TranslationUnitDecl +// NODUPE-E: |-EnumDecl {{.*}} E +// NODUPE-E-NOT: |-EnumDecl {{.*}} E +// NODUPE-E: `- + +int main(int argc, char **argv) { + return 0; +} Index: lldb/lit/SymbolFile/NativePDB/function-types-classes.cpp =================================================================== --- lldb/lit/SymbolFile/NativePDB/function-types-classes.cpp +++ lldb/lit/SymbolFile/NativePDB/function-types-classes.cpp @@ -81,20 +81,12 @@ // classes nested in namespaces and inner classes -// FIXME: LLDB with native pdb plugin doesn't currently resolve nested names -// correctly, because it requires creating clang::NamespaceDecl or -// clang::RecordDecl for the outer namespace or classes. PDB doesn't contain -// sufficient information to distinguish namespace scopes from nested class -// scopes, so the best we can hope for is a heuristic reconstruction of the -// clang AST based on demangling the type's unique name. However, this is -// as-yet unimplemented in the native PDB plugin, so for now all of these will -// all just look like `S` when LLDB prints them. auto e = &three; -// CHECK: (S *(*)(S *, S &)) e = {{.*}} +// CHECK: (A::B::S *(*)(B::A::S *, A::C::S &)) e = {{.*}} auto f = &three; -// CHECK: (S &(*)(S *, S *)) f = {{.*}} +// CHECK: (A::C::S &(*)(A::B::S *, B::A::S *)) f = {{.*}} auto g = &three; -// CHECK: (S *(*)(S &, S *)) g = {{.*}} +// CHECK: (B::A::S *(*)(A::C::S &, A::B::S *)) g = {{.*}} // parameter types that are themselves template instantiations. auto h = &four, TC, TC>, TC>; @@ -102,10 +94,10 @@ // instantiations are emitted by the compiler, as the fully instantiated name. // Only via reconstruction of the AST through the mangled type name (see above // comment) can we hope to do better than this). -// CHECK: (TC (*)(TC, TC >, S>)) h = {{.*}} +// CHECK: (TC (*)(TC, TC>, TC)) h = {{.*}} auto i = &nullary; -// CHECK: (S (*)()) i = {{.*}} +// CHECK: (A::B::S (*)()) i = {{.*}} // Make sure we can handle types that don't have complete debug info. Index: lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt +++ lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt @@ -1,5 +1,6 @@ add_lldb_library(lldbPluginSymbolFileNativePDB PLUGIN CompileUnitIndex.cpp + MangledAST.cpp PdbIndex.cpp PdbUtil.cpp SymbolFileNativePDB.cpp Index: lldb/source/Plugins/SymbolFile/NativePDB/MangledAST.h =================================================================== --- /dev/null +++ lldb/source/Plugins/SymbolFile/NativePDB/MangledAST.h @@ -0,0 +1,30 @@ +//===-- MangledAST.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_MANGLEDAST_H +#define LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_MANGLEDAST_H + +namespace clang { +class TagDecl; +} // namespace clang + +namespace llvm { +class StringRef; +} + +namespace lldb_private { +class ClangASTContext; +class CompilerType; +namespace npdb { +CompilerType CreateClangDeclFromMangledName(ClangASTContext &clang, + llvm::StringRef mangled); +} // namespace npdb +} // namespace lldb_private + +#endif // LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_MANGLEDAST_H Index: lldb/source/Plugins/SymbolFile/NativePDB/MangledAST.cpp =================================================================== --- /dev/null +++ lldb/source/Plugins/SymbolFile/NativePDB/MangledAST.cpp @@ -0,0 +1,91 @@ +//===-- MangledAST.cpp ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MangledAST.h" + +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/lldb-enumerations.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Demangle/MicrosoftDemangle.h" +#include "llvm/Demangle/MicrosoftDemangleNodes.h" +#include "llvm/Demangle/StringView.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::npdb; +using namespace llvm::ms_demangle; + +static std::string render(const Node &node) { + OutputStream OS; + initializeOutputStream(nullptr, nullptr, OS, 1024); + node.output(OS, OF_Default); + OS << '\0'; + return {OS.getBuffer()}; +} + +static clang::TagTypeKind TranslateTagKind(TagKind tk) { + switch (tk) { + case TagKind::Class: + return clang::TagTypeKind::TTK_Class; + case TagKind::Enum: + return clang::TagTypeKind::TTK_Enum; + case TagKind::Struct: + return clang::TagTypeKind::TTK_Struct; + case TagKind::Union: + return clang::TagTypeKind::TTK_Union; + } + llvm_unreachable("Unreachable!"); +} + +static clang::DeclContext *CreateDeclContext(ClangASTContext &clang, + llvm::ArrayRef scope) { + clang::DeclContext *decl_context = clang.GetTranslationUnitDecl(); + if (scope.empty()) + return decl_context; + + clang::DeclContext *top_level_decl = decl_context; + // For now we're just going to pretend that each component of the scope is a + // namespace. This isn't actually true, as they could be functions, nested + // classes with template parameters, or many other things. But it's a nice + // simplifying assumption that lets us make incremental progress while keeping + // things simple. + for (Node *ns : scope) { + std::string name = render(*ns); + decl_context = + clang.GetUniqueNamespaceDeclaration(name.c_str(), decl_context); + } + return decl_context; +} + +CompilerType +lldb_private::npdb::CreateClangDeclFromMangledName(ClangASTContext &clang, + llvm::StringRef mangled) { + StringView sv(mangled.data(), mangled.size()); + Demangler demangler; + TagTypeNode *ttn = demangler.parseTagUniqueName(sv); + if (!ttn) + return CompilerType{}; + + NodeArrayNode &name_components = *ttn->QualifiedName->Components; + + llvm::ArrayRef components(name_components.Nodes, + name_components.Count); + + lldb::AccessType access = + (ttn->Tag == TagKind::Class) ? lldb::eAccessPrivate : lldb::eAccessPublic; + + std::string name = render(*components.back()); + + llvm::ArrayRef scope = components.drop_back(); + clang::TagTypeKind ttk = TranslateTagKind(ttn->Tag); + clang::DeclContext *decl_context = CreateDeclContext(clang, scope); + return clang.CreateRecordType(decl_context, access, name.c_str(), ttk, + lldb::eLanguageTypeC_plus_plus, nullptr); +} Index: lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h +++ lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h @@ -177,7 +177,8 @@ lldb::TypeSP CreateProcedureType(PdbSymUid type_uid, const llvm::codeview::ProcedureRecord &pr); lldb::TypeSP - CreateClassStructUnion(PdbSymUid type_uid, llvm::StringRef name, size_t size, + CreateClassStructUnion(PdbSymUid type_uid, llvm::StringRef name, + llvm::StringRef unique_name, size_t size, clang::TagTypeKind ttk, clang::MSInheritanceAttr::Spelling inheritance); Index: lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -51,6 +51,7 @@ #include "Plugins/Language/CPlusPlus/CPlusPlusNameParser.h" +#include "MangledAST.h" #include "PdbSymUid.h" #include "PdbUtil.h" #include "UdtRecordCompleter.h" @@ -731,27 +732,11 @@ } lldb::TypeSP SymbolFileNativePDB::CreateClassStructUnion( - PdbSymUid type_uid, llvm::StringRef name, size_t size, - clang::TagTypeKind ttk, clang::MSInheritanceAttr::Spelling inheritance) { + PdbSymUid type_uid, llvm::StringRef name, llvm::StringRef unique_name, + size_t size, clang::TagTypeKind ttk, + clang::MSInheritanceAttr::Spelling inheritance) { - // Ignore unnamed-tag UDTs. - name = DropNameScope(name); - if (name.empty()) - return nullptr; - - clang::DeclContext *decl_context = m_clang->GetTranslationUnitDecl(); - - lldb::AccessType access = - (ttk == clang::TTK_Class) ? lldb::eAccessPrivate : lldb::eAccessPublic; - - ClangASTMetadata metadata; - metadata.SetUserID(type_uid.toOpaqueId()); - metadata.SetIsDynamicCXXType(false); - - CompilerType ct = - m_clang->CreateRecordType(decl_context, access, name.str().c_str(), ttk, - lldb::eLanguageTypeC_plus_plus, &metadata); - lldbassert(ct.IsValid()); + CompilerType ct = CreateClangDeclFromMangledName(*m_clang, unique_name); clang::CXXRecordDecl *record_decl = m_clang->GetAsCXXRecordDecl(ct.GetOpaqueQualType()); @@ -771,7 +756,7 @@ // FIXME: Search IPI stream for LF_UDT_MOD_SRC_LINE. Declaration decl; return std::make_shared(type_uid.toOpaqueId(), m_clang->GetSymbolFile(), - ConstString(name), size, nullptr, + ct.GetTypeName(), size, nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct, Type::eResolveStateForward); } @@ -782,14 +767,15 @@ clang::MSInheritanceAttr::Spelling inheritance = GetMSInheritance(m_index->tpi().typeCollection(), cr); - return CreateClassStructUnion(type_uid, cr.getName(), cr.getSize(), ttk, - inheritance); + return CreateClassStructUnion(type_uid, cr.getName(), cr.getUniqueName(), + cr.getSize(), ttk, inheritance); } lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbSymUid type_uid, const UnionRecord &ur) { return CreateClassStructUnion( - type_uid, ur.getName(), ur.getSize(), clang::TTK_Union, + type_uid, ur.getName(), ur.getUniqueName(), ur.getSize(), + clang::TTK_Union, clang::MSInheritanceAttr::Spelling::Keyword_single_inheritance); }