[Lldb-commits] [lldb] [LLDB][NativePDB] Find functions by basename (PR #152295)
via lldb-commits
lldb-commits at lists.llvm.org
Fri Aug 8 12:19:03 PDT 2025
https://github.com/Nerixyz updated https://github.com/llvm/llvm-project/pull/152295
>From b6886d625c55e7f2cfbbbc699ffaf0791ea192ff Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Wed, 6 Aug 2025 13:30:38 +0200
Subject: [PATCH 1/5] [LLDB][NativePDB] Find functions by basename
---
.../NativePDB/SymbolFileNativePDB.cpp | 149 +++++++++++++++---
.../NativePDB/SymbolFileNativePDB.h | 9 ++
.../SymbolFile/NativePDB/find-functions.cpp | 34 ++++
3 files changed, 173 insertions(+), 19 deletions(-)
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index dcea33dd9f854..04a3b9b7b87a2 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -39,6 +39,7 @@
#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
#include "llvm/DebugInfo/PDB/PDB.h"
@@ -1641,6 +1642,94 @@ void SymbolFileNativePDB::DumpClangAST(Stream &s, llvm::StringRef filter) {
clang->GetNativePDBParser()->Dump(s, filter);
}
+void SymbolFileNativePDB::CacheFunctionNames() {
+ if (!m_func_full_names.IsEmpty())
+ return;
+
+ // (segment, code offset) -> gid
+ std::map<std::pair<uint16_t, uint32_t>, uint32_t> addr_ids;
+
+ // First, find all function references in the globals table.
+ for (const uint32_t gid : m_index->globals().getGlobalsTable()) {
+ CVSymbol ref_sym = m_index->symrecords().readRecord(gid);
+ auto kind = ref_sym.kind();
+ if (kind != S_PROCREF && kind != S_LPROCREF)
+ continue;
+
+ ProcRefSym ref =
+ llvm::cantFail(SymbolDeserializer::deserializeAs<ProcRefSym>(ref_sym));
+ if (ref.Name.empty())
+ continue;
+
+ // Find the function this is referencing
+ CompilandIndexItem &cci =
+ m_index->compilands().GetOrCreateCompiland(ref.modi());
+ auto iter = cci.m_debug_stream.getSymbolArray().at(ref.SymOffset);
+ if (iter == cci.m_debug_stream.getSymbolArray().end())
+ continue;
+ kind = iter->kind();
+ if (kind != S_GPROC32 && kind != S_LPROC32)
+ continue;
+
+ ProcSym proc =
+ llvm::cantFail(SymbolDeserializer::deserializeAs<ProcSym>(*iter));
+ if ((proc.Flags & ProcSymFlags::IsUnreachable) != ProcSymFlags::None)
+ continue;
+ if (proc.Name.empty())
+ continue;
+
+ // The function/procedure symbol only contains the demangled name.
+ // The mangled names are in the publics table. Save the address of this
+ // function to lookup the mangled name later.
+ addr_ids.emplace(std::make_pair(proc.Segment, proc.CodeOffset), gid);
+
+ llvm::StringRef basename = MSVCUndecoratedNameParser::DropScope(proc.Name);
+ if (basename.empty())
+ basename = proc.Name;
+
+ m_func_base_names.Append(ConstString(basename), gid);
+ m_func_full_names.Append(ConstString(proc.Name), gid);
+
+ // To see if this is a member function, check the type
+ auto type = m_index->tpi().getType(proc.FunctionType);
+ if (type.kind() == LF_MFUNCTION) {
+ MemberFunctionRecord mfr;
+ llvm::cantFail(
+ TypeDeserializer::deserializeAs<MemberFunctionRecord>(type, mfr));
+ if (!mfr.getThisType().isNoneType())
+ m_func_method_names.Append(ConstString(basename), gid);
+ }
+ }
+
+ // The publics stream contains all mangled function names and their address.
+ for (auto pid : m_index->publics().getPublicsTable()) {
+ PdbGlobalSymId global{pid, true};
+ CVSymbol sym = m_index->ReadSymbolRecord(global);
+ auto kind = sym.kind();
+ if (kind != S_PUB32)
+ continue;
+ PublicSym32 pub =
+ llvm::cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(sym));
+ // We only care about mangled names - if the name isn't mangled, it's
+ // already in the full name map
+ if (!Mangled::IsMangledName(pub.Name))
+ continue;
+
+ // Check if this symbol is for one of our functions
+ auto it = addr_ids.find({pub.Segment, pub.Offset});
+ if (it != addr_ids.end())
+ m_func_full_names.Append(ConstString(pub.Name), it->second);
+ }
+
+ // Sort them before value searching is working properly
+ m_func_full_names.Sort();
+ m_func_full_names.SizeToFit();
+ m_func_method_names.Sort();
+ m_func_method_names.SizeToFit();
+ m_func_base_names.Sort();
+ m_func_base_names.SizeToFit();
+}
+
void SymbolFileNativePDB::FindGlobalVariables(
ConstString name, const CompilerDeclContext &parent_decl_ctx,
uint32_t max_matches, VariableList &variables) {
@@ -1677,34 +1766,56 @@ void SymbolFileNativePDB::FindFunctions(
if (name_type_mask & eFunctionNameTypeFull)
name = lookup_info.GetName();
- // For now we only support lookup by method name or full name.
if (!(name_type_mask & eFunctionNameTypeFull ||
+ name_type_mask & eFunctionNameTypeBase ||
name_type_mask & eFunctionNameTypeMethod))
return;
+ CacheFunctionNames();
- using SymbolAndOffset = std::pair<uint32_t, llvm::codeview::CVSymbol>;
+ std::set<uint32_t> resolved_ids; // avoid duplicate lookups
+ auto resolve_from = [&](UniqueCStringMap<uint32_t> &Names) {
+ std::vector<uint32_t> ids;
+ if (!Names.GetValues(name, ids))
+ return;
- std::vector<SymbolAndOffset> matches = m_index->globals().findRecordsByName(
- name.GetStringRef(), m_index->symrecords());
- for (const SymbolAndOffset &match : matches) {
- if (match.second.kind() != S_PROCREF && match.second.kind() != S_LPROCREF)
- continue;
- ProcRefSym proc(match.second.kind());
- cantFail(SymbolDeserializer::deserializeAs<ProcRefSym>(match.second, proc));
+ for (uint32_t id : ids) {
+ if (resolved_ids.find(id) != resolved_ids.end())
+ continue;
- if (!IsValidRecord(proc))
- continue;
+ PdbGlobalSymId global{id, false};
+ if (parent_decl_ctx.IsValid() &&
+ GetDeclContextContainingUID(toOpaqueUid(global)) != parent_decl_ctx)
+ continue;
- CompilandIndexItem &cci =
- m_index->compilands().GetOrCreateCompiland(proc.modi());
- SymbolContext sc;
+ CVSymbol sym = m_index->ReadSymbolRecord(global);
+ auto kind = sym.kind();
+ lldbassert(kind == S_PROCREF || kind == S_LPROCREF);
- sc.comp_unit = GetOrCreateCompileUnit(cci).get();
- PdbCompilandSymId func_id(proc.modi(), proc.SymOffset);
- sc.function = GetOrCreateFunction(func_id, *sc.comp_unit).get();
+ ProcRefSym proc =
+ cantFail(SymbolDeserializer::deserializeAs<ProcRefSym>(sym));
- sc_list.Append(sc);
- }
+ if (!IsValidRecord(proc))
+ continue;
+
+ CompilandIndexItem &cci =
+ m_index->compilands().GetOrCreateCompiland(proc.modi());
+ SymbolContext sc;
+
+ sc.comp_unit = GetOrCreateCompileUnit(cci).get();
+ PdbCompilandSymId func_id(proc.modi(), proc.SymOffset);
+ sc.function = GetOrCreateFunction(func_id, *sc.comp_unit).get();
+
+ sc_list.Append(sc);
+ resolved_ids.insert(id);
+ }
+ };
+
+ if (name_type_mask & eFunctionNameTypeFull)
+ resolve_from(m_func_full_names);
+ if (name_type_mask & eFunctionNameTypeBase)
+ resolve_from(m_func_base_names);
+ if (name_type_mask & eFunctionNameTypeMethod)
+ resolve_from(m_func_method_names);
}
void SymbolFileNativePDB::FindFunctions(const RegularExpression ®ex,
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
index eda375d4cebe7..e505f3f522fb7 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -260,6 +260,8 @@ class SymbolFileNativePDB : public SymbolFileCommon {
std::vector<CompilerContext> GetContextForType(llvm::codeview::TypeIndex ti);
+ void CacheFunctionNames();
+
llvm::BumpPtrAllocator m_allocator;
lldb::addr_t m_obj_load_address = 0;
@@ -282,6 +284,13 @@ class SymbolFileNativePDB : public SymbolFileCommon {
m_parent_types;
lldb_private::UniqueCStringMap<uint32_t> m_type_base_names;
+
+ /// Global ID -> mangled name/full function name
+ lldb_private::UniqueCStringMap<uint32_t> m_func_full_names;
+ /// Global ID -> basename
+ lldb_private::UniqueCStringMap<uint32_t> m_func_base_names;
+ /// Global ID -> method basename
+ lldb_private::UniqueCStringMap<uint32_t> m_func_method_names;
};
} // namespace npdb
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/find-functions.cpp b/lldb/test/Shell/SymbolFile/NativePDB/find-functions.cpp
index 5ebef61bdbfef..9bea463199829 100644
--- a/lldb/test/Shell/SymbolFile/NativePDB/find-functions.cpp
+++ b/lldb/test/Shell/SymbolFile/NativePDB/find-functions.cpp
@@ -6,24 +6,52 @@
// RUN: lldb-test symbols --find=function --name=main --function-flags=full %t.exe \
// RUN: | FileCheck %s --check-prefix=FIND-MAIN
+// RUN: lldb-test symbols --find=function --name=main --function-flags=method %t.exe \
+// RUN: | FileCheck %s --check-prefix=FIND-NO-FUNCTION
+// RUN: lldb-test symbols --find=function --name=main --function-flags=base %t.exe \
+// RUN: | FileCheck %s --check-prefix=FIND-MAIN
// RUN: lldb-test symbols --find=function --name=static_fn --function-flags=full %t.exe \
// RUN: | FileCheck %s --check-prefix=FIND-STATIC
+// RUN: lldb-test symbols --find=function --name=static_fn --function-flags=method %t.exe \
+// RUN: | FileCheck %s --check-prefix=FIND-NO-FUNCTION
+// RUN: lldb-test symbols --find=function --name=static_fn --function-flags=base %t.exe \
+// RUN: | FileCheck %s --check-prefix=FIND-STATIC
// RUN: lldb-test symbols --find=function --name=varargs_fn --function-flags=full %t.exe \
// RUN: | FileCheck %s --check-prefix=FIND-VAR
+// RUN: lldb-test symbols --find=function --name=varargs_fn --function-flags=method %t.exe \
+// RUN: | FileCheck %s --check-prefix=FIND-NO-FUNCTION
+// RUN: lldb-test symbols --find=function --name=varargs_fn --function-flags=base %t.exe \
+// RUN: | FileCheck %s --check-prefix=FIND-VAR
// RUN: lldb-test symbols --find=function --name=Struct::simple_method --function-flags=full %t.exe \
// RUN: | FileCheck %s --check-prefix=FIND-SIMPLE
+// RUN: lldb-test symbols --find=function --name=Struct::simple_method --function-flags=method %t.exe \
+// RUN: | FileCheck %s --check-prefix=FIND-SIMPLE
+// RUN: lldb-test symbols --find=function --name=Struct::simple_method --function-flags=base %t.exe \
+// RUN: | FileCheck %s --check-prefix=FIND-SIMPLE
// RUN: lldb-test symbols --find=function --name=Struct::virtual_method --function-flags=full %t.exe \
// RUN: | FileCheck %s --check-prefix=FIND-VIRTUAL
+// RUN: lldb-test symbols --find=function --name=Struct::virtual_method --function-flags=method %t.exe \
+// RUN: | FileCheck %s --check-prefix=FIND-VIRTUAL
+// RUN: lldb-test symbols --find=function --name=Struct::virtual_method --function-flags=base %t.exe \
+// RUN: | FileCheck %s --check-prefix=FIND-VIRTUAL
// RUN: lldb-test symbols --find=function --name=Struct::static_method --function-flags=full %t.exe \
// RUN: | FileCheck %s --check-prefix=FIND-STATIC-METHOD
+// RUN: lldb-test symbols --find=function --name=Struct::static_method --function-flags=method %t.exe \
+// RUN: | FileCheck %s --check-prefix=FIND-NO-FUNCTION
+// RUN: lldb-test symbols --find=function --name=Struct::static_method --function-flags=base %t.exe \
+// RUN: | FileCheck %s --check-prefix=FIND-STATIC-METHOD
// RUN: lldb-test symbols --find=function --name=Struct::overloaded_method --function-flags=full %t.exe \
// RUN: | FileCheck %s --check-prefix=FIND-OVERLOAD
+// RUN: lldb-test symbols --find=function --name=Struct::overloaded_method --function-flags=method %t.exe \
+// RUN: | FileCheck %s --check-prefix=FIND-OVERLOAD-METHOD
+// RUN: lldb-test symbols --find=function --name=Struct::overloaded_method --function-flags=base %t.exe \
+// RUN: | FileCheck %s --check-prefix=FIND-OVERLOAD
struct Struct {
int simple_method() {
@@ -69,6 +97,8 @@ int main(int argc, char **argv) {
// FIND-MAIN: Function: id = {{.*}}, name = "main"
// FIND-MAIN-NEXT: FuncType: id = {{.*}}, compiler_type = "int (int, char **)"
+// FIND-NO-FUNCTION: Found 0 functions
+
// FIND-STATIC: Function: id = {{.*}}, name = "{{.*}}static_fn{{.*}}"
// FIND-STATIC-NEXT: FuncType: id = {{.*}}, compiler_type = "int (void)"
@@ -88,3 +118,7 @@ int main(int argc, char **argv) {
// FIND-OVERLOAD: FuncType: id = {{.*}}, compiler_type = "int (void)"
// FIND-OVERLOAD: FuncType: id = {{.*}}, compiler_type = "int (char)"
// FIND-OVERLOAD: FuncType: id = {{.*}}, compiler_type = "int (char, int, ...)"
+
+// FIND-OVERLOAD-METHOD: Function: id = {{.*}}, name = "{{.*}}Struct::overloaded_method{{.*}}"
+// FIND-OVERLOAD-METHOD: FuncType: id = {{.*}}, compiler_type = "int (void)"
+// FIND-OVERLOAD-METHOD: FuncType: id = {{.*}}, compiler_type = "int (char)"
>From f342ea17b1faed05c21b5f63079855decb44eb61 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Thu, 7 Aug 2025 10:53:28 +0200
Subject: [PATCH 2/5] fix: use return value of `insert()`
---
.../Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index 04a3b9b7b87a2..f1cce10b11392 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -1779,7 +1779,7 @@ void SymbolFileNativePDB::FindFunctions(
return;
for (uint32_t id : ids) {
- if (resolved_ids.find(id) != resolved_ids.end())
+ if (!resolved_ids.insert(id).second)
continue;
PdbGlobalSymId global{id, false};
@@ -1806,7 +1806,6 @@ void SymbolFileNativePDB::FindFunctions(
sc.function = GetOrCreateFunction(func_id, *sc.comp_unit).get();
sc_list.Append(sc);
- resolved_ids.insert(id);
}
};
>From 24808f90eecb70ffd3676d0f9b27a2aff0174bcd Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Thu, 7 Aug 2025 10:53:46 +0200
Subject: [PATCH 3/5] fix: check for nullptr
---
.../Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index f1cce10b11392..de06856d15c55 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -1802,8 +1802,13 @@ void SymbolFileNativePDB::FindFunctions(
SymbolContext sc;
sc.comp_unit = GetOrCreateCompileUnit(cci).get();
+ if (!sc.comp_unit)
+ continue;
+
PdbCompilandSymId func_id(proc.modi(), proc.SymOffset);
sc.function = GetOrCreateFunction(func_id, *sc.comp_unit).get();
+ if (!sc.function)
+ continue;
sc_list.Append(sc);
}
>From b88192f63722018afcd9fe7272ea91363ec800c0 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Thu, 7 Aug 2025 10:54:03 +0200
Subject: [PATCH 4/5] fix: comments for class fields
---
.../Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
index e505f3f522fb7..6bbeb8bb14428 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -285,11 +285,11 @@ class SymbolFileNativePDB : public SymbolFileCommon {
lldb_private::UniqueCStringMap<uint32_t> m_type_base_names;
- /// Global ID -> mangled name/full function name
+ /// mangled name/full function name -> Global ID(s)
lldb_private::UniqueCStringMap<uint32_t> m_func_full_names;
- /// Global ID -> basename
+ /// basename -> Global ID(s)
lldb_private::UniqueCStringMap<uint32_t> m_func_base_names;
- /// Global ID -> method basename
+ /// method basename -> Global ID(s)
lldb_private::UniqueCStringMap<uint32_t> m_func_method_names;
};
>From 096b814abb2a4664a4c2cc0298746c59ea359587 Mon Sep 17 00:00:00 2001
From: nerix <nero.9 at hotmail.de>
Date: Fri, 8 Aug 2025 21:18:53 +0200
Subject: [PATCH 5/5] Update
lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
Co-authored-by: Jonas Devlieghere <jonas at devlieghere.com>
---
.../source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index de06856d15c55..75703345692d3 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -1721,7 +1721,7 @@ void SymbolFileNativePDB::CacheFunctionNames() {
m_func_full_names.Append(ConstString(pub.Name), it->second);
}
- // Sort them before value searching is working properly
+ // Sort them before value searching is working properly.
m_func_full_names.Sort();
m_func_full_names.SizeToFit();
m_func_method_names.Sort();
More information about the lldb-commits
mailing list