Index: lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp +++ lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp @@ -745,9 +745,8 @@ m_cxx_record_map); auto error = llvm::codeview::visitMemberRecordStream(field_list_cvt.data(), completer); - completer.complete(); + completer.complete(status.resolved); - status.resolved = true; if (!error) return true; @@ -1230,8 +1229,10 @@ clang::QualType PdbAstBuilder::CreateArrayType(const ArrayRecord &ar) { clang::QualType element_type = GetOrCreateType(ar.ElementType); - uint64_t element_count = - ar.Size / GetSizeOfType({ar.ElementType}, m_index.tpi()); + uint64_t size = GetSizeOfType({ar.ElementType}, m_index.tpi()); + if (size == 0) + return {}; + uint64_t element_count = ar.Size / size; CompilerType array_ct = m_clang.CreateArrayType(ToCompilerType(element_type), element_count, false); Index: lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h +++ lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h @@ -57,6 +57,7 @@ llvm::DenseMap, 8>> &m_cxx_record_map; + std::vector m_static_members; public: UdtRecordCompleter( @@ -72,7 +73,7 @@ #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #include "llvm/DebugInfo/CodeView/CodeViewTypes.def" - void complete(); + void complete(bool &resolved); private: clang::QualType AddBaseClassForTypeIndex( @@ -82,6 +83,7 @@ llvm::codeview::MemberAccess access, llvm::codeview::MethodOptions options, llvm::codeview::MemberAttributes attrs); + void VisitStaticDataMemberRecords(); }; } // namespace npdb Index: lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp +++ lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp @@ -101,40 +101,8 @@ m_cxx_record_map[derived_opaque_ty].insert({name, method_ct}); } -Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, - BaseClassRecord &base) { - clang::QualType base_qt = - AddBaseClassForTypeIndex(base.Type, base.getAccess()); - - auto decl = - m_ast_builder.clang().GetAsCXXRecordDecl(base_qt.getAsOpaquePtr()); - lldbassert(decl); - - auto offset = clang::CharUnits::fromQuantity(base.getBaseOffset()); - m_layout.base_offsets.insert(std::make_pair(decl, offset)); - - return llvm::Error::success(); -} - -Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, - VirtualBaseClassRecord &base) { - AddBaseClassForTypeIndex(base.BaseType, base.getAccess(), base.VTableIndex); - - return Error::success(); -} - -Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, - ListContinuationRecord &cont) { - return Error::success(); -} - -Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, - VFPtrRecord &vfptr) { - return Error::success(); -} - -Error UdtRecordCompleter::visitKnownMember( - CVMemberRecord &cvr, StaticDataMemberRecord &static_data_member) { +void UdtRecordCompleter::VisitStaticDataMemberRecords() { + for (auto &static_data_member : m_static_members) { clang::QualType member_type = m_ast_builder.GetOrCreateType(PdbTypeSymId(static_data_member.Type)); @@ -207,9 +175,49 @@ } } } - + } // FIXME: Add a PdbSymUid namespace for field list members and update // the m_uid_to_decl map with this decl. +} + +Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, + BaseClassRecord &base) { + clang::QualType base_qt = + AddBaseClassForTypeIndex(base.Type, base.getAccess()); + + auto decl = + m_ast_builder.clang().GetAsCXXRecordDecl(base_qt.getAsOpaquePtr()); + lldbassert(decl); + + auto offset = clang::CharUnits::fromQuantity(base.getBaseOffset()); + m_layout.base_offsets.insert(std::make_pair(decl, offset)); + + return llvm::Error::success(); +} + +Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, + VirtualBaseClassRecord &base) { + AddBaseClassForTypeIndex(base.BaseType, base.getAccess(), base.VTableIndex); + + return Error::success(); +} + +Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, + ListContinuationRecord &cont) { + return Error::success(); +} + +Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, + VFPtrRecord &vfptr) { + return Error::success(); +} + +Error UdtRecordCompleter::visitKnownMember( + CVMemberRecord &cvr, StaticDataMemberRecord &static_data_member) { + // In the case of a static member has the type of the record, it will cause + // infinite recursion if we try to complete its type here. Visit static data + // member after completing this record to prevent that. + m_static_members.push_back(static_data_member); return Error::success(); } @@ -288,7 +296,7 @@ return Error::success(); } -void UdtRecordCompleter::complete() { +void UdtRecordCompleter::complete(bool &resolved) { // Ensure the correct order for virtual bases. std::stable_sort(m_bases.begin(), m_bases.end(), [](const IndexedBase &lhs, const IndexedBase &rhs) { @@ -310,4 +318,6 @@ if (auto *record_decl = llvm::dyn_cast(&m_tag_decl)) { m_ast_builder.importer().SetRecordLayout(record_decl, m_layout); } + resolved = true; + VisitStaticDataMemberRecords(); } Index: lldb/test/Shell/SymbolFile/NativePDB/Inputs/local-variables.lldbinit =================================================================== --- lldb/test/Shell/SymbolFile/NativePDB/Inputs/local-variables.lldbinit +++ lldb/test/Shell/SymbolFile/NativePDB/Inputs/local-variables.lldbinit @@ -25,6 +25,8 @@ p Param2 p Local1 p Local2 +p varA.val +p varB.val continue target modules dump ast Index: lldb/test/Shell/SymbolFile/NativePDB/local-variables.cpp =================================================================== --- lldb/test/Shell/SymbolFile/NativePDB/local-variables.cpp +++ lldb/test/Shell/SymbolFile/NativePDB/local-variables.cpp @@ -5,6 +5,26 @@ // RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \ // RUN: %p/Inputs/local-variables.lldbinit 2>&1 | FileCheck %s +class B; +class A { +public: + static const A constA; + static A a; + static B b; + int val = 1; +}; +class B { +public: + static A a; + int val = 2; +}; +A varA; +B varB; +const A A::constA = varA; +A A::a = varA; +B A::b = varB; +A B::a = varA; + int Function(int Param1, char Param2) { unsigned Local1 = Param1 + 1; char Local2 = Param2 + 1; @@ -15,7 +35,7 @@ int main(int argc, char **argv) { int SomeLocal = argc * 2; - return Function(SomeLocal, 'a'); + return varA.val + varB.val + Function(SomeLocal, 'a'); } // CHECK: (lldb) target create "{{.*}}local-variables.cpp.tmp.exe" @@ -28,13 +48,13 @@ // CHECK-NEXT: Process {{.*}} stopped // CHECK-NEXT: * thread #1, stop reason = breakpoint 1.1 // CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`main(argc=8, argv={{.*}}) at local-variables.cpp:{{.*}} -// CHECK-NEXT: 14 } -// CHECK-NEXT: 15 -// CHECK-NEXT: 16 int main(int argc, char **argv) { -// CHECK-NEXT: -> 17 int SomeLocal = argc * 2; -// CHECK-NEXT: 18 return Function(SomeLocal, 'a'); -// CHECK-NEXT: 19 } -// CHECK-NEXT: 20 +// CHECK-NEXT: 34 } +// CHECK-NEXT: 35 +// CHECK-NEXT: 36 int main(int argc, char **argv) { +// CHECK-NEXT: -> 37 int SomeLocal = argc * 2; +// CHECK-NEXT: 38 return varA.val + varB.val + Function(SomeLocal, 'a'); +// CHECK-NEXT: 39 } +// CHECK-NEXT: 40 // CHECK: Process {{.*}} launched: '{{.*}}local-variables.cpp.tmp.exe' // CHECK-NEXT: (lldb) p argc @@ -43,12 +63,12 @@ // CHECK-NEXT: Process {{.*}} stopped // CHECK-NEXT: * thread #1, stop reason = step in // CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`main(argc=8, argv={{.*}}) at local-variables.cpp:{{.*}} -// CHECK-NEXT: 15 -// CHECK-NEXT: 16 int main(int argc, char **argv) { -// CHECK-NEXT: 17 int SomeLocal = argc * 2; -// CHECK-NEXT: -> 18 return Function(SomeLocal, 'a'); -// CHECK-NEXT: 19 } -// CHECK-NEXT: 20 +// CHECK-NEXT: 35 +// CHECK-NEXT: 36 int main(int argc, char **argv) { +// CHECK-NEXT: 37 int SomeLocal = argc * 2; +// CHECK-NEXT: -> 38 return varA.val + varB.val + Function(SomeLocal, 'a'); +// CHECK-NEXT: 39 } +// CHECK-NEXT: 40 // CHECK: (lldb) p SomeLocal // CHECK-NEXT: (int) $1 = 16 @@ -56,13 +76,13 @@ // CHECK-NEXT: Process {{.*}} stopped // CHECK-NEXT: * thread #1, stop reason = step in // CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}} -// CHECK-NEXT: 6 -// CHECK-NEXT: 7 -// CHECK-NEXT: 8 int Function(int Param1, char Param2) { -// CHECK-NEXT: -> 9 unsigned Local1 = Param1 + 1; -// CHECK-NEXT: 10 char Local2 = Param2 + 1; -// CHECK-NEXT: 11 ++Local1; -// CHECK-NEXT: 12 ++Local2; +// CHECK-NEXT: 26 +// CHECK-NEXT: 27 +// CHECK-NEXT: 28 int Function(int Param1, char Param2) { +// CHECK-NEXT: -> 29 unsigned Local1 = Param1 + 1; +// CHECK-NEXT: 30 char Local2 = Param2 + 1; +// CHECK-NEXT: 31 ++Local1; +// CHECK-NEXT: 32 ++Local2; // CHECK: (lldb) p Param1 // CHECK-NEXT: (int) $2 = 16 @@ -72,13 +92,13 @@ // CHECK-NEXT: Process {{.*}} stopped // CHECK-NEXT: * thread #1, stop reason = step in // CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}} -// CHECK-NEXT: 7 -// CHECK-NEXT: 8 int Function(int Param1, char Param2) { -// CHECK-NEXT: 9 unsigned Local1 = Param1 + 1; -// CHECK-NEXT: -> 10 char Local2 = Param2 + 1; -// CHECK-NEXT: 11 ++Local1; -// CHECK-NEXT: 12 ++Local2; -// CHECK-NEXT: 13 return Local1; +// CHECK-NEXT: 27 +// CHECK-NEXT: 28 int Function(int Param1, char Param2) { +// CHECK-NEXT: 29 unsigned Local1 = Param1 + 1; +// CHECK-NEXT: -> 30 char Local2 = Param2 + 1; +// CHECK-NEXT: 31 ++Local1; +// CHECK-NEXT: 32 ++Local2; +// CHECK-NEXT: 33 return Local1; // CHECK: (lldb) p Param1 // CHECK-NEXT: (int) $4 = 16 @@ -90,13 +110,13 @@ // CHECK-NEXT: Process {{.*}} stopped // CHECK-NEXT: * thread #1, stop reason = step in // CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}} -// CHECK-NEXT: 8 int Function(int Param1, char Param2) { -// CHECK-NEXT: 9 unsigned Local1 = Param1 + 1; -// CHECK-NEXT: 10 char Local2 = Param2 + 1; -// CHECK-NEXT: -> 11 ++Local1; -// CHECK-NEXT: 12 ++Local2; -// CHECK-NEXT: 13 return Local1; -// CHECK-NEXT: 14 } +// CHECK-NEXT: 28 int Function(int Param1, char Param2) { +// CHECK-NEXT: 29 unsigned Local1 = Param1 + 1; +// CHECK-NEXT: 30 char Local2 = Param2 + 1; +// CHECK-NEXT: -> 31 ++Local1; +// CHECK-NEXT: 32 ++Local2; +// CHECK-NEXT: 33 return Local1; +// CHECK-NEXT: 34 } // CHECK: (lldb) p Param1 // CHECK-NEXT: (int) $7 = 16 @@ -110,13 +130,13 @@ // CHECK-NEXT: Process {{.*}} stopped // CHECK-NEXT: * thread #1, stop reason = step in // CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}} -// CHECK-NEXT: 9 unsigned Local1 = Param1 + 1; -// CHECK-NEXT: 10 char Local2 = Param2 + 1; -// CHECK-NEXT: 11 ++Local1; -// CHECK-NEXT: -> 12 ++Local2; -// CHECK-NEXT: 13 return Local1; -// CHECK-NEXT: 14 } -// CHECK-NEXT: 15 +// CHECK-NEXT: 29 unsigned Local1 = Param1 + 1; +// CHECK-NEXT: 30 char Local2 = Param2 + 1; +// CHECK-NEXT: 31 ++Local1; +// CHECK-NEXT: -> 32 ++Local2; +// CHECK-NEXT: 33 return Local1; +// CHECK-NEXT: 34 } +// CHECK-NEXT: 35 // CHECK: (lldb) p Param1 // CHECK-NEXT: (int) $11 = 16 @@ -130,13 +150,13 @@ // CHECK-NEXT: Process {{.*}} stopped // CHECK-NEXT: * thread #1, stop reason = step in // CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}} -// CHECK-NEXT: 10 char Local2 = Param2 + 1; -// CHECK-NEXT: 11 ++Local1; -// CHECK-NEXT: 12 ++Local2; -// CHECK-NEXT: -> 13 return Local1; -// CHECK-NEXT: 14 } -// CHECK-NEXT: 15 -// CHECK-NEXT: 16 int main(int argc, char **argv) { +// CHECK-NEXT: 30 char Local2 = Param2 + 1; +// CHECK-NEXT: 31 ++Local1; +// CHECK-NEXT: 32 ++Local2; +// CHECK-NEXT: -> 33 return Local1; +// CHECK-NEXT: 34 } +// CHECK-NEXT: 35 +// CHECK-NEXT: 36 int main(int argc, char **argv) { // CHECK: (lldb) p Param1 // CHECK-NEXT: (int) $15 = 16 @@ -146,9 +166,13 @@ // CHECK-NEXT: (unsigned int) $17 = 18 // CHECK-NEXT: (lldb) p Local2 // CHECK-NEXT: (char) $18 = 'c' +// CHECK-NEXT: (lldb) p varA.val +// CHECK-NEXT: (int) $19 = 1 +// CHECK-NEXT: (lldb) p varB.val +// CHECK-NEXT: (int) $20 = 2 // CHECK-NEXT: (lldb) continue // CHECK-NEXT: Process {{.*}} resuming -// CHECK-NEXT: Process {{.*}} exited with status = 18 (0x00000012) +// CHECK-NEXT: Process {{.*}} exited with status = 21 (0x00000015) // CHECK: (lldb) target modules dump ast // CHECK-NEXT: Dumping clang ast for {{.*}} modules. @@ -157,6 +181,6 @@ // CHECK-NEXT: | |-ParmVarDecl {{.*}} argc 'int' // CHECK-NEXT: | `-ParmVarDecl {{.*}} argv 'char **' // CHECK-NEXT: |-FunctionDecl {{.*}} __scrt_common_main_seh 'int ()' static -// CHECK-NEXT: `-FunctionDecl {{.*}} Function 'int (int, char)' +// CHECK-NEXT: |-FunctionDecl {{.*}} Function 'int (int, char)' // CHECK-NEXT: |-ParmVarDecl {{.*}} Param1 'int' // CHECK-NEXT: `-ParmVarDecl {{.*}} Param2 'char'