[Lldb-commits] [lldb] [lldb][NativePDB] Route expression function calls through FunctionCallLabel (PR #227021)
Charles Zablit via lldb-commits
lldb-commits at lists.llvm.org
Fri Oct 2 08:58:35 PDT 2026
================
@@ -3182,6 +3163,149 @@ SymbolFileNativePDB::StripMangledFunctionName(const llvm::StringRef mangled,
return mangled;
}
+std::optional<std::string>
+SymbolFileNativePDB::MakeFunctionCallLabel(PdbSymUid uid,
+ llvm::StringRef lookup_name) {
+ if (lookup_name.empty())
+ return std::nullopt;
+
+ lldb::ModuleSP module_sp = m_objfile_sp->GetModule();
+ if (!module_sp)
+ return std::nullopt;
+
+ return FunctionCallLabel{/*discriminator=*/{},
+ /*module_id=*/module_sp->GetID(),
+ /*symbol_id=*/uid.toOpaqueId(),
+ /*lookup_name=*/lookup_name}
+ .toString();
+}
+
+std::optional<std::string>
+SymbolFileNativePDB::GetFunctionCallLabel(PdbCompilandSymId id) {
+ const CompilandIndexItem *cci = m_index->compilands().GetCompiland(id.modi);
+ if (!cci)
+ return std::nullopt;
+
+ CVSymbol sym_record = cci->m_debug_stream.readSymbolAtOffset(id.offset);
+ if (sym_record.kind() != S_LPROC32 && sym_record.kind() != S_GPROC32)
+ return std::nullopt;
+
+ ProcSym proc(static_cast<SymbolRecordKind>(sym_record.kind()));
+ if (auto err = SymbolDeserializer::deserializeAs<ProcSym>(sym_record, proc)) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), std::move(err),
+ "Failed to deserialize ProcSym record: {0}");
+ return std::nullopt;
+ }
+
+ // Functions with internal linkage have no public symbol, so fall back to the
+ // name in the procedure record.
+ llvm::StringRef lookup_name =
+ FindMangledSymbol(SegmentOffset(proc.Segment, proc.CodeOffset),
+ proc.FunctionType)
+ .value_or(proc.Name);
+ return MakeFunctionCallLabel(id, lookup_name);
+}
+
+std::optional<std::string>
+SymbolFileNativePDB::GetMethodCallLabel(TypeIndex method_type,
+ llvm::StringRef qualified_name) {
+ if (std::optional<PdbCompilandSymId> func_id =
+ FindMethodDefinition(qualified_name, method_type))
+ return GetFunctionCallLabel(*func_id);
+ return std::nullopt;
+}
+
+std::optional<PdbCompilandSymId>
+SymbolFileNativePDB::FindMethodDefinition(llvm::StringRef qualified_name,
+ TypeIndex method_type) {
+ CacheGlobalBaseNames();
+
+ std::vector<uint32_t> ids;
+ m_func_full_names.GetValues(ConstString(qualified_name), ids);
+
+ for (uint32_t id : ids) {
+ CVSymbol sym = m_index->ReadSymbolRecord(PdbGlobalSymId{id, false});
+ if (sym.kind() != S_PROCREF && sym.kind() != S_LPROCREF)
+ continue;
+ auto ref_or_err = SymbolDeserializer::deserializeAs<ProcRefSym>(sym);
+ if (!ref_or_err) {
+ llvm::consumeError(ref_or_err.takeError());
+ continue;
+ }
+
+ PdbCompilandSymId func_id(ref_or_err->modi(), ref_or_err->SymOffset);
+ CVSymbol func_sym = m_index->ReadSymbolRecord(func_id);
+ if (func_sym.kind() != S_GPROC32 && func_sym.kind() != S_LPROC32)
+ continue;
+ auto proc_or_err = SymbolDeserializer::deserializeAs<ProcSym>(func_sym);
+ if (!proc_or_err) {
+ llvm::consumeError(proc_or_err.takeError());
+ continue;
+ }
+
+ // Overloads share the name, so only the type identifies the definition.
+ if (proc_or_err->FunctionType == method_type)
+ return func_id;
+ }
+ return std::nullopt;
+}
+
+/// Returns true if \p discriminator names a structor variant that is the
+/// function described by the procedure record.
+///
+/// In the Microsoft ABI, complete and base object structors share one
+/// definition, while closures and deleting destructors are separate functions
+/// without debug info.
+static bool IsDefinedStructorVariant(llvm::StringRef discriminator) {
+ if (discriminator.empty())
+ return true;
+
+ const bool is_ctor = discriminator.consume_front("C");
+ if (!is_ctor && !discriminator.consume_front("D"))
+ return false;
+
+ uint64_t kind;
+ if (!llvm::to_integer(discriminator, kind))
+ return false;
+
+ if (is_ctor)
+ return kind == clang::CXXCtorType::Ctor_Complete ||
+ kind == clang::CXXCtorType::Ctor_Base;
+ return kind == clang::CXXDtorType::Dtor_Complete ||
+ kind == clang::CXXDtorType::Dtor_Base;
+}
+
+llvm::Expected<SymbolContext>
+SymbolFileNativePDB::ResolveFunctionCallLabel(FunctionCallLabel &label) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+
+ if (!IsDefinedStructorVariant(label.discriminator))
----------------
charles-zablit wrote:
Clang fills it in when it mangles the label of a structor. I added a clarifying comment.
https://github.com/llvm/llvm-project/blob/fe1de64cb3c255ecf6f035ca3562c4550479f632/clang/lib/AST/Mangle.cpp#L227
https://github.com/llvm/llvm-project/pull/227021
More information about the lldb-commits
mailing list