[Lldb-commits] [lldb] [LLDB][NativePDB] Allow type lookup in namespaces (PR #149876)
via lldb-commits
lldb-commits at lists.llvm.org
Mon Jul 28 03:20:11 PDT 2025
https://github.com/Nerixyz updated https://github.com/llvm/llvm-project/pull/149876
>From fa3c96b19ba174904036b031015a073cfd759c76 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Mon, 21 Jul 2025 20:32:58 +0200
Subject: [PATCH 1/4] [LLDB][NativePDB] Allow type lookup in namespaces
---
.../NativePDB/SymbolFileNativePDB.cpp | 58 ++++++++-
.../NativePDB/SymbolFileNativePDB.h | 4 +
lldb/source/Symbol/Type.cpp | 8 +-
.../Inputs/namespace-access.lldbinit | 18 +++
.../SymbolFile/NativePDB/namespace-access.cpp | 114 ++++++++++++++++++
5 files changed, 196 insertions(+), 6 deletions(-)
create mode 100644 lldb/test/Shell/SymbolFile/NativePDB/Inputs/namespace-access.lldbinit
create mode 100644 lldb/test/Shell/SymbolFile/NativePDB/namespace-access.cpp
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index 20d8c1acf9c42..5141632649dd5 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -1630,6 +1630,53 @@ size_t SymbolFileNativePDB::ParseSymbolArrayInScope(
return count;
}
+void SymbolFileNativePDB::CacheTypeNames() {
+ if (!m_type_base_names.IsEmpty())
+ return;
+
+ LazyRandomTypeCollection &types = m_index->tpi().typeCollection();
+ for (auto ti = types.getFirst(); ti; ti = types.getNext(*ti)) {
+ CVType cvt = types.getType(*ti);
+ llvm::StringRef name;
+ // We are only interested in records, unions, and enums.
+ // We aren't interested in forward references as we'll visit the actual
+ // type later anyway.
+ switch (cvt.kind()) {
+ case LF_STRUCTURE:
+ case LF_CLASS: {
+ ClassRecord cr;
+ llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr));
+ if (cr.isForwardRef())
+ continue;
+ name = cr.Name;
+ } break;
+ case LF_UNION: {
+ UnionRecord ur;
+ llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur));
+ if (ur.isForwardRef())
+ continue;
+ name = ur.Name;
+ } break;
+ case LF_ENUM: {
+ EnumRecord er;
+ llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
+ if (er.isForwardRef())
+ continue;
+ name = er.Name;
+ } break;
+ default:
+ continue;
+ }
+ if (name.empty())
+ continue;
+
+ auto base_name = MSVCUndecoratedNameParser::DropScope(name);
+ m_type_base_names.Append(ConstString(base_name), ti->getIndex());
+ }
+
+ m_type_base_names.Sort();
+}
+
void SymbolFileNativePDB::DumpClangAST(Stream &s, llvm::StringRef filter) {
auto ts_or_err = GetTypeSystemForLanguage(eLanguageTypeC_plus_plus);
if (!ts_or_err)
@@ -1720,11 +1767,14 @@ void SymbolFileNativePDB::FindTypes(const lldb_private::TypeQuery &query,
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
- std::vector<TypeIndex> matches =
- m_index->tpi().findRecordsByName(query.GetTypeBasename().GetStringRef());
+ // We can't query for the basename or full name because the type might reside
+ // in an anonymous namespace. Cache the basenames first.
+ CacheTypeNames();
+ std::vector<uint32_t> matches;
+ m_type_base_names.GetValues(query.GetTypeBasename(), matches);
- for (TypeIndex type_idx : matches) {
- TypeSP type_sp = GetOrCreateType(type_idx);
+ for (uint32_t match_idx : matches) {
+ TypeSP type_sp = GetOrCreateType(TypeIndex(match_idx));
if (!type_sp)
continue;
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
index 9891313f11d0b..457b301c4a486 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -258,6 +258,8 @@ class SymbolFileNativePDB : public SymbolFileCommon {
void ParseInlineSite(PdbCompilandSymId inline_site_id, Address func_addr);
+ void CacheTypeNames();
+
llvm::BumpPtrAllocator m_allocator;
lldb::addr_t m_obj_load_address = 0;
@@ -278,6 +280,8 @@ class SymbolFileNativePDB : public SymbolFileCommon {
llvm::DenseMap<lldb::user_id_t, std::shared_ptr<InlineSite>> m_inline_sites;
llvm::DenseMap<llvm::codeview::TypeIndex, llvm::codeview::TypeIndex>
m_parent_types;
+
+ lldb_private::UniqueCStringMap<uint32_t> m_type_base_names;
};
} // namespace npdb
diff --git a/lldb/source/Symbol/Type.cpp b/lldb/source/Symbol/Type.cpp
index 0a886e56100a1..ddb22d611140b 100644
--- a/lldb/source/Symbol/Type.cpp
+++ b/lldb/source/Symbol/Type.cpp
@@ -134,7 +134,9 @@ bool TypeQuery::ContextMatches(
if (ctx == ctx_end)
return false; // Pattern too long.
- if (ctx->kind == CompilerContextKind::Namespace && ctx->name.IsEmpty()) {
+ if ((ctx->kind & CompilerContextKind::Namespace) ==
+ CompilerContextKind::Namespace &&
+ ctx->name.IsEmpty()) {
// We're matching an anonymous namespace. These are optional, so we check
// if the pattern expects an anonymous namespace.
if (pat->name.IsEmpty() && (pat->kind & CompilerContextKind::Namespace) ==
@@ -164,7 +166,9 @@ bool TypeQuery::ContextMatches(
auto should_skip = [this](const CompilerContext &ctx) {
if (ctx.kind == CompilerContextKind::Module)
return GetIgnoreModules();
- if (ctx.kind == CompilerContextKind::Namespace && ctx.name.IsEmpty())
+ if ((ctx.kind & CompilerContextKind::Namespace) ==
+ CompilerContextKind::Namespace &&
+ ctx.name.IsEmpty())
return !GetStrictNamespaces();
return false;
};
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/Inputs/namespace-access.lldbinit b/lldb/test/Shell/SymbolFile/NativePDB/Inputs/namespace-access.lldbinit
new file mode 100644
index 0000000000000..e61ed2e2f453e
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/NativePDB/Inputs/namespace-access.lldbinit
@@ -0,0 +1,18 @@
+b main
+r
+
+type lookup S
+type lookup ::S
+type lookup Outer::S
+type lookup Outer::Inner1::S
+type lookup Inner1::S
+type lookup Outer::Inner1::Inner2::S
+type lookup Inner2::S
+type lookup Outer::Inner2::S
+type lookup Outer::A
+type lookup A
+type lookup ::A
+expr sizeof(S)
+expr sizeof(A)
+
+quit
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/namespace-access.cpp b/lldb/test/Shell/SymbolFile/NativePDB/namespace-access.cpp
new file mode 100644
index 0000000000000..e171d189347d9
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/NativePDB/namespace-access.cpp
@@ -0,0 +1,114 @@
+// clang-format off
+// REQUIRES: target-windows
+
+// Test namespace lookup.
+// RUN: %build --nodefaultlib -o %t.exe -- %s
+// RUN: %lldb -f %t.exe -s \
+// RUN: %p/Inputs/namespace-access.lldbinit 2>&1 | FileCheck %s
+
+struct S {
+ char a[1];
+};
+
+namespace Outer {
+
+ struct S {
+ char a[2];
+ };
+
+ namespace Inner1 {
+ struct S {
+ char a[3];
+ };
+
+ namespace Inner2 {
+ struct S {
+ char a[4];
+ };
+ } // namespace Inner2
+ } // namespace Inner1
+
+ namespace Inner2 {
+ struct S {
+ char a[5];
+ };
+ } // namespace Inner2
+
+ namespace {
+ struct A {
+ char a[6];
+ };
+ } // namespace
+
+} // namespace Outer
+
+namespace {
+ struct A {
+ char a[7];
+ };
+} // namespace
+
+int main(int argc, char **argv) {
+ S s;
+ Outer::S os;
+ Outer::Inner1::S oi1s;
+ Outer::Inner1::Inner2::S oi1i2s;
+ Outer::Inner2::S oi2s;
+ A a1;
+ Outer::A a2;
+ return sizeof(s) + sizeof(os) + sizeof(oi1s) + sizeof(oi1i2s) + sizeof(oi2s) + sizeof(a1) + sizeof(a2);
+}
+
+
+
+// CHECK: (lldb) type lookup S
+// CHECK: struct S {
+// CHECK: struct S {
+// CHECK: struct S {
+// CHECK: struct S {
+// CHECK: struct S {
+// CHECK: }
+// CHECK-NEXT: (lldb) type lookup ::S
+// CHECK-NEXT: struct S {
+// CHECK-NEXT: char a[1];
+// CHECK-NEXT: }
+// CHECK-NEXT: (lldb) type lookup Outer::S
+// CHECK-NEXT: struct S {
+// CHECK-NEXT: char a[2];
+// CHECK-NEXT: }
+// CHECK-NEXT: (lldb) type lookup Outer::Inner1::S
+// CHECK-NEXT: struct S {
+// CHECK-NEXT: char a[3];
+// CHECK-NEXT: }
+// CHECK-NEXT: (lldb) type lookup Inner1::S
+// CHECK-NEXT: struct S {
+// CHECK-NEXT: char a[3];
+// CHECK-NEXT: }
+// CHECK-NEXT: (lldb) type lookup Outer::Inner1::Inner2::S
+// CHECK-NEXT: struct S {
+// CHECK-NEXT: char a[4];
+// CHECK-NEXT: }
+// CHECK-NEXT: (lldb) type lookup Inner2::S
+// CHECK-NEXT: struct S {
+// CHECK: struct S {
+// CHECK: }
+// CHECK-NEXT: (lldb) type lookup Outer::Inner2::S
+// CHECK-NEXT: struct S {
+// CHECK-NEXT: char a[5];
+// CHECK-NEXT: }
+// CHECK-NEXT: (lldb) type lookup Outer::A
+// CHECK-NEXT: struct A {
+// CHECK-NEXT: char a[6];
+// CHECK-NEXT: }
+// CHECK-NEXT: (lldb) type lookup A
+// CHECK-NEXT: struct A {
+// CHECK: struct A {
+// CHECK: }
+// CHECK-NEXT: (lldb) type lookup ::A
+// CHECK-NEXT: struct A {
+// CHECK-NEXT: char a[7];
+// CHECK-NEXT: }
+// CHECK-NEXT: (lldb) expr sizeof(S)
+// CHECK-NEXT: (__size_t) $0 = 1
+// CHECK-NEXT: (lldb) expr sizeof(A)
+// CHECK-NEXT: (__size_t) $1 = 7
>From 288b5f7ddbca800509434f945495d972252f43a5 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Tue, 22 Jul 2025 14:35:34 +0200
Subject: [PATCH 2/4] refactor: move basename discovery to `BuildParentMap`
---
.../NativePDB/SymbolFileNativePDB.cpp | 61 +++----------------
.../NativePDB/SymbolFileNativePDB.h | 2 -
2 files changed, 10 insertions(+), 53 deletions(-)
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index 5141632649dd5..cae4c510a0e5f 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -1630,53 +1630,6 @@ size_t SymbolFileNativePDB::ParseSymbolArrayInScope(
return count;
}
-void SymbolFileNativePDB::CacheTypeNames() {
- if (!m_type_base_names.IsEmpty())
- return;
-
- LazyRandomTypeCollection &types = m_index->tpi().typeCollection();
- for (auto ti = types.getFirst(); ti; ti = types.getNext(*ti)) {
- CVType cvt = types.getType(*ti);
- llvm::StringRef name;
- // We are only interested in records, unions, and enums.
- // We aren't interested in forward references as we'll visit the actual
- // type later anyway.
- switch (cvt.kind()) {
- case LF_STRUCTURE:
- case LF_CLASS: {
- ClassRecord cr;
- llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr));
- if (cr.isForwardRef())
- continue;
- name = cr.Name;
- } break;
- case LF_UNION: {
- UnionRecord ur;
- llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur));
- if (ur.isForwardRef())
- continue;
- name = ur.Name;
- } break;
- case LF_ENUM: {
- EnumRecord er;
- llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
- if (er.isForwardRef())
- continue;
- name = er.Name;
- } break;
- default:
- continue;
- }
- if (name.empty())
- continue;
-
- auto base_name = MSVCUndecoratedNameParser::DropScope(name);
- m_type_base_names.Append(ConstString(base_name), ti->getIndex());
- }
-
- m_type_base_names.Sort();
-}
-
void SymbolFileNativePDB::DumpClangAST(Stream &s, llvm::StringRef filter) {
auto ts_or_err = GetTypeSystemForLanguage(eLanguageTypeC_plus_plus);
if (!ts_or_err)
@@ -1767,9 +1720,9 @@ void SymbolFileNativePDB::FindTypes(const lldb_private::TypeQuery &query,
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
- // We can't query for the basename or full name because the type might reside
- // in an anonymous namespace. Cache the basenames first.
- CacheTypeNames();
+ // We can't query for the full name because the type might reside
+ // in an anonymous namespace. Search for the basename in our map and check the
+ // matching types afterwards.
std::vector<uint32_t> matches;
m_type_base_names.GetValues(query.GetTypeBasename(), matches);
@@ -2253,9 +2206,13 @@ void SymbolFileNativePDB::BuildParentMap() {
RecordIndices &indices = record_indices[tag.asTag().getUniqueName()];
if (tag.asTag().isForwardRef())
indices.forward = *ti;
- else
+ else {
indices.full = *ti;
+ auto base_name = MSVCUndecoratedNameParser::DropScope(tag.name());
+ m_type_base_names.Append(ConstString(base_name), ti->getIndex());
+ }
+
if (indices.full != TypeIndex::None() &&
indices.forward != TypeIndex::None()) {
forward_to_full[indices.forward] = indices.full;
@@ -2341,6 +2298,8 @@ void SymbolFileNativePDB::BuildParentMap() {
TypeIndex fwd = full_to_forward[full];
m_parent_types[fwd] = m_parent_types[full];
}
+
+ m_type_base_names.Sort();
}
std::optional<PdbCompilandSymId>
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
index 457b301c4a486..02e56484d7525 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -258,8 +258,6 @@ class SymbolFileNativePDB : public SymbolFileCommon {
void ParseInlineSite(PdbCompilandSymId inline_site_id, Address func_addr);
- void CacheTypeNames();
-
llvm::BumpPtrAllocator m_allocator;
lldb::addr_t m_obj_load_address = 0;
>From 1dbde101df5aa51cc31f789da2545a75a3cf4475 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Mon, 28 Jul 2025 12:19:38 +0200
Subject: [PATCH 3/4] refactor: convert test to use split-file
---
.../Inputs/namespace-access.lldbinit | 18 ---
.../SymbolFile/NativePDB/namespace-access.cpp | 114 ---------------
.../NativePDB/namespace-access.test | 135 ++++++++++++++++++
3 files changed, 135 insertions(+), 132 deletions(-)
delete mode 100644 lldb/test/Shell/SymbolFile/NativePDB/Inputs/namespace-access.lldbinit
delete mode 100644 lldb/test/Shell/SymbolFile/NativePDB/namespace-access.cpp
create mode 100644 lldb/test/Shell/SymbolFile/NativePDB/namespace-access.test
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/Inputs/namespace-access.lldbinit b/lldb/test/Shell/SymbolFile/NativePDB/Inputs/namespace-access.lldbinit
deleted file mode 100644
index e61ed2e2f453e..0000000000000
--- a/lldb/test/Shell/SymbolFile/NativePDB/Inputs/namespace-access.lldbinit
+++ /dev/null
@@ -1,18 +0,0 @@
-b main
-r
-
-type lookup S
-type lookup ::S
-type lookup Outer::S
-type lookup Outer::Inner1::S
-type lookup Inner1::S
-type lookup Outer::Inner1::Inner2::S
-type lookup Inner2::S
-type lookup Outer::Inner2::S
-type lookup Outer::A
-type lookup A
-type lookup ::A
-expr sizeof(S)
-expr sizeof(A)
-
-quit
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/namespace-access.cpp b/lldb/test/Shell/SymbolFile/NativePDB/namespace-access.cpp
deleted file mode 100644
index e171d189347d9..0000000000000
--- a/lldb/test/Shell/SymbolFile/NativePDB/namespace-access.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-// clang-format off
-// REQUIRES: target-windows
-
-// Test namespace lookup.
-// RUN: %build --nodefaultlib -o %t.exe -- %s
-// RUN: %lldb -f %t.exe -s \
-// RUN: %p/Inputs/namespace-access.lldbinit 2>&1 | FileCheck %s
-
-struct S {
- char a[1];
-};
-
-namespace Outer {
-
- struct S {
- char a[2];
- };
-
- namespace Inner1 {
- struct S {
- char a[3];
- };
-
- namespace Inner2 {
- struct S {
- char a[4];
- };
- } // namespace Inner2
- } // namespace Inner1
-
- namespace Inner2 {
- struct S {
- char a[5];
- };
- } // namespace Inner2
-
- namespace {
- struct A {
- char a[6];
- };
- } // namespace
-
-} // namespace Outer
-
-namespace {
- struct A {
- char a[7];
- };
-} // namespace
-
-int main(int argc, char **argv) {
- S s;
- Outer::S os;
- Outer::Inner1::S oi1s;
- Outer::Inner1::Inner2::S oi1i2s;
- Outer::Inner2::S oi2s;
- A a1;
- Outer::A a2;
- return sizeof(s) + sizeof(os) + sizeof(oi1s) + sizeof(oi1i2s) + sizeof(oi2s) + sizeof(a1) + sizeof(a2);
-}
-
-
-
-// CHECK: (lldb) type lookup S
-// CHECK: struct S {
-// CHECK: struct S {
-// CHECK: struct S {
-// CHECK: struct S {
-// CHECK: struct S {
-// CHECK: }
-// CHECK-NEXT: (lldb) type lookup ::S
-// CHECK-NEXT: struct S {
-// CHECK-NEXT: char a[1];
-// CHECK-NEXT: }
-// CHECK-NEXT: (lldb) type lookup Outer::S
-// CHECK-NEXT: struct S {
-// CHECK-NEXT: char a[2];
-// CHECK-NEXT: }
-// CHECK-NEXT: (lldb) type lookup Outer::Inner1::S
-// CHECK-NEXT: struct S {
-// CHECK-NEXT: char a[3];
-// CHECK-NEXT: }
-// CHECK-NEXT: (lldb) type lookup Inner1::S
-// CHECK-NEXT: struct S {
-// CHECK-NEXT: char a[3];
-// CHECK-NEXT: }
-// CHECK-NEXT: (lldb) type lookup Outer::Inner1::Inner2::S
-// CHECK-NEXT: struct S {
-// CHECK-NEXT: char a[4];
-// CHECK-NEXT: }
-// CHECK-NEXT: (lldb) type lookup Inner2::S
-// CHECK-NEXT: struct S {
-// CHECK: struct S {
-// CHECK: }
-// CHECK-NEXT: (lldb) type lookup Outer::Inner2::S
-// CHECK-NEXT: struct S {
-// CHECK-NEXT: char a[5];
-// CHECK-NEXT: }
-// CHECK-NEXT: (lldb) type lookup Outer::A
-// CHECK-NEXT: struct A {
-// CHECK-NEXT: char a[6];
-// CHECK-NEXT: }
-// CHECK-NEXT: (lldb) type lookup A
-// CHECK-NEXT: struct A {
-// CHECK: struct A {
-// CHECK: }
-// CHECK-NEXT: (lldb) type lookup ::A
-// CHECK-NEXT: struct A {
-// CHECK-NEXT: char a[7];
-// CHECK-NEXT: }
-// CHECK-NEXT: (lldb) expr sizeof(S)
-// CHECK-NEXT: (__size_t) $0 = 1
-// CHECK-NEXT: (lldb) expr sizeof(A)
-// CHECK-NEXT: (__size_t) $1 = 7
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/namespace-access.test b/lldb/test/Shell/SymbolFile/NativePDB/namespace-access.test
new file mode 100644
index 0000000000000..f6c1ccf22fa18
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/NativePDB/namespace-access.test
@@ -0,0 +1,135 @@
+# REQUIRES: target-windows
+
+# Test namespace lookup.
+# RUN: split-file %s %t
+# RUN: %build --nodefaultlib -o %t.exe -- %t/main.cpp
+# RUN: %lldb -f %t.exe -s \
+# RUN: %t/commands.input 2>&1 | FileCheck %s
+
+#--- main.cpp
+
+struct S {
+ char a[1];
+};
+
+namespace Outer {
+
+ struct S {
+ char a[2];
+ };
+
+ namespace Inner1 {
+ struct S {
+ char a[3];
+ };
+
+ namespace Inner2 {
+ struct S {
+ char a[4];
+ };
+ } // namespace Inner2
+ } // namespace Inner1
+
+ namespace Inner2 {
+ struct S {
+ char a[5];
+ };
+ } // namespace Inner2
+
+ namespace {
+ struct A {
+ char a[6];
+ };
+ } // namespace
+
+} // namespace Outer
+
+namespace {
+ struct A {
+ char a[7];
+ };
+} // namespace
+
+int main(int argc, char **argv) {
+ S s;
+ Outer::S os;
+ Outer::Inner1::S oi1s;
+ Outer::Inner1::Inner2::S oi1i2s;
+ Outer::Inner2::S oi2s;
+ A a1;
+ Outer::A a2;
+ return sizeof(s) + sizeof(os) + sizeof(oi1s) + sizeof(oi1i2s) + sizeof(oi2s) + sizeof(a1) + sizeof(a2);
+}
+
+#--- commands.input
+
+b main
+r
+
+type lookup S
+type lookup ::S
+type lookup Outer::S
+type lookup Outer::Inner1::S
+type lookup Inner1::S
+type lookup Outer::Inner1::Inner2::S
+type lookup Inner2::S
+type lookup Outer::Inner2::S
+type lookup Outer::A
+type lookup A
+type lookup ::A
+expr sizeof(S)
+expr sizeof(A)
+
+quit
+
+# CHECK: (lldb) type lookup S
+# CHECK: struct S {
+# CHECK: struct S {
+# CHECK: struct S {
+# CHECK: struct S {
+# CHECK: struct S {
+# CHECK: }
+# CHECK-NEXT: (lldb) type lookup ::S
+# CHECK-NEXT: struct S {
+# CHECK-NEXT: char a[1];
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) type lookup Outer::S
+# CHECK-NEXT: struct S {
+# CHECK-NEXT: char a[2];
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) type lookup Outer::Inner1::S
+# CHECK-NEXT: struct S {
+# CHECK-NEXT: char a[3];
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) type lookup Inner1::S
+# CHECK-NEXT: struct S {
+# CHECK-NEXT: char a[3];
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) type lookup Outer::Inner1::Inner2::S
+# CHECK-NEXT: struct S {
+# CHECK-NEXT: char a[4];
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) type lookup Inner2::S
+# CHECK-NEXT: struct S {
+# CHECK: struct S {
+# CHECK: }
+# CHECK-NEXT: (lldb) type lookup Outer::Inner2::S
+# CHECK-NEXT: struct S {
+# CHECK-NEXT: char a[5];
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) type lookup Outer::A
+# CHECK-NEXT: struct A {
+# CHECK-NEXT: char a[6];
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) type lookup A
+# CHECK-NEXT: struct A {
+# CHECK: struct A {
+# CHECK: }
+# CHECK-NEXT: (lldb) type lookup ::A
+# CHECK-NEXT: struct A {
+# CHECK-NEXT: char a[7];
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) expr sizeof(S)
+# CHECK-NEXT: (__size_t) $0 = 1
+# CHECK-NEXT: (lldb) expr sizeof(A)
+# CHECK-NEXT: (__size_t) $1 = 7
>From 8344a98e1302081e2c71475e914b3d041d80f175 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Mon, 28 Jul 2025 12:19:55 +0200
Subject: [PATCH 4/4] refactor: create context in symbol file plugin
---
.../Plugins/SymbolFile/NativePDB/PdbUtil.h | 8 +++
.../NativePDB/SymbolFileNativePDB.cpp | 62 +++++++++++++++++--
.../NativePDB/SymbolFileNativePDB.h | 2 +
lldb/source/Symbol/Type.cpp | 14 ++---
4 files changed, 72 insertions(+), 14 deletions(-)
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
index 1f888f4de1fed..505224c207fc9 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
@@ -72,6 +72,14 @@ struct CVTagRecord {
return cvunion.Name;
}
+ CompilerContextKind contextKind() const {
+ if (m_kind == Struct || m_kind == Class)
+ return CompilerContextKind::ClassOrStruct;
+ if (m_kind == Enum)
+ return CompilerContextKind::Enum;
+ return CompilerContextKind::Union;
+ }
+
private:
CVTagRecord(llvm::codeview::ClassRecord &&c);
CVTagRecord(llvm::codeview::UnionRecord &&u);
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index cae4c510a0e5f..71cfb4b360f62 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -1727,14 +1727,15 @@ void SymbolFileNativePDB::FindTypes(const lldb_private::TypeQuery &query,
m_type_base_names.GetValues(query.GetTypeBasename(), matches);
for (uint32_t match_idx : matches) {
- TypeSP type_sp = GetOrCreateType(TypeIndex(match_idx));
- if (!type_sp)
+ std::vector context = GetContextForType(TypeIndex(match_idx));
+ if (context.empty())
continue;
- // We resolved a type. Get the fully qualified name to ensure it matches.
- ConstString name = type_sp->GetQualifiedName();
- TypeQuery type_match(name.GetStringRef(), TypeQueryOptions::e_exact_match);
- if (query.ContextMatches(type_match.GetContextRef())) {
+ if (query.ContextMatches(context)) {
+ TypeSP type_sp = GetOrCreateType(TypeIndex(match_idx));
+ if (!type_sp)
+ continue;
+
results.InsertUnique(type_sp);
if (results.Done(query))
return;
@@ -2362,3 +2363,52 @@ SymbolFileNativePDB::GetParentType(llvm::codeview::TypeIndex ti) {
return std::nullopt;
return parent_iter->second;
}
+
+std::vector<CompilerContext>
+SymbolFileNativePDB::GetContextForType(TypeIndex ti) {
+ CVType type = m_index->tpi().getType(ti);
+ if (!IsTagRecord(type))
+ return {};
+
+ CVTagRecord tag = CVTagRecord::create(type);
+
+ std::optional<Type::ParsedName> parsed_name =
+ Type::GetTypeScopeAndBasename(tag.name());
+ if (!parsed_name)
+ return {{tag.contextKind(), ConstString(tag.name())}};
+
+ std::vector<CompilerContext> ctx;
+ // assume everything is a namespace at first
+ for (llvm::StringRef scope : parsed_name->scope) {
+ ctx.emplace_back(CompilerContextKind::Namespace, ConstString(scope));
+ }
+ // we know the kind of our own type
+ ctx.emplace_back(tag.contextKind(), ConstString(parsed_name->basename));
+
+ // try to find the kind of parents
+ for (auto &el : llvm::reverse(llvm::drop_end(ctx))) {
+ std::optional<TypeIndex> parent = GetParentType(ti);
+ if (!parent)
+ break;
+
+ ti = *parent;
+ type = m_index->tpi().getType(ti);
+ switch (type.kind()) {
+ case LF_CLASS:
+ case LF_STRUCTURE:
+ case LF_INTERFACE:
+ el.kind = CompilerContextKind::ClassOrStruct;
+ continue;
+ case LF_UNION:
+ el.kind = CompilerContextKind::Union;
+ continue;
+ case LF_ENUM:
+ el.kind = CompilerContextKind::Enum;
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
+ return ctx;
+}
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
index 02e56484d7525..eda375d4cebe7 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -258,6 +258,8 @@ class SymbolFileNativePDB : public SymbolFileCommon {
void ParseInlineSite(PdbCompilandSymId inline_site_id, Address func_addr);
+ std::vector<CompilerContext> GetContextForType(llvm::codeview::TypeIndex ti);
+
llvm::BumpPtrAllocator m_allocator;
lldb::addr_t m_obj_load_address = 0;
diff --git a/lldb/source/Symbol/Type.cpp b/lldb/source/Symbol/Type.cpp
index ddb22d611140b..c20dd87aeb3b5 100644
--- a/lldb/source/Symbol/Type.cpp
+++ b/lldb/source/Symbol/Type.cpp
@@ -134,9 +134,7 @@ bool TypeQuery::ContextMatches(
if (ctx == ctx_end)
return false; // Pattern too long.
- if ((ctx->kind & CompilerContextKind::Namespace) ==
- CompilerContextKind::Namespace &&
- ctx->name.IsEmpty()) {
+ if (ctx->kind == CompilerContextKind::Namespace && ctx->name.IsEmpty()) {
// We're matching an anonymous namespace. These are optional, so we check
// if the pattern expects an anonymous namespace.
if (pat->name.IsEmpty() && (pat->kind & CompilerContextKind::Namespace) ==
@@ -166,9 +164,7 @@ bool TypeQuery::ContextMatches(
auto should_skip = [this](const CompilerContext &ctx) {
if (ctx.kind == CompilerContextKind::Module)
return GetIgnoreModules();
- if ((ctx.kind & CompilerContextKind::Namespace) ==
- CompilerContextKind::Namespace &&
- ctx.name.IsEmpty())
+ if (ctx.kind == CompilerContextKind::Namespace && ctx.name.IsEmpty())
return !GetStrictNamespaces();
return false;
};
@@ -820,10 +816,12 @@ Type::GetTypeScopeAndBasename(llvm::StringRef name) {
case ':':
if (prev_is_colon && template_depth == 0) {
llvm::StringRef scope_name = name.slice(name_begin, pos.index() - 1);
- // The itanium demangler uses this string to represent anonymous
+ // The demanglers use these strings to represent anonymous
// namespaces. Convert it to a more language-agnostic form (which is
// also used in DWARF).
- if (scope_name == "(anonymous namespace)")
+ if (scope_name == "(anonymous namespace)" ||
+ scope_name == "`anonymous namespace'" ||
+ scope_name == "`anonymous-namespace'")
scope_name = "";
result.scope.push_back(scope_name);
name_begin = pos.index() + 1;
More information about the lldb-commits
mailing list